From 67c022184e556cea0247e86a26481e2594fe1f63 Mon Sep 17 00:00:00 2001 From: Rupert Carmichael <5050061-carmiker@users.noreply.gitlab.com> Date: Tue, 9 Jun 2020 18:47:51 -0400 Subject: [PATCH] Initial Public Release --- .gitignore | 4 + COPYING | 674 + Database/BS Memory.bml | 44 + Database/Cheat Codes.bml | 87497 ++++++++++++++++ Database/Sufami Turbo.bml | 213 + Database/Super Famicom.bml | 16069 +++ Database/boards.bml | 962 + Database/ipl.rom | Bin 0 -> 64 bytes LICENSE | 41 + Makefile | 123 + emulator/audio/audio.cpp | 73 + emulator/audio/audio.hpp | 94 + emulator/audio/stream.cpp | 125 + emulator/cheat.hpp | 57 + emulator/emulator.cpp | 8 + emulator/emulator.hpp | 58 + emulator/game.hpp | 112 + emulator/interface.hpp | 109 + emulator/memory/memory.hpp | 30 + emulator/memory/readable.hpp | 63 + emulator/memory/writable.hpp | 65 + emulator/platform.hpp | 29 + emulator/random.hpp | 96 + emulator/types.hpp | 72 + filter/2xsai.cpp | 25 + filter/filter.cpp | 25 + filter/filter.hpp | 129 + filter/hq2x.cpp | 200 + filter/lq2x.cpp | 46 + filter/none.cpp | 24 + filter/ntsc-composite.cpp | 50 + filter/ntsc-rf.cpp | 50 + filter/ntsc-rgb.cpp | 50 + filter/ntsc-svideo.cpp | 50 + filter/pixellate2x.cpp | 40 + filter/sai/sai.cpp | 1175 + filter/scale2x.cpp | 46 + filter/scanlines-black.cpp | 28 + filter/scanlines-dark.cpp | 48 + filter/scanlines-light.cpp | 48 + filter/snes_ntsc/snes_ntsc.c | 251 + filter/snes_ntsc/snes_ntsc.h | 228 + filter/snes_ntsc/snes_ntsc_config.h | 26 + filter/snes_ntsc/snes_ntsc_impl.h | 439 + filter/super-2xsai.cpp | 25 + filter/super-eagle.cpp | 25 + gb/Core/apu.c | 1040 + gb/Core/apu.h | 164 + gb/Core/camera.c | 149 + gb/Core/camera.h | 29 + gb/Core/debugger.c | 2459 + gb/Core/debugger.h | 43 + gb/Core/display.c | 1227 + gb/Core/display.h | 54 + gb/Core/gb.c | 1084 + gb/Core/gb.h | 725 + gb/Core/gb_struct_def.h | 5 + gb/Core/joypad.c | 92 + gb/Core/joypad.h | 25 + gb/Core/mbc.c | 154 + gb/Core/mbc.h | 32 + gb/Core/memory.c | 1015 + gb/Core/memory.h | 18 + gb/Core/printer.c | 216 + gb/Core/printer.h | 63 + gb/Core/random.c | 38 + gb/Core/random.h | 12 + gb/Core/rewind.c | 208 + gb/Core/rewind.h | 14 + gb/Core/save_state.c | 377 + gb/Core/save_state.h | 24 + gb/Core/sgb.c | 842 + gb/Core/sgb.h | 66 + gb/Core/sgb_animation_logo.inc | 563 + gb/Core/sgb_border.inc | 658 + gb/Core/sm83_cpu.c | 1521 + gb/Core/sm83_cpu.h | 11 + gb/Core/sm83_disassembler.c | 788 + gb/Core/symbol_hash.c | 110 + gb/Core/symbol_hash.h | 38 + gb/Core/timing.c | 294 + gb/Core/timing.h | 44 + gb/LICENSE | 21 + gb/README | 5 + heuristics/bs-memory.cpp | 33 + heuristics/game-boy.cpp | 298 + heuristics/heuristics.cpp | 34 + heuristics/heuristics.hpp | 37 + heuristics/sufami-turbo.cpp | 39 + heuristics/super-famicom.cpp | 605 + jg.cpp | 914 + libco/aarch64.c | 109 + libco/amd64.c | 165 + libco/arm.c | 84 + libco/doc/style.css | 12 + libco/doc/targets.html | 89 + libco/doc/usage.html | 108 + libco/fiber.c | 55 + libco/libco.c | 37 + libco/libco.h | 28 + libco/ppc.c | 431 + libco/ppc64v2.c | 279 + libco/settings.h | 38 + libco/sjlj.c | 145 + libco/ucontext.c | 86 + libco/x86.c | 119 + lzma/7z.h | 202 + lzma/7zAlloc.c | 80 + lzma/7zAlloc.h | 19 + lzma/7zArcIn.c | 1771 + lzma/7zBuf.c | 36 + lzma/7zBuf.h | 35 + lzma/7zBuf2.c | 52 + lzma/7zCrc.c | 128 + lzma/7zCrc.h | 25 + lzma/7zCrcOpt.c | 115 + lzma/7zDec.c | 591 + lzma/7zFile.c | 286 + lzma/7zFile.h | 83 + lzma/7zStream.c | 176 + lzma/7zTypes.h | 375 + lzma/7zVersion.h | 27 + lzma/7zVersion.rc | 55 + lzma/Aes.c | 306 + lzma/Aes.h | 38 + lzma/AesOpt.c | 184 + lzma/Alloc.c | 455 + lzma/Alloc.h | 51 + lzma/Bcj2.c | 257 + lzma/Bcj2.h | 146 + lzma/Bcj2Enc.c | 311 + lzma/Bra.c | 230 + lzma/Bra.h | 64 + lzma/Bra86.c | 82 + lzma/BraIA64.c | 53 + lzma/Compiler.h | 33 + lzma/CpuArch.c | 218 + lzma/CpuArch.h | 336 + lzma/Delta.c | 64 + lzma/Delta.h | 19 + lzma/DllSecur.c | 108 + lzma/DllSecur.h | 20 + lzma/LzFind.c | 1127 + lzma/LzFind.h | 121 + lzma/LzFindMt.c | 853 + lzma/LzFindMt.h | 101 + lzma/LzHash.h | 57 + lzma/Lzma2Dec.c | 488 + lzma/Lzma2Dec.h | 120 + lzma/Lzma2DecMt.c | 1082 + lzma/Lzma2DecMt.h | 79 + lzma/Lzma2Enc.c | 803 + lzma/Lzma2Enc.h | 55 + lzma/Lzma86.h | 111 + lzma/Lzma86Dec.c | 54 + lzma/Lzma86Enc.c | 106 + lzma/LzmaDec.c | 1185 + lzma/LzmaDec.h | 234 + lzma/LzmaEnc.c | 2976 + lzma/LzmaEnc.h | 76 + lzma/LzmaLib.c | 40 + lzma/LzmaLib.h | 131 + lzma/MtCoder.c | 601 + lzma/MtCoder.h | 141 + lzma/MtDec.c | 1138 + lzma/MtDec.h | 201 + lzma/Ppmd.h | 85 + lzma/Ppmd7.c | 712 + lzma/Ppmd7.h | 142 + lzma/Ppmd7Dec.c | 191 + lzma/Ppmd7Enc.c | 187 + lzma/Precomp.h | 10 + lzma/RotateDefs.h | 30 + lzma/Sha256.c | 248 + lzma/Sha256.h | 26 + lzma/Sort.c | 141 + lzma/Sort.h | 18 + lzma/Threads.c | 95 + lzma/Threads.h | 68 + lzma/Xz.c | 90 + lzma/Xz.h | 460 + lzma/XzCrc64.c | 86 + lzma/XzCrc64.h | 26 + lzma/XzCrc64Opt.c | 69 + lzma/XzDec.c | 2766 + lzma/XzEnc.c | 1329 + lzma/XzEnc.h | 60 + lzma/XzIn.c | 319 + lzma/lzma.cpp | 81 + lzma/lzma.hpp | 7 + nall/adaptive-array.hpp | 64 + nall/algorithm.hpp | 26 + nall/any.hpp | 83 + nall/arguments.hpp | 161 + nall/arithmetic.hpp | 89 + nall/arithmetic/barrett.hpp | 28 + nall/arithmetic/natural.hpp | 342 + nall/arithmetic/unsigned.hpp | 61 + nall/array-span.hpp | 92 + nall/array-view.hpp | 138 + nall/array.hpp | 89 + nall/atoi.hpp | 87 + nall/beat/archive/container.hpp | 200 + nall/beat/archive/create.hpp | 86 + nall/beat/archive/extract.hpp | 27 + nall/beat/archive/node.hpp | 332 + nall/beat/single/apply.hpp | 88 + nall/beat/single/create.hpp | 99 + nall/bit.hpp | 85 + nall/cd.hpp | 31 + nall/cd/crc16.hpp | 18 + nall/cd/edc.hpp | 65 + nall/cd/efm.hpp | 68 + nall/cd/rspc.hpp | 128 + nall/cd/scrambler.hpp | 35 + nall/cd/session.hpp | 478 + nall/cd/sync.hpp | 27 + nall/chrono.hpp | 183 + nall/cipher/chacha20.hpp | 109 + nall/counting-sort.hpp | 19 + nall/database/odbc.hpp | 299 + nall/database/sqlite3.hpp | 218 + nall/decode/base.hpp | 37 + nall/decode/base64.hpp | 47 + nall/decode/bmp.hpp | 76 + nall/decode/bwt.hpp | 47 + nall/decode/gzip.hpp | 78 + nall/decode/html.hpp | 40 + nall/decode/huffman.hpp | 36 + nall/decode/inflate.hpp | 349 + nall/decode/lzsa.hpp | 72 + nall/decode/mtf.hpp | 25 + nall/decode/png.hpp | 332 + nall/decode/rle.hpp | 44 + nall/decode/url.hpp | 39 + nall/decode/zip.hpp | 136 + nall/directory.hpp | 348 + nall/dl.hpp | 126 + nall/dsp/dsp.hpp | 5 + nall/dsp/iir/biquad.hpp | 164 + nall/dsp/iir/dc-removal.hpp | 29 + nall/dsp/iir/one-pole.hpp | 46 + nall/dsp/resampler/cubic.hpp | 84 + nall/elliptic-curve/curve25519.hpp | 57 + nall/elliptic-curve/ed25519.hpp | 144 + nall/elliptic-curve/modulo25519-optimized.hpp | 218 + nall/elliptic-curve/modulo25519-reference.hpp | 84 + nall/emulation/21fx.hpp | 140 + nall/encode/base.hpp | 38 + nall/encode/base64.hpp | 68 + nall/encode/bmp.hpp | 47 + nall/encode/bwt.hpp | 86 + nall/encode/html.hpp | 18 + nall/encode/huffman.hpp | 84 + nall/encode/lzsa.hpp | 86 + nall/encode/mtf.hpp | 30 + nall/encode/rle.hpp | 56 + nall/encode/url.hpp | 27 + nall/encode/wav.hpp | 52 + nall/encode/zip.hpp | 101 + nall/endian.hpp | 43 + nall/file-buffer.hpp | 249 + nall/file-map.hpp | 225 + nall/file.hpp | 104 + nall/function.hpp | 78 + nall/galois-field.hpp | 70 + nall/hash/crc16.hpp | 55 + nall/hash/crc32.hpp | 55 + nall/hash/crc64.hpp | 55 + nall/hash/hash.hpp | 47 + nall/hash/sha224.hpp | 106 + nall/hash/sha256.hpp | 106 + nall/hash/sha384.hpp | 119 + nall/hash/sha512.hpp | 119 + nall/hashset.hpp | 133 + nall/hid.hpp | 121 + nall/http/client.hpp | 56 + nall/http/message.hpp | 104 + nall/http/request.hpp | 184 + nall/http/response.hpp | 273 + nall/http/role.hpp | 158 + nall/http/server.hpp | 226 + nall/image.hpp | 169 + nall/image/blend.hpp | 71 + nall/image/core.hpp | 173 + nall/image/fill.hpp | 84 + nall/image/interpolation.hpp | 62 + nall/image/load.hpp | 99 + nall/image/scale.hpp | 177 + nall/image/static.hpp | 28 + nall/image/utility.hpp | 179 + nall/induced-sort.hpp | 176 + nall/inline-if.hpp | 11 + nall/inode.hpp | 163 + nall/instance.hpp | 39 + nall/interpolation.hpp | 56 + nall/intrinsics.hpp | 174 + nall/iterator.hpp | 79 + nall/literals.hpp | 20 + nall/locale.hpp | 87 + nall/location.hpp | 78 + nall/mac/poly1305.hpp | 122 + nall/macos/guard.hpp | 15 + nall/main.hpp | 42 + nall/map.hpp | 58 + nall/matrix-multiply.hpp | 36 + nall/matrix.hpp | 213 + nall/maybe.hpp | 91 + nall/memory.hpp | 163 + nall/merge-sort.hpp | 82 + nall/nall.hpp | 101 + nall/path.hpp | 155 + nall/platform.hpp | 124 + nall/pointer.hpp | 34 + nall/posix/service.hpp | 114 + nall/posix/shared-memory.hpp | 147 + nall/primitives.hpp | 26 + nall/primitives/bit-field.hpp | 124 + nall/primitives/bit-range.hpp | 255 + nall/primitives/boolean.hpp | 30 + nall/primitives/integer.hpp | 86 + nall/primitives/literals.hpp | 143 + nall/primitives/natural.hpp | 84 + nall/primitives/real.hpp | 39 + nall/primitives/types.hpp | 45 + nall/property.hpp | 13 + nall/queue.hpp | 113 + nall/random.hpp | 168 + nall/range.hpp | 51 + nall/reed-solomon.hpp | 218 + nall/run.hpp | 214 + nall/serial.hpp | 113 + nall/serializer.hpp | 201 + nall/service.hpp | 13 + nall/set.hpp | 266 + nall/shared-memory.hpp | 12 + nall/shared-pointer.hpp | 291 + nall/simd.hpp | 11 + nall/smtp.hpp | 314 + nall/stdint.hpp | 65 + nall/string.hpp | 366 + nall/string/allocator/adaptive.hpp | 123 + nall/string/allocator/copy-on-write.hpp | 92 + .../allocator/small-string-optimization.hpp | 95 + nall/string/allocator/vector.hpp | 84 + nall/string/atoi.hpp | 25 + nall/string/cast.hpp | 288 + nall/string/compare.hpp | 58 + nall/string/convert.hpp | 53 + nall/string/core.hpp | 75 + nall/string/eval/evaluator.hpp | 146 + nall/string/eval/literal.hpp | 99 + nall/string/eval/node.hpp | 37 + nall/string/eval/parser.hpp | 164 + nall/string/find.hpp | 65 + nall/string/format.hpp | 138 + nall/string/markup/bml.hpp | 189 + nall/string/markup/find.hpp | 137 + nall/string/markup/node.hpp | 147 + nall/string/markup/xml.hpp | 217 + nall/string/match.hpp | 90 + nall/string/pascal.hpp | 79 + nall/string/replace.hpp | 94 + nall/string/split.hpp | 41 + nall/string/transform/cml.hpp | 120 + nall/string/transform/dml.hpp | 346 + nall/string/trim.hpp | 102 + nall/string/utf8.hpp | 32 + nall/string/utility.hpp | 165 + nall/string/vector.hpp | 60 + nall/string/view.hpp | 89 + nall/suffix-array.hpp | 386 + nall/terminal.hpp | 65 + nall/thread.hpp | 137 + nall/traits.hpp | 47 + nall/unique-pointer.hpp | 106 + nall/utility.hpp | 29 + nall/variant.hpp | 148 + nall/varint.hpp | 122 + nall/vector.hpp | 156 + nall/vector/access.hpp | 47 + nall/vector/assign.hpp | 28 + nall/vector/compare.hpp | 18 + nall/vector/core.hpp | 50 + nall/vector/iterator.hpp | 57 + nall/vector/memory.hpp | 147 + nall/vector/modify.hpp | 137 + nall/vector/specialization/uint8_t.hpp | 38 + nall/vector/utility.hpp | 47 + nall/vfs.hpp | 3 + nall/vfs/fs/file.hpp | 51 + nall/vfs/memory/file.hpp | 67 + nall/vfs/vfs.hpp | 71 + nall/view.hpp | 7 + nall/windows/detour.hpp | 189 + nall/windows/guard.hpp | 34 + nall/windows/guid.hpp | 17 + nall/windows/launcher.hpp | 91 + nall/windows/registry.hpp | 119 + nall/windows/service.hpp | 13 + nall/windows/shared-memory.hpp | 27 + nall/windows/utf8.hpp | 86 + nall/xorg/clipboard.hpp | 14 + nall/xorg/guard.hpp | 51 + nall/xorg/xorg.hpp | 18 + processor/arm7tdmi/algorithms.cpp | 96 + processor/arm7tdmi/arm7tdmi.cpp | 30 + processor/arm7tdmi/arm7tdmi.hpp | 285 + processor/arm7tdmi/disassembler.cpp | 413 + processor/arm7tdmi/instruction.cpp | 544 + processor/arm7tdmi/instructions-arm.cpp | 314 + processor/arm7tdmi/instructions-thumb.cpp | 225 + processor/arm7tdmi/memory.cpp | 40 + processor/arm7tdmi/registers.cpp | 58 + processor/arm7tdmi/serialization.cpp | 71 + processor/gsu/disassembler.cpp | 268 + processor/gsu/gsu.cpp | 39 + processor/gsu/gsu.hpp | 85 + processor/gsu/instruction.cpp | 94 + processor/gsu/instructions.cpp | 424 + processor/gsu/registers.hpp | 164 + processor/gsu/serialization.cpp | 56 + processor/hg51b/hg51b.cpp | 125 + processor/hg51b/hg51b.hpp | 182 + processor/hg51b/instruction.cpp | 639 + processor/hg51b/instructions.cpp | 350 + processor/hg51b/registers.cpp | 106 + processor/hg51b/serialization.cpp | 57 + processor/processor.hpp | 3 + processor/spc700/algorithms.cpp | 130 + processor/spc700/disassembler.cpp | 305 + processor/spc700/instruction.cpp | 266 + processor/spc700/instructions.cpp | 592 + processor/spc700/memory.cpp | 19 + processor/spc700/serialization.cpp | 17 + processor/spc700/spc700.cpp | 62 + processor/spc700/spc700.hpp | 164 + processor/upd96050/disassembler.cpp | 192 + processor/upd96050/instructions.cpp | 245 + processor/upd96050/memory.cpp | 64 + processor/upd96050/serialization.cpp | 51 + processor/upd96050/upd96050.cpp | 48 + processor/upd96050/upd96050.hpp | 128 + processor/wdc65816/algorithms.cpp | 363 + processor/wdc65816/disassembler.cpp | 474 + processor/wdc65816/instruction.cpp | 64 + processor/wdc65816/instruction.hpp | 258 + processor/wdc65816/instructions-modify.cpp | 93 + processor/wdc65816/instructions-other.cpp | 247 + processor/wdc65816/instructions-pc.cpp | 142 + processor/wdc65816/instructions-read.cpp | 209 + processor/wdc65816/instructions-write.cpp | 176 + processor/wdc65816/memory.cpp | 88 + processor/wdc65816/registers.hpp | 65 + processor/wdc65816/serialization.cpp | 33 + processor/wdc65816/wdc65816.cpp | 41 + processor/wdc65816/wdc65816.hpp | 288 + sfc/cartridge/cartridge.cpp | 161 + sfc/cartridge/cartridge.hpp | 126 + sfc/cartridge/load.cpp | 730 + sfc/cartridge/save.cpp | 190 + sfc/cartridge/serialization.cpp | 3 + sfc/controller/controller.cpp | 63 + sfc/controller/controller.hpp | 46 + sfc/controller/gamepad/gamepad.cpp | 48 + sfc/controller/gamepad/gamepad.hpp | 18 + sfc/controller/justifier/justifier.cpp | 162 + sfc/controller/justifier/justifier.hpp | 27 + sfc/controller/mouse/mouse.cpp | 86 + sfc/controller/mouse/mouse.hpp | 22 + .../super-multitap/super-multitap.cpp | 70 + .../super-multitap/super-multitap.hpp | 21 + sfc/controller/super-scope/super-scope.cpp | 133 + sfc/controller/super-scope/super-scope.hpp | 31 + sfc/coprocessor/armdsp/armdsp.cpp | 109 + sfc/coprocessor/armdsp/armdsp.hpp | 36 + sfc/coprocessor/armdsp/memory.cpp | 91 + sfc/coprocessor/armdsp/registers.hpp | 22 + sfc/coprocessor/armdsp/serialization.cpp | 25 + sfc/coprocessor/coprocessor.cpp | 26 + sfc/coprocessor/coprocessor.hpp | 26 + sfc/coprocessor/cx4/cx4.cpp | 191 + sfc/coprocessor/cx4/cx4.hpp | 90 + sfc/coprocessor/cx4/data.cpp | 187 + sfc/coprocessor/cx4/functions.cpp | 251 + sfc/coprocessor/cx4/oam.cpp | 228 + sfc/coprocessor/cx4/opcodes.cpp | 228 + sfc/coprocessor/cx4/serialization.cpp | 35 + sfc/coprocessor/dip/dip.cpp | 21 + sfc/coprocessor/dip/dip.hpp | 14 + sfc/coprocessor/dip/serialization.cpp | 3 + sfc/coprocessor/dsp1/dsp1.cpp | 48 + sfc/coprocessor/dsp1/dsp1.hpp | 10 + sfc/coprocessor/dsp1/dsp1emu.cpp | 1626 + sfc/coprocessor/dsp1/dsp1emu.hpp | 129 + sfc/coprocessor/dsp1/serialization.cpp | 52 + sfc/coprocessor/dsp2/dsp2.cpp | 136 + sfc/coprocessor/dsp2/dsp2.hpp | 38 + sfc/coprocessor/dsp2/opcodes.cpp | 177 + sfc/coprocessor/dsp2/serialization.cpp | 22 + sfc/coprocessor/dsp4/dsp4.cpp | 62 + sfc/coprocessor/dsp4/dsp4.hpp | 10 + sfc/coprocessor/dsp4/dsp4emu.c | 2150 + sfc/coprocessor/dsp4/dsp4emu.h | 108 + sfc/coprocessor/dsp4/serialization.cpp | 72 + sfc/coprocessor/epsonrtc/epsonrtc.cpp | 205 + sfc/coprocessor/epsonrtc/epsonrtc.hpp | 90 + sfc/coprocessor/epsonrtc/memory.cpp | 180 + sfc/coprocessor/epsonrtc/serialization.cpp | 53 + sfc/coprocessor/epsonrtc/time.cpp | 182 + sfc/coprocessor/event/event.cpp | 122 + sfc/coprocessor/event/event.hpp | 51 + sfc/coprocessor/event/serialization.cpp | 9 + sfc/coprocessor/hitachidsp/data-rom.cpp | 100 + sfc/coprocessor/hitachidsp/hitachidsp.cpp | 43 + sfc/coprocessor/hitachidsp/hitachidsp.hpp | 52 + sfc/coprocessor/hitachidsp/memory.cpp | 273 + sfc/coprocessor/hitachidsp/serialization.cpp | 16 + sfc/coprocessor/icd/boot-roms.cpp | 21 + sfc/coprocessor/icd/icd.cpp | 181 + sfc/coprocessor/icd/icd.hpp | 85 + sfc/coprocessor/icd/interface.cpp | 105 + sfc/coprocessor/icd/io.cpp | 81 + sfc/coprocessor/icd/serialization.cpp | 43 + sfc/coprocessor/mcc/mcc.cpp | 257 + sfc/coprocessor/mcc/mcc.hpp | 52 + sfc/coprocessor/mcc/serialization.cpp | 30 + sfc/coprocessor/msu1/msu1.cpp | 182 + sfc/coprocessor/msu1/msu1.hpp | 53 + sfc/coprocessor/msu1/serialization.cpp | 24 + sfc/coprocessor/necdsp/necdsp.cpp | 63 + sfc/coprocessor/necdsp/necdsp.hpp | 21 + sfc/coprocessor/necdsp/serialization.cpp | 25 + sfc/coprocessor/obc1/obc1.cpp | 70 + sfc/coprocessor/obc1/obc1.hpp | 23 + sfc/coprocessor/obc1/serialization.cpp | 7 + sfc/coprocessor/sa1/bwram.cpp | 121 + sfc/coprocessor/sa1/dma.cpp | 128 + sfc/coprocessor/sa1/io.cpp | 522 + sfc/coprocessor/sa1/iram.cpp | 36 + sfc/coprocessor/sa1/memory.cpp | 139 + sfc/coprocessor/sa1/rom.cpp | 71 + sfc/coprocessor/sa1/sa1.cpp | 314 + sfc/coprocessor/sa1/sa1.hpp | 287 + sfc/coprocessor/sa1/serialization.cpp | 143 + sfc/coprocessor/sdd1/decompressor.cpp | 286 + sfc/coprocessor/sdd1/decompressor.hpp | 95 + sfc/coprocessor/sdd1/sdd1.cpp | 132 + sfc/coprocessor/sdd1/sdd1.hpp | 39 + sfc/coprocessor/sdd1/serialization.cpp | 67 + sfc/coprocessor/sharprtc/memory.cpp | 67 + sfc/coprocessor/sharprtc/serialization.cpp | 14 + sfc/coprocessor/sharprtc/sharprtc.cpp | 134 + sfc/coprocessor/sharprtc/sharprtc.hpp | 46 + sfc/coprocessor/sharprtc/time.cpp | 83 + sfc/coprocessor/spc7110/alu.cpp | 83 + sfc/coprocessor/spc7110/data.cpp | 58 + sfc/coprocessor/spc7110/dcu.cpp | 57 + sfc/coprocessor/spc7110/decompressor.cpp | 190 + sfc/coprocessor/spc7110/serialization.cpp | 60 + sfc/coprocessor/spc7110/spc7110.cpp | 316 + sfc/coprocessor/spc7110/spc7110.hpp | 123 + sfc/coprocessor/st0010/data.hpp | 130 + sfc/coprocessor/st0010/opcodes.cpp | 301 + sfc/coprocessor/st0010/serialization.cpp | 3 + sfc/coprocessor/st0010/st0010.cpp | 39 + sfc/coprocessor/st0010/st0010.hpp | 39 + sfc/coprocessor/superfx/bus.cpp | 41 + sfc/coprocessor/superfx/core.cpp | 103 + sfc/coprocessor/superfx/io.cpp | 113 + sfc/coprocessor/superfx/memory.cpp | 100 + sfc/coprocessor/superfx/serialization.cpp | 6 + sfc/coprocessor/superfx/superfx.cpp | 71 + sfc/coprocessor/superfx/superfx.hpp | 77 + sfc/coprocessor/superfx/timing.cpp | 49 + sfc/cpu/cpu.cpp | 123 + sfc/cpu/cpu.hpp | 244 + sfc/cpu/dma.cpp | 189 + sfc/cpu/io.cpp | 293 + sfc/cpu/irq.cpp | 94 + sfc/cpu/memory.cpp | 86 + sfc/cpu/serialization.cpp | 103 + sfc/cpu/timing.cpp | 274 + sfc/dsp/SPC_DSP.cpp | 1048 + sfc/dsp/SPC_DSP.h | 308 + sfc/dsp/blargg_common.h | 186 + sfc/dsp/blargg_config.h | 26 + sfc/dsp/blargg_endian.h | 185 + sfc/dsp/blargg_source.h | 100 + sfc/dsp/dsp.cpp | 80 + sfc/dsp/dsp.hpp | 28 + sfc/dsp/serialization.cpp | 28 + sfc/expansion/21fx/21fx.cpp | 145 + sfc/expansion/21fx/21fx.hpp | 37 + sfc/expansion/expansion.cpp | 39 + sfc/expansion/expansion.hpp | 19 + sfc/expansion/satellaview/satellaview.cpp | 129 + sfc/expansion/satellaview/satellaview.hpp | 22 + sfc/interface/configuration.cpp | 76 + sfc/interface/configuration.hpp | 72 + sfc/interface/interface.cpp | 344 + sfc/interface/interface.hpp | 90 + sfc/memory/memory-inline.hpp | 32 + sfc/memory/memory.cpp | 106 + sfc/memory/memory.hpp | 49 + sfc/memory/protectable.hpp | 54 + sfc/memory/readable.hpp | 45 + sfc/memory/writable.hpp | 43 + sfc/ppu-fast/background.cpp | 158 + sfc/ppu-fast/io.cpp | 699 + sfc/ppu-fast/line.cpp | 171 + sfc/ppu-fast/mode7.cpp | 69 + sfc/ppu-fast/mode7hd.cpp | 253 + sfc/ppu-fast/object.cpp | 192 + sfc/ppu-fast/ppu.cpp | 206 + sfc/ppu-fast/ppu.hpp | 370 + sfc/ppu-fast/serialization.cpp | 166 + sfc/ppu-fast/window.cpp | 75 + sfc/ppu/background.cpp | 232 + sfc/ppu/background.hpp | 85 + sfc/ppu/counter/counter-inline.hpp | 84 + sfc/ppu/counter/counter.hpp | 48 + sfc/ppu/counter/serialization.cpp | 11 + sfc/ppu/io.cpp | 755 + sfc/ppu/main.cpp | 195 + sfc/ppu/mode7.cpp | 68 + sfc/ppu/mosaic.cpp | 26 + sfc/ppu/mosaic.hpp | 13 + sfc/ppu/oam.cpp | 74 + sfc/ppu/object.cpp | 221 + sfc/ppu/object.hpp | 91 + sfc/ppu/ppu.cpp | 214 + sfc/ppu/ppu.hpp | 179 + sfc/ppu/screen.cpp | 182 + sfc/ppu/screen.hpp | 47 + sfc/ppu/serialization.cpp | 281 + sfc/ppu/window.cpp | 107 + sfc/ppu/window.hpp | 47 + sfc/sfc.hpp | 150 + sfc/slot/bsmemory/bsmemory.cpp | 577 + sfc/slot/bsmemory/bsmemory.hpp | 168 + sfc/slot/bsmemory/serialization.cpp | 67 + sfc/slot/slot.cpp | 2 + sfc/slot/slot.hpp | 2 + sfc/slot/sufamiturbo/serialization.cpp | 3 + sfc/slot/sufamiturbo/sufamiturbo.cpp | 17 + sfc/slot/sufamiturbo/sufamiturbo.hpp | 12 + sfc/smp/io.cpp | 182 + sfc/smp/memory.cpp | 42 + sfc/smp/serialization.cpp | 55 + sfc/smp/smp.cpp | 53 + sfc/smp/smp.hpp | 100 + sfc/smp/timing.cpp | 78 + sfc/system/serialization.cpp | 119 + sfc/system/system.cpp | 242 + sfc/system/system.hpp | 54 + 656 files changed, 213542 insertions(+) create mode 100644 .gitignore create mode 100644 COPYING create mode 100644 Database/BS Memory.bml create mode 100644 Database/Cheat Codes.bml create mode 100644 Database/Sufami Turbo.bml create mode 100644 Database/Super Famicom.bml create mode 100644 Database/boards.bml create mode 100644 Database/ipl.rom create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 emulator/audio/audio.cpp create mode 100644 emulator/audio/audio.hpp create mode 100644 emulator/audio/stream.cpp create mode 100644 emulator/cheat.hpp create mode 100644 emulator/emulator.cpp create mode 100644 emulator/emulator.hpp create mode 100644 emulator/game.hpp create mode 100644 emulator/interface.hpp create mode 100644 emulator/memory/memory.hpp create mode 100644 emulator/memory/readable.hpp create mode 100644 emulator/memory/writable.hpp create mode 100644 emulator/platform.hpp create mode 100644 emulator/random.hpp create mode 100644 emulator/types.hpp create mode 100644 filter/2xsai.cpp create mode 100644 filter/filter.cpp create mode 100644 filter/filter.hpp create mode 100644 filter/hq2x.cpp create mode 100644 filter/lq2x.cpp create mode 100644 filter/none.cpp create mode 100644 filter/ntsc-composite.cpp create mode 100644 filter/ntsc-rf.cpp create mode 100644 filter/ntsc-rgb.cpp create mode 100644 filter/ntsc-svideo.cpp create mode 100644 filter/pixellate2x.cpp create mode 100644 filter/sai/sai.cpp create mode 100644 filter/scale2x.cpp create mode 100644 filter/scanlines-black.cpp create mode 100644 filter/scanlines-dark.cpp create mode 100644 filter/scanlines-light.cpp create mode 100755 filter/snes_ntsc/snes_ntsc.c create mode 100755 filter/snes_ntsc/snes_ntsc.h create mode 100755 filter/snes_ntsc/snes_ntsc_config.h create mode 100755 filter/snes_ntsc/snes_ntsc_impl.h create mode 100644 filter/super-2xsai.cpp create mode 100644 filter/super-eagle.cpp create mode 100644 gb/Core/apu.c create mode 100644 gb/Core/apu.h create mode 100644 gb/Core/camera.c create mode 100644 gb/Core/camera.h create mode 100644 gb/Core/debugger.c create mode 100644 gb/Core/debugger.h create mode 100644 gb/Core/display.c create mode 100644 gb/Core/display.h create mode 100644 gb/Core/gb.c create mode 100644 gb/Core/gb.h create mode 100644 gb/Core/gb_struct_def.h create mode 100644 gb/Core/joypad.c create mode 100644 gb/Core/joypad.h create mode 100644 gb/Core/mbc.c create mode 100644 gb/Core/mbc.h create mode 100644 gb/Core/memory.c create mode 100644 gb/Core/memory.h create mode 100644 gb/Core/printer.c create mode 100644 gb/Core/printer.h create mode 100644 gb/Core/random.c create mode 100644 gb/Core/random.h create mode 100644 gb/Core/rewind.c create mode 100644 gb/Core/rewind.h create mode 100644 gb/Core/save_state.c create mode 100644 gb/Core/save_state.h create mode 100644 gb/Core/sgb.c create mode 100644 gb/Core/sgb.h create mode 100644 gb/Core/sgb_animation_logo.inc create mode 100644 gb/Core/sgb_border.inc create mode 100644 gb/Core/sm83_cpu.c create mode 100644 gb/Core/sm83_cpu.h create mode 100644 gb/Core/sm83_disassembler.c create mode 100644 gb/Core/symbol_hash.c create mode 100644 gb/Core/symbol_hash.h create mode 100644 gb/Core/timing.c create mode 100644 gb/Core/timing.h create mode 100644 gb/LICENSE create mode 100644 gb/README create mode 100644 heuristics/bs-memory.cpp create mode 100644 heuristics/game-boy.cpp create mode 100644 heuristics/heuristics.cpp create mode 100644 heuristics/heuristics.hpp create mode 100644 heuristics/sufami-turbo.cpp create mode 100644 heuristics/super-famicom.cpp create mode 100644 jg.cpp create mode 100644 libco/aarch64.c create mode 100755 libco/amd64.c create mode 100644 libco/arm.c create mode 100755 libco/doc/style.css create mode 100755 libco/doc/targets.html create mode 100755 libco/doc/usage.html create mode 100755 libco/fiber.c create mode 100755 libco/libco.c create mode 100755 libco/libco.h create mode 100755 libco/ppc.c create mode 100644 libco/ppc64v2.c create mode 100644 libco/settings.h create mode 100755 libco/sjlj.c create mode 100755 libco/ucontext.c create mode 100755 libco/x86.c create mode 100644 lzma/7z.h create mode 100644 lzma/7zAlloc.c create mode 100644 lzma/7zAlloc.h create mode 100644 lzma/7zArcIn.c create mode 100644 lzma/7zBuf.c create mode 100644 lzma/7zBuf.h create mode 100644 lzma/7zBuf2.c create mode 100644 lzma/7zCrc.c create mode 100644 lzma/7zCrc.h create mode 100644 lzma/7zCrcOpt.c create mode 100644 lzma/7zDec.c create mode 100644 lzma/7zFile.c create mode 100644 lzma/7zFile.h create mode 100644 lzma/7zStream.c create mode 100644 lzma/7zTypes.h create mode 100644 lzma/7zVersion.h create mode 100644 lzma/7zVersion.rc create mode 100644 lzma/Aes.c create mode 100644 lzma/Aes.h create mode 100644 lzma/AesOpt.c create mode 100644 lzma/Alloc.c create mode 100644 lzma/Alloc.h create mode 100644 lzma/Bcj2.c create mode 100644 lzma/Bcj2.h create mode 100644 lzma/Bcj2Enc.c create mode 100644 lzma/Bra.c create mode 100644 lzma/Bra.h create mode 100644 lzma/Bra86.c create mode 100644 lzma/BraIA64.c create mode 100644 lzma/Compiler.h create mode 100644 lzma/CpuArch.c create mode 100644 lzma/CpuArch.h create mode 100644 lzma/Delta.c create mode 100644 lzma/Delta.h create mode 100644 lzma/DllSecur.c create mode 100644 lzma/DllSecur.h create mode 100644 lzma/LzFind.c create mode 100644 lzma/LzFind.h create mode 100644 lzma/LzFindMt.c create mode 100644 lzma/LzFindMt.h create mode 100644 lzma/LzHash.h create mode 100644 lzma/Lzma2Dec.c create mode 100644 lzma/Lzma2Dec.h create mode 100644 lzma/Lzma2DecMt.c create mode 100644 lzma/Lzma2DecMt.h create mode 100644 lzma/Lzma2Enc.c create mode 100644 lzma/Lzma2Enc.h create mode 100644 lzma/Lzma86.h create mode 100644 lzma/Lzma86Dec.c create mode 100644 lzma/Lzma86Enc.c create mode 100644 lzma/LzmaDec.c create mode 100644 lzma/LzmaDec.h create mode 100644 lzma/LzmaEnc.c create mode 100644 lzma/LzmaEnc.h create mode 100644 lzma/LzmaLib.c create mode 100644 lzma/LzmaLib.h create mode 100644 lzma/MtCoder.c create mode 100644 lzma/MtCoder.h create mode 100644 lzma/MtDec.c create mode 100644 lzma/MtDec.h create mode 100644 lzma/Ppmd.h create mode 100644 lzma/Ppmd7.c create mode 100644 lzma/Ppmd7.h create mode 100644 lzma/Ppmd7Dec.c create mode 100644 lzma/Ppmd7Enc.c create mode 100644 lzma/Precomp.h create mode 100644 lzma/RotateDefs.h create mode 100644 lzma/Sha256.c create mode 100644 lzma/Sha256.h create mode 100644 lzma/Sort.c create mode 100644 lzma/Sort.h create mode 100644 lzma/Threads.c create mode 100644 lzma/Threads.h create mode 100644 lzma/Xz.c create mode 100644 lzma/Xz.h create mode 100644 lzma/XzCrc64.c create mode 100644 lzma/XzCrc64.h create mode 100644 lzma/XzCrc64Opt.c create mode 100644 lzma/XzDec.c create mode 100644 lzma/XzEnc.c create mode 100644 lzma/XzEnc.h create mode 100644 lzma/XzIn.c create mode 100644 lzma/lzma.cpp create mode 100644 lzma/lzma.hpp create mode 100644 nall/adaptive-array.hpp create mode 100755 nall/algorithm.hpp create mode 100755 nall/any.hpp create mode 100644 nall/arguments.hpp create mode 100644 nall/arithmetic.hpp create mode 100644 nall/arithmetic/barrett.hpp create mode 100644 nall/arithmetic/natural.hpp create mode 100644 nall/arithmetic/unsigned.hpp create mode 100644 nall/array-span.hpp create mode 100644 nall/array-view.hpp create mode 100644 nall/array.hpp create mode 100755 nall/atoi.hpp create mode 100644 nall/beat/archive/container.hpp create mode 100644 nall/beat/archive/create.hpp create mode 100644 nall/beat/archive/extract.hpp create mode 100644 nall/beat/archive/node.hpp create mode 100644 nall/beat/single/apply.hpp create mode 100644 nall/beat/single/create.hpp create mode 100755 nall/bit.hpp create mode 100644 nall/cd.hpp create mode 100644 nall/cd/crc16.hpp create mode 100644 nall/cd/edc.hpp create mode 100644 nall/cd/efm.hpp create mode 100644 nall/cd/rspc.hpp create mode 100644 nall/cd/scrambler.hpp create mode 100644 nall/cd/session.hpp create mode 100644 nall/cd/sync.hpp create mode 100644 nall/chrono.hpp create mode 100644 nall/cipher/chacha20.hpp create mode 100644 nall/counting-sort.hpp create mode 100644 nall/database/odbc.hpp create mode 100644 nall/database/sqlite3.hpp create mode 100644 nall/decode/base.hpp create mode 100644 nall/decode/base64.hpp create mode 100644 nall/decode/bmp.hpp create mode 100644 nall/decode/bwt.hpp create mode 100755 nall/decode/gzip.hpp create mode 100644 nall/decode/html.hpp create mode 100644 nall/decode/huffman.hpp create mode 100755 nall/decode/inflate.hpp create mode 100644 nall/decode/lzsa.hpp create mode 100644 nall/decode/mtf.hpp create mode 100755 nall/decode/png.hpp create mode 100644 nall/decode/rle.hpp create mode 100644 nall/decode/url.hpp create mode 100755 nall/decode/zip.hpp create mode 100755 nall/directory.hpp create mode 100755 nall/dl.hpp create mode 100644 nall/dsp/dsp.hpp create mode 100644 nall/dsp/iir/biquad.hpp create mode 100644 nall/dsp/iir/dc-removal.hpp create mode 100644 nall/dsp/iir/one-pole.hpp create mode 100644 nall/dsp/resampler/cubic.hpp create mode 100644 nall/elliptic-curve/curve25519.hpp create mode 100644 nall/elliptic-curve/ed25519.hpp create mode 100644 nall/elliptic-curve/modulo25519-optimized.hpp create mode 100644 nall/elliptic-curve/modulo25519-reference.hpp create mode 100644 nall/emulation/21fx.hpp create mode 100644 nall/encode/base.hpp create mode 100644 nall/encode/base64.hpp create mode 100644 nall/encode/bmp.hpp create mode 100644 nall/encode/bwt.hpp create mode 100644 nall/encode/html.hpp create mode 100644 nall/encode/huffman.hpp create mode 100644 nall/encode/lzsa.hpp create mode 100644 nall/encode/mtf.hpp create mode 100644 nall/encode/rle.hpp create mode 100644 nall/encode/url.hpp create mode 100644 nall/encode/wav.hpp create mode 100755 nall/encode/zip.hpp create mode 100755 nall/endian.hpp create mode 100644 nall/file-buffer.hpp create mode 100755 nall/file-map.hpp create mode 100755 nall/file.hpp create mode 100755 nall/function.hpp create mode 100644 nall/galois-field.hpp create mode 100755 nall/hash/crc16.hpp create mode 100755 nall/hash/crc32.hpp create mode 100644 nall/hash/crc64.hpp create mode 100644 nall/hash/hash.hpp create mode 100644 nall/hash/sha224.hpp create mode 100755 nall/hash/sha256.hpp create mode 100644 nall/hash/sha384.hpp create mode 100644 nall/hash/sha512.hpp create mode 100755 nall/hashset.hpp create mode 100755 nall/hid.hpp create mode 100755 nall/http/client.hpp create mode 100755 nall/http/message.hpp create mode 100755 nall/http/request.hpp create mode 100755 nall/http/response.hpp create mode 100755 nall/http/role.hpp create mode 100755 nall/http/server.hpp create mode 100755 nall/image.hpp create mode 100755 nall/image/blend.hpp create mode 100755 nall/image/core.hpp create mode 100755 nall/image/fill.hpp create mode 100755 nall/image/interpolation.hpp create mode 100755 nall/image/load.hpp create mode 100755 nall/image/scale.hpp create mode 100755 nall/image/static.hpp create mode 100755 nall/image/utility.hpp create mode 100644 nall/induced-sort.hpp create mode 100644 nall/inline-if.hpp create mode 100755 nall/inode.hpp create mode 100644 nall/instance.hpp create mode 100755 nall/interpolation.hpp create mode 100755 nall/intrinsics.hpp create mode 100644 nall/iterator.hpp create mode 100644 nall/literals.hpp create mode 100644 nall/locale.hpp create mode 100755 nall/location.hpp create mode 100644 nall/mac/poly1305.hpp create mode 100644 nall/macos/guard.hpp create mode 100755 nall/main.hpp create mode 100755 nall/map.hpp create mode 100755 nall/matrix-multiply.hpp create mode 100644 nall/matrix.hpp create mode 100755 nall/maybe.hpp create mode 100755 nall/memory.hpp create mode 100755 nall/merge-sort.hpp create mode 100755 nall/nall.hpp create mode 100644 nall/path.hpp create mode 100755 nall/platform.hpp create mode 100644 nall/pointer.hpp create mode 100644 nall/posix/service.hpp create mode 100644 nall/posix/shared-memory.hpp create mode 100644 nall/primitives.hpp create mode 100644 nall/primitives/bit-field.hpp create mode 100644 nall/primitives/bit-range.hpp create mode 100644 nall/primitives/boolean.hpp create mode 100644 nall/primitives/integer.hpp create mode 100644 nall/primitives/literals.hpp create mode 100644 nall/primitives/natural.hpp create mode 100644 nall/primitives/real.hpp create mode 100644 nall/primitives/types.hpp create mode 100644 nall/property.hpp create mode 100644 nall/queue.hpp create mode 100755 nall/random.hpp create mode 100755 nall/range.hpp create mode 100644 nall/reed-solomon.hpp create mode 100755 nall/run.hpp create mode 100755 nall/serial.hpp create mode 100755 nall/serializer.hpp create mode 100755 nall/service.hpp create mode 100755 nall/set.hpp create mode 100755 nall/shared-memory.hpp create mode 100755 nall/shared-pointer.hpp create mode 100644 nall/simd.hpp create mode 100755 nall/smtp.hpp create mode 100755 nall/stdint.hpp create mode 100755 nall/string.hpp create mode 100755 nall/string/allocator/adaptive.hpp create mode 100755 nall/string/allocator/copy-on-write.hpp create mode 100755 nall/string/allocator/small-string-optimization.hpp create mode 100755 nall/string/allocator/vector.hpp create mode 100644 nall/string/atoi.hpp create mode 100755 nall/string/cast.hpp create mode 100755 nall/string/compare.hpp create mode 100755 nall/string/convert.hpp create mode 100755 nall/string/core.hpp create mode 100755 nall/string/eval/evaluator.hpp create mode 100755 nall/string/eval/literal.hpp create mode 100755 nall/string/eval/node.hpp create mode 100755 nall/string/eval/parser.hpp create mode 100755 nall/string/find.hpp create mode 100755 nall/string/format.hpp create mode 100755 nall/string/markup/bml.hpp create mode 100644 nall/string/markup/find.hpp create mode 100755 nall/string/markup/node.hpp create mode 100755 nall/string/markup/xml.hpp create mode 100755 nall/string/match.hpp create mode 100644 nall/string/pascal.hpp create mode 100755 nall/string/replace.hpp create mode 100755 nall/string/split.hpp create mode 100755 nall/string/transform/cml.hpp create mode 100755 nall/string/transform/dml.hpp create mode 100755 nall/string/trim.hpp create mode 100644 nall/string/utf8.hpp create mode 100755 nall/string/utility.hpp create mode 100755 nall/string/vector.hpp create mode 100755 nall/string/view.hpp create mode 100644 nall/suffix-array.hpp create mode 100644 nall/terminal.hpp create mode 100755 nall/thread.hpp create mode 100755 nall/traits.hpp create mode 100644 nall/unique-pointer.hpp create mode 100755 nall/utility.hpp create mode 100644 nall/variant.hpp create mode 100755 nall/varint.hpp create mode 100644 nall/vector.hpp create mode 100644 nall/vector/access.hpp create mode 100644 nall/vector/assign.hpp create mode 100644 nall/vector/compare.hpp create mode 100644 nall/vector/core.hpp create mode 100644 nall/vector/iterator.hpp create mode 100644 nall/vector/memory.hpp create mode 100644 nall/vector/modify.hpp create mode 100644 nall/vector/specialization/uint8_t.hpp create mode 100644 nall/vector/utility.hpp create mode 100644 nall/vfs.hpp create mode 100644 nall/vfs/fs/file.hpp create mode 100644 nall/vfs/memory/file.hpp create mode 100644 nall/vfs/vfs.hpp create mode 100644 nall/view.hpp create mode 100755 nall/windows/detour.hpp create mode 100644 nall/windows/guard.hpp create mode 100755 nall/windows/guid.hpp create mode 100755 nall/windows/launcher.hpp create mode 100755 nall/windows/registry.hpp create mode 100644 nall/windows/service.hpp create mode 100644 nall/windows/shared-memory.hpp create mode 100755 nall/windows/utf8.hpp create mode 100644 nall/xorg/clipboard.hpp create mode 100755 nall/xorg/guard.hpp create mode 100755 nall/xorg/xorg.hpp create mode 100644 processor/arm7tdmi/algorithms.cpp create mode 100644 processor/arm7tdmi/arm7tdmi.cpp create mode 100644 processor/arm7tdmi/arm7tdmi.hpp create mode 100644 processor/arm7tdmi/disassembler.cpp create mode 100644 processor/arm7tdmi/instruction.cpp create mode 100644 processor/arm7tdmi/instructions-arm.cpp create mode 100644 processor/arm7tdmi/instructions-thumb.cpp create mode 100644 processor/arm7tdmi/memory.cpp create mode 100644 processor/arm7tdmi/registers.cpp create mode 100644 processor/arm7tdmi/serialization.cpp create mode 100644 processor/gsu/disassembler.cpp create mode 100644 processor/gsu/gsu.cpp create mode 100644 processor/gsu/gsu.hpp create mode 100644 processor/gsu/instruction.cpp create mode 100644 processor/gsu/instructions.cpp create mode 100644 processor/gsu/registers.hpp create mode 100644 processor/gsu/serialization.cpp create mode 100644 processor/hg51b/hg51b.cpp create mode 100644 processor/hg51b/hg51b.hpp create mode 100644 processor/hg51b/instruction.cpp create mode 100644 processor/hg51b/instructions.cpp create mode 100644 processor/hg51b/registers.cpp create mode 100644 processor/hg51b/serialization.cpp create mode 100644 processor/processor.hpp create mode 100644 processor/spc700/algorithms.cpp create mode 100644 processor/spc700/disassembler.cpp create mode 100644 processor/spc700/instruction.cpp create mode 100644 processor/spc700/instructions.cpp create mode 100644 processor/spc700/memory.cpp create mode 100644 processor/spc700/serialization.cpp create mode 100644 processor/spc700/spc700.cpp create mode 100644 processor/spc700/spc700.hpp create mode 100644 processor/upd96050/disassembler.cpp create mode 100644 processor/upd96050/instructions.cpp create mode 100644 processor/upd96050/memory.cpp create mode 100644 processor/upd96050/serialization.cpp create mode 100644 processor/upd96050/upd96050.cpp create mode 100644 processor/upd96050/upd96050.hpp create mode 100755 processor/wdc65816/algorithms.cpp create mode 100755 processor/wdc65816/disassembler.cpp create mode 100644 processor/wdc65816/instruction.cpp create mode 100644 processor/wdc65816/instruction.hpp create mode 100755 processor/wdc65816/instructions-modify.cpp create mode 100755 processor/wdc65816/instructions-other.cpp create mode 100755 processor/wdc65816/instructions-pc.cpp create mode 100755 processor/wdc65816/instructions-read.cpp create mode 100755 processor/wdc65816/instructions-write.cpp create mode 100644 processor/wdc65816/memory.cpp create mode 100644 processor/wdc65816/registers.hpp create mode 100755 processor/wdc65816/serialization.cpp create mode 100755 processor/wdc65816/wdc65816.cpp create mode 100755 processor/wdc65816/wdc65816.hpp create mode 100644 sfc/cartridge/cartridge.cpp create mode 100644 sfc/cartridge/cartridge.hpp create mode 100644 sfc/cartridge/load.cpp create mode 100644 sfc/cartridge/save.cpp create mode 100644 sfc/cartridge/serialization.cpp create mode 100644 sfc/controller/controller.cpp create mode 100644 sfc/controller/controller.hpp create mode 100644 sfc/controller/gamepad/gamepad.cpp create mode 100644 sfc/controller/gamepad/gamepad.hpp create mode 100644 sfc/controller/justifier/justifier.cpp create mode 100644 sfc/controller/justifier/justifier.hpp create mode 100644 sfc/controller/mouse/mouse.cpp create mode 100644 sfc/controller/mouse/mouse.hpp create mode 100644 sfc/controller/super-multitap/super-multitap.cpp create mode 100644 sfc/controller/super-multitap/super-multitap.hpp create mode 100644 sfc/controller/super-scope/super-scope.cpp create mode 100644 sfc/controller/super-scope/super-scope.hpp create mode 100644 sfc/coprocessor/armdsp/armdsp.cpp create mode 100644 sfc/coprocessor/armdsp/armdsp.hpp create mode 100644 sfc/coprocessor/armdsp/memory.cpp create mode 100644 sfc/coprocessor/armdsp/registers.hpp create mode 100644 sfc/coprocessor/armdsp/serialization.cpp create mode 100644 sfc/coprocessor/coprocessor.cpp create mode 100644 sfc/coprocessor/coprocessor.hpp create mode 100644 sfc/coprocessor/cx4/cx4.cpp create mode 100644 sfc/coprocessor/cx4/cx4.hpp create mode 100644 sfc/coprocessor/cx4/data.cpp create mode 100644 sfc/coprocessor/cx4/functions.cpp create mode 100644 sfc/coprocessor/cx4/oam.cpp create mode 100644 sfc/coprocessor/cx4/opcodes.cpp create mode 100644 sfc/coprocessor/cx4/serialization.cpp create mode 100644 sfc/coprocessor/dip/dip.cpp create mode 100644 sfc/coprocessor/dip/dip.hpp create mode 100644 sfc/coprocessor/dip/serialization.cpp create mode 100644 sfc/coprocessor/dsp1/dsp1.cpp create mode 100644 sfc/coprocessor/dsp1/dsp1.hpp create mode 100644 sfc/coprocessor/dsp1/dsp1emu.cpp create mode 100644 sfc/coprocessor/dsp1/dsp1emu.hpp create mode 100644 sfc/coprocessor/dsp1/serialization.cpp create mode 100644 sfc/coprocessor/dsp2/dsp2.cpp create mode 100644 sfc/coprocessor/dsp2/dsp2.hpp create mode 100644 sfc/coprocessor/dsp2/opcodes.cpp create mode 100644 sfc/coprocessor/dsp2/serialization.cpp create mode 100644 sfc/coprocessor/dsp4/dsp4.cpp create mode 100644 sfc/coprocessor/dsp4/dsp4.hpp create mode 100644 sfc/coprocessor/dsp4/dsp4emu.c create mode 100644 sfc/coprocessor/dsp4/dsp4emu.h create mode 100644 sfc/coprocessor/dsp4/serialization.cpp create mode 100644 sfc/coprocessor/epsonrtc/epsonrtc.cpp create mode 100644 sfc/coprocessor/epsonrtc/epsonrtc.hpp create mode 100644 sfc/coprocessor/epsonrtc/memory.cpp create mode 100644 sfc/coprocessor/epsonrtc/serialization.cpp create mode 100644 sfc/coprocessor/epsonrtc/time.cpp create mode 100644 sfc/coprocessor/event/event.cpp create mode 100644 sfc/coprocessor/event/event.hpp create mode 100644 sfc/coprocessor/event/serialization.cpp create mode 100644 sfc/coprocessor/hitachidsp/data-rom.cpp create mode 100644 sfc/coprocessor/hitachidsp/hitachidsp.cpp create mode 100644 sfc/coprocessor/hitachidsp/hitachidsp.hpp create mode 100644 sfc/coprocessor/hitachidsp/memory.cpp create mode 100644 sfc/coprocessor/hitachidsp/serialization.cpp create mode 100644 sfc/coprocessor/icd/boot-roms.cpp create mode 100644 sfc/coprocessor/icd/icd.cpp create mode 100644 sfc/coprocessor/icd/icd.hpp create mode 100644 sfc/coprocessor/icd/interface.cpp create mode 100644 sfc/coprocessor/icd/io.cpp create mode 100644 sfc/coprocessor/icd/serialization.cpp create mode 100644 sfc/coprocessor/mcc/mcc.cpp create mode 100644 sfc/coprocessor/mcc/mcc.hpp create mode 100644 sfc/coprocessor/mcc/serialization.cpp create mode 100644 sfc/coprocessor/msu1/msu1.cpp create mode 100644 sfc/coprocessor/msu1/msu1.hpp create mode 100644 sfc/coprocessor/msu1/serialization.cpp create mode 100644 sfc/coprocessor/necdsp/necdsp.cpp create mode 100644 sfc/coprocessor/necdsp/necdsp.hpp create mode 100644 sfc/coprocessor/necdsp/serialization.cpp create mode 100644 sfc/coprocessor/obc1/obc1.cpp create mode 100644 sfc/coprocessor/obc1/obc1.hpp create mode 100644 sfc/coprocessor/obc1/serialization.cpp create mode 100644 sfc/coprocessor/sa1/bwram.cpp create mode 100644 sfc/coprocessor/sa1/dma.cpp create mode 100644 sfc/coprocessor/sa1/io.cpp create mode 100644 sfc/coprocessor/sa1/iram.cpp create mode 100644 sfc/coprocessor/sa1/memory.cpp create mode 100644 sfc/coprocessor/sa1/rom.cpp create mode 100644 sfc/coprocessor/sa1/sa1.cpp create mode 100644 sfc/coprocessor/sa1/sa1.hpp create mode 100644 sfc/coprocessor/sa1/serialization.cpp create mode 100644 sfc/coprocessor/sdd1/decompressor.cpp create mode 100644 sfc/coprocessor/sdd1/decompressor.hpp create mode 100644 sfc/coprocessor/sdd1/sdd1.cpp create mode 100644 sfc/coprocessor/sdd1/sdd1.hpp create mode 100644 sfc/coprocessor/sdd1/serialization.cpp create mode 100644 sfc/coprocessor/sharprtc/memory.cpp create mode 100644 sfc/coprocessor/sharprtc/serialization.cpp create mode 100644 sfc/coprocessor/sharprtc/sharprtc.cpp create mode 100644 sfc/coprocessor/sharprtc/sharprtc.hpp create mode 100644 sfc/coprocessor/sharprtc/time.cpp create mode 100644 sfc/coprocessor/spc7110/alu.cpp create mode 100644 sfc/coprocessor/spc7110/data.cpp create mode 100644 sfc/coprocessor/spc7110/dcu.cpp create mode 100644 sfc/coprocessor/spc7110/decompressor.cpp create mode 100644 sfc/coprocessor/spc7110/serialization.cpp create mode 100644 sfc/coprocessor/spc7110/spc7110.cpp create mode 100644 sfc/coprocessor/spc7110/spc7110.hpp create mode 100644 sfc/coprocessor/st0010/data.hpp create mode 100644 sfc/coprocessor/st0010/opcodes.cpp create mode 100644 sfc/coprocessor/st0010/serialization.cpp create mode 100644 sfc/coprocessor/st0010/st0010.cpp create mode 100644 sfc/coprocessor/st0010/st0010.hpp create mode 100644 sfc/coprocessor/superfx/bus.cpp create mode 100644 sfc/coprocessor/superfx/core.cpp create mode 100644 sfc/coprocessor/superfx/io.cpp create mode 100644 sfc/coprocessor/superfx/memory.cpp create mode 100644 sfc/coprocessor/superfx/serialization.cpp create mode 100644 sfc/coprocessor/superfx/superfx.cpp create mode 100644 sfc/coprocessor/superfx/superfx.hpp create mode 100644 sfc/coprocessor/superfx/timing.cpp create mode 100644 sfc/cpu/cpu.cpp create mode 100644 sfc/cpu/cpu.hpp create mode 100644 sfc/cpu/dma.cpp create mode 100644 sfc/cpu/io.cpp create mode 100644 sfc/cpu/irq.cpp create mode 100644 sfc/cpu/memory.cpp create mode 100644 sfc/cpu/serialization.cpp create mode 100644 sfc/cpu/timing.cpp create mode 100644 sfc/dsp/SPC_DSP.cpp create mode 100644 sfc/dsp/SPC_DSP.h create mode 100644 sfc/dsp/blargg_common.h create mode 100644 sfc/dsp/blargg_config.h create mode 100644 sfc/dsp/blargg_endian.h create mode 100644 sfc/dsp/blargg_source.h create mode 100644 sfc/dsp/dsp.cpp create mode 100644 sfc/dsp/dsp.hpp create mode 100644 sfc/dsp/serialization.cpp create mode 100644 sfc/expansion/21fx/21fx.cpp create mode 100644 sfc/expansion/21fx/21fx.hpp create mode 100644 sfc/expansion/expansion.cpp create mode 100644 sfc/expansion/expansion.hpp create mode 100644 sfc/expansion/satellaview/satellaview.cpp create mode 100644 sfc/expansion/satellaview/satellaview.hpp create mode 100644 sfc/interface/configuration.cpp create mode 100644 sfc/interface/configuration.hpp create mode 100644 sfc/interface/interface.cpp create mode 100644 sfc/interface/interface.hpp create mode 100644 sfc/memory/memory-inline.hpp create mode 100644 sfc/memory/memory.cpp create mode 100644 sfc/memory/memory.hpp create mode 100644 sfc/memory/protectable.hpp create mode 100644 sfc/memory/readable.hpp create mode 100644 sfc/memory/writable.hpp create mode 100644 sfc/ppu-fast/background.cpp create mode 100644 sfc/ppu-fast/io.cpp create mode 100644 sfc/ppu-fast/line.cpp create mode 100644 sfc/ppu-fast/mode7.cpp create mode 100644 sfc/ppu-fast/mode7hd.cpp create mode 100644 sfc/ppu-fast/object.cpp create mode 100644 sfc/ppu-fast/ppu.cpp create mode 100644 sfc/ppu-fast/ppu.hpp create mode 100644 sfc/ppu-fast/serialization.cpp create mode 100644 sfc/ppu-fast/window.cpp create mode 100644 sfc/ppu/background.cpp create mode 100644 sfc/ppu/background.hpp create mode 100755 sfc/ppu/counter/counter-inline.hpp create mode 100755 sfc/ppu/counter/counter.hpp create mode 100644 sfc/ppu/counter/serialization.cpp create mode 100644 sfc/ppu/io.cpp create mode 100644 sfc/ppu/main.cpp create mode 100644 sfc/ppu/mode7.cpp create mode 100644 sfc/ppu/mosaic.cpp create mode 100644 sfc/ppu/mosaic.hpp create mode 100644 sfc/ppu/oam.cpp create mode 100644 sfc/ppu/object.cpp create mode 100644 sfc/ppu/object.hpp create mode 100644 sfc/ppu/ppu.cpp create mode 100644 sfc/ppu/ppu.hpp create mode 100644 sfc/ppu/screen.cpp create mode 100644 sfc/ppu/screen.hpp create mode 100644 sfc/ppu/serialization.cpp create mode 100644 sfc/ppu/window.cpp create mode 100644 sfc/ppu/window.hpp create mode 100644 sfc/sfc.hpp create mode 100644 sfc/slot/bsmemory/bsmemory.cpp create mode 100644 sfc/slot/bsmemory/bsmemory.hpp create mode 100644 sfc/slot/bsmemory/serialization.cpp create mode 100644 sfc/slot/slot.cpp create mode 100644 sfc/slot/slot.hpp create mode 100644 sfc/slot/sufamiturbo/serialization.cpp create mode 100644 sfc/slot/sufamiturbo/sufamiturbo.cpp create mode 100644 sfc/slot/sufamiturbo/sufamiturbo.hpp create mode 100644 sfc/smp/io.cpp create mode 100644 sfc/smp/memory.cpp create mode 100644 sfc/smp/serialization.cpp create mode 100644 sfc/smp/smp.cpp create mode 100644 sfc/smp/smp.hpp create mode 100644 sfc/smp/timing.cpp create mode 100644 sfc/system/serialization.cpp create mode 100644 sfc/system/system.cpp create mode 100644 sfc/system/system.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..85787ec --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +objs/* +bsnes/* +*.o +*.d diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Database/BS Memory.bml b/Database/BS Memory.bml new file mode 100644 index 0000000..c851008 --- /dev/null +++ b/Database/BS Memory.bml @@ -0,0 +1,44 @@ +database + revision: 2020-01-01 + +//BS Memory (JPN) + +database + revision: 2018-04-14 + +game + sha256: 80c34b50817d58820bc8c88d2d9fa462550b4a76372e19c6467cbfbc8cf5d9ef + label: 鮫亀 キャラカセット + name: Same Game - Chara Cassette + region: BSMC-ZS5J-JPN + revision: BSMC-ZS5J-0 + board: BSMC-CR-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 859c7f7b4771d920a5bdb11f1d247ab6b43fb026594d1062f6f72d32cd340a0a + label: 鮫亀 キャラデータ集 + name: Same Game - Chara Data Shuu + region: BSMC-YS5J-JPN + revision: BSMC-YS5J-0 + board: BSMC-CR-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: c92a15fdd9b0133f9ea69105d0230a3acd1cdeef98567462eca86ea02a959e4e + label: SDガンダム ジーネクスト ユニット&マップコレクション + name: SD Gundam G Next - Unit & Map Collection + region: BSMC-ZX3J-JPN + revision: BSMC-ZX3J-0 + board: BSMC-BR-01 + memory + type: ROM + size: 0x80000 + content: Program + diff --git a/Database/Cheat Codes.bml b/Database/Cheat Codes.bml new file mode 100644 index 0000000..0e17e76 --- /dev/null +++ b/Database/Cheat Codes.bml @@ -0,0 +1,87497 @@ +database revision=2015-09-28 + +cartridge sha256:8e844d77da01f86ace52823f1f974c9230f09e6a6cbf33a07abfe9beeff00292 + name:10-Yard Fight (USA, Europe) + cheat + description:Your team runs faster + code:a18d/05/0a + +cartridge sha256:e868400409c70876b98dad2cca87b8e9ee31877b0cccbbd8405be5c54922722a + name:1942 (Japan, USA) + cheat + description:Don't die when touched + code:f828/b9 + cheat + description:Most enemies die instantly + code:dc02/ff/01 + cheat + description:Infinite lives - 1P game + code:b824/ce/ad + cheat + description:Infinite rolls + code:d309/ce/ad + cheat + description:Hit anywhere + code:b44e/b0/30+b4b5/9d/ad+b404/9d/ad+b44b/20/ad + cheat + description:Rapid fire + code:d2bc/10/00 + cheat + description:After continue P1 has 6 lives - 2P game + code:b84b/02/05 + cheat + description:After continue P1 has 9 lives - 2P game + code:b84b/02/08 + cheat + description:P2 has 6 lives - 2P game + code:b859/02/05 + cheat + description:P2 has 9 lives - 2P game + code:b859/02/08 + cheat + description:Start with 9 rolls - both players + code:d851/03/09 + cheat + description:Start with 6 lives - 1P game + code:b7de/02/05 + cheat + description:Start with 9 lives - 1P game + code:b7de/02/08 + cheat + description:Invincibility + code:048e/88 + cheat + description:Infinite rolls (alt) + code:0436/03 + cheat + description:Infinite lives + code:0432/02 + +cartridge sha256:9f54aafa367247b99c344ba9a0c58ad8fa8aceeeae1c304b8fefc9985c3c118c + name:1943 - The Battle of Midway (USA) + cheat + description:Infinite energy + code:b2f0/04/b1 + cheat + description:Infinite energy (alt) + code:b2e2/8d/ad+b29b/ce/ee + cheat + description:Infinite power-ups + code:a7ec/bd + cheat + description:Infinite weapon upgrade time + code:b31a/ce/cd + cheat + description:Don't instantly die from touching boss planes + code:dbc0/04/d7 + cheat + description:Always shoot power shots + code:9b82/00/0b + cheat + description:Hit anywhere + code:dbfc/10/00+dc08/b0/24+c859/99/bd+db97/99/ad+c8a6/99/ad+ea45/99/ad+ce65/99/ad + cheat + description:10 power points + code:f3db/03/0a + cheat + description:20 power points + code:f3db/03/14 + cheat + description:30 power points + code:f3db/03/1e + cheat + description:Start on mission 5 + code:f3e2/00/08 + cheat + description:Start on mission 10 + code:f3e2/00/12 + cheat + description:Start on mission 15 + code:f3e2/00/1c + cheat + description:Start on mission 20 + code:f3e2/00/26 + 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 + name:1945 [p1] + cheat + description:Invincibility + code:9298/20/ad+94e9/20/ad + cheat + description:Infinite Bombs + code:83b7/20/ad + +cartridge sha256:c457644ccfb93f8978326e728931800283821e531edc409fca9c0167495319c4 + name:3-D WorldRunner (USA) + cheat + description:Invincibility + code:a41d/60 + cheat + description:Infinite lives + code:96bb/01/00 + cheat + description:Infinite time + code:94b2/c6/a5 + cheat + description:Slow down timer + code:94af/c0/ff + cheat + description:Speed up timer + code:94af/c0/60 + cheat + description:Start with and keep laser missiles + code:9dbe/04/00 + cheat + description:Autofire + code:9dbf/a5/a9 + cheat + description:Start with 1 life + code:96b1/03/01+966b/33/31 + cheat + description:Start with 6 lives + code:96b1/03/06+966b/33/36 + cheat + description:Start with 9 lives + code:96b1/03/09+966b/33/39 + cheat + description:Start on world 2 + code:8903/a9/a2+8904/00/01+8905/85/86 + cheat + description:Start on world 3 + code:8903/a9/a2+8904/00/02+8905/85/86 + cheat + description:Start on world 4 + code:8903/a9/a2+8904/00/03+8905/85/86 + cheat + description:Start on world 5 + code:8903/a9/a2+8904/00/04+8905/85/86 + cheat + description:Start on world 6 + code:8903/a9/a2+8904/00/05+8905/85/86 + cheat + description:Start on world 7 + code:8903/a9/a2+8904/00/06+8905/85/86 + cheat + description:No enemies or pitfalls + code:003a/05 + +cartridge sha256:df696ce2af90b18ca2b57468bdc525afce371bb1868152eb2cbbe1d62252f617 + name:720 Degrees (USA) + cheat + description:Infinite continues + code:f530/ce/ad + cheat + description:9 continues + code:c2ab/03/09 + cheat + description:6 continues + code:c2ab/03/06 + cheat + description:No continues instead of 2 + code:c2ab/03/01 + cheat + description:Start with all equipment + code:c2cf/00/04 + cheat + description:Start with half equipment + code:c2cf/00/02 + cheat + description:Start on level 2 + code:c2a4/ad/ea+c2a5/0e/a9+c2a6/02/02 + cheat + description:Start on level 3 + code:c2a4/ad/ea+c2a5/0e/a9+c2a6/02/03 + cheat + description:Start on level 4 + code:c2a4/ad/ea+c2a5/0e/a9+c2a6/02/04 + 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 + name:8 Eyes (USA) + cheat + description:Invincibility - Orin + code:bb3d/f0/d0 + cheat + description:Invincibility - Cutrus + code:c976/f0/d0 + cheat + description:Infinite health - Orin + code:bb9d/8d/ad + cheat + description:Infinite health - Cutrus + code:c9f7/8d/ad + cheat + description:Most attacks won't damage Orin + code:bb9d/8d/2c + cheat + description:Most attacks won't damage Cutrus + code:c9f7/8d/2c + cheat + description:Start with more health - Orin + code:a26c/2f/40 + cheat + description:Start with more health - Cutrus + code:a26d/2f/40 + cheat + description:Infinite ammo + code:bed4/8d/ad + cheat + description:Start with all weapons + code:ee1b/86/85 + cheat + description:Start with max ammo + code:a26e/2f/4f + cheat + description:Start with some item power + code:a26e/00/2f + cheat + description:Never lose item power once gained + code:bed4/8d/2c + cheat + description:Start with Dagger + code:ee1f/86/e6 + 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 + name:Abadox - The Deadly Inner War (USA) + cheat + description:Invincibility + code:dd08/f0/d0+de0c/d0/f0 + cheat + description:Invincible against touching enemies + code:efe2/a5/60 + cheat + description:Invincible against walls (does not stop music) + code:d5ab/c0/00 + cheat + description:Infinite lives (lives never decrease) + code:c7d1/09 + cheat + description:Infinite lives (lives increase when you die) + code:c7d0/e6 + cheat + description:Hit anywhere + code:f1d5/90/d0+f1fa/d0/b0+f1b1/90/b0+f210/30/24 + cheat + description:Invincibility (music stops if you touch a wall) + code:0086/00+008a/00 + cheat + description:One hit kills - bosses + code:03de/00 + cheat + description:Weapon shoots clones + code:008c/ff + 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 + cheat + description:Start at level 2 + code:cc74/01/02 + cheat + description:Start at level 3 + code:cc74/01/03 + cheat + description:Start at level 4 + code:cc74/01/05 + cheat + description:Start at level 6 + code:cc74/01/06 + +cartridge sha256:6da6c8ac123df0f51e6f1b2ba79cb067d3352262532604ab08cf5dd587e84006 + name:Action in New York (Europe) + cheat + description:Invincibility + code:dcde/60 + cheat + description:One hit kills + code:ed4e/f0/d0 + cheat + description:No enemies + code:d5b2/50/24 + +cartridge sha256:005c48a5984e3b75e069ef78d736266b12f7f6b102d88d90172ba9ae480b378b + name:Addams Family, The (USA) + cheat + description:Invincibility + code:8496/ad + cheat + description:Infinite life + code:c5ca/ce/2c + cheat + description:Infinite lives + code:e3d8/ce/2c + cheat + description:Infinite Things + code:e68b/ce/2c + cheat + description:No Piranah Plant enemies + code:ac01/90/b0 + cheat + description:Get items from anywhere - from above + code:a684/90/24 + cheat + description:Get items from anywhere - from the right + code:a695/90/24 + cheat + description:Get items from anywhere - from the left + code:a69f/90/24 + cheat + description:Get items from anywhere - from below + code:a68b/b0/24 + cheat + description:Walk through walls + code:877c/d0/50+8787/d0/50 + cheat + description:Start with 1 life - 1st game only + code:c0e4/03/01 + cheat + description:Start with 6 lives - 1st game only + code:c0e4/03/06 + cheat + description:Start with 9 lives - 1st game only + code:c0e4/03/09 + cheat + description:Start in the tree + code:c0c6/00/01 + cheat + description:Start in the crypt + code:c0c6/00/02 + cheat + description:Start in the hallway + code:c0c6/00/03 + cheat + description:Start in Fester's room + code:c0c6/00/08 + cheat + description:Start in Pugsly's room + code:c0c6/00/09 + cheat + description:Start in the toy room + code:c0c6/00/0a + cheat + description:Start in Wednesday's room + code:c0c6/00/0b + cheat + description:Start in the attic + code:c0c6/00/0c + cheat + description:Start in a secret room + code:c0c6/00/0f + cheat + description:Start in a secret room + code:c0c6/00/10 + cheat + description:Start in a secret room + code:c0c6/00/11 + cheat + description:Start in the bone room + code:c0c6/00/1d + cheat + description:Start in the freezer + code:c0c6/00/21 + cheat + description:Start in the furnace + code:c0c6/00/22 + cheat + description:Start in Gomez's room + code:c0c6/00/20 + +cartridge sha256:b3e09c94e33e0293672c1405c60fc69b2ab1564c8a4ee988e3ab6ada51484eea + name:Addams Family, The - Pugsley's Scavenger Hunt (USA) + cheat + description:Invincibility + code:c448/60 + cheat + description:Invincibility status effect + code:e9b4/f0/24 + cheat + description:Infinite health + code:c448/ad + cheat + description:Infinite health (alt) + code:c447/01/00 + cheat + description:Infinite lives + code:c4b2/ce/ad + cheat + description:Infinite lives (alt) + code:c4b2/bd + cheat + description:Always able to fly + code:ec5b/35/00 + cheat + description:Always able to fly (alt) + code:e799/f0/24 + cheat + description:No enemies + code:9d49/30/10 + cheat + description:Enemies can't move horizontally + code:9cef/f0/d0 + cheat + description:Enemies can't move vertically + code:9d08/f0/d0 + cheat + description:Mega-jump + code:eee0/10/18 + cheat + description:Sweets count as extra lives + code:c40f/f0/d0 + cheat + description:Start with 1 life + code:c6ea/05/01 + cheat + description:Start with 9 lives + code:c6ea/05/09 + cheat + description:Start with 1 heart + code:c6fa/02/01 + cheat + description:Start with 4 hearts + code:c6fa/02/04 + cheat + description:Infinite health (alt 2) + code:0435/02 + cheat + description:Infinite lives (alt 2) + code:0438/09 + +cartridge sha256:22e92af92aed2d8d7bddb60732963642788b3ea9341592ce2c66a542a3d7ce7d + name:Advanced Dungeons & Dragons - DragonStrike (USA) + cheat + description:Invincibility + code:cf47/60 + cheat + description:Infinite health + code:cf47/ad + cheat + description:Infinite health (alt) + code:cf45/e5/e9 + cheat + description:Weapon power doesn't weaken with health + code:cf4f/8d/2c + cheat + description:Gold dragon has excellent armor class + code:c025/63/66 + cheat + description:Gold dragon flies faster + code:c028/41/47 + cheat + description:Silver dragon flies faster + code:c027/64/68 + cheat + description:Bronze dragon flies faster + code:c026/53/57 + cheat + description:Start wtih less health - bronze dragon + code:a044/28/14 + cheat + description:Start wtih more health - bronze dragon + code:a044/28/50 + cheat + description:Start wtih less health - silver dragon + code:a045/3c/1e + cheat + description:Start wtih more health - silver dragon + code:a045/3c/50 + cheat + description:Start wtih less health - gold dragon + code:a046/50/2a + cheat + description:Start wtih more health - gold dragon + code:a046/50/65 + +cartridge sha256:df2609c80e818bb95983b30a3ac1435ea2332ac83e29fde469f397e1d5a2db93 + name:Advanced Dungeons & Dragons - Heroes of the Lance (USA) + cheat + description:Infinite HP for party in most battles + code:8492/95/b5 + +cartridge sha256:60061c0042741f7c1e53ad8f738c27ffd9057310ff5d556662b3667e5700e751 + name:Advanced Dungeons & Dragons - Hillsfar (USA) + cheat + description:Infinite Knock Rings + code:b5ce/ce/ad+b5cd/58/00 + cheat + description:Faster timer when lock-picking + code:b3b5/20/10 + cheat + description:Slower timer when lock-picking + code:b3b5/20/50 + cheat + description:Very slow timer when lock-picking + code:b3b5/20/f0 + cheat + description:Start with 50% less gold on a character that you create + code:8ce7/0a/05 + cheat + description:Start with 50% more gold on a character that you create + code:8ce7/0a/0f + cheat + description:Start with 100% more gold on a character that you create + code:8ce7/0a/14 + +cartridge sha256:38e5253131d264395a302d0910316f94bec00f60db616caa7a53806f08c5b5f9 + name:Advanced Dungeons & Dragons - Pool of Radiance (USA) + cheat + description:Create super characters + code:8fb3/9d + cheat + description:Girdle Of Giant strength (must be used to be effective) + code:8f33/ca+8933/44 + cheat + description:Extra EXP points + code:8b42/36 + cheat + description:One hit ends battle with no gold or EXP + code:87b3/28 + +cartridge sha256:5ee479ef04d80366a75dd144cbeb47d0347ee82025d1b65dd358e1f6498c9a39 + name:Adventure Island II (USA) + cheat + description:Invincibility + code:deb9/d0/f0 + cheat + description:Invincibility (alt) + code:dede/a9/60 + cheat + description:Infinite health + code:d034/ce/ee + cheat + description:Infinite health (alt) + code:d034/ce/ad + cheat + description:Infinite health against hitting objects + code:df48/02/00 + cheat + description:Infinite Axes + code:aa6b/51 + cheat + description:Infinite Axes plus get an extra Red Camptosaurus + code:bab0/bf + cheat + description:Infinite lives + code:bcf1/ce/ad + cheat + description:Hit anywhere + code:ddc0/b0/d0+de04/99/b9+de21/99/b9+de85/99/b9+ddbd/20/ad+ddbf/ff/06+ddbe/c3/02 + cheat + description:Never lose Dinosaur + code:bca0/85/a5+df08/85/a5+df6e/85/a5 + cheat + description:Get fruits from anywhere + code:a74d/4d/00 + cheat + description:Multi-jump (hold jump to float) + code:b19a/5f/9c+b1a1/5f/a3 + cheat + description:Hold jump to float + code:b2ad/02/fe + cheat + description:Reversible skateboard + code:a1f6/20/00 + cheat + description:Faster running + code:a048/20/30 + cheat + description:Higher jump + code:b1d8/bd/ad+b4ab/01/04 + cheat + description:Start with 2 lives + code:e0a8/03/01 + cheat + description:Start with 7 lives + code:e0a8/03/06 + cheat + description:Start with 10 lives + code:e0a8/03/09 + +cartridge sha256:e8dc8c0441c54d09a1cfe0c112a3137bb6d709989b23e6528f8e30360e1ad910 + name:Adventure Island 3 (USA) + cheat + description:Invincibility + code:acec/01/00 + cheat + description:Infinite health + code:fd91/ce/ad + cheat + description:Infinite vitality + code:fd91/ce/cd + cheat + description:Infinite lives + code:b5f5/8d/ad + cheat + description:Hit anywhere + code:ab04/03/00+addc/b9/60+ad8f/99/b9+ae8d/99/b9 + cheat + description:Hold jump to float + code:a05a/d0/f0 + cheat + description:Don't die when hitting spikes + code:aeb7/01/00 + cheat + description:Don't lose pet when hitting spikes + code:af45/e6/85 + cheat + description:Mega-jumping Master Higgins + code:aa80/7b/bd + cheat + description:Gain 99 lives after gaining 100 fruit + code:a64c/02/00 + cheat + description:Keep items after dying - after 1st stage + code:b1bc/9d/2c + cheat + description:Start a new game to view the ending + code:a507/04/00+a503/0a/03 + cheat + description:Start with 2 lives + code:a0d0/03/01 + cheat + description:Start with 7 lives + code:a0d0/03/06 + cheat + description:Start with 9 lives + code:a0d0/03/09 + cheat + description:Start with 2 Red Taylors + code:a062/8d/ee + cheat + description:Start with 2 Blue Taylors + code:a065/8d/ee + cheat + description:Start with 2 Classies + code:a068/8d/ee + cheat + description:Start with 2 Don-Dons + code:a06b/8d/ee + cheat + description:Start with 2 Poleys + code:a06e/8d/ee + cheat + description:Start with 2 Boomerangs + code:a071/8d/ee + cheat + description:Start with 2 Axes + code:a074/8d/ee + cheat + description:Start with 2 invincibility crystals + code:a077/8d/ee + +cartridge sha256:185e4adb2cbcb71ebf0fd3f6af767f2215f93916cd2ccf932ce5864d3953239a + name:Adventures in the Magic Kingdom (USA) + cheat + description:Invincibility + code:f51e/60 + cheat + description:Infinite health + code:f9aa/c6/60 + cheat + description:Infinite time + code:fa24/b0/60 + cheat + description:Infinite candles + code:e654/ce/ad + cheat + description:Infinite lives + code:f9c3/ce/ad + cheat + description:Almost infinite health in attractions + code:f9aa/c6/a5 + cheat + description:All items for free + code:b283/fd/2c+b228/7c/00 + cheat + description:Mega-jump + code:ec4f/fa/f8 + cheat + description:'Life' costs less + code:b44e/06/03 + cheat + description:'Life' costs more + code:b44e/06/0c + cheat + description:'Freeze' costs less + code:b44f/08/04 + cheat + description:'Freeze' costs more + code:b44f/08/0f + cheat + description:'Invincible' costs less + code:b450/0a/05 + cheat + description:'Invincible' costs more + code:b450/0a/14 + cheat + description:'Life Up' costs less + code:b451/0c/06 + cheat + description:'Life Up' costs more + code:b451/0c/18 + cheat + description:Never lose a life in 'attractions' + code:f9c3/ce/ad + cheat + description:More 'Freeze' time + code:b24b/b4/ff + cheat + description:Less 'Freeze' time + code:b24b/b4/40 + cheat + description:More 'Invincible' time + code:b25f/3c/c0 + cheat + description:Start with less health in attractions + code:8162/03/01 + cheat + description:Start with more health in attractions + code:8162/03/05 + cheat + description:Start with even more health in attractions + code:8162/03/09 + cheat + description:Start with 1 life + code:80ed/03/01 + cheat + description:Start with 6 lives + code:80ed/03/06 + cheat + description:Start with 9 lives + code:80ed/03/09 + +cartridge sha256:0e862077f390348b8e109caa8189ff5ecdf3fac53eefc204369fae880e077d19 + name:Adventures of Bayou Billy, The (USA) + cheat + description:Infinite health + code:e2cd/07/01+9c9b/ce/ad + cheat + description:Infinite lives + code:e31b/c6/24 + cheat + description:Always have pistol + code:8476/ac/a0+8478/07/ea+8477/c1/01 + cheat + description:Always have knife + code:8476/ac/a0+8478/07/ea+8477/c1/02 + cheat + description:Always have ugly stick + code:8476/ac/a0+8478/07/ea+8477/c1/03 + cheat + description:Always have whip + code:8476/ac/a0+8478/07/ea+8477/c1/05 + cheat + description:Start a new game to view the ending (game A or B) + code:e798/04/05 + cheat + description:Start with 1 life + code:e400/02/00 + cheat + description:Start with 6 lives + code:e400/02/05 + cheat + description:Start with 9 lives + code:e400/02/08 + cheat + description:Start on level 2 + code:e40a/00/01+e40c/39/fb+e408/04/00 + cheat + description:Start on level 3 + code:e40a/00/02+e40c/39/fb+e408/04/00 + cheat + description:Start on level 4 + code:e40a/00/03+e40c/39/fb+e408/04/00 + cheat + description:Start on level 5 + code:e40a/00/04+e40c/39/fb+e408/04/00 + cheat + description:Start on level 6 + code:e40a/00/05+e40c/39/fb+e408/04/00 + cheat + description:Start on level 7 + code:e40a/00/06+e40c/39/fb+e408/04/00 + cheat + description:Start on level 8 + code:e40a/00/07+e40c/39/fb+e408/04/00 + 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 + name:Adventures of Dino Riki (USA) + cheat + description:Invincibility + code:8a30/60 + cheat + description:Don't fall into the pits (you'll still lose any special ability you currently have) + code:89c1/02/00 + cheat + description:Hit anywhere + code:99ff/bd/4c+9a01/03/9a+9a00/64/4f + cheat + description:Once Macho, stay Macho + code:89e5/45/05 + cheat + description:Start and stay as Macho-Riki + code:8581/85/c6 + cheat + description:Start as Macho-Riki + code:8581/85/e6 + cheat + description:Start with infinite lives + code:860e/c6/a5 + cheat + description:Start with 1 life + code:84d9/02/00 + cheat + description:Start with 6 lives + code:84d9/02/05 + cheat + description:Start with 9 lives + code:84d9/02/08 + cheat + description:Start with infinite life hearts + code:8a3f/c6/a5 + cheat + description:Start with 4 life hearts + code:84dd/02/04 + cheat + description:Start with 8 life hearts + code:84dd/02/08 + cheat + description:Start on stage 2-1 + code:84d0/85/46+84cd/00/02 + cheat + description:Start on stage 3-1 + code:84d0/85/46+84cd/00/04 + cheat + description:Start on stage 4-1 + code:84d0/85/46+84cd/00/06 + cheat + description:Start on stage 4-2 + code:84d0/85/46+84cd/00/08 + cheat + description:Start on stage 4-3 + code:84d0/85/46+84cd/00/0a + cheat + description:Start on stage 4-4 + code:84d0/85/46+84cd/00/0c + +cartridge sha256:bb5859ced6b028934edddc734e3599f8dd7857b92838baf6a7d46df5dd151f6b + name:Adventures of Dr. Franken, The (USA) (Proto) + cheat + description:Infinite health + code:e6ef/c6/a5 + +cartridge sha256:a0bc241936acf1993a300ab21c197a2647b6c072cfbb8e3f83424a9ab6655cc7 + name:Adventures of Gilligan's Island, The (USA) + cheat + description:Infinite time + code:f20b/c6/a5 + cheat + description:Infinite rope + code:b358/ce/ad + cheat + description:Infinite supply of food + code:b32d/ce/ad + cheat + description:Start with 9 units of food + code:dd23/02/09 + cheat + description:Start with 1 unit of food + code:dd23/02/01 + cheat + description:More time for Episode 1 + code:f27b/09/0b + cheat + description:More time for Episode 2 + code:f27c/0b/0d + cheat + description:More time for Episode 3 + code:f27d/13/14 + cheat + description:Start with 9 ropes + code:dd28/02/09 + cheat + description:Start with 1 rope + code:dd28/02/01 + cheat + description:Start on Episode 2 + code:dc6a/00/01+dc6b/85/24 + cheat + description:Start on Episode 3 + code:dc6a/00/02+dc6b/85/24 + +cartridge sha256:c5e47c0479f500b86995fc8d09e132f5ba3f54cfd9a2a601ea3848bb60871a20 + name:Adventures of Lolo (USA) + cheat + description:Invincibility + code:9988/06/00+c8c1/45/00+ceb1/e6/a5 + cheat + description:Infinite lives + code:9995/c6/a5 + cheat + description:Infinite shots + code:b058/c6/a5 + cheat + description:Always have shot ability + code:b055/fb/06 + cheat + description:Hit anywhere + code:b12f/b0/d0+b130/0a/44 + cheat + description:Chests are always open + code:af76/f0/90 + cheat + description:Walk through anything + code:ace0/f0/24 + cheat + description:Walk faster + code:ae43/ff/fe+ae25/ff/fe+ae3f/01/02+ae29/01/02 + cheat + description:1 life for Lolo + code:98c1/05/01 + cheat + description:9 lives for Lolo + code:98c1/05/09 + +cartridge sha256:12d3119e25f7b40a7ccc546f5d92edaad86fb0083facf6dd61db512bac45f99d + name:Adventures of Lolo 2 (USA) + cheat + description:Invincibility + code:abba/e6/60 + cheat + description:Infinite lives + code:9b26/c6/24 + cheat + description:Always have shot ability + code:a8f8/fb/04 + cheat + description:Never lose magic shots + code:a8fb/c6/24 + cheat + description:Start with 1 life + code:99d2/05/01 + cheat + description:Start with 10 lives + code:99d2/05/0a + cheat + description:Start with 15 lives + code:99d2/05/0f + cheat + description:Start with 2 magic shots + code:9a05/00/02 + cheat + description:Start with 4 magic shots + code:9a05/00/04 + cheat + description:Start on world 5 + code:99b4/00/04 + cheat + description:Start on world 10 + code:99b4/00/09 + cheat + description:Start on world 15 + code:99b4/00/0e + cheat + description:Start on world 20 + code:99b4/00/13 + cheat + description:Start on world 25 + code:99b4/00/18 + cheat + description:Start on world 30 + code:99b4/00/1d + +cartridge sha256:24f7bb802a0ddce0648ea9f156db42b3eaf4cc6598ce852ffac9f849bf92abee + name:Adventures of Lolo 3 (USA) + cheat + description:Invincibility + code:96f6/e6/60+8d26/e6/60 + cheat + description:Always have shot ability + code:8a94/fb/02 + cheat + description:Infinite shots for each room on pick-up + code:8a95/c6/a5 + +cartridge sha256:322d6be47ed539c3dd3c1c92398e9842c3922d7c13914b9c72752ddec377145c + name:Adventures of Rad Gravity, The (USA) + cheat + description:Infinite health + code:ebe2/bd + +cartridge sha256:03db3d003eaa91e1434093ea259a82b9f2d5ed5b02404f9feba05819f69f81c4 + name:Adventures of Rocky and Bullwinkle and Friends, The (USA) + cheat + description:Infinite health + code:8c9d/8d/ad + cheat + description:Infinite lives + code:8c7b/ce/ad + cheat + description:Infinite Bombs + code:86c1/ce/cd + cheat + description:Get bombs from anywhere + code:8b41/98/00+8b60/9b/00 + cheat + description:Rocky loses no health when flying when you have full health + code:846f/07/06 + cheat + description:Rocky loses more health when flying when you have full health + code:8468/02/06 + cheat + description:Bullwinkle loses no health when headbutting + code:8475/01/00 + cheat + description:Bullwinkle loses more health when headbutting + code:8471/04/08 + cheat + description:Start with no Bombs + code:801f/0a/00+d284/0a/00 + cheat + description:Start with 2 lives + code:801a/04/01 + cheat + description:Start with 30 Bombs + code:801f/0a/1e + +cartridge sha256:227e8a900206d0f8c67b7cb09eaee25f181085623b42bd9694dc30986d955f27 + name:Adventures of Tom Sawyer (USA) + cheat + description:Infinite lives + code:c114/c6/a6 + cheat + description:Hit anywhere + code:b88e/35/00+e379/b0/50+bcc0/b0/50+c3ef/b0/50 + cheat + description:Only 5 T's lost from skulls + code:c526/0a/05 + cheat + description:Start with 1 Tom - P1 + code:a0b5/03/01 + cheat + description:Start with 1 Tom - P2 + code:a37b/03/01 + cheat + description:Start with 6 Toms - P1 + code:a0b5/03/06 + cheat + description:Start with 6 Toms - P2 + code:a37b/03/06 + cheat + description:Start with 9 Toms - P1 + code:a0b5/03/09 + cheat + description:Start with 9 Toms - P2 + code:a37b/03/09 + cheat + description:Start at the river - P1 + code:a552/be/c9 + cheat + description:Start in the forest - P1 + code:a552/be/d4 + cheat + description:Start in the house - P1 + code:a552/be/df + cheat + description:Start in the sky - P1 + code:a552/be/ea + cheat + description:Start in the cave - P1 + code:a552/be/f5 + cheat + description:Start at the river - P2 + code:a380/01/02+a38a/03/08 + cheat + description:Start in the forest - P2 + code:a380/01/03+a38a/03/0d + cheat + description:Start in the house - P2 + code:a380/01/04+a38a/03/12 + cheat + description:Start in the sky - P2 + code:a380/01/05+a38a/03/17 + cheat + description:Start in the cave - P2 + code:a380/01/06+a38a/03/1c + +cartridge sha256:69300586af39342fccc249134f6f44ebbd0fce7c1e5b93151cff63bb35072add + name:After Burner (USA) (Unl) + cheat + description:Invincibility + code:924b/85/a5 + cheat + description:Infinite lives + code:e2a9/c6/c5 + cheat + description:Infinite missiles + code:8af2/c6/c5 + +cartridge sha256:4fb12ad1c791c7ee8d5ec824eff871d71b43b92c4e93b45ed0b60f022459b917 + name:After Burner (Japan) + cheat + description:Infinite lives + code:e1f1/c6/a5 + +cartridge sha256:1b5857f9fd57d6f50d8d1e57db67203155fb2974ae426deac3398efef1dbf042 + name:Aigina no Yogen - Balubalouk no Densetsu Yori (Japan) + cheat + description:Invincibility + code:95d1/ad + cheat + description:Infinite lives + code:9439/bd + +cartridge sha256:e10ff4cfeaf0c16a71d7fffbf79ad3260c119431db6fad603d07ec971746849a + name:Airball (Unknown) (Proto1) + cheat + description:Can use float at any difficulty level + code:c580/10/00 + +cartridge sha256:6d0215929f2dfeeecdeee4dd50b8aec07f279a8ab8df1dc4e877bbcad3db0d37 + name:Air Fortress (USA) + cheat + description:Invincibility + code:a7d8/f0/d0+a7dd/d0/f0 + cheat + description:Infinite energy + code:cdcf/8d/ad+ce01/8d/ad + cheat + description:Don't take damage inside fortress + code:cdcd/e5/24+cdff/e5/24 + cheat + description:Infinite lives + code:9c34/c6/c5 + cheat + description:Infinite lives outside fortress + code:9c34/c6/a5 + cheat + description:Infinite Beam Bullets + code:9e45/01/00 + cheat + description:Hit anywhere - inside fortress + code:9c5a/bc/4c+9c5c/64/9c+9c5b/a4/a1+9cfd/95/a5 + cheat + description:Hit anywhere - outside fortress + code:ab17/3b/00+ab27/fd/4c+ab28/4c/5c+ab65/95/a5+ab29/65/ab + cheat + description:Double Bombs on pick-up + code:ac47/05/10 + cheat + description:Extra energy on pick-up + code:aa7b/64/7f+aa80/64/7f + cheat + description:Start with 1 life + code:9a64/03/01 + cheat + description:Start with 6 lives + code:9a64/03/06 + cheat + description:Start with 9 lives + code:9a64/03/09 + cheat + description:Start on level 2 + code:9a5a/29/a2+9a5b/07/01+9a5c/85/86 + cheat + description:Start on level 3 + code:9a5a/29/a2+9a5b/07/02+9a5c/85/86 + cheat + description:Start on level 4 + code:9a5a/29/a2+9a5b/07/03+9a5c/85/86 + cheat + description:Start on level 5 + code:9a5a/29/a2+9a5b/07/04+9a5c/85/86 + cheat + description:Start on level 6 + code:9a5a/29/a2+9a5b/07/05+9a5c/85/86 + cheat + description:Start on level 7 + code:9a5a/29/a2+9a5b/07/06+9a5c/85/86 + +cartridge sha256:b82c1234165cd725d8e7f3e51926bceb834744eb49ad915bd3ea8b76fa465eb1 + name:Airwolf (USA) + cheat + description:Infinite health + code:af6d/bd + cheat + description:Infinite lives + code:82e1/bd + cheat + description:Start with 1 life + code:cd36/03/01 + cheat + description:Start with 6 lives + code:cd36/03/06 + cheat + description:Start with 9 lives + code:cd36/03/09 + cheat + description:Start at last mission reached + code:ccac/5b/61 + cheat + description:Start with 30 missiles + code:8261/0f/1e + cheat + description:Start with 45 missiles + code:8261/0f/2d + cheat + description:Start with infinite missiles + code:a1d0/c6/24 + cheat + description:Sets missiles to 5 when you refuel + code:85e5/0f/05 + cheat + description:Sets missiles to 30 when you refuel + code:85e5/0f/1e + cheat + description:Infinite health (alt) + code:00b9/00 + cheat + description:Infinite lives (alt) + code:036c/02 + +cartridge sha256:60b1aebdc0a19afc5d3e7dc4f09d8a968580e007197461a8a142656702c27f0d + name:Akumajou Dracula (Japan) + cheat + description:Infinite health + code:e7c0/85/ad + cheat + description:Infinite lives + code:c312/c6/a9 + cheat + description:Infinite time + code:a0b4/20/ad + cheat + description:Clock doesn't use hearts + code:daaa/84/a4 + cheat + description:Weapons don't use hearts + code:dae5/84/a4 + cheat + description:Can't add hearts + code:e7e9/85/a4 + cheat + description:Keep weapon after losing a life + code:c33b/8d/2c + cheat + description:Start with rapid-fire shots + code:b680/01/00 + cheat + description:Start with 80 hearts + code:c983/05/50 + cheat + description:Start with 99 hearts + code:c983/05/63 + +cartridge sha256:c70f0f5d4054ce7c4850259879c9823add73ccc234ddcf96d95681bb78bd2c58 + name:Akumajou Densetsu (Japan) + cheat + description:Infinite life + code:8c27/a5/85 + cheat + description:Infinite hearts + code:8b7c/01/00 + cheat + description:Infinite time + code:899d/03/05 + cheat + description:Infinite lives + code:897c/85/ad + cheat + description:Multi-jump + code:8bd7/10/60+97dc/56/58+93dc/56/58+9859/c9/28+9863/65/d8+985b/b0/90+9868/08/05+9861/0c/05+9866/26/05+9860/d0/a9+985d/ad/8d+9862/ad/8d+9838/85/a5+9858/04/a5+985a/08/0a + cheat + description:Invincibility (blinking) + code:007d/01 + cheat + description:Trevor Belmont - Have fully powered whip + code:008b/02 + cheat + description:Have no special weapon + code:0082/00 + cheat + description:Have Axe + code:0082/01 + cheat + description:Have Clock + code:0082/0b + cheat + description:Have Cross + code:0082/02 + cheat + description:Have Dagger + code:0082/03 + cheat + description:Have Holy Water + code:0082/04 + +cartridge sha256:ff5b96853cf67171918aad5157661dc223e0002e0373e2580cee2e207bb0a682 + name:Akumajou Special - Boku Dracula-kun (Japan) + cheat + description:Invincibility + code:dd88/60 + cheat + description:Infinite health + code:dd88/c6/a5 + cheat + description:Infinite lives + code:dcae/c6/a5 + +cartridge sha256:4c95afeda9a92842933c174983fee954cf40d1301d32f6169f6653f1e5cdc10f + name:Al Unser Jr. Turbo Racing (USA) + cheat + description:Can't be slowed down by signs and grass, prevents suspension from being shot + code:d7f8/29/00+d851/85/a5+d801/c6/a5 + +cartridge sha256:722096b8929442310bc268f9cfea10b26cff8a7e900197b54c73b4a8603b5d96 + name:Aladdin (Europe) + cheat + description:Invincibility + code:ccff/f0/d0+f983/f0/d0 + cheat + description:Infinite energy + code:ba0d/85/a5 + cheat + description:Infinite lives + code:c2c7/8d/ad + cheat + description:Infinite Apples + code:c88c/8d/ad + +cartridge sha256:4b088e1e78981308da68883cf8292337ff8d899bf82a78d17e7a7af2745846e7 + name:Alfred Chicken (USA) + cheat + description:Invincibility + code:f4ad/a5 + cheat + description:Infinite time (alt) + code:b8c2/60 + cheat + description:Infinite lives + code:f8cc/01/e0 + cheat + description:Infinite lives (alt) + code:f8ca/ad + cheat + description:Infinite time + code:b8b0/ad/60 + cheat + description:255 points for each present collected + code:f9a4/32/ff + cheat + description:108 points for each present collected + code:f9a4/32/64 + cheat + description:Only need 1 diamond for an extra life + code:b146/06/01 + cheat + description:3 balloons needed to complete a level + code:ca2a/b1/a9+ca2b/51/03 + cheat + description:2 balloons needed to complete a level + code:ca2a/b1/a9+ca2b/51/02 + cheat + description:1 balloon needed to complete a level + code:ca2a/b1/a9+ca2b/51/01 + cheat + description:Start with 1 life + code:c655/02/00 + cheat + description:Start with 2 lives + code:c655/02/01 + cheat + description:Always spring-jump + code:dd68/90 + +cartridge sha256:d73a9a1fae7396754c19eecd6aa9e44d02c230df8efed0bafd86aa1cb0dd2a23 + name:Alien 3 (USA) + cheat + description:Invincibility + code:9c97/ce/ad+e9cb/64/0f+d5d4/64/0f + cheat + description:Infinite health + code:fab3/8d/ad + cheat + description:Infinite time + code:b28e/9d/bd + cheat + description:Infinite lives + code:e24a/ce/ad + cheat + description:Infinite gun heat + code:dc9f/ee/a5 + cheat + description:Invincible against long falls + code:cf54/0f/00 + cheat + description:Infinite Radar + code:aa6e/ce/ad + cheat + description:Infinite ammo for Machine gun + code:dcaf/ce/ad + cheat + description:Infinite ammo for Grenade Launcher + code:dc6d/ce/ad + cheat + description:Infinite ammo for Grenade Launcher 2 + code:bd46/ce/ad + cheat + description:Infinite ammo for Flame Thrower + code:d903/ce/ad + cheat + description:Hit anywhere + code:b697/0d/00+f542/e5/60 + cheat + description:Super-jump + code:a036/03/15+a039/03/15 + cheat + description:Level skip (pause and press any key (except left) + code:b3ef/42/36 + cheat + description:Always have Radar + code:e9cf/00/ff + cheat + description:Invincibility (alt) + code:03c8/4a + cheat + description:Infinite health (alt) + code:074a/12 + cheat + description:Infinite time (alt) + 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 + name:Alien Syndrome (Japan) + cheat + description:Infinite lives + code:cefc/b1 + cheat + description:Infinite time + code:f789/bd + cheat + description:Don't lose life when touched + code:8928/b1 + +cartridge sha256:d676ef6f7aa3b042ae5a0c95a7f07fabb4c3a5fccb3767ae1950713e51189a47 + name:Alien Syndrome (USA) (Unl) + cheat + description:Infinite time + code:f23f/ce/ad + cheat + description:Don't lose life when shot or touched + code:c98a/ff/00 + cheat + description:Don't lose life from falling down holes + code:ca76/ff/00 + cheat + description:Set timer to 440 + code:f199/33/34 + cheat + description:1 life after continue + code:c3a4/04/01 + cheat + description:8 lives after continue + code:c3a4/04/08 + cheat + description:Start with 1 life - both players + code:c511/04/01 + cheat + description:Start with 8 lives - both players + code:c511/04/08 + cheat + description:Start with Flame Thrower + code:c56c/00/01 + cheat + description:Start with Fireball + code:c56c/00/02 + cheat + description:Start with Laser + code:c56c/00/03 + cheat + description:Start on round 2 + code:fbf8/10/01+fbfa/00/b4+fbfb/20/03 + cheat + description:Start on round 3 + code:fbf8/10/02+fbfa/00/b4+fbfb/20/03 + cheat + description:Start on round 4 + code:fbf8/10/03+fbfa/00/b4+fbfb/20/03 + cheat + description:Start on round 5 + code:fbf8/10/04+fbfa/00/b4+fbfb/20/03 + cheat + description:Start on round 6 + code:fbf8/10/05+fbfa/00/b4+fbfb/20/03 + cheat + description:Start on round 7 + code:fbf8/10/06+fbfa/00/b4+fbfb/20/03 + +cartridge sha256:a762d0a90d16c84b5f2b014816b37675cf5115320be7e815effbb64d91b2014d + name:All Night Nippon Super Mario Brothers (Japan) (Promotion Card) + cheat + description:All blocks are starmen + code:89c9/cd + cheat + description:Invisible 1-up blocks are visible and all mushroom blocks are 1-ups + code:89f9/c1 + cheat + description:Start on level 8-4 + code:c4b2/00/07+c4bc/00/03 + +cartridge sha256:3addebdec132929ecad2a8612a4ba54ccc39b9ada2295692f836c6b48d015054 + name:Alpha Mission (USA) + cheat + description:Invincibility + code:c1aa/91/b1 + cheat + description:Infinite lives + code:92d7/c6/a5 + cheat + description:Keep power up after death + code:8375/85/24 + cheat + description:Keep energy after death + code:8377/85/24 + cheat + description:Thunder uses 25% normal energy + code:980b/08/04 + cheat + description:Triple energy gained on 'E' pick-up + code:b6a1/02/06 + cheat + description:Less energy lost on 'Bad E' pick-ups + code:b6b4/04/02 + cheat + description:Shield doesn't use energy + code:c004/85/a5 + cheat + description:You can re-use weapon after selecting + code:8c70/85/25 + cheat + description:Start with all weapons available + code:8347/03/ff + cheat + description:Start with 1 life + code:8356/03/01 + cheat + description:Start with double lives + code:8356/03/06 + cheat + description:Start with triple lives + code:8356/03/09 + +cartridge sha256:a978de5d5f343eacb0a6f12427327ecbe9b2e9cf881569aec7b838bd44237d84 + name:Amagon (USA) + cheat + description:Invincibility + code:d3f2/f0/d0 + cheat + description:Invincible against enemies + code:a19c/a9/60 + cheat + description:Invincible against bullets + code:a121/a9/60 + cheat + description:Invincible against area boss + code:a1f0/a9/60 + cheat + description:Infinite mega-power + code:a255/95/24 + cheat + description:Infinite ammo + code:f663/01/00 + cheat + description:Infinite ammo (alt) + code:f664/95/b5 + cheat + description:Hit anywhere + code:f6bf/62/00 + cheat + description:One hit kills + code:f6d2/4e/00 + cheat + description:Multi-jump + code:ce7c/06/00+ce8e/04/00+ce87/06/08 + cheat + description:Gain 10 bullets on pick-up + code:cd6b/02/01 + cheat + description:Gain 30 bullets on pick-up + code:cd6b/02/03 + cheat + description:Start with no bullets + code:e299/04/01 + cheat + description:Start with 600 bullets + code:e299/04/07 + cheat + description:Start with infinite lives + code:cf27/01/00 + cheat + description:Start with 1 life + code:e29d/04/01 + cheat + description:Start with 8 lives + code:e29d/04/08 + +cartridge sha256:be12cff13a06e0b5de2dad4d431f7cf9a6aa73be45cdbd952dfd03a9d23571b6 + name:American Gladiators (USA) + cheat + description:Less joust time + code:943a/63/3c + cheat + description:Stop joust timer + code:a32b/ce/2c + cheat + description:Less cannonball time + code:801c/63/3c + cheat + description:Stop cannonball time + code:9104/ce/2c + cheat + description:Less wall time + code:aa4a/63/3c + cheat + description:Stop wall timer + code:aa98/de/2c + cheat + description:More assault time + code:8726/3d/63 + cheat + description:Less assault time + code:8726/3d/29 + cheat + description:Stop assault timer + code:8755/ce/2c + cheat + description:More power ball time - level 1 + code:915a/3d/63 + cheat + description:More power ball time - level 2 + code:915b/38/63 + cheat + description:More power ball time - level 3 + code:915c/33/63 + cheat + description:More power ball time - level 4 + code:915d/2e/63 + cheat + description:Start with 1 life - P1 + code:86a3/05/01 + cheat + description:Start with 8 lives - P1 + code:86a3/05/08 + cheat + description:Start with 10 lives - P1 + code:86a3/05/0a + cheat + description:Start with 20 lives - P1 + code:86a3/05/14 + cheat + description:Start with 1 life - P2 + code:86e3/05/01 + cheat + description:Start with 8 lives - P2 + code:86e3/05/08 + cheat + description:Start with 10 lives - P2 + code:86e3/05/0a + cheat + description:Start with 20 lives - P2 + code:86e3/05/14 + cheat + description:Start on level 2 - P1 + code:86a1/00/01 + cheat + description:Start on level 3 - P1 + code:86a1/00/02 + cheat + description:Start on level 4 - P1 + code:86a1/00/03 + cheat + description:Start on level 2 - P2 + code:86e1/00/01 + cheat + description:Start on level 3 - P2 + code:86e1/00/02 + cheat + description:Start on level 4 - P2 + code:86e1/00/03 + +cartridge sha256:427876021e6c077479a1a1171e013f84ae951197005a317b099df3b6c2862603 + name:Anticipation (USA) + cheat + description:More time to answer questions + code:97b7/19/32 + cheat + description:Less time to answer questions + code:97b7/19/0f + cheat + description:Infinite chances + code:a670/c0/00 + +cartridge sha256:bb834eb82f0ac53114035e6f353434a934d4aa47742644740de5fa8b2b033b5b + name:Arch Rivals - A Basketbrawl! (USA) + cheat + description:Never miss a shot - both players + code:9a61/d0/24 + cheat + description:More time for a quarter + code:ba27/34/38+b171/34/38 + cheat + description:Less time for a quarter + code:ba27/34/32+b171/34/32 + cheat + description:Run faster without ball + code:90f3/20/60+9160/20/60 + cheat + description:Super speed + code:90e9/04/25+9154/04/25 + +cartridge sha256:751d3bf4722ce117d8ab7ff78059f42206ead5299716d91d5ff27d3900d555ad + name:Archon (USA) + cheat + description:Unrestricted ground movement + code:d05d/eb/00 + cheat + description:Unrestricted flying movement + code:d044/04/00 + +cartridge sha256:7768ef85519c94dc40d09bc598121825d103fcf1d4927be59f597b0a3509d15f + name:Argus (Japan) + cheat + description:Invincibility + code:980c/85/a5 + cheat + description:Infinite lives + code:812f/c6/c5 + +cartridge sha256:a3763e702f8ae0818480cf0a8b2395d3f928c539f75e230ed43fa6b904fe6365 + name:Arkanoid (USA) + cheat + description:Infinite lives - both players + code:8678/c6/a9 + cheat + description:Infinite lives + code:8678/c6/a5 + cheat + description:Paddle hits ball anywhere + code:a8df/33/00+a8e7/90/50 + cheat + description:No lasers + code:80e6/20/ad + cheat + description:Square ball + code:a1a1/e6 + cheat + description:Start with 1 life - P1 + code:9c13/03/01 + cheat + description:Start with 6 lives - P1 + code:9c13/03/06 + cheat + description:Start with 9 lives - P1 + code:9c13/03/09 + cheat + description:Start on boss level + code:9c1f/01/24 + cheat + description:Start on level 0 + code:9c1f/01/00 + cheat + description:Start on level 1 + code:9c1f/01/01 + cheat + description:Start on level 2 + code:9c1f/01/02 + cheat + description:Start on level 3 + code:9c1f/01/03 + cheat + description:Start on level 4 + code:9c1f/01/04 + cheat + description:Start on level 5 + code:9c1f/01/05 + cheat + description:Start on level 6 + code:9c1f/01/06 + cheat + description:Start on level 7 + code:9c1f/01/07 + cheat + description:Start on level 8 + code:9c1f/01/08 + cheat + description:Start on level 9 + code:9c1f/01/09 + cheat + description:Start on level 10 + code:9c1f/01/0a + cheat + description:Start on level 11 + code:9c1f/01/0b + cheat + description:Start on level 12 + code:9c1f/01/0c + cheat + description:Start on level 13 + code:9c1f/01/0d + cheat + description:Start on level 14 + code:9c1f/01/0e + cheat + description:Start on level 15 + code:9c1f/01/0f + cheat + description:Start on level 16 + code:9c1f/01/10 + cheat + description:Start on level 17 + code:9c1f/01/11 + cheat + description:Start on level 18 + code:9c1f/01/12 + cheat + description:Start on level 19 + code:9c1f/01/13 + cheat + description:Start on level 20 + code:9c1f/01/14 + cheat + description:Start on level 21 + code:9c1f/01/15 + cheat + description:Start on level 22 + code:9c1f/01/17 + cheat + description:Start on level 23 + code:9c1f/01/17 + cheat + description:Start on level 24 + code:9c1f/01/18 + cheat + description:Start on level 25 + code:9c1f/01/19 + cheat + description:Start on level 26 + code:9c1f/01/1a + cheat + description:Start on level 27 + code:9c1f/01/1b + cheat + description:Start on level 28 + code:9c1f/01/1c + cheat + description:Start on level 29 + code:9c1f/01/1d + cheat + description:Start on level 30 + code:9c1f/01/1e + cheat + description:Start on level 31 + code:9c1f/01/1f + cheat + description:Start on level 32 + code:9c1f/01/20 + cheat + description:Start on level 33 + code:9c1f/01/21 + cheat + description:Start on level 34 + code:9c1f/01/22 + cheat + description:Start on level 35 + code:9c1f/01/23 + cheat + description:Start on level 36 + code:9c1f/01/24 + +cartridge sha256:8593b6ae7b19b2e767ad2c207c5a83dea90030414f45eef4c0dec3c3a5530364 + name:Arkanoid II (Japan) + cheat + description:Infinite lives + code:c8d2/c6/c5 + +cartridge sha256:381fcbe2b714c38fdeb4045d93f0867fe80f4a219077c3dc5a683a05a8b8e78a + name:Arkista's Ring (USA) + cheat + description:Infinite health + code:9516/e5/24 + cheat + description:Less damage from powerful monsters + code:9507/0f/03 + cheat + description:Infinite lives + code:bc32/ce/ad + cheat + description:Hit anywhere + code:ae2a/c0/00 + cheat + description:Walk through walls + code:9742/18/00+9717/0f/00+978a/9c/00+96dc/16/00 + cheat + description:Start with fewer hearts + code:8546/05/02 + cheat + description:Start with more hearts + code:8546/05/09 + cheat + description:Start with 20 continues + code:8534/0b/15 + cheat + description:Start with 5 continues + code:8534/0b/06 + cheat + description:Start with 1 life + code:854e/03/01 + cheat + description:Start with 6 lives + code:854e/03/06 + cheat + description:Start with 9 lives + code:854e/03/09 + 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 + name:Armadillo (Japan) + cheat + description:Invincibility + code:b4a8/c9/a9+b4a9/03/00 + +cartridge sha256:20aaf9705d2cc17bac10468544afb250019f43983677b904ca88328f67aa9439 + name:Astro Fang - Super Machine (Japan) + cheat + description:Infinite fuel + code:d98a/85/a5 + cheat + description:Infinite Missiles + code:b278/85/a5 + +cartridge sha256:a08e6b53f1fa593e001719d87e2f203deb24ee1d389a8f3f339d75e9fb7c02f4 + name:Astyanax (USA) + cheat + description:Invincibility + code:8174/d0/f0 + cheat + description:Infinite health + code:c536/85/a5 + cheat + description:Infinite SP (spell) + code:c38c/18/30 + cheat + description:Hit anywhere + code:d9cc/b0/24+d9b5/30/24 + cheat + description:Multi-jump + code:828d/77/80+828f/10/80+8291/35/32 + cheat + description:Double health and SP + code:8a46/14/28 + cheat + description:Keep weapons after death + code:cb30/ce/ad + cheat + description:Start with Blast Spell + code:8a4c/00/01 + cheat + description:Start with Bind Spell + code:8a4c/00/02 + cheat + description:Start with extra weapon power + code:8a42/04/14 + cheat + description:Start with 1 life + code:8cbb/02/00+8a52/02/00 + cheat + description:Start with double lives + code:8cbb/02/05+8a52/02/05 + cheat + description:Start with triple lives + code:8cbb/02/08+8a52/02/08 + cheat + description:Invincibility (alt) + code:007d/03 + cheat + description:Infinie lives + code:0096/03 + +cartridge sha256:2137d1621d29df50100f4d0fba3bafa0be56ccd0c832e44cd29dd7f0d75b374e + name:Athena (USA) + cheat + description:Infinite health (after first 2 units) + code:a533/85/24 + cheat + description:Infinite time + code:b733/01/00 + cheat + description:Collect items from anywhere + code:89c9/b0/10 + cheat + description:Start with energy boost + code:f1cf/0c/20 + cheat + description:Start with extra time + code:e758/05/07 + cheat + description:Start with less time + code:e758/05/04 + cheat + description:Start with 1 life + code:f1cb/02/00 + cheat + description:Start with 6 lives + code:f1cb/02/05 + cheat + description:Start with 9 lives + code:f1cb/02/08 + 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 + name:Attack of the Killer Tomatoes (USA) + cheat + description:Invincibility + code:f1e6/60 + cheat + description:Infinite health + code:f1f6/ad + cheat + description:Infinite lives + code:f4f4/cd + 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 + name:Atlantis no Nazo (Japan) + cheat + description:Infinite lives + code:81e8/ce/bd + cheat + description:Partial invincibility + code:b79f/20/ad+b279/20/ad+b411/20/ad+81b0/20/ad + +cartridge sha256:f91113b6a4bcd39d86ad5bbeaeb0f103461ada2cae513d1648a77ee575caf69b + name:Auto-Upturn (Asia) (PAL) (Unl) + cheat + description:Infinite health (blinking) + code:a3f6/c6/a5+a42b/c6/a5 + cheat + description:Infinite lives + code:a416/c6/a5 + cheat + description:Infinite time + code:95c6/c6/a5 + +cartridge sha256:fb20d9562088cfa620ad0221e6e6f6c6d1f08e5a9cee2a97c0ef4fc39f050c6c + name:Baby Boomer (USA) (Unl) + cheat + description:Infinite lives + code:e242/ce/cd + +cartridge sha256:2bd744ff0d76653b9e218f6cea37f86bbdc6bc9b7a816c5fa236594ed1eb496a + name:Back to the Future (USA) + cheat + description:Invincibility - Street stages + code:8afa/05/00+8aff/37/10+8b3c/f0/10 + cheat + description:Disable all timers + code:9aeb/a5/60 + cheat + description:Never lose a life in Hill Valley game + code:814c/ce/ad + cheat + description:Never lose a life in Cafe game + code:819b/ce/ad + cheat + description:Never lose a life in School game + code:81c3/ce/ad + cheat + description:Never lose a life in Dancing Hall game + code:81eb/ce/ad + cheat + description:Start with 1 life + code:80ac/04/01 + cheat + description:Start with 8 lives + code:80ac/04/08 + +cartridge sha256:b265adba4a6f751f4da7b157672f324264f11fed3ca0b1e4ca703eb0b8a5ab77 + name:Back to the Future Part II & III (USA) + cheat + description:Infinite lives + code:81ab/ce/ad + cheat + description:Infinite fuel + code:8209/e5/24+821a/e5/24 + cheat + description:Keep shots + code:8c44/85/24 + cheat + description:Quicker shots + code:88c5/19/09 + cheat + description:Start with 20 nuclear fuel units + code:c22f/01/02 + cheat + description:Start with 30 nuclear fuel units + code:c22f/01/03 + cheat + description:Start with 20 lives + code:c22a/01/02 + cheat + description:Start with 30 lives + code:c22a/01/03 + +cartridge sha256:56382fac9104b26797de262a7c70ddd5850451d81a5008f3943d7bc492cbeb41 + name:Bad Dudes (USA) + cheat + description:Invincibility + code:8102/10/50+91df/ad/60+8101/0a/b8 + cheat + description:Infinite health + code:810e/f0/10 + cheat + description:Infinite health (alt) + code:8118/8d/ad + cheat + description:Infinite lives + code:c578/ce/ad + cheat + description:Infinite continues + code:c598/ce/2c + cheat + description:Infinite time + code:fb61/ce/cd + cheat + description:Hit anywhere + code:9135/5c/00 + cheat + description:One hit kills + code:dcbf/f0/10 + cheat + description:Start with 1 life and 1 continue + code:a2ff/03/01 + cheat + description:Start with double lives and continues + code:a2ff/03/06 + cheat + description:Start with triple lives and continues + code:a2ff/03/09 + cheat + description:Gain double usual energy from drinks + code:87d5/05/09 + 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 + name:Bad News Baseball (USA) + cheat + description:Balls are considered strikes + code:9410/e8/ea + cheat + description:Play as girls team + code:c102/13/71+c100/90/01 + cheat + description:Have 0 outs + code:050d/00 + cheat + description:Have 2 outs + code:050d/02 + cheat + description:Team 1 score is 0 + code:0305/00 + cheat + description:Team 2 score is 0 + code:0306/00 + +cartridge sha256:98658d5c8e530994730be6f4f7f76fe09142dee90e0afca613f5d6baaf208f52 + name:Bad Street Brawler (USA) + cheat + description:Infinite health + code:c9f2/9d/bd + cheat + description:Infinite time + code:d723/d6/d5 + cheat + description:Don't die at time out + code:d716/ce/ad + cheat + description:Infinite lives + code:d117/c6/a9 + cheat + description:Infinite lives (alt) + code:d20c/c6/c5 + cheat + description:Start with 1 life + code:d026/03/01 + cheat + description:Start with 6 lives + code:d026/03/06 + cheat + description:Start with 9 lives + code:d026/03/09 + cheat + description:Start on level 5 + code:a7b2/00/04 + cheat + description:Start on level 10 + code:a7b2/00/09 + cheat + description:Start on level 15 + code:a7b2/00/0e + cheat + description:Infinite health (alt) + code:05f1/14 + +cartridge sha256:7328b2eb1c9fe06b98e0cba5c9058bf026e06a94900d490f79436d714eb48d6b + name:Balloon Fight (USA) + cheat + description:Infinite lives + code:f2fd/d6/b5 + cheat + description:Start with only one balloon + code:f3b6/02/01 + cheat + description:Balloons are unburstable + code:efa7/84/60 + cheat + description:Enemies can't burst balloons + code:ea60/0b + cheat + description:Start with 1 life + code:f1f1/02/00 + cheat + description:Start with 6 lives + code:f1f1/02/05 + cheat + description:Start with 9 lives + code:f1f1/02/08 + cheat + description:Start on level 5 - 2P only + code:f1fd/00/04 + cheat + description:Start on level 10 - 2P only + code:f1fd/00/09 + cheat + description:Start on level 15 - 2P only + code:f1fd/00/0e + cheat + description:Infinite lives - P1 + code:0041/02 + cheat + description:Infinite lives - P2 + code:0042/02 + +cartridge sha256:d718f10d4ab57f7ed3891a84bdc496472a242b9c8496a3c0a0de77b45ae2fd58 + name:Banana Prince (Germany) + cheat + description:Invincibility + code:a03e/24/04 + cheat + description:Invincible to enemies + code:aa24/40/00 + cheat + description:Invincible to shots + code:a9d1/40/00 + cheat + description:Invincible to lava + code:baf5/30/50 + cheat + description:Infinite energy + code:a92a/ce/cd + cheat + description:Infinite lives + code:d3ab/ce/cd + cheat + description:Infinite time + code:d42f/ce/cd + cheat + description:Infinite errors in quizes + code:af55/ce/ad + cheat + description:Max health when you die instead of 00 + code:b4ab/00/0c + cheat + description:Each Ring worth 10 + code:cd71/90/70 + cheat + description:Disable invincibility flickering + code:da1c/10/50 + cheat + description:Dice always at 9 in bonus island + code:e6b5/00/09 + cheat + description:Don't loose health when you touch lava + code:bb06/ce/ad + cheat + description:Start with 9 lives + code:de61/03/09 + cheat + description:Start with max health + code:de79/06/0c + +cartridge sha256:bb30e4f4b1f6d8ccfdbd538b6f20347ed732cd37e8ac0a8305a277cf298b3dc8 + name:Barbie (USA) + cheat + description:Invincibility (blinks) + code:d5b8/f0/d0 + cheat + description:Infinite Z's on Dream Meter + code:dfcc/ce/ad + cheat + description:Can re-enter Barbie's dream an infinite number of times + code:8660/ce/ad + cheat + description:Cannot re-enter Barbie's dream + code:808f/02/00 + cheat + description:Start with 9 Z's (1st credit only) + code:aa80/05/09 + cheat + description:Start with 1 Z (1st credit only) + code:aa80/05/01 + +cartridge sha256:f22944452be3259aac853258759f469e7d2e2447c6178f26cc7bd0e89945bc04 + name:Baseball (USA, Europe) + cheat + description:Balls are considered strikes + code:d752/a5/a9 + +cartridge sha256:8bb20791eb3f4fd2455c33f0eead4538af3372205fba70fd4c3e0867b2c34c9a + name:Baseball Simulator 1.000 (USA) + cheat + description:Balls are considered strikes + code:9e44/02/01 + cheat + description:Strike outs aren't allowed + code:a6e5/e6/a9 + cheat + description:Balls aren't counted + code:8670/e6/a5 + cheat + description:1 strike and you're out + code:86d9/03/01 + cheat + description:2 strikes and you're out + code:86d9/03/02 + cheat + description:5 strikes and you're out + code:86d9/03/05 + cheat + description:Strikes aren't counted + code:8667/e6/a5 + cheat + description:1 ball and you walk + code:86d3/04/01 + cheat + description:2 balls and you walk + code:86d3/04/02 + cheat + description:3 balls and you walk + code:86d3/04/03 + cheat + description:9 balls and you walk + code:86d3/04/09 + +cartridge sha256:b035ec9e2a7fc408c19bb2ffd22dceb0483a73e5f5bf232132628c9d8657b1e8 + name:Baseball Stars (USA) + cheat + description:Balls are considered strikes + code:d4e9/03/00 + +cartridge sha256:5f8807999205f3800e445d6265b66fa6edff0070fc38905f7284f0ad437f9f53 + name:Baseball Stars II (USA) + cheat + description:Balls are considered strikes + code:d4c3/f0/a9 + cheat + description:Strikes do not count + code:d55a/ee/ad + cheat + description:Balls do not count + code:d4d6/ee/ad + cheat + description:One strike for an out + code:d561/03/01 + cheat + description:Two strikes for an out + code:d561/03/02 + cheat + description:Four strikes for an out + code:d561/03/04 + cheat + description:Five strikes for an out (only 3 show on screen) + code:d561/03/05 + cheat + description:One ball for a walk + code:d4dd/04/01 + cheat + description:Two balls for a walk + code:d4dd/04/02 + cheat + description:Three balls for a walk + code:d4dd/04/03 + cheat + description:Five balls for a walk (only 3 show on screen) + code:d4dd/04/05 + cheat + description:Six balls for a walk (only 3 show on screen) + code:d4dd/04/06 + cheat + description:One out per side instead of 3 (against human players) + code:d673/03/01 + cheat + description:Two outs per side (against human players) + code:d673/03/02 + cheat + description:Four outs per side (against human players) + code:d673/03/04 + cheat + description:One out per side instead of 3 (against computer) + code:8315/03/01 + cheat + description:Two outs per side (against computer) + code:8315/03/02 + cheat + description:Four outs per side (against computer) + code:8315/03/04 + cheat + description:Game ends after 1 inning + code:9ca6/23/01 + cheat + description:Game ends after 2 innings + code:9ca6/23/03 + cheat + description:Game ends after 3 innings + code:9ca6/23/06 + cheat + description:Game ends after 4 innings + code:9ca6/23/08 + cheat + description:Game ends after 5 innings + code:9ca6/23/0a + cheat + description:Game ends after 6 innings + code:9ca6/23/0c + cheat + description:Game ends after 7 innings + code:9ca6/23/0e + cheat + description:Game ends after 8 innings + code:9ca6/23/10 + +cartridge sha256:b9af9efdf490e14895e7980097a86d2f69d6396383773c221e77c6183a4ab9c8 + name:Bases Loaded II - Second Season (USA) + cheat + description:Balls are considered strikes + code:c6cd/4c/ad + cheat + description:1 strike and you're out - most of the time + code:c891/03/01 + cheat + description:2 strikes and you're out - most of the time + code:c891/03/02 + cheat + description:Outs aren't counted + code:8a1e/ee/ad + cheat + description:Only 2 outs allowed + code:8a1b/02/01 + cheat + description:Only 1 out allowed + code:8a1b/02/00 + cheat + description:Strikes aren't counted + code:89f2/ee/ad+ccd3/ee/ad + cheat + description:Balls aren't counted + code:8a0a/ee/ad+8a0d/ee/ad + +cartridge sha256:5d84d61e7e4c2b7d72a2b4599bd8cc415b71c90d1e332a83f95d96c75bc48efd + name:Bases Loaded 3 (USA) + cheat + description:Computer can't score + code:f754/ee/ad+f75e/fe/ad + cheat + description:Balls are counted as strikes + code:9861/0e/ff+9863/f9/0e + cheat + description:Some strikes aren't counted + code:9895/ee/ad + cheat + description:Balls aren't counted + code:98ca/ee/ad + cheat + description:Strike outs aren't counted + code:8395/ee/ad + cheat + description:1 strike and you're out + code:9892/02/00 + cheat + description:2 strikes and you're out + code:9892/02/01 + cheat + description:Each strike out counts as 3 outs + code:839c/03/01 + cheat + description:Each strike out counts as 2 outs + code:839c/03/02 + cheat + description:5 strike outs allowed + code:839c/03/05 + cheat + description:9 strike outs allowed + code:839c/03/01 + +cartridge sha256:e4aa19e0fd2800b58655eac814e1d9a9aa16d83eabd641789f8a6625591063a3 + name:Bases Loaded 4 (USA) + cheat + description:Balls are considered strikes + code:a34a/0c/ff+a34c/f9/0e + cheat + description:Balls do not count + code:a37c/ee/ad + cheat + description:Strikes do not count + code:a39f/ee/ad + cheat + description:2 strikes and you're out + code:a39c/02/01 + cheat + description:4 strikes and you're out + code:a39c/02/03 + cheat + description:1 ball and you walk + code:a374/03/00 + cheat + description:2 balls and you walk + code:a374/03/01 + cheat + description:3 balls and you walk + code:a374/03/02 + cheat + description:Some batters start with count of 1 and 1 - 2P mode + code:9e73/00/01+849e/00/01 + cheat + description:Some batters start with count of 2 and 2 - 2P mode + code:9e73/00/02+849e/00/02 + +cartridge sha256:a37c97557fc4a8853057c1d193ba9144e560152a2723338a0490ee4fcac5227a + name:Bashi Bazook - Morphoid Masher (USA) (Proto) + cheat + description:Invincibility + code:948f/29/a9 + cheat + description:Everything is Free + code:8201/17/00+8202/8d/ad + cheat + description:One Hit Kills + code:b168/90/d0 + +cartridge sha256:f28821df0114eb6cff1d7b4eadcee87713591709da1dd8b3525cf250156111f1 + name:Batman - The Video Game (USA) + cheat + description:Infinite health + code:9a10/c6/11 + cheat + description:Infinite health (alt) + code:c6c6/c5 + cheat + description:Regenerates health meter (except Joker's gun) + code:c6c4/c5 + cheat + description:Infinite lives + code:c634/c6/a5 + cheat + description:Infinite weapons + code:9c81/85/a5 + cheat + description:Infinite bullets on pick-up + code:9c7b/e5/24 + cheat + description:Hit anywhere + one hit kills + code:9b47/4c/ad + cheat + description:Extra health on heart pick-up + code:9e81/01/04 + cheat + description:Double usual bullets on pick-up + code:9e52/0a/14 + cheat + description:Half usual bullets on pick-up + code:9e52/0a/05 + cheat + description:Multi-jump + code:94b5/dc/f5 + cheat + description:Start with 1 life + code:dc8c/02/00 + cheat + description:Start with 6 lives + code:dc8c/02/05 + cheat + description:Start with 9 lives + code:dc8c/02/08 + 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 + name:Batman - Return of the Joker (USA) + cheat + description:Invincibility + code:b192/8d/ad+aa54/8d/ad+af21/8d/ad + cheat + description:Invincible to bosses + code:b06d/85/ad + cheat + description:Invincibility lasts until next stage + code:9549/02/00 + cheat + description:Protection from enemy bullets + code:af21/8d/ad + cheat + description:Protection from collisions + code:aa54/8d/ad + cheat + description:Protection from electric grids + code:82d6/8d/ad + cheat + description:Infinite health + code:c603/8d/ad + cheat + description:Infinite weapons + code:c4dc/ce/cd + cheat + description:Infinite lives + code:d52a/ce/ad + cheat + description:Each Backpack Energy Capsule counts as two + code:ab6e/02/04 + cheat + description:Each Backpack Energy Capsule counts as four + code:ab6e/02/08 + cheat + description:Don't get stunned when hit + code:b18d/8d/2c + cheat + description:Stand your ground + code:b1b8/04/00+b1c0/8c/2c + cheat + description:Intense knock-back when hit (may get stuck if you knock back into a wall) + code:b1b6/ff/fe+b1bc/00/01 + cheat + description:Continue game with 3 life increments instead of 8 + code:915e/0e/04 + cheat + description:Start with 7 Backpack Energy Capsules instead of none + code:d499/fe/0c + cheat + description:Start with 3 life increments instead of 8 + code:d49e/0e/04 + cheat + description:Start with 1 life + code:d4a3/02/00 + cheat + description:Start with 100 lives + code:d4a3/02/64 + cheat + description:Invincibility after first hit + code:0479/00 + cheat + description:Infinite health + code:0478/08 + cheat + description:Infinite Baterangs + code:0141/0a + cheat + description:Bosses lose health quickly + code:00aa/00 + cheat + description:Start on stage 1-2 + code:0400/02 + cheat + description:Start on stage 1-3 + code:0400/04 + cheat + description:Start on stage 2-1 + code:0400/06 + cheat + description:Start on stage 2-2 + code:0400/08 + cheat + description:Start on stage 3-1 + code:0400/0a + cheat + description:Start on stage 3-2 + code:0400/0c + cheat + description:Start on stage 3-3 + code:0400/0e + cheat + description:Start on stage 4-1 + code:0400/10 + cheat + description:Start on stage 4-2 + code:0400/12 + cheat + description:Start on stage 4-3 + code:0400/14 + cheat + description:Start on stage 5-1 + code:0400/16 + cheat + description:Start on stage 5-2 + code:0400/18 + cheat + description:Start on stage 6-1 + code:0400/1a + cheat + description:Start on stage 6-2 + code:0400/1c + cheat + description:Start on stage 6-3 + code:0400/1e + cheat + description:Start on stage 7-1 + code:0400/20 + cheat + description:Start on stage 7-2 + code:0400/22 + +cartridge sha256:8b7363e037883aaa36d2c643c36a6f09ce49bd515f166154bd2a48e0a6468b9d + name:Batman Returns (USA) + cheat + description:Infinite Batarangs + code:c4dc/ce/ad + cheat + description:Don't lose health from spin attack + code:8a65/02/00 + cheat + description:Almost infinite lives and health + code:c603/8d/2c + cheat + description:Small hearts give more health + code:81d1/10/30 + cheat + description:Hit anywhere + code:a1bd/90/d0+a1b2/90/d0 + cheat + description:One hit kills + code:a215/b0/24 + cheat + description:Power punch + code:a546/02/0f + cheat + description:Power slide attack + code:a54b/05/0f + cheat + description:Power jump kick + code:a54a/05/1a + cheat + description:Walk faster horizontally + code:8dd4/01/04+8dee/01/04 + cheat + description:Start with 9 Batarangs + code:802b/05/09 + cheat + description:Start with full health + code:8013/28/3f + cheat + description:Start with less health + code:8013/28/10 + 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 + name:BattleCity (Japan) + cheat + description:Infinite freeze time once you obtain a clock + code:dc00/ce/ad + cheat + description:256 seconds of freeze time once you obtain a clock + code:e9f6/0a/ff + +cartridge sha256:a50c0b6d93f7e20ecfd8a95abd5b7bccd4cf290901376fcf9e4053b3f964fca1 + name:Battle Formula (Japan) + cheat + description:Infinite life + code:9ad8/85/a5 + +cartridge sha256:d095eab5376c2b7c4f1c09018c9591598831c557e0b691c01ca2480e49e60c0a + name:Battle of Olympus, The (USA) + cheat + description:Invincibility + code:8491/d0/f0 + cheat + description:Infinite health + code:d8df/85/a5 + cheat + description:Hit anywhere + code:846d/d0/18+846e/ee/60 + cheat + description:Get items from anywhere (press down) + code:8ded/e9/00+8de7/b0/24 + cheat + description:Start with less stamina + code:c031/10/08 + cheat + description:Start with more stamina + code:c031/10/20 + cheat + description:Start with Sandals of Hermes + code:ca01/02/00 + cheat + description:Start with Staff of Fennel + code:c037/00/01+c03c/85/24+c03e/85/24 + cheat + description:Start with Sword + code:c037/00/02+c03c/85/24+c03e/85/24 + cheat + description:Start with Divine Sword + code:c037/00/03+c03c/85/24+c03e/85/24 + +cartridge sha256:c49a5d7f565646d76bdc307ccb0202197f579b77c5bf5ea409b5cb29f72edf3a + name:Battleship (USA) + cheat + description:1 round per level + code:8cb3/05/01 + cheat + description:3 rounds per level + code:8cb3/05/03 + cheat + description:Each ship can take only one hit + code:8d31/b9/ad + cheat + description:You only have RIM-66 missiles + code:8d21/95/85 + cheat + description:Start on level 2 + code:8c54/00/01+8c59/85/86+8c55/85/86 + cheat + description:Start on level 3 + code:8c54/00/02+8c59/85/86+8c55/85/86 + cheat + description:Start on level 4 + code:8c54/00/03+8c59/85/86+8c55/85/86 + cheat + description:Start on level 5 + code:8c54/00/04+8c59/85/86+8c55/85/86 + cheat + description:Start on level 6 + code:8c54/00/05+8c59/85/86+8c55/85/86 + cheat + description:Start on level 7 + code:8c54/00/06+8c59/85/86+8c55/85/86 + cheat + description:Start on level 8 + code:8c54/00/07+8c59/85/86+8c55/85/86 + +cartridge sha256:56d25e05dde2048c3a9b4e36ab5325091310ce2b65171615b5596fc542db66fa + name:Battletoads (USA) + cheat + description:Infinite lives + code:a3a2/d6/24 + cheat + description:One hit kills + code:d383/b9 + cheat + description:Enemies easier to kill + code:d383/9d/2c + cheat + description:Mega-jumping + code:8e53/d8/f0 + cheat + description:Double health from flies + code:cfba/08/10 + cheat + description:Maximum health from flies + code:cfba/08/2f + cheat + description:Super fast punching + code:a6b5/01/00 + cheat + description:Force 2-player mode + code:e5f0/31/00 + cheat + description:Start with 0 lives + code:e5fa/03/00 + cheat + description:Start with 1 life + code:e5fa/03/01 + cheat + description:Start with 6 lives + code:e5fa/03/06 + cheat + description:Start with 9 lives + code:e5fa/03/09 + cheat + description:Start on level 2 - Wookie Hole + code:8320/00/02 + cheat + description:Start on level 3 - Turbo Tunnel + code:8320/00/03 + cheat + description:Start on level 4 - Arctic Cavern + code:8320/00/04 + cheat + description:Start on level 5 - Surf City + code:8320/00/05 + cheat + description:Start on level 6 - Karnath's Lair + code:8320/00/06 + cheat + description:Start on level 7 - Volkmire's Inferno + code:8320/00/07 + cheat + description:Start on level 8 - Intruder Excluder + code:8320/00/08 + cheat + description:Start on level 9 - Terra Tubes + code:8320/00/09 + cheat + description:Start on level 10 - Rat Race + code:8320/00/0a + cheat + description:Start on level 11 - Clinger Winger + code:8320/00/0b + cheat + description:Start on level 12 - The Revolution + code:8320/00/0c + cheat + description:Invincibility + code:0574/02 + cheat + description:Infinite lives (alt) + code:0011/05 + +cartridge sha256:4f67a81cc978e5aaf8aa03046c27ddc954f835e2110e346bc28d35f6b4ac61ca + name:Battletoads-Double Dragon (USA) + cheat + description:Infinite lives (except stage 4) + code:b0a0/d6/24 + cheat + description:Infinite lives on stage 4 + code:995a/d6/24 + cheat + description:Bonus score now gives invincibility (instead of invincibility pod) + code:f44d/2c/7d + cheat + description:Longer invincibility + code:f451/05/1f + cheat + description:Even longer invincibility + code:f451/05/35 + cheat + description:Double Dragon super punch + code:88de/02/10 + cheat + description:Battletoads super punch + code:88bb/04/10 + cheat + description:Stronger enemies + code:d1b1/0f/20 + cheat + description:Start with 10 continues + code:82eb/02/09 + cheat + description:Start with full lives + code:9889/03/05 + cheat + description:Start with 1 life + code:9889/03/00 + 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 + name:Beauty and the Beast (Europe) + cheat + description:Infinite hits + code:cf7c/c6/bd + cheat + description:Infinite lives + code:d48a/c6/bd + cheat + description:Infinite time + code:d2a8/e6/bd + +cartridge sha256:b9434d2f359f6e464da36fbcf6d9eb794b7edff03b89467d1609158f13bfef52 + name:Beetlejuice (USA) + cheat + description:Invincibility + code:dc05/f0/d0 + cheat + description:Invincibility (blinking) + code:d71f/8d/ad + cheat + description:Infinite hits + code:d716/01/00 + cheat + description:Infinite lives + code:d417/ce/ad + cheat + description:Take fewer hits to die + code:8095/02/01+d3ff/02/01 + cheat + description:Start with 1 life + code:8090/03/01 + cheat + description:Start with 6 lives + code:8090/03/06 + cheat + description:Start with 9 lives + code:8090/03/09 + +cartridge sha256:f93163a51f4a671c5f4da390d4d286d6d8440d87dfe24285c40ed73dc422bf7d + name:Bee 52 (USA) (Unl) + cheat + description:Invincibility + code:e375/f0/d0 + cheat + description:Invincibility (alt) + code:e1f3/85/a5 + cheat + description:Infinite lives + code:cdd1/ce/ad + cheat + description:Hit anywhere - sting attack + code:e321/d0/50+e322/3b/18 + cheat + description:Keep pick-ups + code:fe2a/20/ad + cheat + description:Don't get stunned + code:d65e/d0/24 + cheat + description:Fly quicker + code:ceff/30/24+cf1b/10/24 + cheat + description:Start with 1 life + code:fc24/03/01 + cheat + description:Start with 6 lives + code:fc24/03/06 + cheat + description:Start with 9 lives + code:fc24/03/09 + +cartridge sha256:2366af9fc0512d39bfa6e908b4caa12be3d21225af49274ffe2ff51cf0b9c1e6 + name:Best of the Best - Championship Karate (USA) + cheat + description:Infinite time (round never ends) + code:d2e8/c6/a5 + cheat + description:Each round is 0:10 instead of 1:00 + code:d774/01/00+d771/85/e6 + cheat + description:Each round is 0:20 + code:d774/01/00+d76f/85/a9+d770/5e/02 + cheat + description:Each round is 0:30 + code:d774/01/00+d76f/85/a9+d770/5e/03 + cheat + description:Each round is 0:40 + code:d774/01/00+d76f/85/a9+d770/5e/04 + cheat + description:Each round is 0:50 + code:d774/01/00+d76f/85/a9+d770/5e/05 + cheat + description:Each round is 2:00 + code:d774/01/02 + cheat + description:Each round is 3:00 + code:d774/01/03 + cheat + description:Each round is 4:00 + code:d774/01/04 + cheat + description:Each round is 5:00 + code:d774/01/05 + cheat + description:Each round is 6:00 + code:d774/01/06 + cheat + description:Each round is 7:00 + code:d774/01/07 + cheat + description:Each round is 8:00 + code:d774/01/08 + cheat + description:Each round is 9:00 + code:d774/01/09 + cheat + description:Each match is 1 round instead of 5 + code:da1b/05/01 + cheat + description:Each match is 2 rounds + code:da1b/05/02 + cheat + description:Each match is 3 rounds + code:da1b/05/03 + cheat + description:Each match is 4 rounds + code:da1b/05/04 + cheat + description:Each match is 6 rounds + code:da1b/05/06 + cheat + description:Gain more strength and reflex points in training + code:e80e/04/08+e981/02/00 + cheat + description:Gain more resistance points in training + code:e80e/04/10+e981/02/00 + cheat + description:All physical types are 30 (causes graphic errors near top of screen) + code:d5fc/b1/a9+d5fd/02/1e + cheat + description:All physical types are 50 (causes graphic errors near top of screen) + code:d5fc/b1/a9+d5fd/02/32 + cheat + description:Start with 50 resistance points + code:8002/1e/32 + cheat + description:Start with 50 strength points + code:8001/28/32 + cheat + description:Start with 50 reflex points + code:8003/14/32 + cheat + description:Start with 70 resistance points + code:8002/1e/46 + cheat + description:Start with 70 strength points + code:8001/28/46 + cheat + description:Start with 70 reflex points + code:8003/14/46 + +cartridge sha256:18c134f8cc7effc0b90dcca86a27c305cbd7dadfb159689c89790c7fe4ff9b77 + name:Bible Adventures (USA) (v1.4) (Unl) + cheat + description:Infinite health + code:dae4/9d/bd + +cartridge sha256:b56f867ad6b067f9ca7e46afb8e7a953fa281404232e2497c88e43448a2c3a57 + name:Bible Adventures (USA) (v1.3) (Unl) + cheat + description:Infinite health + code:dae8/9d/bd + +cartridge sha256:981b39b22c9b17055c90a612b9c8ea6711541ff5196018043f3516ed238f3ce9 + name:Bible Adventures (USA) (v1.2) (Unl) + cheat + description:Infinite health + code:dafe/9d/bd + +cartridge sha256:88ee64119746de659f70f3d459c62dd2af3b21f29f5064ea14f0fb03904cbcfe + name:Bible Adventures (USA) (v1.1) (Unl) + cheat + description:Infinite health + code:daa3/9d/bd + +cartridge sha256:2807c405f072a1e828cbdd4812822ec301979472fd9b8c6225aa4d1dca89613c + name:Bible Adventures (USA) (Unl) + cheat + description:Infinite health + code:d61c/9d/bd + +cartridge sha256:32fa00d52f39b053c30061d6789944fc61c0c88c885bd8248ff5771fd2f78ae6 + name:Bigfoot (USA) + cheat + description:Infinite nitros + code:abce/de/bd + cheat + description:Longer nitro boost + code:abca/64/ff + cheat + description:Shorter nitro boost + code:abca/64/20 + cheat + description:Engines are half price + code:8cc1/08/04 + cheat + description:Engines cost more + code:8cc1/08/09 + cheat + description:Tires are half price + code:8cc2/06/03 + cheat + description:Tires cost more + code:8cc2/06/09 + cheat + description:Transmission work is half price + code:8cc3/04/02 + cheat + description:Transmission work is double price + code:8cc3/04/08 + cheat + description:Suspension is half price + code:8cc4/02/01 + cheat + description:Suspension is triple price + code:8cc4/02/06 + cheat + description:P1 gets P2's nitros + code:b16f/fe/ee+b168/8d/ad + +cartridge sha256:b183c0952994cadc1c8d6dd290730f43ecacb051d3dfe53784578635a1049455 + name:Bill & Ted's Excellent Video Game Adventure (USA) + cheat + description:Infinite skeleton keys + code:b249/ce/ad + cheat + description:Infinite coins for locals + code:c90b/8d/ad + cheat + description:Infinite Good Stuff + code:989b/99/b9 + cheat + description:Phone call segments cost only 1 coin + code:e196/8d/ad + cheat + description:Ted starts with 99 coins instead of 15 + code:cecb/15/99 + cheat + description:Bill starts with 99 coins + code:e1d8/15/99 + cheat + description:Ted starts with 5 coins + code:cecb/15/05 + cheat + description:Bill starts with 5 coins + code:e1d8/15/05 + +cartridge sha256:ddf58f90fa5966137e71a0f30a162bf03b3e8b1b99f4f1d16cac26d5e2cf5b35 + name:Bill Elliott's NASCAR Challenge (USA) + cheat + description:Accelerate faster + code:c38e/90/b0 + cheat + description:Infinite 'free time' in the pits + code:843e/ce/ad + cheat + description:Freeze timer while crew works on car in pits + code:8692/ce/ad + +cartridge sha256:4f59f3ef6045be753ed5f7988e4b302b7f71216354a644f760f4a0aa43af7d22 + name:Bio Force Ape (Japan) (En) (Proto) + cheat + description:Infinite health + code:ba5f/8d/ad + cheat + description:Walk through walls + code:9600/38/60+96b0/38/60 + cheat + description:Start on level 2 + code:8427/00/01 + cheat + description:Start on level 3 + code:8427/00/02 + +cartridge sha256:92c481350b63c57385834dfa0ab02aeb527df7e80cec14a3e1a1a77118cd38d1 + name:Bio Miracle Bokutte Upa (Japan) + cheat + description:Hit anywhere - normal enemies + code:e642/45/00+bc96/26/00 + +cartridge sha256:aeb61fd5cf5a5ed73344c46a43f8a8d539f601ff57e8f56c49bc1caea4ab3d9e + name:Bionic Commando (USA) + cheat + description:Invincibility + code:e7d7/ce/60 + cheat + description:Infinite lives in main game + code:b77d/c6/a5 + cheat + description:Infinite lives in sub-game + code:81ba/c6/a5 + cheat + description:Don't take damage from bullets and collisions + code:e7d7/ce/ad + cheat + description:Don't take damage from spikes + code:ae72/ce/ee + cheat + description:Don't take damange from bullets and collisions in sub-game + code:9138/ce/ad + cheat + description:Hit anywhere + code:ec1b/20/60+90c9/98/60+ecfb/38/60+8eaf/bd/60+eb46/99/ad + cheat + description:Autofire - main game + code:b92b/f8/fa + cheat + description:Longer grapple line - sidescrolling levels + code:9276/30/50+928c/40/56+9260/3a/5f + cheat + description:Longest grapple line - sidescrolling levels + code:9277/90/d0+9261/90/d0+928d/90/d0 + cheat + description:Longer range for normal 3-way gun - sidescrolling levels + code:bde8/09/17 + cheat + description:Longer range for fireball 3-way gun - sidescrolling levels + code:be44/0c/15 + cheat + description:Use with BIO Code 11 for improved autofire with normal gun + code:b949/0a/00 + cheat + description:Have all items (using the hidden gun will crash the game) + code:b042/f0/b0+b126/f0/d0 + cheat + description:Start with 3 life energy capsules + code:ca39/00/03+ca3b/be/ea + cheat + description:Start with 1 life + code:ca35/02/00 + cheat + description:Start with double lives + code:ca35/02/05 + cheat + description:Start with triple lives + code:ca35/02/08 + cheat + description:Start with 3-way gun + code:ca4f/cb/ce + +cartridge sha256:99806081ba58c0a108bcc61468972d4b2319de74d7dca1bba932f1a3bd2fe1cc + name:Black Bass, The (USA) + cheat + description:Always have fish checking out your lure + code:03c7/ff + cheat + description:Fish on screen will always bite your lure + code:03f7/00 + cheat + description:Rank 1st place + code:0445/01 + +cartridge sha256:abde6fc87b2d90e0b40cd3420d4b7381e1f23285efbbdc62fd27b59c591ad2cc + name:Blades of Steel (USA) + cheat + description:Invincible in minigame + code:a77d/d0/50 + cheat + description:Faster timer + code:c6b6/07/04 + cheat + description:Slower timer + code:c6b6/07/14 + cheat + description:Player with puck don't slow down + code:d81d/20/00 + cheat + description:Players can take only one punch + code:a423/05/01 + cheat + description:Players 2/CPU don't throw punches + code:a6ce/49/a9+a5d2/bd/ad + cheat + description:Start a new game to view the ending + code:c655/03/07 + +cartridge sha256:7a26c62a9b1605cbedf7cd5b2672aa0fc15b688b227a6cb57dbf74aa71a05f1c + name:Blaster Master (USA) + cheat + description:Infinite car health + code:89b4/ea + cheat + description:Enemies are killed instantly + code:d70b/07 + cheat + description:Infinite lives + code:c537/c6/a5 + cheat + description:Infinite Hover + code:9328/c6/a5 + cheat + description:Infinite Homing Missiles + code:9858/ce/2c + cheat + description:Infinite Thunderbreaks + code:99c0/ce/2c + cheat + description:Infinite Multi-Warheads + code:9ade/ce/2c + cheat + description:Start with all abilities + code:c2cc/00/ff + cheat + description:Start with 5 of each weapon + code:c309/00/05 + cheat + description:Start with 10 of each weapon + code:c309/00/0a + cheat + description:Start with 15 of each weapon + code:c309/00/0f + cheat + description:Start with 99 of each weapon + code:c309/00/63 + cheat + description:Start with 99 of each weapon and max Hover + code:c309/00/ff + cheat + description:Start with 1 life + code:c302/02/00 + cheat + description:Start with 6 lives + code:c302/02/05 + cheat + description:Start with 9 lives + code:c302/02/08 + cheat + description:Start on world 2 + code:c2fe/08/09 + cheat + description:Start on world 3 + code:c2fe/08/0a + cheat + description:Start on world 4 + code:c2fe/08/0b + cheat + description:Start on world 5 + code:c2fe/08/0c + cheat + description:Start on world 6 + code:c2fe/08/0d + cheat + description:Start on world 7 + code:c2fe/08/0e + cheat + description:Start on world 8 + code:c2fe/08/0f + cheat + description:Start at the boss of world 1 + code:c2fd/09/a9+c2fe/08/00 + cheat + description:Start at the boss of world 2 + code:c2fd/09/a9+c2fe/08/01 + cheat + description:Start at the boss of world 3 + code:c2fd/09/a9+c2fe/08/02 + cheat + description:Start at the boss of world 4 + code:c2fd/09/a9+c2fe/08/03 + cheat + description:Start at the boss of world 5 + code:c2fd/09/a9+c2fe/08/04 + cheat + description:Start at the boss of world 6 + code:c2fd/09/a9+c2fe/08/05 + cheat + description:Start at the boss of world 7 + code:c2fd/09/a9+c2fe/08/06 + cheat + description:Start at the boss of world 8 + code:c2fd/09/a9+c2fe/08/07 + cheat + description:Die to see ending + code:c53a/16/42 + 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 + name:Blue Marlin, The (USA) + cheat + description:Line is a 1000 yards long + code:edf3/02/04 + cheat + description:Catch fish right after they bite - most of the time + code:ead9/c8/00 + cheat + description:When fish bite they are close to the boat + code:ead9/c8/09 + cheat + description:Line is set to 153 feet + code:ead9/c8/99 + cheat + description:Pull fish in quicker + code:edda/00/01 + cheat + description:Vitality always at max + code:ec5c/69/a9+ec5d/01/0f + +cartridge sha256:46fb05f80167bd185bd6eef40e1f86a0dcdd36e250ef8e2b29a575550d75473a + name:Blues Brothers, The (USA) + cheat + description:Invincibility + code:ed66/f0/d0+e420/f0/d0 + cheat + description:Infinite health + code:e098/de/bd + cheat + description:Infinite lives + code:e0bf/de/bd + cheat + description:Multi-jump + code:f1d0/00/01 + 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:7e59dcd2576d2e83f6f628a7bb8d5f1e54fa300f7ecb9aa5e1e0f6d967be8371 + name:Bo Jackson Baseball (USA) + cheat + description:Balls are considered strikes + code:c487/18/00 + +cartridge sha256:2967746c2a434c97a074b14d894ea132fab8e443899f6ca870718eeee1669039 + name:Bomberman (USA) + cheat + description:Immune to explosions + code:c6e5/a5/a9 + cheat + description:Infinite time + code:c650/a5 + cheat + description:Infinite lives + code:c498/a5 + cheat + description:Hit anywhere (all enemies killed with one bomb) + code:c716/37/00+c71d/30/00 + cheat + description:Remove all breakable blocks + code:ca6a/02/00 + cheat + description:Never lose Detonator once obtained + code:c48b/85/24 + cheat + description:Increase Bomb detonation time + code:cd2b/a0/ff + cheat + description:Reduce Bomb detonation time + code:cd2b/a0/70 + cheat + description:Use up to 10 Bombs + code:cd07/a6/a2+cd08/74/09 + cheat + description:Walk through walls + code:cf7f/49/a9+cf80/01/00 + cheat + description:Decrease time + code:c44c/96 + cheat + description:Increase timer + code:c44c/fe + cheat + description:Start with double power Bomb blasts + code:c3c8/10/20 + cheat + description:Start with triple power Bomb blasts + code:c3c8/10/30 + cheat + description:Start with maximum power Bomb blasts + code:c3c8/10/80 + cheat + description:Start with Detonator, max Bomb power and use up to 10 Bombs + code:c3dc/2d/00 + cheat + description:Start with and keep Detonator + code:c98e/a5/a9+ccdf/0e/00 + cheat + description:Start with 1 life + code:c3ab/00 + cheat + description:Start with 10 lives + code:c3ab/09 + cheat + description:Start on stage 10 + code:c3b7/0a + cheat + description:Start on stage 20 + code:c3b7/14 + cheat + description:Start on stage 30 + code:c3b7/1e + cheat + description:Start on stage 40 + code:c3b7/28 + cheat + description:Start on stage 50 + code:c3b7/32 + 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 + name:Bomberman II (USA) + cheat + description:Infinite lives + code:cac4/ce/2c + cheat + description:Infinite time + code:98af/ce/2c + cheat + description:Super start + code:ce2d/00/04+ce5c/00/04 + cheat + description:Immune to explosions + code:87a1/a5/a9+87a2/ae/01 + cheat + description:Walk through walls + code:879c/a5/a9+879d/ad/01 + cheat + description:Always have Detonator + code:87c2/03/00 + cheat + description:Hit anywhere (kill all enemies with one bomb) + code:8327/2f/1b+8328/29/61+8326/b1/ad+8329/80/ea + cheat + description:Remove all breakable bricks + code:b946/20/00+b94f/20/ad + cheat + description:Slower timer + code:98ab/3b/63 + cheat + description:Faster timer + code:98ab/3b/1e + cheat + description:Bomb has a longer fuse + code:928b/4b/7f + cheat + description:Bomb has a shorter fuse + code:928b/4b/20 + cheat + description:Stop Bombs from exploding + code:ba95/de/2c + cheat + description:Dollar sign acts as flame face + code:9056/c7/80 + cheat + description:Dollar sign acts as Bomb + code:9056/c7/74 + cheat + description:Dollar sign acts as heart with Bomb + code:9056/c7/8c + cheat + description:Dollar sign acts as skate + code:9056/c7/91 + cheat + description:Dollar sign acts as vest for a short time + code:9056/c7/a9 + cheat + description:Start with 1 life + code:c980/02/00 + cheat + description:Start with 6 lives + code:c980/02/05 + cheat + description:Start with 9 lives + code:c980/02/08 + 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 + name:Bonk's Adventure (USA) + cheat + description:Infinite lives + code:a765/ce/ad + cheat + description:Hit anywhere + code:a52a/03/00+a27e/27/53 + cheat + description:Super-jump when normal + code:808f/0c/24 + cheat + description:Keep speed up after powered down + code:94e5/8d/2c + cheat + description:Gain energy from picking up smiles + code:a756/00/04 + cheat + description:Start with less initial energy (but more maximum energy) + code:80b0/0c/04 + cheat + description:Start with more energy + code:80b0/0c/18 + cheat + description:Start with 1 life + code:80c0/02/00 + cheat + description:Start with 6 lives + code:80c0/02/05 + cheat + description:Start with 9 lives + code:80c0/02/08 + cheat + description:Start on stage 2-1 + code:80ab/00/07 + cheat + description:Start on stage 3-1 + code:80ab/00/0d + cheat + description:Start on stage 4-1 + code:80ab/00/12 + cheat + description:Start on Stage 5-1 + code:80ab/00/17 + cheat + description:Start on stage 6-1 + code:80ab/00/21 + +cartridge sha256:0e58f270e7b116782e0822f52058eff66465df49527c6f8c6f0eca994d8cae7a + name:Boulder Dash (USA) + cheat + description:Invincibility + code:c603/01/00+c3c9/a5/60+c18f/2f/4d + cheat + description:Infinite lives + code:ae02/d6/b5 + cheat + description:Infinite time + code:cfd5/20/ad + cheat + description:One Diamond needed to open exit + code:ccb6/25/00 + cheat + description:Speed up timer + code:cfd2/3f/1f + cheat + description:Slow down timer + code:cfd2/3f/ff + cheat + description:1 life after continue + code:af98/03/01 + cheat + description:6 lives after continue + code:af98/03/06 + cheat + description:9 lives after continue + code:af98/03/09 + cheat + description:Start with 1 life + code:db40/03/01 + cheat + description:Start with 6 lives + code:db40/03/06 + cheat + description:Start with 9 lives + code:db40/03/09 + +cartridge sha256:a8b6829d8d1e17cc23c8815e0b0add09e26fc5a2a27ad6bba260cef926535af2 + name:Bram Stoker's Dracula (USA) + cheat + description:Invincibility + code:d1e0/d0/50 + cheat + description:Invincibility after getting hit + code:ba46/20/ad + cheat + description:Infinite health (except falling off cliffs) + code:b5a5/de/bd + cheat + description:Infinite health + code:b5a5/de/ad + cheat + description:Infinite lives + code:e3f2/bc/bf + cheat + description:Infinite lives (alt) + code:e3f1/ce/ad + cheat + description:Infinite time + code:c1e1/01/00 + cheat + description:Infinite time (alt) + code:c1fc/8d/ad+c1f7/8d/ad + cheat + description:Infinite ammo + code:ed7e/ce/ad + cheat + description:Infinite weapons (except scene 1 daytime) + code:ed80/02/bb + cheat + description:Faster timer + code:c1e1/01/02 + cheat + description:Always have 63 ammo + code:c277/05/00 + cheat + description:Disable axe + code:f1dc/02/ff + +cartridge sha256:e1487d23800aa2c29cb9da6f2bf538aa10044930ef566d087f7acf1aa649fb9e + name:BreakThru (USA) + cheat + description:Infinite lives - both players + code:c13f/c6/24 + cheat + description:Infinite weapon time + code:d24b/c6/24 + cheat + description:Start each life with 3-way firing and 99 seconds + code:c33e/00/63 + cheat + description:Start with 1 life - P1 + code:c2b9/03/01 + cheat + description:Start with 6 lives - P1 + code:c2b9/03/06 + cheat + description:Start with 9 lives - P1 + code:c2b9/03/09 + cheat + description:Start with 1 life - P2 + code:c2c4/03/01 + cheat + description:Start with 6 lives - P2 + code:c2c4/03/06 + cheat + description:Start with 9 lives - P2 + code:c2c4/03/09 + cheat + description:Start on level 2 + code:c27b/01/02 + cheat + description:Start on level 3 + code:c27b/01/03 + cheat + description:Start on level 4 + code:c27b/01/04 + cheat + description:Start on level 5 + code:c27b/01/05 + +cartridge sha256:fde81fc5af055819700842db8650077d64b853f95b3542bf12f039a6df48115d + name:Break Time - The National Pool Tour (USA) + cheat + description:Start in Milwaukee + code:836d/85/86+836c/00/01 + cheat + description:Start in Atlanta + code:836d/85/86+836c/00/02 + cheat + description:Start in Los Angeles + code:836d/85/86+836c/00/03 + cheat + description:Start in Las Vegas + code:836d/85/86+836c/00/04 + +cartridge sha256:3bcce1ff03b55c20eeaefa44f35f19b3f06b3ff88a86ed51968bad9bd44d9144 + name:Bubble Bath Babes (USA) (Unl) + cheat + description:Infinite credits + code:930b/c6/a5 + cheat + description:View slideshow + code:8045/01/08+892a/85/e6+892b/64/88+8935/0b/0c + +cartridge sha256:31523322db8f94e7244f6e2d958692a412c1395fc744601d83d1e5111eff9042 + name:Bubble Bobble (USA) + cheat + description:Skip only 2 levels + code:cb11/04/02 + cheat + description:Skip 10 levels + code:cb11/04/0a + cheat + description:Lots of bubble power + code:d533/19/00 + cheat + description:Monsters move faster + code:8478/01/02+8488/fe/ff + cheat + description:Monsters move super fast + code:8478/01/03+8488/fd/ff + cheat + description:Angry monsters move faster + code:847d/02/03+848d/fe/fd + cheat + description:Always wear turbo shoes + code:d47d/06/00+d4d1/06/00 + cheat + description:Start with 1 life - both players + code:ca38/03/01 + cheat + description:Start with 6 lives - both players + code:ca38/03/06 + cheat + description:Start with 9 lives - both players + code:ca38/03/09 + cheat + description:Start on level 10 + code:ca30/01/0a + cheat + description:Start on level 25 + code:ca30/01/19 + cheat + description:Start on level 50 + code:ca30/01/32 + cheat + description:Start on level 75 + code:ca30/01/4b + 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 + name:Bucky O'Hare (USA) + cheat + description:Infinite lives + code:ce69/c6/a5 + cheat + description:Hit anywhere + code:869a/b0/24+867f/b0/24+8684/69/a9+869f/69/a9 + cheat + description:One hit kills + code:db4e/9d/bd + cheat + description:Multi-jump + code:8fb9/b0/00+8fa3/10/00 + cheat + description:Double Bucky's special health + code:bf06/8c/98 + cheat + description:Triple Bucky's special health + code:bf06/8c/a4 + cheat + description:All characters always selectable + code:8cce/10/f0 + cheat + description:All characters start with normal special health + code:bf0a/0c/8c + cheat + description:All characters start with 2x special health + code:bf0a/0c/98 + cheat + description:All characters start with 3x special health + code:bf0a/0c/a4 + cheat + description:1 life after continue + code:cfa6/02/00 + cheat + description:6 lives after continue + code:cfa6/02/05 + cheat + description:10 lives after continue + code:cfa6/02/09 + cheat + description:Press Start to complete the level + code:c3d5/01/08+c3d8/01/00+c3d7/09/1c+c3d4/49/a9 + cheat + description:Start a new game to see ending + code:cdb8/02/09 + cheat + description:Start with 1/2 health + code:bf14/14/06 + cheat + description:Start with 1 life + code:bf02/02/00 + cheat + description:Start with 6 lives + code:bf02/02/05 + cheat + description:Start with 10 lives + code:bf02/02/09 + 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 + name:Bugs Bunny Birthday Blowout, The (USA) + cheat + description:Invincibility + code:a371/60 + cheat + description:Infinite health + code:a384/8d/ad + cheat + description:Infinite lives + code:d464/ce/ad + cheat + description:Mega-jumping Bugs + code:8a17/06/0b + cheat + description:Two hearts of energy gained on pick-up + code:a299/04/08 + cheat + description:Less energy gained on pick-up + code:a299/04/01 + cheat + description:Stunned for longer + code:a370/30/60 + cheat + description:Stunned for less time + code:a370/30/15 + cheat + description:Use hammer when stunned + code:8954/3e/00 + +cartridge sha256:7882e99e08deb1c22a3c38b17e12bd6373af503fd76e97b31699f3d19bef5aad + name:Bugs Bunny Crazy Castle, The (USA) + cheat + description:Invincibility + code:e282/d0/24 + cheat + description:Baddies go as fast as Bugs Bunny + code:c2c2/f0/24 + cheat + description:Make platforms invisible + code:c050/01/04 + cheat + description:Start with super rabbit punches + code:e4a4/f0/29+e4a0/10/29 + cheat + description:Start with infinite lives + code:c11c/c6/a5 + cheat + description:Start with 1 life + code:c031/05/01 + cheat + description:Start with 10 lives + code:c031/05/0a + cheat + description:Start on level 10 + code:c01c/20/ad+ffa6/00/09 + cheat + description:Start on level 20 + code:c01c/20/ad+ffa6/00/13 + cheat + description:Start on level 30 + code:c01c/20/ad+ffa6/00/1d + cheat + description:Start on level 40 + code:c01c/20/ad+ffa6/00/27 + +cartridge sha256:6f37316bbfec539809a946f7020e7a411fe5dbe204157522f01b9c616e918247 + name:Bugs Bunny Fun House (USA) (Beta) + cheat + description:Infinite turns + code:ccfd/ce/ad + cheat + description:Slower timer + code:962b/3c/80 + cheat + description:Faster timer + code:962b/3c/1f + cheat + description:Quicker turning + code:acde/04/02 + cheat + description:More time from Large Glop Clocks + code:98eb/0f/1e + cheat + description:Less time from Large Glop Clocks + code:98eb/0f/07 + cheat + description:1 turn after continuing + code:cd25/03/01 + cheat + description:9 turns after continuing + code:cd25/03/09 + cheat + description:Start with 1 turn + code:c892/03/01 + cheat + description:Start with 9 turns + code:c892/03/09 + cheat + description:Start on Floor 2 + code:c88d/01/07 + cheat + description:Start on Floor 4 + code:c88d/01/13 + cheat + description:Start on Floor 6 + code:c88d/01/1f + cheat + description:Start on Floor 8 + code:c88d/01/2b + +cartridge sha256:ba8c9990f378b941ea362858509182b2b009e5b463e9732dc0071392b6253c2b + name:Bump'n'Jump (USA) + cheat + description:Jump OK, even with no power + code:9b67/14/00 + cheat + description:Gain double power on every pick-up + code:a530/01/02 + cheat + description:Jump OK at any speed + code:9b6f/00/40 + cheat + description:Set jump OK speed to 190 + code:9b77/05/09 + cheat + description:Set jump OK speed to 130 + code:9b77/05/03 + cheat + description:Start on scene 2 + code:8494/00/01 + cheat + description:Start on scene 3 + code:8494/00/02 + cheat + description:Start On scene 4 + code:8494/00/03 + cheat + description:Start on scene 5 + code:8494/00/04 + cheat + description:Start on scene 6 + code:8494/00/05 + cheat + description:Start on scene 7 + code:8494/00/06 + cheat + description:Start on scene 8 + code:8494/00/07 + cheat + description:Start on scene 9 + code:8494/00/08 + cheat + description:Start on scene 10 + code:8494/00/09 + cheat + description:Start on scene 11 + code:8494/00/0a + cheat + description:Start on scene 12 + code:8494/00/0b + cheat + description:Start on scene 13 + code:8494/00/0c + cheat + description:Start on scene 14 + code:8494/00/0d + cheat + description:Start on scene 15 + code:8494/00/0e + +cartridge sha256:abbddcb7c85a9956f94e6185aa1f30c34c45ad0db2f7f9db40066d749ffa7920 + name:Burai Fighter (USA) + cheat + description:Infinite lives + code:ef90/ce/fe + cheat + description:Extra lives for Eagle level + code:b690/05/09 + cheat + description:Extra lives for Albatross level + code:b691/04/08 + cheat + description:Extra lives for Ace level + code:b692/03/06 + cheat + description:More power for weapons + code:e126/01/03 + cheat + description:Maximum power for weapons + code:e126/01/0a + cheat + description:Increase cobalt power picked up + code:e15e/02/09 + cheat + description:Never lose weapon power + code:f2e8/99/b9 + cheat + description:Never lose speed up + code:f2f3/85/a4 + cheat + description:Never lose weapons + code:f2ef/85/a4 + cheat + description:Never lose rotating pod + code:f2f1/85/a4 + cheat + description:Never lose anything + code:f2eb/a9/60 + cheat + description:Start with laser + code:f16d/85/e6 + cheat + description:Start with rotating pod + code:f171/85/e6 + +cartridge sha256:8f349b0ed7d31a07ccdf26958de8219165eff7c9ad43801a82c5dcf831fd82c2 + name:BurgerTime (USA) + cheat + description:Infinite Pepper Spray + code:d743/5c/ea + cheat + description:Anti-gravity shoes + code:d260/d0/24 + cheat + description:Peter Pepper gets super speed + code:db09/1c/1f + cheat + description:Fast play for experts + code:fd4f/20/ad + cheat + description:Monsters always move slowly + code:daed/bd/ad + cheat + description:Monsters move at double speed + code:daed/bd/ad+daee/18/1c + cheat + description:Monsters move at quadruple speed + code:daed/bd/ad+daee/18/1f + cheat + description:Start with infinite lives + code:e856/d6/a5 + cheat + description:Start with 8 lives + code:cb54/04/08 + cheat + description:Start with infinite peppers + code:d742/d6/b5 + cheat + description:Start with double peppers + code:cb65/05/10 + +cartridge sha256:2b4ac20082e2f45a8f8fd4922a0e995829719a523e118a9eec891c3206adf25b + name:B-Wings (Japan) + cheat + description:Invincibility + code:a53c/a5/85 + cheat + description:Infinite lives + code:ad73/ce/bd + cheat + description:Enable unlimited morphs + code:b38a/f0/50 + cheat + description:Enable secret weapons morph + code:b397/0b/0e + cheat + description:Can always morph + code:b38a/50/24 + cheat + description:Start with secret weapon 1 + code:b0fc/01/0b + cheat + description:Start with secret weapon 2 + code:b0fc/01/0d + +cartridge sha256:47dfae941b3c660be476bc28f199474b6c418431e3d493da4384a6aef3cc5016 + name:Cabal (USA) + cheat + description:Invincibility + code:94fb/d0/f0 + cheat + description:Infinite lives + code:928a/d6/24 + cheat + description:Infinite lives (alt) + code:928a/d6/d5 + cheat + description:Infinite grenades + code:adbd/01/00 + cheat + description:Shorter immunity + code:9293/c0/40 + cheat + description:Longer immunity + code:9393/c0/ff + cheat + description:12 Grenades on pick-up + code:ac6f/04/0c + cheat + description:2 Grenades on pick-up + code:ac6f/04/02 + cheat + description:Start with 20 grenades + code:8a69/f3/f4 + cheat + description:Start with 50 grenades + code:8a69/f3/f7 + cheat + description:Start with 9 lives - both players + code:96be/f7/fb + cheat + description:Start with 1 life - both players + code:96be/f7/f3 + 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 + name:California Raisins - The Grape Escape (USA) (Proto1) + cheat + description:Infinite health + code:d924/c6/a5 + cheat + description:Infinite health (alt) + code:0048/04 + cheat + description:Infinite lives + code:0049/02 + +cartridge sha256:9ea5bedef90810b89afb70db90c6e0338aa2a6976603058dafe08838009651f0 + name:California Raisins - The Grape Escape (USA) (Proto2) + cheat + description:Invincibility + code:d12e/f0/d0 + cheat + description:Infinite lives + code:ce89/c6/c5 + 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 + name:Capcom's Gold Medal Challenge '92 (USA) + cheat + description:Massive run power + code:f6d2/f9/a9+f6d3/f0/50+f6d4/f6/ea + +cartridge sha256:6d694349435603c0dcd7645081b0761e109f3994b30f9d822586c991d93510d8 + name:Captain America and the Avengers (USA) + cheat + description:Infinite life - Captain America and Hawkeye, 1P mode + code:b87f/99/b9 + cheat + description:Infinite continues + code:b75b/c6/a5 + cheat + description:Large power stones worth 20 points + code:a37d/0a/14 + cheat + description:Large power stones worth 30 points + code:a37d/0a/1e + cheat + description:Large power stones worth 50 points + code:a37d/0a/32 + cheat + description:Small power stones worth 10 points + code:a335/01/0a + cheat + description:Hawkeye shoots arrows faster + code:98b3/1b/5b + cheat + description:Faster Captain America and Hawkeye - one direction only + code:a27e/ff/fe+a280/01/02 + cheat + description:Even faster Captain America and Hawkeye - one direction only + code:a27e/ff/fd+a280/01/03 + 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 + name:Captain Comic - The Adventure (USA) (Unl) + cheat + description:Invincibility + code:ec00/ad + cheat + description:Infinite energy + code:ec06/bd + cheat + description:Infinite lives + code:e702/ad + 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 + name:Captain Planet and the Planeteers (USA) + cheat + description:Invincibility + code:cb7f/8d/ad + cheat + description:Infinite lives (alt) + code:b6f7/ce/cd + cheat + description:Infinite lives, outside levels + code:b6f7/ce/ad + cheat + description:Infinite lives, inside levels + code:b65c/ce/ad + cheat + description:Infinite power, outside levels + code:a27c/ce/ad+a469/ce/ad + cheat + description:Infinite power, inside levels + code:aba8/ce/ad+b40c/ce/ad + cheat + description:Start with 2 lives instead of 5, outside levels + code:e4fd/04/01 + cheat + description:Start with 10 lives, outside levels + code:e4fd/04/09 + cheat + description:Start with 10 lives, inside levels + code:e605/04/09 + cheat + description:Start with 2 lives, inside levels + code:e605/04/01 + cheat + description:Start inside level 1 instead of outside. + code:e078/2c/00 + +cartridge sha256:da7886920245b1342185ed5fb963798dc38f96e8c5186b9c23446ef68c58a248 + name:Captain Skyhawk (USA) (Rev A) + cheat + description:Infinite lives + code:8445/c6/a9 + cheat + description:Infinite lives (alt) + code:8445/c6/c5 + cheat + description:Infinite Maverick missiles + code:9a23/c6/a9 + cheat + description:Infinite Hawk Bombs + code:9cc6/c6/a9 + cheat + description:Double cost of Hawk Bombs + code:acfc/02/04 + cheat + description:Double cost of Phoenix missiles + code:ad24/02/04 + cheat + description:Double cost of Maverick missiles + code:ad10/05/0a + cheat + description:Start with half Hawk Bombs + code:d5d6/06/03 + cheat + description:Start with 20 Hawk Bombs + code:d5d6/06/14 + cheat + description:Start with 8 Phoenix and Maverick missiles + code:d5da/02/08 + cheat + description:Start with 1 life + code:d5b6/05/01 + cheat + description:Start with 10 lives + code:d5b6/05/0a + +cartridge sha256:141cda262aad72971c00dd9a9655f32cee03e259d371bd8937a864e3300e9e58 + name:Captain Skyhawk (USA) + cheat + description:Invincibility (PRG0) + code:9d9e/f0/d0 + cheat + description:Infinite lives + code:8445/c6/a9 + cheat + description:Infinite lives (alt) + code:8445/c6/c5 + cheat + description:Infinite Maverick missiles + code:9a23/c6/a9 + cheat + description:Infinite Hawk Bombs + code:9cc6/c6/a9 + cheat + description:Double cost of Hawk Bombs + code:acfc/02/04 + cheat + description:Double cost of Phoenix missiles + code:ad24/02/04 + cheat + description:Double cost of Maverick missiles + code:ad10/05/0a + cheat + description:Start with half Hawk Bombs + code:d5d6/06/03 + cheat + description:Start with 20 Hawk Bombs + code:d5d6/06/14 + cheat + description:Start with 8 Phoenix and Maverick missiles + code:d5da/02/08 + cheat + description:Start with 1 life + code:d5b6/05/01 + cheat + description:Start with 10 lives + code:d5b6/05/0a + +cartridge sha256:f76f1779454a8a98168c2c26bc79058161cbaefb3006c8e6aa8c63d301a66f4f + name:Casino Kid (USA) + cheat + description:Always win hand in Blackjack + code:86c9/d0/a9 + cheat + description:Always win hand in Poker + code:9c1b/4c/ad + cheat + description:Can always bet all money in Blackjack + code:859d/90/a9 + cheat + description:Can always bet all money in Poker + code:8a64/68/86 + +cartridge sha256:87e479b14421fc4b56553937dc817789ebfb2987b0724c6790705f0361a955a7 + name:Casino Kid II (USA) + cheat + description:Can't double down in blackjack (game will say you do not have enough money) + code:8c15/05/09 + cheat + description:Can't split in blackjack (game will say you do not have enough money) + code:8d46/05/09 + cheat + description:Start new game with $82 instead of $200 + code:c14f/4e/20 + cheat + description:Start new game with $512 + code:c14f/4e/c8 + cheat + description:Start new game with $21,171 + code:c154/00/20 + cheat + description:Start new game with $131,272 + code:c154/00/c8 + cheat + description:Start new game with $1,342,377 + code:c159/00/08 + cheat + description:Start new game with $5,368,909 + code:c159/00/20 + +cartridge sha256:98ba2353111a0b2cf557b03d8b8c4f5c15d7be56e47182536d710913d62582fa + name:Castelian (USA) + cheat + description:Invincibility + code:edc0/85/a5 + cheat + description:Infinite lives + code:c31a/d6/b5 + cheat + description:Infinite lives (alt) + code:c31a/d6/d5 + cheat + description:Infinite time + code:a07f/c6/a5 + cheat + description:Start with 1 life + code:c1e7/03/01 + cheat + description:Start with 6 lives + code:c1e7/03/06 + cheat + description:Start with 9 lives + code:c1e7/03/09 + cheat + description:Start with 5 continues + code:c216/02/05 + cheat + description:Start with 8 continues + code:c216/02/08 + +cartridge sha256:3668454e1904ada7f80ec2f94c4c2d45272d8a8c9e8d3b78ceebae5f890eb164 + name:Castle of Deceit (USA) (Unl) + cheat + description:Infinite energy + code:dbf1/ce/ad + cheat + description:Infinite lives + code:d51f/ce/ad + +cartridge sha256:6887230077d8eefa311d313672c31e7497211e21c5df78aa8d2030ea72471108 + name:Castle of Dragon (USA) + cheat + description:Infinite health + code:bf95/00/7f + cheat + description:Super health + code:c02b/04/ff + cheat + description:No harm from most enemy attacks + code:bf6d/ce/ad + cheat + description:Stop Skeletons from fighting + code:9be3/10/01 + cheat + description:Faster fighting + code:c297/01/04 + cheat + description:Super strong enemies + code:bf51/1b/12 + cheat + description:Start with Knives + code:c023/00/02 + cheat + description:Start with Knives and Mace + code:c023/00/03 + cheat + description:Start with Armor + code:c023/00/80 + cheat + description:Start with Armor, Knives and Mace + code:c023/00/83 + +cartridge sha256:9abebd837287a38ab64153ff662b3bd79ebc8e55b07c2fc2fef8c15244517576 + name:Castlequest (USA) + cheat + description:Invincibility + code:8dba/8d/ad + cheat + description:Infinite lives + code:8dc6/c6/a5 + cheat + description:Infinite keys + code:a658/f0/60 + cheat + description:75 lives instead of 50 + code:a2b6/32/4b + cheat + description:25 lives instead of 50 + code:a2b6/32/19 + cheat + description:Don't lose life from 'reset' or 'back' options + code:fbcc/c6/a5 + cheat + description:Use sword (press 'B') as long as you like + code:831d/ce/ad + cheat + description:Now you can move while using sword + code:8492/07/a2 + cheat + description:Must use with the last code for permanent sword-wielding ability + code:8308/17/05 + cheat + description:Supercharged speed-up + code:852c/02/04+853c/02/04 + cheat + description:Turbo fuel-injected 16-valve speed-up + code:852c/02/08+853c/02/08 + +cartridge sha256:7eba1637cd2fdbc4f0732eb5249e32d827dbdadbd7e165f961440af4310880dc + name:Castlevania (USA) (Rev A) + cheat + description:Invincibility + code:e6d2/a5/c5 + cheat + description:Invincibility after one hit + code:e8fa/c6/a6 + cheat + description:Infinite health + code:e75b/85/ad + cheat + description:Infinite lives + code:c2f3/c6/a9 + cheat + description:Infinite time + code:a0af/20/ad + cheat + description:Infinite hearts + code:da58/84/a4+da8b/84/a4 + cheat + description:Keep weapons after dying + code:c317/8d/2c + cheat + description:Gain triple shot on weapon pick-up + code:e7b0/00/02 + cheat + description:Don't get knocked back when hit + code:971b/8f + cheat + description:Jump 3x as high + code:9b90/c5 + cheat + description:Jump 2x as high + code:9b90/e0 + cheat + description:Multi-jump + code:941d/8d/a9+941e/43/01+941f/01/8d+9420/ee/6c+9421/6c/04+9422/04/4a+94ca/ad/20+94cb/14/01+94cc/05/94+9792/90/60+948c/e5/8e+948d/a1/94 + cheat + description:Start with 40 hearts + code:c991/05/28 + cheat + description:Start with 80 hearts + code:c991/05/50 + cheat + description:Start with 1 life + code:c97a/04/01+c875/04/01 + cheat + description:Start with 8 lives + code:c97a/04/08+c875/04/08 + cheat + description:Start on last level + code:b990/8e/ae+b988/03/09+b98d/00/12 + cheat + description:Invincibility (blinking) + code:005b/02 + cheat + description:Infinite health (alt) + 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 + name:Castlevania (USA) + cheat + description:Infinite time + code:a0af/20/ad + cheat + description:Hit anywhere (Whip) + code:e51b/ce/00+e52b/be/00 + cheat + description:Jump 3x as high + code:9b90/c5 + cheat + description:Jump 2x as high + code:9b90/e0 + cheat + description:Multi-jump + code:941d/8d/a9+941e/43/01+941f/01/8d+9420/ee/6c+9421/6c/04+9422/04/4a+94ca/ad/20+94cb/14/01+94cc/05/94+9792/90/60+948c/e5/8e+948d/a1/94 + cheat + description:Keep sub-weapon after dying + code:c2c8/8d/ad + cheat + description:Walk through walls + code:9f49/4d + cheat + description:Start on last level + code:b990/8e/ae+b988/03/09+b98d/00/12 + 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 + name:Castlevania II - Simon's Quest (USA) + cheat + description:Invincibility + code:864b/f0/d0 + cheat + description:Invincibility (enemies die on contact) + code:8735/de/23+8736/87/89 + cheat + description:Invincibility against water + code:80bb/e7/e0+fee3/ff/4c+fee5/ff/c4+fee4/ff/f4+fee2/ff/01+fee1/ff/8b+80bc/c0/fe+fee0/ff/ce + cheat + description:Invincibility against poisonous swamps and spikes + code:8045/d0/50 + cheat + description:Infinite health + code:d35f/85/a5 + cheat + description:Infinite lives + code:c294/c6/24 + cheat + description:Infinite Laurels + code:d921/c6/05 + cheat + description:Infinite Laurel time + code:8199/ce/ad + cheat + description:Infinite Garlic + code:d935/c6/a5 + cheat + description:Stops time (always daytime) + code:d79b/85/a5 + cheat + description:One hit kills + code:8926/40/00 + cheat + description:Hit anywhere - whip + code:8917/47/00+891c/54/00+88fd/61/00 + cheat + description:Hit anywhere - sub-weapons + code:8a09/30/b0+8a27/30/b0 + cheat + description:Small hearts worth 100 + code:8762/84 + cheat + description:Enemies always drop large Hearts + code:82a9/d0/b0+82ae/bd/ad+82b0/04/fa + cheat + description:Can use sub-weapons regardless of Heart count + code:d876/b0/f0 + cheat + description:Multi-jump + code:89d9/10/80+89da/13/d0+89db/a0/0c+89dd/20/4c+89df/86/89+89d8/03/29+89d7/6c/f5+89d6/ad/a5+89e9/00/fb+89de/ed/ee+89dc/f0/ea + cheat + description:Jump higher (4 1/3 blocks) + code:89ef/38/20 + cheat + description:Buy a White Crystal and receive the Red Crystal and all of Dracula's Relics + code:ee29/20/ff + cheat + description:Buy Thorn Whip and receive the Flame Whip (do not buy any other whips) + code:edf3/07/04 + cheat + description:Whip much faster + code:dc11/f0/d0 + cheat + description:Diamond can destroy any block + code:da12/18/a7+da13/c1/da+d691/8e/ea + cheat + description:Whip can destroy any block + code:d639/00+d628/00+d65d/10+d691/ea + cheat + description:Whip destroys all enemies/townspeople on screen + code:88d8/75 + cheat + description:Towns never sleep (can enter doors) + code:87af/11/00+814f/d0/f0 + cheat + description:Ponds open instantly without needing a Crystal + code:cd70/d0/f0 + cheat + description:Faster dialog text + code:ee98/f0/d0 + cheat + description:Walk faster + code:8770/ff/fe+8910/ff/fe+891b/01/02+8756/01/02 + cheat + description:Always get the best ending + code:a17e/a5/85 + cheat + description:Start with 100 Experience (E) + code:f12c/09 + cheat + description:Start with more health + code:c55e/30/50 + cheat + description:Start with 25 hearts + code:c55a/50/25 + cheat + description:Start with 75 hearts + code:c55a/50/75 + cheat + description:Start with 1 life + code:c553/03/01 + cheat + description:Start with 6 lives + code:c553/03/06 + cheat + description:Start with 9 lives + code:c553/03/09 + cheat + description:Invincibility (alt 2) + 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:Stops time (time set to 12:02) + 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 + name:Castlevania III - Dracula's Curse (USA) + cheat + description:Invincibility (disable if you cannot enter a door) + code:8112/f0/d0 + cheat + description:Invincibility (disable if you cannot enter a door) (alt) + code:b241/85/a5 + cheat + description:Infinite health + code:828a/85/a9 + cheat + description:Infinite lives + code:8993/85/a9 + cheat + description:Infinite hearts + code:ba03/90/91 + cheat + description:Hit anywhere (Whip) + code:b287/18/00 + cheat + description:High jump + code:9633/09/03 + cheat + description:Multi-jump + code:8be0/10/60+985c/65/d8+9854/b0/90+985f/26/05+985a/0c/05+9861/08/05+9859/d0/a9+97d5/4f/51+93e7/4f/51+985b/ad/8d+9856/ad/8d+9851/04/a5+9831/85/a5+9852/c9/26+9853/08/0a + cheat + description:No knock-back when hurt + code:823c/8d/60 + cheat + description:Disable automatic upwards scrolling (on vertical stages) + code:d73b/82/80 + cheat + description:Walk twice as fast to the left + code:9728/ff/fe + cheat + description:Walk twice as fast to the right + code:96ec/01/02 + cheat + description:Start with 9500 seconds + code:b33f/01 + cheat + description:Start each stage with 99 hearts + code:90c1/05/99 + 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 (alt) + code:0084/99 + cheat + description:Alucard has best attack + code:008f/02 + cheat + description:Trevor Belmont has best Whip + code:008e/02 + cheat + description:Enable Sypha + code:003a/01 + cheat + description:Enable Grant + code:003a/02 + cheat + description:Enable Alucard + code:003a/03 + cheat + description:Have Triple Shot (III) + code:0087/02 + cheat + description:Trevor Belmont's sub-weapon - Axe + code:0085/01 + cheat + description:Trevor Belmont's sub-weapon - Clock + code:0085/0b + cheat + description:Trevor Belmont's sub-weapon - Cross + code:0085/02 + cheat + description:Trevor Belmont's sub-weapon - Dagger + code:0085/03 + cheat + description:Trevor Belmont's sub-weapon - Holy Water + code:0085/04 + cheat + description:Sypha Belnades' sub-weapon - Fire Spell + code:0086/05 + cheat + description:Sypha Belnades' sub-weapon - Ice Spell + code:0086/06 + cheat + description:Sypha Belnades' sub-weapon - Lightning Spell + code:0086/07 + cheat + description:Grant Danasty's sub-weapon - Dagger + code:0086/08 + cheat + description:Grant Danasty's sub-weapon - Axe + code:0086/09 + cheat + description:Grant Danasty'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:52451a89296cfcb006beb6363ddc8486fcc88154338cbec778a846056c522f50 + name:Cat Ninden Teyandee (Japan) + cheat + description:Infinite health + code:003f/0b + cheat + description:Infinite magic energy + code:0040/ff + +cartridge sha256:c20a8cc1b2dacb8a45e706b5763ac6c82c17b4ee4fb547ba4a853e4aabd6e35c + name:Challenge of the Dragon (USA) (Unl) + cheat + description:Infinite health + code:e252/9d/ad + cheat + description:Infinite lives + code:e49a/99/b9 + cheat + description:Always have Bombs + code:eca6/d0/50 + +cartridge sha256:7f4b9307e228c737b5f6e4ef3efb40438aa2024b95b29f9aabf18a15af6ed185 + name:Challenge of the Dragon (Asia) (PAL) (Unl) + cheat + description:Invincibility + code:a079/f0/60 + cheat + description:Infinite health + code:a120/c6/a5 + cheat + description:Infinite lives + code:8f1a/c6/a9 + +cartridge sha256:d5b039637a2315458f71ec57a287f93b3532e6243b712b55767f07dc83c5a3c9 + name:Championship Pool (USA) + cheat + description:1 foul loses the game (instead of 3) - only in 10-ball in party mode + code:b01f/03/01 + cheat + description:2 fouls in a row loses the game - only on 9 and 10-ball in party mode + code:b01f/03/02 + cheat + description:Fouls don't count - only on 9 and 10-ball and rotation in party mode + code:ba7c/9d/bd + 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:ba92/9d/bd + cheat + description:Always break in 9 or 10-ball - P1 + code:806e/a5/a9+806f/ed/00 + cheat + description:Always break in 9 or 10-ball - P2 + code:806e/a5/a9+806f/ed/01 + +cartridge sha256:a8f18eb52126cdf3d004877f8c4c315ddf15f823f13f42b0154da17db21ecddd + name:Championship Rally (Europe) + cheat + description:Drive a short distance to finish lap + code:cb5d/20/00 + +cartridge sha256:ebdd748cd488c4acdc5d2c7321de692c1ab0b37044cf0c6ea043457176dbd306 + name:Cheetahmen II (USA) (Unl) + cheat + description:Infinite health - level 1 and 2 + code:a3bc/ce/ad + cheat + description:Infinite health - level 3 + code:a3dc/ce/ad + cheat + description:Infinite health - level 4 + code:a384/ce/ad + cheat + description:Infinite lives - level 1 and 2 + code:b378/ce/ad + cheat + description:Infinite lives - level 3 + code:b30f/ce/ad + cheat + description:Infinite lives - level 4 + code:b2ad/ce/ad + +cartridge sha256:b705f866955c7d19292b55a9b0f3ec0e970e3f2509c3da15708b7afd879d98ed + name:Chessmaster, The (USA) + cheat + description:Move pieces anywhere + code:cb6f/56/00+cb73/85/a5+cb78/85/a5 + +cartridge sha256:e84d90fefb92f2b6ab70e35bfb990978c7e384e357ec6b995c3880bff4c5b460 + name:Chip 'n Dale - Rescue Rangers (USA) + cheat + description:Infinite health + code:d086/f8/18 + cheat + description:Multi-jump + code:cc45/01/00+c9a8/0a/a5 + cheat + description:Freeze mechanical bulldog + code:8f38/bd/60 + cheat + description:Freeze mechanical mice + code:8fc6/bd/60 + cheat + description:Freeze buzzer + code:9096/bd/60 + cheat + description:Freeze buzz bomb + code:94fb/bd/60 + cheat + description:Freeze racket-rod + code:95e2/bd/60 + cheat + description:Freeze ditz + code:945f/bd/60 + cheat + description:Freeze hawk bomber + code:9750/bd/60 + cheat + description:Freeze bouncing boxes + code:9be9/bd/60 + cheat + description:Mega-jump + code:c9af/06/0a + cheat + description:Never get stunned + code:d005/de/04 + cheat + description:Press Start to finish the level + code:c78d/98/6d + +cartridge sha256:afa359b53e90781ed3810642c09f7cb22f0ba21c40142649771bfb21a897b4d3 + name:Chip 'n Dale - Rescue Rangers 2 (USA) + cheat + description:Invincibility (glitchy) + code:aa20/f0/d0 + cheat + description:Infinite health + code:b0a3/de/dd + cheat + description:Infinite health - both players + code:b0a3/de/b9 + cheat + description:Infinite lives - both players + code:aec4/d6/a7 + cheat + description:Almost infinite lives - both players + code:aec4/d6/24 + cheat + description:Infinite credits + code:f5bc/c6/a9 + cheat + description:Never get stunned + code:acaa/d6/ea + cheat + description:Start with 1 life - both players + code:f5b5/03/01 + cheat + description:Start with 2 lives - both players + code:f5b5/03/02 + cheat + description:Start with 4 lives - both players + code:f5b5/03/04 + cheat + description:Start with 5 lives - both players + code:f5b5/03/05 + cheat + description:Start with 1 heart - both players + code:f592/03/01 + cheat + description:Start with 2 hearts - both players + code:f592/03/02 + cheat + description:Start with 4 hearts - both players + code:f592/03/04 + cheat + description:Start with 5 hearts - both players + code:f592/03/05 + cheat + description:Start with 1 credit + code:f578/03/01 + cheat + description:Start with 2 credits + code:f578/03/02 + cheat + description:Start with 6 credits + code:f578/03/06 + cheat + description:Start with 9 credits + code:f578/03/09 + cheat + description:Start with 255 credits (ignore the counter) + code:f578/03/ff + +cartridge sha256:21a7f7a5a043ddc2017cd97b4088156b0d728271455966ab6748a79eddd3410e + name:Chubby Cherub (USA) + cheat + description:Infinite lives + code:8207/c6/a5 + cheat + description:Infinite power + code:a70d/85/a5 + cheat + description:Half regular power gained from food + code:8ee4/08/04 + cheat + description:Slow down power loss on the ground + code:a6f8/02/01 + cheat + description:Slow down power loss in the air + code:a6fe/09/03 + cheat + description:Infinite Gau (shots) + code:8d7e/eb/02 + cheat + description:Double Gau (shots) on candy pick-up + code:a859/04/08 + cheat + description:Start with 1 life + code:8290/02/00 + cheat + description:Start with double lives + code:8290/02/05 + cheat + description:Start with triple lives + code:8290/02/08 + cheat + description:Start on Stage 5 + code:8293/01/05+8291/00/04 + cheat + description:Start on Stage 10 + code:8293/01/0a+8291/00/09 + +cartridge sha256:fa701601d39819ef26821d05350ccb793cc606191e03c06203a4274b434dfaeb + name:Circus Caper (USA) + cheat + description:Invincibility in normal levels + code:f479/03/f5+f478/52/0e+f477/ad/20 + cheat + description:Infinite power (health) + code:f501/8d/2c + cheat + description:Infinite power (health) (alt) + code:f501/8d/ad + cheat + description:Full energy from food + code:e85f/02/00 + cheat + description:Start with lots of weapons + code:eb97/00/ff + cheat + description:Start on stage 2 (starts on stage 1 after continuing) + code:c0e4/01/02 + cheat + description:Start on stage 3 (starts on stage 1 after continuing) + code:c0e4/01/03 + cheat + description:Start on stage 4 (starts on stage 1 after continuing) + code:c0e4/01/04 + cheat + description:Start on stage 5 (starts on stage 1 after continuing) + code:c0e4/01/05 + cheat + description:Start on stage 6 (starts on stage 1 after continuing) + code:c0e4/01/06 + cheat + description:Infinite power (health) (alt 2) + code:0392/7a + +cartridge sha256:590535e8cda84cb4054425539bc320c16307f141d688b57f258a162dedc8888f + name:City Connection (USA) + cheat + description:Infinite lives + code:d17e/c6/a5 + cheat + description:Infinite Oil + code:94c2/c6/a5 + cheat + description:Start with double lives + code:85cf/02/05 + cheat + description:Start with triple lives + code:85cf/02/08 + cheat + description:Start with extra Oil + code:85d1/05/20 + cheat + description:Start on level 1 + code:85cd/00/01 + cheat + description:Start on level 2 + code:85cd/00/02 + cheat + description:Start on level 3 + code:85cd/00/03 + cheat + description:Start on level 4 + code:85cd/00/04 + cheat + description:Start on level 5 + code:85cd/00/05 + 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 + name:Clash at Demonhead (USA) + cheat + description:Invincibility + code:9293/d0/f0+90d1/f0/d0 + cheat + description:Infinite health + code:c502/85/a5 + cheat + description:Infinite barrier hits + code:adf4/ce/ad + cheat + description:Infinite supply of all items bought + code:a5c4/de/ad + cheat + description:Don't die when power hits zero + code:b15b/ee/ae + cheat + description:All items in shop are free + code:c4b0/e5/60 + cheat + description:Start with 1 of each item + code:cbf7/9d/fe + cheat + description:Start with extra cash + code:cc34/f4/06+cc36/9a/9b + cheat + description:Start with 50% power + code:cc0e/10/08+a9e7/10/08+cc12/04/02 + cheat + description:Start with 150% power + code:cc0e/10/18+cc12/04/06+a9e7/10/18 + cheat + description:Start with 200% power + code:cc0e/10/20+cc12/04/08+a9e7/10/20 + cheat + description:Infinite health (alt) + code:009f/10 + +cartridge sha256:79969ab6741823e5560794489d5b20a677a1207c06265855e5d7b633e6fef29a + name:Cliffhanger (USA) + cheat + description:Protection from most hits + code:9c61/ce/ad + cheat + description:Infinite lives + code:cd8c/ce/ad + cheat + description:Infinite continues + code:ef15/76/bb + cheat + description:Don't burn money at campfire + code:9af2/9d/bd + cheat + description:Some bags contain mega-money, some contain no money + code:cafc/18/17 + cheat + description:Start with 2 lives + code:cc56/03/01 + cheat + description:Start with 6 lives + code:cc56/03/05 + cheat + description:Start with 8 lives + code:cc56/03/07 + cheat + description:Start with 10 lives + code:cc56/03/09 + cheat + description:Start with 1 continue + code:cc43/03/01 + cheat + description:Start with 5 continues + code:cc43/03/05 + cheat + description:Start with 7 continues + code:cc43/03/07 + cheat + description:Start with 9 continues + code:cc43/03/09 + cheat + description:Start with 2x health (does not show on meter) + code:cc9f/10/20 + cheat + description:Start with 1/2 health + code:cc9f/10/08 + cheat + description:Start with $100 + code:cc6e/8d/ee + cheat + description:Start with $10,000 + code:cc6b/8d/ee + cheat + description:Start with $650,000 (displays $xx0000 until you pick up first money bag) + code:cc6b/8d/ce + cheat + description:Infinite health + code:0405/10 + cheat + description:Infinite lives (alt) + code:0406/03 + +cartridge sha256:ed0a1a5ca7cf404116d0073e8ccd213a082d2ac50132f54f3c8621f3dbcdb248 + name:Clu Clu Land (World) + cheat + description:Infinite lives - both players + code:d3b3/24 + cheat + description:Infinite time + code:cb15/24 + cheat + description:Increase extra time + code:d3f4/06 + cheat + description:Shoot more rays + code:dae5/02/05 + cheat + description:Shoot shorter rays + code:dae9/20/10 + cheat + description:Shoot longer rays + code:dae9/20/50 + cheat + description:Enemy can go thru gold bars + code:d750/04/00 + cheat + description:Start with 1 life - both players + code:c34c/01 + cheat + description:Start with 10 lives - both players + code:c34c/10 + cheat + description:Start with 1 life - P2 + code:c359/85/e6 + +cartridge sha256:711eee6690af76a59321f49c8dbfec39eef702775e6cc2a1e63553b40fa3aa5f + name:Cobra Command (USA) + cheat + description:Immune to weapon damage + code:dc5f/e5/24 + cheat + description:Start with infinite lives + code:81b0/ce/ad + cheat + description:Start with 1 life + code:e23c/04/00 + cheat + description:Start with 9 lives + code:e23c/04/08 + 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 + name:Cobra Triangle (USA) + cheat + description:Invincibility + code:ab6c/d0/60 + cheat + description:Infinite continue options + code:a63a/ce/ad + cheat + description:Don't lose life after dying from damage + code:e90f/ce/ad + cheat + description:Don't lose life after dying from time running out + code:e965/ce/ad + cheat + description:Never lose your power-ups + code:e6a1/8d/f0+e6a2/28/0b + cheat + description:Hit anywhere + code:b421/b0/d0+acc2/b0/d0+b432/97/9c+ad49/99/b9+b422/12/0e+acc3/1a/17 + cheat + description:Gain an extra minute + code:83a8/8d/ee+83a9/15/13 + 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 + name:Code Name - Viper (USA) + cheat + description:Invincibility + code:d55c/20/ad + cheat + description:Infinite health + code:9966/f9/ed+9a5e/01/00 + cheat + description:Infinite health (alt) + code:996d/8d/ad + cheat + description:Infinite lives + code:ef1c/ce/ad + cheat + description:Infinite Gun + code:a1fa/01/00 + cheat + description:Infinite Machine Gun + code:a21b/01/00 + cheat + description:Hit anywhere + code:d856/38/00+9c1d/03/10+9c20/13/34+9c1c/bd/ad + cheat + description:Double usual bullets on new life + code:ef18/32/64 + cheat + description:Half bullets on new life + code:ef18/32/19 + cheat + description:Machine Gun with 256 bullets on new life + code:ef11/8d/ee + cheat + description:Upper level jump + code:8fce/b9/ad+908f/fa/f9 + cheat + description:Keep Machine Gun after dying + code:ef11/8d/2c+ef0e/8d/2c + cheat + description:Have Bomb (can exit level without the Bomb) + code:d58d/04/00 + cheat + description:Start with 1 life + code:e4f0/03/01 + cheat + description:Start with 6 lives + code:e4f0/03/06 + cheat + description:Start with 9 lives + code:e4f0/03/09 + cheat + description:Start with Machine Gun and 256 bullets + code:e4fc/8d/ee + cheat + description:Start with double usual bullets + code:e503/32/64 + cheat + description:Start with half usual bullets + code:e503/32/19 + 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 + name:Colorful Dragon (Asia) (PAL) (Unl) + cheat + description:Invincibility + code:9a02/f0/d0 + cheat + description:Infinite lives + code:99bc/d6/b5 + cheat + description:Start on level 2 + code:8037/01/02 + cheat + description:Start on level 5 + code:8037/01/05 + cheat + description:Start on level 10 + code:8037/01/0a + cheat + description:Start on level 15 + code:8037/01/0f + cheat + description:Start on level 20 + code:8037/01/14 + +cartridge sha256:0512b4aa2220f74e40fe8652b758893fa87efb6c3407808f7dda0e1901017432 + name:Commando (USA) + cheat + description:Invincibility + code:d176/85/60 + cheat + description:Infinite Grenades + code:b5b0/ca/ea + cheat + description:Infinite lives + code:c907/ce/a0 + cheat + description:Infinite lives (alt) + code:c907/ce/ad + cheat + description:Get items from anywhere + code:df00/14/00+d640/dc/00 + cheat + description:Hit anywhere + code:e3f6/53/00+e406/43/00 + cheat + description:Walk through anything + code:b784/09/00+b753/06/00 + cheat + description:Start with 1 life - both players + code:c5cd/03/00 + cheat + description:Start with 6 lives - both players + code:c5cd/03/06 + cheat + description:Start with 9 lives - both players + code:c5cd/03/09 + cheat + description:Start with double rations of grenades + code:c5d5/05/10 + cheat + description:Have all power-ups - both players + code:04ab/e9 + cheat + description:Have rapid fire - both players + code:0074/00 + +cartridge sha256:8ae9b624c08b86f6af41b5d58c328188c6df9c35868ae0763d75a22fbfb6c712 + name:Conan (USA) + cheat + description:Invincibility + code:87bf/20/ad+8461/20/ad + cheat + description:Infinite lives + code:dec5/c6/a5+db6b/c6/a5 + cheat + description:Infinite health + code:e9d1/8d/ad + +cartridge sha256:a5b8e24589539b0b84a6ad98aee9c91eb86eff795162be38b020dc42c3e3eca7 + name:Conquest of the Crystal Palace (USA) + cheat + description:Invincibility + code:d1e7/f0/d0+d1e5/a5/85 + cheat + description:Invincibility (alt) + code:e59b/20/ad + cheat + description:Infinite lives + code:e160/20/2c + cheat + description:Infinite lives (alt) + code:e163/85/a5 + cheat + description:Infinite energy (will display wrong info) + code:d1ca/bd/ee + cheat + description:Infinite energy for Farron + code:e5a0/20/ad + cheat + description:Infinite fire power + code:d393/bd + cheat + description:Maximum energy without Life Crystal + code:fa03/0e/14 + cheat + description:Don't use up money when buying things + code:e129/20/2c+e132/20/2c + cheat + description:Super-jump without Flight Crystal + code:d664/02/00+d666/03/01 + cheat + description:Increase super-jump to mega-jump + code:d6bb/0e/15 + cheat + description:Increase super-jump to super-mega-jump + code:d6bb/0e/45 + +cartridge sha256:62c9d4e0578cb1e615ce9bb2c8ebc15b1e8de4c928c5c07ba9a85c11aa36ae4d + name:Contra (Japan) + cheat + description:Invincibility + code:e1fa/20/ad + cheat + description:Infinite lives + code:d939/d6/a5 + +cartridge sha256:d41e28b1a33b3b6768e7c39c9fdfb1fda4b49940542d14085911fabd399e1ca9 + name:Contra (USA) + cheat + description:Invincibility + code:e2c9/20/ad + cheat + description:Invincibility (blinking) + code:d467/b5 + cheat + description:Invincibility (blinking) (alt) + code:d466/05/00 + cheat + description:Hit anywhere + code:e388/90/d0+e3a1/b0/24+e37f/b0/24+e3c7/20/ad + cheat + description:Enemies die automatically (causes graphical glitches in some levels) + code:e3f1/08/00+e358/f0/a9+e360/29/42 + cheat + description:Multi-jump - both players + code:d476/b5/20+d477/b0/9f+d478/f0/d6+d479/08/ea+d480/d6/b5+d9e9/95/b5+d54a/a9/60 + cheat + description:Jump higher + code:d6ef/fc/fb+d6e9/fb/fa + cheat + description:Run 2x as fast + code:d761/ff/fe+d75d/01/02 + cheat + description:Run 4x as fast + code:d75d/01/04+d761/ff/fc + cheat + description:Keep weapons after dying + code:dad3/95/a5 + cheat + description:Keep weapons after dying (alt) + code:dad3/2c + cheat + description:Press Select to change weapons - P1 + code:f61a/ff/20+f618/ff/d0+f62f/ff/d0+f623/ff/d0+f61b/ff/f0+f614/ff/f0+f622/ff/04+d042/a4/4c+f616/ff/4c+f62d/ff/4c+f613/ff/25+f612/ff/a4+f615/ff/03+f617/ff/53+f621/ff/c9+f625/ff/a9+f628/ff/01+f627/ff/69+f619/ff/29+f61f/ff/29+f629/ff/85+f62b/ff/a5+f62c/ff/f5+f61d/ff/a5+f61c/ff/0e+f62e/ff/46+d044/d0/f6+f61e/ff/aa+f62a/ff/aa+f620/ff/07+f624/ff/02+d043/25/12 + cheat + description:Press Start to complete the level + code:d04d/25/3b + cheat + description:Start with infinite lives + code:da03/b5 + cheat + description:Start new life with Machine Gun + code:dad2/01 + cheat + description:Start new life with Fireball + code:dad2/02 + cheat + description:Start new life with Spread Gun + code:dad2/03 + cheat + description:Start new life with Laser + code:dad2/04 + cheat + description:Start on level 2 + code:c479/3f/30+c475/00/01 + cheat + description:Start on level 3 + code:c479/3f/30+c475/00/02 + cheat + description:Start on level 4 + code:c479/3f/30+c475/00/03 + cheat + description:Start on level 5 + code:c479/3f/30+c475/00/04 + cheat + description:Start on level 6 + code:c479/3f/30+c475/00/05 + cheat + description:Start on level 7 + code:c479/3f/30+c475/00/06 + cheat + description:Start on level 8 + code:c479/3f/30+c475/00/07 + 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 + name:Contra Force (USA) + cheat + description:Invincibility + code:a5ca/20/ad+a5b1/20/ad + cheat + description:Infinite lives (alt) + code:ac9e/99/b9 + cheat + description:Infinite lives - all characters + code:e07d/01/00 + cheat + description:Keep weapons after death + code:ac8f/99/b9 + cheat + description:Start with 9 lives - all characters + code:f636/03/09 + cheat + description:Start with 6 lives - all characters + code:f636/03/06 + cheat + description:Start with 1 life - all characters + code:f636/03/01 + +cartridge sha256:22ea833fd9466795bd2b05df96a47081ca45a26f545af1242f4c89b2d6688bdd + name:Cool World (USA) + cheat + description:Infinite lives + code:e4be/ce/2c + cheat + description:Infinite Bombs + code:eed1/c6/a5 + cheat + description:Infinite Erasers + code:eeec/c6/a5 + cheat + description:Lots of Erasers + code:af70/00/28 + cheat + description:Start with 3 Bombs + code:b2e4/01/03 + cheat + description:Start with 6 Bombs + code:b2e4/01/06 + cheat + description:Start with 9 Bombs + code:b2e4/01/09 + cheat + description:Start with 2 lives + code:c0c7/02/01+af44/02/01 + cheat + description:Start with 7 lives + code:c0c7/02/06+af44/02/06 + cheat + description:Start with 10 lives + code:c0c7/02/09+af44/02/09 + cheat + description:Start with 3 Erasers + code:c0cc/01/03+af6a/01/03 + cheat + description:Start with 6 Erasers + code:c0cc/01/06+af6a/01/06 + cheat + description:Start with 9 Erasers + code:c0cc/01/09+af6a/01/09 + cheat + description:Infinite energy + code:04e8/00 + +cartridge sha256:528d501320ed0276bbc542f03c7c05fb59f9eeb540cd0d39e7286b1542aa153a + name:Cowboy Kid (USA) + cheat + description:Infinite lives + code:cbf8/99/b9 + cheat + description:Hit anywhere + code:93a0/5e/7c+939d/c9/a9 + cheat + description:Infinite health + code:0698/08 + +cartridge sha256:23b16928a7615ec599536b17dd2026370e2e1a13835f61276ea383d6b4d3f8c0 + name:Crackout (USA) (Proto) + cheat + description:Infinite lives + code:b87a/c6/a5 + +cartridge sha256:fda4fd839497634df5e77b1842f88c05ffa0ac13a894c9ea288aedcd168489c3 + name:Crash 'n' the Boys - Street Challenge (USA) + cheat + description:Start with 99 Gold + code:b5e8/05/99 + cheat + description:Start with 50 Gold + code:b5e8/05/50 + +cartridge sha256:b504d0ebff8aa6439f1f9606526d8739f5007c1fdac31f9550caa7ca26edce16 + name:Crisis Force (Japan) + cheat + description:Infinite lives + code:86fd/d6/b5 + cheat + description:Infinite Bombs + code:861c/de/bd + cheat + description:Start on stage 2 + code:cb14/00/01 + cheat + description:Start on stage 3 + code:cb14/00/02 + cheat + description:Start on stage 4 + code:cb14/00/03 + cheat + description:Start on stage 5 + code:cb14/00/04 + cheat + description:Start on stage 6 + code:cb14/00/05 + cheat + description:Start on stage 7 + code:cb14/00/06 + +cartridge sha256:7eca4ce264363ab8cc2c9aeb52f2e5be43a72a8223bac977492c7f8d78a49fb4 + name:Cross Fire (USA) (Proto) + cheat + description:Invincibility + code:93e8/d0/f0+93e3/f0/d0 + cheat + description:Infinite energy + code:8779/d0/a9+877b/ad/8d + cheat + description:Infinite lives + code:81bf/ce/ad + cheat + description:Protection from enemies + code:fafb/8d/ad+a00b/ce/ad + +cartridge sha256:5ad644d368f70b61700b74a1d04778888efcbbf98d5435d79f9fcefd23ac39c2 + name:Crystalis (USA) + cheat + description:Always fire charged shot + code:9c79/4a/a9+9c7a/4a/01 + cheat + description:Always fire bracelet charged shot + code:9c79/4a/a9+9c7a/4a/03 + cheat + description:Faster sword charge + code:9e10/03/00 + cheat + description:Allow sword charge while moving + code:9e00/4c/ad + cheat + description:First pupil gives you more gold + code:d269/64/ff + cheat + description:Magic doesn't use up MP + code:9afe/8d/ad + cheat + description:Immune to poison + code:ef5e/0f/00 + cheat + description:Immune to paralysis + code:efc5/0f/00 + cheat + description:Stronger poison + code:ef96/04/06 + cheat + description:Weaker poison + code:ef96/04/02 + cheat + description:Walk through walls + code:99cb/06/00 + cheat + description:Don't get charged for boarding at Inn + code:963d/8d/ad+9643/8d/ad + cheat + description:Don't get charged for items in shops + code:99e3/8d/ad+99e9/8d/ad + cheat + description:Start with some gold + code:c993/8d/ee + +cartridge sha256:e239709320fca149b40a1f04625741dc2b6d3b9cc933d4062882ad762fa67ca7 + name:Cyberball (USA) + cheat + description:Infinite level time + code:f4b0/ce/ad + cheat + description:Start with level time at 1 minute + code:93ff/03/01 + cheat + description:Start with level time at 2 minutes + code:93ff/03/02 + cheat + description:Start with level time at 5 minutes + code:93ff/03/05 + cheat + description:Start with level time at 9 minutes + code:93ff/03/09 + cheat + description:Goals worth 0 points + code:802a/02/00 + cheat + description:Goals worth 1 points + code:802a/02/01 + cheat + description:Goals worth 5 points + code:802a/02/05 + cheat + description:Goals worth 9 points + code:802a/02/09 + cheat + description:Goals worth mega points + code:802a/02/63 + +cartridge sha256:ad1e14d08657d99c8b70f779931f62524b4beb529090b82b368925d8b642e40c + name:Cybernoid - The Fighting Machine (USA) + cheat + description:Infinite Bombs + code:9976/ce/ad + cheat + description:Infinite Genocides + code:bd8d/ce/ad + cheat + description:Infinite Shields + code:9d93/ce/ad + cheat + description:Infinite Seekers + code:977b/ce/ad + cheat + description:20 Genocides on new life + code:a192/02/14 + cheat + description:Keep rear laser after death + code:a142/8d/2c + cheat + description:Keep mace after death + code:a148/8d/2c+a145/8d/2c + cheat + description:Start with rear laser + code:8199/00/ff + cheat + description:Start with infinite lives + code:a164/ce/ad + cheat + description:Start new life with 20 shields + code:823e/01/14+a197/01/14 + cheat + description:Start with 20 seekers and bouncers + code:8242/05/14+a19c/05/14 + cheat + description:Start with double Bombs + code:8233/14/28+a18d/14/28 + cheat + description:Start with 1 life + code:8206/ff/f7 + cheat + description:Start with 5 lives + code:8206/ff/fb + cheat + description:Start with 18 lives + code:8206/ff/08 + cheat + description:Invincibility + code:06d4/00 + cheat + description:Infinite lives + code:06d5/ff + +cartridge sha256:9d832956a533292e740be553e0eb46d3a3d449578bcbaa9c7556a31d2b6a594d + name:D.J. Boy (Unl) + cheat + description:Infinite health + code:8662/9d/ad + cheat + description:Infinite time + code:8d1f/85/a5 + cheat + description:Infinite lives + code:f788/c6/a5 + +cartridge sha256:4cbf1c1d0be227127513065ccbc8ecf5e5ee61a7a58b6dea79ff01f0eb9f26af + name:Danny Sullivan's Indy Heat (USA) + cheat + description:Infinite turbos + code:b905/de/ad + cheat + description:Infinite fuel + code:8ee5/9d/ad + cheat + description:Everything costs how much you have + code:b1c6/9d/ed + cheat + description:Don't take damage in the front + code:a2e0/99/b9 + cheat + description:Start with $255,000 + code:933a/64/ff + +cartridge sha256:9b6d967f493a565e25b51aee044354f857c5cefc41f476d4f259e7368b1fdd70 + name:Darkman (USA) + cheat + description:Infinite health + code:cdc3/8d/ad + cheat + description:Infinite health (alt) + code:0496/37+04b5/37 + cheat + description:Infinite lives + code:0497/04 + cheat + description:Multi-jump + code:8746/1d/00+8736/5e/00 + cheat + description:Hit anywhere - side-scrolling levels + code:9c8e/d0/24+9c86/f0/24+9c6c/f0/24 + cheat + description:Never lose balance + code:cb5d/90/60 + +cartridge sha256:f97f05a4f8747d81dc8adaf07df70d1f87366632ae3e93103d387043ef5ec508 + name:Darkwing Duck (USA) + cheat + description:Invincibility + code:813d/d0/f0 + cheat + description:Infinite health + code:f9ed/c9/60 + cheat + description:Infinite lives + code:cb15/ce/2c + cheat + description:Infinite lives (alt) + code:cb15/ce/cd + cheat + description:Infinite gas (if you avoid the "Go" missions) + code:89bb/ad/60 + cheat + description:More gas on pick-up + code:8904/70/75 + cheat + description:Start with infinite health + code:f9f3/8d/ad + cheat + description:Start with 2 lives + code:c95a/73/71 + cheat + description:Start with 6 lives + code:c95a/73/75 + cheat + description:Start with 9 lives + code:c95a/73/78 + +cartridge sha256:227e789fef94eabcf24a5ec9a3944de58b183bbc7d96140269d1c908f162b853 + name:Dash Galaxy in the Alien Asylum (USA) + cheat + description:Invincibility + code:c7b3/ad/ea + cheat + description:No damage from shots and collisions + code:9502/01/00 + cheat + description:Infinite Oxygen + code:9515/ce/ad + cheat + description:Infinite Bombs in elevator shaft + code:da78/ad/ee + cheat + description:Infinite Bombs in rooms + code:daea/ad/ee + cheat + description:Infinite Detonators in shafts + code:da9d/ad/ee + cheat + description:Infinite Detonators in rooms + code:db0f/ad/ee + cheat + description:Infinite Keys in shafts + code:a405/ad/ee + cheat + description:Infinite Keys in rooms + code:a19e/ad/ee + cheat + description:Can't lose lives in rooms + code:9166/ce/ad + cheat + description:Can't lose lives in elevator shaft + code:9133/ce/ad + cheat + description:Oxygen used up more slowly in shaft + code:a158/78/ff + cheat + description:Oxygen used up more quickly in rooms + code:af2d/ff/70 + cheat + description:Start with 1 life + code:90f5/03/01 + cheat + description:Start with 6 lives + code:90f5/03/06 + cheat + description:Start with 9 lives + code:90f5/03/09 + cheat + description:Start with 99 lives + code:90f5/03/63 + cheat + description:Start on level 5 + code:9d01/85/a9+9d02/de/05 + cheat + description:Start on level 10 + code:9d01/85/a9+9d02/de/0a + cheat + description:Start on level 15 + code:9d01/85/a9+9d02/de/0f + cheat + description:Start on level 20 + code:9d01/85/a9+9d02/de/14 + +cartridge sha256:911fb75ec1f900a5c258635fae79e56520eeb4aec35b40737c44b735eeccdc56 + name:David Crane's A Boy and His Blob - Trouble on Blobolonia (USA) + cheat + description:Invincible (restart if you die underwater and get stuck by being unable to call your Blob) + code:c090/a9/60 + cheat + description:Never take damage from enemies + code:9c96/d0/60 + cheat + description:Infinite lives + code:89a9/c6/24 + cheat + description:Infinite Jellybeans + code:c16d/01/00 + cheat + description:1 life only + code:bc37/05/00 + cheat + description:Double lives + code:bc37/05/0a + cheat + description:Fast play + code:808a/20/ad + cheat + description:Gives 10 Orange Jellybeans + code:bd0b/00/10 + cheat + description:10 Lime Jellybeans + code:bcfd/00/10 + cheat + description:99 Licorice Jellybeans + code:bcf1/72/99 + cheat + description:Double Strawberry Jellybeans + code:bcf3/15/30 + cheat + description:Double Cola Jellybeans + code:bcf7/18/36 + cheat + description:Double Cinnamon Jellybeans + code:bcf9/24/48 + cheat + description:Double Apple Jellybeans + code:bcfb/12/24 + cheat + description:Double Vanilla Jellybeans + code:bcff/30/60 + cheat + description:Double Ketchup Jellybeans + code:bd07/06/12 + cheat + description:Triple Coconut Jellybeans + code:bcf5/06/18 + cheat + description:Triple Rootbeer Jellybeans + code:bd03/06/18 + cheat + description:10 Vitamin A for Vita-Blaster + code:bd0d/00/10 + cheat + description:10 Vitamin B for Vita-Blaster + code:bd0f/00/10 + cheat + description:10 Vitamin C for Vita-Blaster + code:bd11/00/10 + cheat + description:Start with 101 of all starting Jellybeans + code:bc22/bd/ad+bc23/f0/77 + +cartridge sha256:41f949cfedf7167985f779c0782ee17ee83d82e35111c5f22ee5037f54313a06 + name:Day Dreamin' Davey (USA) + cheat + description:Infinite health + code:94d2/85/a5 + cheat + description:Hit anywhere + code:b472/4a/00 + 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 + name:Days of Thunder (USA) + cheat + description:Faster acceleration + code:f381/bd/ad + cheat + description:Tires don't burst + code:9a68/ff/00 + cheat + description:Better left-hand cornering + code:9cad/f8/f5 + cheat + description:Maximum acceleration + code:f3bb/03/05+f381/bd/ad + cheat + description:Start with more fuel + code:f34d/9f/ff + cheat + description:Start with less fuel + code:f34d/9f/5f + 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 + name:Deadly Towers (USA) + cheat + description:Invincibility + code:99aa/29/a9 + cheat + description:Infinite HP + code:99df/e5/24 + cheat + description:1 Ludder gives 10 on pick-up + code:9fb4/01/0a + cheat + description:5 Ludder gives 20 on pick-up + code:9fb3/05/14 + cheat + description:Shopkeeper forgets to charge you + code:c6b3/f9/2c + cheat + description:Start with 127 Ludder + code:812b/32/7f + cheat + description:Start with 75 Ludder + code:812b/32/4b + 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 + name:Deathbots (USA) (Rev 1) (Unl) + cheat + description:Infinite energy + code:aa71/9d/bd + cheat + description:Infinite lives + code:a0a5/ce/ad + cheat + description:Infinite shots + code:ae30/99/b9 + +cartridge sha256:5dac8da44ac4e28bebf3d33c8e00e1fdffcc7baee3ff98bec5a10415d1226791 + name:Deathbots (USA) (Unl) + cheat + description:Infinite energy + code:aa71/9d/bd + cheat + description:Infinite lives + code:a0a5/ce/ad + cheat + description:Infinite shots + code:ae30/99/b9 + +cartridge sha256:bf58512dc3bc427d14a6d851445801967cd14f3d02ae236eabceeb7928a55462 + name:Defender II (USA) + cheat + description:Invincibility + code:dee1/85/a5 + cheat + description:Infinite lives + code:cfe0/24 + cheat + description:Infinite Smart Bombs + code:d5fc/24 + cheat + description:Super speed + code:e429/07+e3ed/07 + cheat + description:Start with 1 life + code:cfb7/01 + cheat + description:Start with 6 lives + code:cfb7/06 + cheat + description:Start with 9 lives + code:cfb7/09 + +cartridge sha256:9e31d3d918a352c0c5a81c52efc364253f3fb75cc84151ee904ad078be62d8e1 + name:Defender of the Crown (USA) + cheat + description:Only 10 soldiers in your Garrison + code:e368/14/0a + cheat + description:40 soldiers in your Garrison + code:e368/14/28 + cheat + description:Soldiers for free + code:990b/01/00 + cheat + description:Triple the cost of soldiers + code:990b/01/03 + cheat + description:Halve the cost of knights + code:990c/08/04 + cheat + description:Double the cost of knights + code:990c/08/10 + cheat + description:Halve the cost of catapults + code:990d/0f/07 + cheat + description:Halve the cost of castles + code:990e/14/0a + +cartridge sha256:c408dd19ca49e55173ff2c491868f437d8100671f7b9646ee20e3204e0ba216f + name:Demon Sword (USA) (USA) + cheat + description:Invincibility + code:8a3b/20/ad + cheat + description:Infinite health (life) + code:c646/85/a5 + cheat + description:Infinite powers and lives + code:e6db/01/00 + cheat + description:Infinite lives + code:d0d7/85/a5 + cheat + description:Phoenix always rescues you + code:e060/ad/ee + cheat + description:Infinite Fire, Lightning, Power Beams on pick-up + code:f778/9d/bd + cheat + description:Hit anywhere + code:c720/b5/38+c721/98/60+c6f9/4c/ad + cheat + description:Extra dart strength + code:a178/8d/ee + cheat + description:Start with 44 Red Spheres + code:a174/85/a2+a187/8d/8e + cheat + description:Start with 44 Black Spheres + code:a174/85/a2+a18a/8d/8e + cheat + description:Start with 44 Fire Spheres + code:a174/85/a2+a17b/8d/8e + cheat + description:Start with 44 Lightning Bolts + code:a174/85/a2+a17e/8d/8e + cheat + description:Start with 44 Power Beams + code:a174/85/a2+a181/8d/8e + cheat + description:Start with 1 life + code:ddeb/02/00 + cheat + description:Start with 6 lives + code:ddeb/02/05 + cheat + description:Start with 9 lives + code:ddeb/02/08 + cheat + description:Start on level 2 + code:a178/8d/60+a173/00/01 + cheat + description:Start on level 3 + code:a178/8d/60+a173/00/02 + cheat + description:Start on level 4 + code:a178/8d/60+a173/00/03 + cheat + description:Start on level 5 + code:a178/8d/60+a173/00/04 + cheat + description:Start on level 6 + code:a178/8d/60+a173/00/05 + 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 + name:Dengeki - Big Bang! (Japan) + cheat + description:Invincibility (blinking) + code:90d9/03/90+90d1/f0/24+90d8/d0/a9 + +cartridge sha256:281ad7bdb4f94e2303d95c6078c20295e240b80370fdceda27950966b0e09198 + name: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 + name:Destination Earthstar (USA) + cheat + description:Infinite lives + code:ddee/c6/a5 + cheat + description:Less energy + code:8bfb/99/55 + cheat + description:More energy + code:8bfb/99/ff + cheat + description:Don't lose special weapon in sub-game + code:ef7d/ca/ea + cheat + description:Start with 1 life + code:ec62/03/01 + 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 + name:Destiny of an Emperor (USA) + cheat + description:No random battles + code:f47a/c5/a9+f4d7/39/ad + cheat + description:Buy 300 provisions for no money + code:92c2/64/00 + cheat + description:Buy 30,000 provisions for no money + code:92c5/27/00+92c6/10/00 + cheat + description:Dagger costs nothing + code:bbf3/32/00 + cheat + description:Bandana costs nothing + code:bce4/32/00 + cheat + description:Flail costs nothing + code:bbfc/64/00 + cheat + description:Robe costs nothing + code:bca2/64/00 + cheat + description:Elixir A costs nothing + code:bbba/14/00 + cheat + description:Resurrect costs nothing + code:bbae/64/00 + cheat + description:Steed costs nothing + code:bba6/c8/00 + cheat + description:Gullwing costs nothing + code:bb8c/c8/00 + cheat + description:Leather costs nothing + code:bca9/2c/00+bcaa/01/00 + cheat + description:Walk anywhere + code:f336/4c/ad + +cartridge sha256:163479e2b1571538cf2f0f147bcbdebaab8ed8b0251f87dabd9bc4c80d786ea1 + name:Dick Tracy (USA) + cheat + description:Infinite health + code:97ed/ed/2c + cheat + description:Infinite hand gun bullets + code:a920/ce/ad + cheat + description:Infinite machine gun bullets + code:a0ea/ce/ad + cheat + description:Infinite super punches + code:a245/ce/ad + cheat + description:Infinite tear gas + code:a20d/ce/ad + cheat + description:More super punches on pick-up + code:9185/0a/14 + cheat + description:Mega-jump + code:a060/f7/f4 + cheat + description:Take more damage + code:97ec/38/18 + cheat + description:Infinite health (alt) + code:0663/09 + cheat + description:Infinite hand gun bullets (alt) + code:0761/31 + +cartridge sha256:e060fd43ef58d6e022f1fcab853a388142fd68d4bbd00dedc095992152e27976 + name:Die Hard (USA) + cheat + description:Infinite health against Pistol ammo + code:a786/85/a5 + cheat + description:Infinite health against Submachine Gun ammo + code:a795/85/a5 + cheat + description:Infinite health against punches + code:a7a3/85/a5 + cheat + description:Infinite Pistol ammo + code:8273/ce/60 + cheat + description:Infinite Submachine Gun ammo + code:827d/ce/60 + cheat + description:Infinite ammo on all guns + code:826d/a5/60 + cheat + description:Infinite time + code:f1bc/a5/60 + cheat + description:Lose foot health very slowly + code:f397/8d/ad + cheat + description:Time runs at 1/4 normal speed + code:f1b1/3c/f0 + cheat + description:Time runs at 1/3 normal speed + code:f1b1/3c/b4 + cheat + description:Time runs at 1/2 normal speed + code:f1b1/3c/78 + cheat + description:Time runs at 2x normal speed + code:f1b1/3c/1e + cheat + description:Time runs at 3x normal speed + code:f1b1/3c/14 + cheat + description:Time runs at 4x normal speed + code:f1b1/3c/0f + cheat + description:Start with no Pistol shots instead of 15 + code:c1a1/0f/00 + cheat + description:Start with 5 Pistol ammo + code:c1a1/0f/05 + cheat + description:Start with 10 Pistol ammo + code:c1a1/0f/0a + cheat + description:Start with 20 Pistol ammo + code:c1a1/0f/14 + cheat + description:Start with 25 Pistol ammo + code:c1a1/0f/19 + cheat + description:Start with 1 life point instead of 16 + code:c19d/10/01 + cheat + description:Start with 2 life points + code:c19d/10/02 + cheat + description:Start with 4 life points + code:c19d/10/04 + cheat + description:Start with 8 life point + code:c19d/10/08 + cheat + description:Start with 12 life points + code:c19d/10/0c + cheat + description:Start with 20 life points + code:c19d/10/14 + 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 + name:Digger - The Legend of the Lost City (USA) + cheat + description:Infinite health + code:f9d1/c6/a5 + cheat + description:Infinite lives + code:86e7/c6/a5 + cheat + description:Less rocks on pick-up + code:c332/09/05 + cheat + description:Infinite rocks on pick-up + code:f606/ce/ad + cheat + description:Infinite rope on pick-up + code:b38d/ce/ad + cheat + description:Infinite dynamite on pick-up + code:a08e/ce/ad + cheat + description:Start with weapons + code:fc19/00/09 + cheat + description:Infinite time (disable before exiting stage) + code:0187/09 + +cartridge sha256:7c8b6add50b20e4612e3043df0671e701cd2aa163e4af864913e3940feee27f2 + name: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 + name:Dig Dug II - Trouble in Paradise (USA) + cheat + description:Instant inflate and explode + code:e205/d0/24 + cheat + description:Never lose lives from touching water + code:be25/ce/ad + cheat + description:Never lose lives from Fygar's flame + code:c6eb/ce/ad + cheat + description:Never lose lives from hitting enemies + code:d0f1/ce/ad + cheat + description:Turbo speed + code:f371/29/a9+f372/03/02 + cheat + description:Start with 1 life - both players + code:e981/03/01 + cheat + description:Start with 8 lives - both players + code:e981/03/08 + +cartridge sha256:5aaa8382ec79c170472840dfd8e9d93512bdf2be09ecd6b3709a9d27658888cd + name:Dirty Harry (USA) + cheat + description:Infinite health + code:cca2/e5/24 + cheat + description:Infinite lives + code:ccb9/ce/ad + cheat + description:Maximum health from Chili Dogs + code:b1e5/02/00 + cheat + description:Only 10 Magnum Bullets allowed + code:d5de/19/0a+d5e2/19/0a + cheat + description:50 Magnum Bullets allowed + code:d5de/19/32+d5e2/19/32 + cheat + description:Start with 1 life + code:d57c/05/01 + cheat + description:Start with 10 lives + code:d57c/05/0a + 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 + name:Doki! Doki! Yuuenchi (Japan) + cheat + description:Invincibility + code:9101/30/10 + cheat + description:Infinite hits + code:afe8/ce/ad + cheat + description:Infinite lives + code:dfdc/ce/ad + +cartridge sha256:aa408f5a6b97c0d738e7e8b489a5617ad4a9ecdee2b05c4ee504210ce31b2825 + name:Donkey Kong (World) (Rev A) + cheat + description:Invincible against barrels + code:ecac/85/a5 + cheat + description:Invincible against fireballs + code:edb2/85/a5 + cheat + description:Infinite lives + code:caf1/c6/a5 + cheat + description:Hammer lasts 3.4 times longer + code:d636/4b/ff + cheat + description:Start with 1 life + code:c9ff/03/01 + cheat + description:Start with 9 lives + code:c9ff/03/09 + +cartridge sha256:b15b298dc37692d0bed2cbf922727ea48ed38bbd6cf3acdd28be6d2b9be344d3 + name:Donkey Kong 3 (World) + cheat + description:Invincibility + code:cbe0/f0/60 + cheat + description:Reduce the time for pros + code:c7cc/80/0a + cheat + description:Normal spray more powerful + code:d01a/01/02 + cheat + description:Normal spray longer + code:d01b/00/32 + cheat + description:Spray cuts through baddies + code:d15f/01/00 + cheat + description:Normal bees explode + code:e04a/33/00 + cheat + description:Speeding Stanley + code:ccae/03/06 + cheat + description:Start with infinite lives + code:c979/d6/a5 + cheat + description:Start with 1 life + code:c685/03/01 + cheat + description:Start with 9 lives + code:c685/03/09 + +cartridge sha256:950ebe68e7f74219b9e5e104200b03165d59c24264f02e32c12be967fd311ac2 + name:Donkey Kong Jr. (World) (Rev A) + cheat + description:Cannot die from falling from a high platform + code:da30/05/01 + +cartridge sha256:07dd16464d769429c651bd203ac2e74c7aa5852824482ca8877959d643bc8689 + name:Donkey Kong Jr. Math (USA, Europe) + cheat + description:Always get the correct answer + code:d543/0a/00+d533/1a/00 + +cartridge sha256:234c2f62cbc3c72eb7519425a1893229e19a3fd1b1630fb75f3e951960a300e5 + name:Donkey Kong Classics (USA, Europe) + cheat + description:Donkey Kong - Infinite lives + code:89f1/a5 + cheat + description:Donkey Kong - Start with 1 life + code:88e7/01 + cheat + description:Donkey Kong - Start with 6 lives + code:88e7/06 + cheat + description:Donkey Kong - Start with 9 lives + code:88e7/09 + cheat + description:Donkey Kong - Controllable jump + code:8de6/0d/00 + cheat + description:Donkey Kong - Keep hammer longer + code:954b/4b/80 + cheat + description:Donkey Kong Jr - Infinite lives + code:c126/a5 + cheat + description:Donkey Kong Jr - Start with 1 life + code:be65/01 + cheat + description:Donkey Kong Jr - Start with 6 lives + code:be65/06 + cheat + description:Donkey Kong Jr - Start with 9 lives + code:be65/09 + cheat + description:Donkey Kong Jr - Controllable jump + code:c3c0/0d/00 + cheat + description:Donkey Kong Jr - Faster single vine climbing + code:cd66/40/80 + cheat + description:Donkey Kong Jr - Can fall onto platforms + code:d021/05/01 + cheat + description:Donkey Kong Jr - Speed up + code:ccdd/f0/a0+ccbf/f0/a0 + +cartridge sha256:56cb5897c539b6874e311a314767df85186184690f10d9982b02cb90ff606537 + name:Double Dare (USA) + cheat + description:Infinite time to answer questions + code:8ba7/ce/ad + +cartridge sha256:8f2f9ba926280edd3652745e1d04a30ecce64089fbf3f022a35b4039a2dd7b66 + name:Double Dragon (USA) + cheat + description:Infinite lives + code:e2b3/02/88 + cheat + description:Infinite time + code:f33f/01/00 + cheat + description:Gain hearts quickly + code:fbc2/e6/c6 + cheat + description:Gain a heart every time you hit an enemy + code:fbdf/c0 + cheat + description:More health - P1 + code:f841/4a/ea + cheat + description:More health - P2 or computer + code:f84a/4a/ea + cheat + description:No enemies + code:9959/5d + cheat + description:Enemies will not fight back + code:8959/5d + cheat + description:Slow motion + code:cce9/9c + cheat + description:Timer will count down faster + code:f332/30/20 + cheat + description:Timer will count down super-fast + code:f332/30/10 + cheat + description:Disable level 4 wall trap + code:d32d/ff + cheat + description:Start with 1 life + code:e2b3/02/00 + cheat + description:Start with 6 lives + code:e2b3/02/05 + cheat + description:Start with 9 lives + code:e2b3/02/08 + 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 + name:Double Dragon II - The Revenge (USA) (Rev A) + cheat + description:Invincibility (blinking) - both players + code:807b/28/00 + cheat + description:No enemies + code:9021/72 + cheat + description:Enemies die automatically + code:b137/b1/a9+b138/29/27 + cheat + description:Never lose lives from falling + code:8427/de/ad + cheat + description:Never lose lives from low energy + code:8a97/de/ad + cheat + description:Never lose lives from water + code:8b6d/de/ad + cheat + description:Uppercut after only two punches + code:bb68/02/01 + cheat + description:Slow down gameplay + code:ed89/00/ff + cheat + description:Start with 259 lives - P1 + code:ee58/04/ff + cheat + description:Start with 8 lives - P1 + code:ee58/04/08 + cheat + description:Start with 8 lives - P2 + code:ee6d/04/08 + cheat + description:Start with 1 life - P1 + code:ee58/04/01 + cheat + description:Start with 1 life - P2 + code:ee6d/04/01 + cheat + description:Start on mission 2 + code:ee32/00/01 + cheat + description:Start on mission 3 + code:ee32/00/02 + cheat + description:Start on mission 4 + code:ee32/00/03 + cheat + description:Start on mission 5 + code:ee32/00/05 + cheat + description:Start on mission 6 + code:ee32/00/06 + cheat + description:Start on mission 7 + code:ee32/00/09 + cheat + description:Start on mission 8 + code:ee32/00/0c + cheat + description:Start at final boss + code:ee32/00/0e + cheat + description:Start at final boss (alt) + code:ee32/0e + 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 + name:Double Dragon II - The Revenge (USA) + cheat + description:Invincibility (blinking) - both players + code:807b/28/00 + cheat + description:No enemies + code:9021/72 + cheat + description:Enemies die automatically + code:b137/b1/a9+b138/29/27 + cheat + description:Never lose lives from falling + code:8427/de/ad + cheat + description:Never lose lives from low energy + code:8a97/de/ad + cheat + description:Never lose lives from water + code:8b6d/de/ad + cheat + description:Uppercut after only two punches + code:bb68/02/01 + cheat + description:Slow down gameplay + code:ed89/00/ff + cheat + description:Start with 259 lives - P1 + code:ee58/04/ff + cheat + description:Start with 8 lives - P1 + code:ee58/04/08 + cheat + description:Start with 8 lives - P2 + code:ee6d/04/08 + cheat + description:Start with 1 life - P1 + code:ee58/04/01 + cheat + description:Start with 1 life - P2 + code:ee6d/04/01 + cheat + description:Start on mission 2 + code:ee32/00/01 + cheat + description:Start on mission 3 + code:ee32/00/02 + cheat + description:Start on mission 4 + code:ee32/00/03 + cheat + description:Start on mission 5 + code:ee32/00/05 + cheat + description:Start on mission 6 + code:ee32/00/06 + cheat + description:Start on mission 7 + code:ee32/00/09 + cheat + description:Start on mission 8 + code:ee32/00/0c + cheat + description:Start at final boss + code:ee32/00/0e + cheat + description:Start at final boss (alt) + code:ee32/0e + 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 + name:Double Dragon III - The Sacred Stones (USA) + cheat + description:Infinite health - Bill, Jimmy and Chin + code:b039/20/ad + cheat + description:Infinite special weapons - everyone + code:b405/01/00+b329/de/2c + cheat + description:More powerful punch, weapon and high kick + code:b064/a5/a9 + cheat + description:More health - Billy and Jimmy + code:9c82/54/64 + cheat + description:More health - Ranzou + code:9c8a/4a/64 + cheat + description:Less health - Billy and Jimmy + code:9c82/54/2a + cheat + description:Less health - Ranzou + code:9c8a/4a/25 + cheat + description:Less health - Chin + code:9c8f/64/32 + cheat + description:Start with Chin enabled + code:bcb3/0f/00 + cheat + description:Start with Ranzou enabled + code:bcc6/08/00 + cheat + description:Start with Jimmy enabled + code:f1c9/05/00 + cheat + description:Start with 255 health - Billy and Jimmy + code:9c82/54/ff + cheat + description:Start with 255 health - Chin + code:9c8f/64/ff + cheat + description:Start with 255 health - Ranzou + code:9c8a/4a/ff + cheat + description:Start with 99 weapon use - Billy, Jimmy and Chin + code:9c94/05/63 + cheat + description:Infinite health - P1 + code:045d/40 + cheat + description:Infinite health - P2 + code:045e/40 + +cartridge sha256:eb0e5f318e84e931a9bd663764c43fefa1a78565fa1328c1544b41bc8155ccb1 + name:Double Dribble (USA) (Rev A) + cheat + description:CPU scores add to your score + code:c489/f8/f4 + cheat + description:CPU never scores + code:c489/f8/fc + cheat + description:50 points - team 1 + code:07f4/50 + cheat + description:50 points - team 2 + code:07f8/50 + +cartridge sha256:f5517606d81d4e993d7fb86f11cae24c7b5029fd7184c7247771d6d7791e54ab + name:Double Dribble (USA) + cheat + description:CPU scores add to your score + code:c489/f8/f4 + cheat + description:CPU never scores + code:c489/f8/fc + cheat + description:50 points - team 1 + code:07f4/50 + cheat + description:50 points - team 2 + code:07f8/50 + +cartridge sha256:ddc08430b83061814fec929872aa6df3abc1a624888a8e3eb3fa96abb8d32e36 + name:Double Moon Densetsu (Japan) + cheat + description:Play as girl + code:b6dc/f0/d0 + +cartridge sha256:aa3b652591a7310e6e2cc025deabd9accf49506bd2313265fee67f2c5e83036a + name:Drac's Night Out (USA) (Proto) + cheat + description:Infinite Blood + code:c650/8d/ad + cheat + description:Infinite time + code:c5fe/ee/ed + +cartridge sha256:af505b8530b3303ebe0bf727730733cdbcd83ce1a19781d9487cd7cb202933c1 + name:Dragon Fighter (USA) + cheat + description:Invincibility + code:e508/d0/f0 + cheat + description:Invincibility (alt) + code:004d/4f + cheat + description:Invincible to spikes + code:d3dd/01/00 + cheat + description:Infinite health + code:e55c/85/a5 + cheat + description:Max Dragon energy + code:dc30/a5/84 + cheat + description:Always shoot special + code:d22f/00/7f + 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 + name:Dragon Power (USA) + cheat + description:Infinite health (POW) + code:9a6d/c6/a5 + cheat + description:Start with 128 health (POW) + code:8325/64/80 + cheat + description:Start with 24 Wind Waves (turtle shells) (hold B then press A) + code:831e/85/84 + 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 + name:Dragon Spirit - The New Legend (USA) + cheat + description:Invincibility and three heads after one hit (blinking) + code:ab88/a8 + cheat + description:Infinite health + code:aa61/c6/a1 + cheat + description:Hit anywhere + code:bdf0/d0/a9+bda1/d0/a9 + cheat + description:Always gold dragon + code:d894/84/86 + cheat + description:Always blue dragon + code:d894/84/a4 + cheat + description:Invincibility + code:0588/00 + +cartridge sha256:5564e54943deddc6d290b256638c774aa379a0d33dcea3b0a4f0c4b9fc2034e3 + name:Dragon's Lair (USA) + cheat + description:Infinite E (health) + code:d0ac/fc/00 + cheat + description:Infinite Candle energy + code:f9c3/ce/ad+f9e2/ce/ad + cheat + description:Infinite lives + code:d626/ff/00 + cheat + description:Less energy gained on pick-up + code:f769/10/05 + cheat + description:More energy gained on pick-up + code:f769/10/27 + cheat + description:Start with Axe + code:d5b4/00/01 + cheat + description:Start with Fireball + code:d5b4/00/02 + cheat + description:Start with 1 extra life + code:d5ac/fb/f7 + cheat + description:Start with 6 extra lives + code:d5ac/fb/fc + cheat + description:Start with 9 extra lives + code:d5ac/fb/ff + cheat + description:Start on level 2 + code:d57a/00/01 + cheat + description:Start on level 3 + code:d57a/00/02 + cheat + description:Start on level 4 + code:d57a/00/03 + 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 + name:Dragon Warrior (USA) + cheat + description:Infinite Magic Power + code:db96/85/a5 + cheat + description:Take no damage in swamp + code:cde3/02/00 + cheat + description:Start with 256 gold coins + code:f697/85/e6 + cheat + description:All spells use only one magic point + code:db96/85/c6 + cheat + description:Barriers cause half usual damage + code:ce48/0f/07 + +cartridge sha256:c15ab051ff066f018cf4b0159780c58026114bb47a6376ef81c1571a39a8fe9b + name:Dragon Warrior II (USA) + cheat + description:One hit kills + code:a6b7/90/50 + cheat + description:Prince of Midenhall starts with 50 HP + code:bdc3/1c/32 + cheat + description:Prince of Midenhall starts with 99 HP + code:bdc3/1c/63 + cheat + description:Prince of Midenhall starts with 40 strength points + code:bdc1/05/28 + cheat + description:Prince of Midenhall starts with 80 strength points + code:bdc1/05/50 + cheat + description:Prince of Midenhall starts with 40 agility points + code:bdc2/04/28 + cheat + description:Prince of Midenhall starts with 80 agility points + code:bdc2/04/50 + cheat + description:Prince of Cannock starts with 50 HP + code:bdc7/1f/32 + cheat + description:Prince of Cannock starts with 99 HP + code:bdc7/1f/63 + cheat + description:Prince of Cannock starts with 40 strength points + code:bdc5/04/28 + cheat + description:Prince of Cannock starts with 60 strength points + code:bdc5/04/3c + cheat + description:Prince of Cannock starts with 30 agility points + code:bdc6/04/1e + cheat + description:Prince of Cannock starts with 60 agility points + code:bdc6/04/3c + cheat + description:Prince of Cannock starts with 40 magic points + code:bdc8/06/28 + cheat + description:Prince of Cannock starts with 60 magic points + code:bdc8/06/3c + cheat + description:Princess of Moonbrooke starts with 50 HP + code:bdcb/20/32 + cheat + description:Princess of Moonbrooke starts with 99 HP + code:bdcb/20/63 + cheat + description:Princess of Moonbrooke starts with 25 strength points + code:bdc9/02/19 + cheat + description:Princess of Moonbrooke starts with 50 strength points + code:bdc9/02/32 + cheat + description:Princess of Moonbrooke starts with 40 agility points + code:bdca/16/28 + cheat + description:Princess of Moonbrooke starts with 40 magic points + code:bdcc/1c/28 + +cartridge sha256:f91a8bfc25bd267f5ae77bafa7fc650f77f8e50067869e99682b32d5b410644e + name:Dragon Warrior III (USA) + cheat + description:King gives 255 gold + code:913f/32/ff + cheat + description:King gives mega-gold + code:9152/00/01 + cheat + description:Player starts with increased strength and/or attack power + code:b26c/07/6f + cheat + description:Player starts with greatly increased strength and/or attack power + code:b26c/07/fe + cheat + description:Player starts with increased agility and/or defense + code:b271/05/63 + cheat + description:Player starts with greatly increased agility and/or defense + code:b271/05/ff + cheat + description:Player starts with increased vitality and/or HP + code:b276/07/63 + cheat + description:Player starts with greatly increased vitality and/or HP + code:b276/07/ff + cheat + description:Player starts with increased magic, maximum magic points and/or intelligence + code:b27b/06/63 + cheat + description:Player starts with greatly increased magic, maximum magic points and/or intelligence + code:b27b/06/ff + cheat + description:Player starts with increased luck + code:b280/04/62 + cheat + description:Player starts with greatly increased luck + code:b280/04/fe + cheat + description:Wizard starts with increased strength and/or attack power + code:b26d/01/63 + cheat + description:Wizard starts with greatly increased strength and/or attack power + code:b26d/01/fe + cheat + description:Wizard starts with increased agility and/or defense + code:b272/04/62 + cheat + description:Wizard starts with greatly increased agility and/or defense + code:b272/04/ff + cheat + description:Wizard starts with increased vitality and/or maximum HP + code:b277/02/62 + cheat + description:Wizard starts with greatly increased vitality and/or maximum HP + code:b277/02/99 + cheat + description:Wizard starts with increased magic, intelligence and/or maximum magic + code:b27c/09/63 + cheat + description:Wizard starts with increased luck + code:b281/02/63 + cheat + description:Wizard starts with greatly increased luck + code:b281/02/fe + cheat + description:Pilgrim starts with increased strength and/or attack power + code:b26e/03/62 + cheat + description:Pilgrim starts with greatly increased strength and/or attack power + code:b26e/03/fe + cheat + description:Pilgrim starts with increased agility and/or defense + code:b273/04/62 + cheat + description:Pilgrim starts with increased vitality and/or maximum HP + code:b278/03/63 + cheat + description:Pilgrim starts with greatly increased vitality and/or maximum HP + code:b278/03/fe + cheat + description:Pilgrim starts with increased magic and/or intelligence + code:b27d/08/63 + cheat + description:Pilgrim starts with greatly increased magic and/or intelligence + code:b27d/08/fe + cheat + description:Pilgrim starts with increased luck + code:b282/03/62 + cheat + description:Pilgrim starts with greatly increased luck + code:b282/03/fe + cheat + description:Soldier starts with increased strength and/or attack power + code:b270/09/63 + cheat + description:Soldier starts with greatly increased strength and/or attack power + code:b270/09/fe + cheat + description:Soldier starts with increased agility and/or defense + code:b275/02/62 + cheat + description:Soldier starts with increased vitality and/or maximum HP + code:b27a/07/63 + cheat + description:Start with 6 battle-axes + code:af10/ff/05 + cheat + description:Start with 6 broadswords + code:af10/ff/06 + cheat + description:Start with 6 wizard's wands + code:af10/ff/07 + cheat + description:Start with 6 demon's axes + code:af10/ff/0f + cheat + description:Start with 6 multi-edge swords + code:af10/ff/14 + cheat + description:Start with 6 staffs of force + code:af10/ff/15 + cheat + description:Start with 6 swords of illusion + code:af10/ff/16 + cheat + description:Start with 6 falcon swords + code:af10/ff/18 + cheat + description:Start with 6 armor of radiance + code:af10/ff/28 + +cartridge sha256:e49cb745370065a40aff078ae52b5de1c0db137fedcbe93b78ab18d76479deed + name:Dragon Warrior IV (USA) + cheat + description:No damage and lose no MP - all members (don't combine with the "start with items" codes) + code:8466/b5/60 + cheat + description:Start Chapter 1 with 25 gold + code:91d8/32/19 + cheat + description:Start Chapter 1 with 100 gold + code:91d8/32/64 + cheat + description:Start Chapter 1 with 255 gold + code:91d8/32/ff + cheat + description:Start Chapter 1 with lots 'o gold + code:902a/57/58 + cheat + description:Start Chapter 1 with 15 HP + code:a28f/1b/0f + cheat + description:Start Chapter 1 with 100 HP + code:a28f/1b/64 + cheat + description:Start Chapter 1 with 255 HP + code:a28f/1b/ff + cheat + description:Start Chapter 1 with final key + code:91c3/ff/73 + cheat + description:Start Chapter 1 with metal babble sword + code:91c3/ff/0e + cheat + description:Start Chapter 1 with multi-edge sword + code:91c3/ff/13 + cheat + description:Start Chapter 1 with thorn whip + code:91c3/ff/09 + cheat + description:Start Chapter 1 with shield of strength + code:91c3/ff/40 + cheat + description:Start Chapter 1 with dragon shield + code:91c3/ff/43 + cheat + description:Start Chapter 1 with final key and chain sickle + code:91c3/ff/73+91c4/ff/04 + cheat + description:Start Chapter 1 with metal babble sword and boomerang + code:91c3/ff/0e+91c4/ff/0b + cheat + description:Start Chapter 1 with multi-edge sword and wizard's ring + code:91c3/ff/13+91c4/ff/59 + cheat + description:Start Chapter 1 with thorn whip and demon hammer + code:91c3/ff/09+91c4/ff/12 + cheat + description:Start Chapter 1 with shield of strength and meteorite armband + code:91c3/ff/40+91c4/ff/50 + cheat + description:Start Chapter 1 with dragon shield and iron fan + code:91c3/ff/43+91c4/ff/0d + cheat + description:Start Chapter 2 with 50 gold + code:91d9/64/32 + cheat + description:Start Chapter 2 with 255 gold + code:91d9/64/ff + cheat + description:Start Chapter 2 with lots of gold + code:902a/57/58 + cheat + description:Start Alena with 100 HP + code:a290/10/64 + cheat + description:Start Alena with 255 HP + code:a290/10/ff + cheat + description:Start Alena with final key + code:91ca/ff/73 + cheat + description:Start Alena with fire claw + code:91ca/ff/1a + cheat + description:Start Alena with multi-edge sword + code:91ca/ff/13 + cheat + description:Start Alena with thorn whip + code:91ca/ff/09 + cheat + description:Start Alena with boomerang + code:91cb/ff/0b + cheat + description:Start Alena with final key and fire claw + code:91ca/ff/73+91cb/ff/1a + cheat + description:Start Alena with multi-edge sword and wizard's ring + code:91ca/ff/13+91cb/ff/59 + cheat + description:Start Alena with thorn whip and demon hammer + code:91ca/ff/09+91cb/ff/12 + cheat + description:Start Alena with shield of strength and meteorite arm band + code:91ca/ff/40+91cb/ff/50 + cheat + description:Start Alena with dragon shield and iron fan + code:91ca/ff/43+91cb/ff/0d + cheat + description:Start Brey with final key + code:91b3/ff/73 + cheat + description:Start Brey with magma staff + code:91b3/ff/1e + cheat + description:Start Brey with multi-edge sword + code:91b3/ff/13 + cheat + description:Start Brey with thorn whip + code:91b3/ff/09 + cheat + description:Start Brey with shield of strength + code:91b3/ff/40 + cheat + description:Start Brey with dragon shield + code:91b3/ff/43 + cheat + description:Start Brey with boomerang + code:91b4/ff/0b + cheat + description:Start Brey with final key and magma staff + code:91b3/ff/73+91b4/ff/1e + cheat + description:Start Brey with multi-edge sword and wizard's ring + code:91b3/ff/13+91b4/ff/59 + cheat + description:Start Brey with thorn whip and demon hammer + code:91b3/ff/09+91b4/ff/12 + cheat + description:Start Brey with shield of strength and meteorite arm band + code:91b3/ff/40+91b4/ff/50 + cheat + description:Start Brey with dragon shield and iron fan + code:91b3/ff/43+91b4/ff/0d + cheat + description:Start Cristo with final key + code:919b/ff/73 + cheat + description:Start Cristo with metal babble sword + code:919b/ff/0e + cheat + description:Start Cristo with multi-edge sword + code:919b/ff/13 + cheat + description:Start Cristo with thorn whip + code:919b/ff/09 + cheat + description:Start Cristo with shield of strength + code:919b/ff/40 + cheat + description:Start Cristo with dragon shield + code:919b/ff/43 + cheat + description:Start Cristo with final key and chain sickle + code:919b/ff/73+919c/ff/04 + cheat + description:Start Cristo with metal babble sword and boomerang + code:919b/ff/0e+919c/ff/0b + cheat + description:Start Cristo with multi-edge sword and wizard's ring + code:919b/ff/13+919c/ff/59 + cheat + description:Start Cristo with thorn whip and demon hammer + code:919b/ff/09+919c/ff/12 + cheat + description:Start Cristo with shield of strength and meteorite arm band + code:919b/ff/40+919c/ff/50 + cheat + description:Start Cristo with dragon shield and iron fan + code:919b/ff/43+919c/ff/0d + cheat + description:Start Chapter 3 with 16 HP + code:a28e/14/10 + cheat + description:Start Chapter 3 with 100 HP + code:a28e/14/64 + cheat + description:Start Chapter 3 with 255 HP + code:a28e/14/ff + cheat + description:Start Chapter 3 with 100 gold + code:91da/00/64 + cheat + description:Start Chapter 3 with 255 gold + code:91da/00/ff + cheat + description:Start Chapter 3 with final key + code:91bb/ff/f3 + cheat + description:Start Chapter 3 with metal babble sword + code:91bb/ff/0b + cheat + description:Start Chapter 3 with multi-edge sword + code:91bb/ff/16 + cheat + description:Start Chapter 3 with thorn whip + code:91bb/ff/0b + cheat + description:Start Chapter 3 with shield of strength + code:91bb/ff/41 + cheat + description:Start Chapter 3 with dragon shield + code:91bb/ff/40 + cheat + description:Start Chapter 3 with final key and chain sickle + code:91bb/ff/73+91bc/ff/04 + cheat + description:Start Chapter 3 with metal babble sword and boomerang + code:91bb/ff/0e+91bc/ff/0b + cheat + description:Start Chapter 3 with multi-edge sword and wizard's ring + code:91bb/ff/13+91bc/ff/59 + cheat + description:Start Chapter 3 with thorn whip and demon hammer + code:91bb/ff/09+91bc/ff/12 + cheat + description:Start Chapter 3 with shield of strength and meteorite arm band + code:91bb/ff/40+91bc/ff/50 + cheat + description:Start Chapter 3 with dragon shield and iron fan + code:91bb/ff/43+91bc/ff/0d + cheat + description:Start Nara with 100 HP + code:a28b/12/64 + cheat + description:Start Nara with 255 HP + code:a28b/12/ff + cheat + description:Start Nara with final key + code:91a3/ff/73 + cheat + description:Start Nara with metal babble sword + code:91a3/ff/0e + cheat + description:Start Nara with multi-edge sword + code:91a3/ff/13 + cheat + description:Start Nara with thorn whip + code:91a3/ff/09 + cheat + description:Start Nara with shield of strength + code:91a3/ff/40 + cheat + description:Start Nara with dragon shield + code:91a3/ff/43 + cheat + description:Start Nara with final key and chain sickle + code:91a3/ff/73+91a4/ff/04 + cheat + description:Start Nara with metal babble sword and boomerang + code:91a3/ff/0e+91a4/ff/0b + cheat + description:Start Nara with multi-edge sword and wizard's ring + code:91a3/ff/13+91a4/ff/59 + cheat + description:Start Nara with thorn whip and demon hammer + code:91a3/ff/09+91a4/ff/12 + cheat + description:Start Nara with shield of strength and meteorite arm band + code:91a3/ff/40+91a4/ff/50 + cheat + description:Start Nara with dragon shield and iron fan + code:91a3/ff/43+91a4/ff/0d + cheat + description:Start Mara with 100 HP + code:a28c/10/64 + cheat + description:Start Mara with 255 HP + code:a28c/10/ff + cheat + description:Start Mara with final key + code:91a9/ff/73 + cheat + description:Start Mara with magma staff + code:91a9/ff/1e + cheat + description:Start Mara with multi-edge sword + code:91a9/ff/13 + cheat + description:Start Mara with thorn whip + code:91a9/ff/09 + cheat + description:Start Mara with shield of strength + code:91a9/ff/40 + cheat + description:Start Mara with dragon shield + code:91a9/ff/43 + cheat + description:Start Mara with final key and chain sickle + code:91a9/ff/73+91aa/ff/04 + cheat + description:Start Mara with metal babble sword and boomerang + code:91a9/ff/0e+91aa/ff/0b + cheat + description:Start Mara with multi-edge sword and wizard's ring + code:91a9/ff/13+91aa/ff/59 + cheat + description:Start Mara with thorn whip and demon hammer + code:91a9/ff/09+91aa/ff/12 + cheat + description:Start Mara with shield of strength and meteorite arm band + code:91a9/ff/40+91aa/ff/50 + cheat + description:Start Mara with dragon shield and iron fan + code:91a9/ff/43+91aa/ff/0d + cheat + description:Start Chapter 5 with final key + code:9195/ff/73 + cheat + description:Start Chapter 5 with zenithian sword + code:9195/ff/21 + cheat + description:Start Chapter 5 with zenithian shield + code:9195/ff/44 + cheat + description:Start Chapter 5 with zenithian armor + code:9195/ff/37 + cheat + description:Start Chapter 5 with zenithian helmet + code:9195/ff/4b + +cartridge sha256:a0b2ec9b44033fc4d2356259ad99a4f2dcdf5396da53efdfcb17a54c0e7fcdbe + name:Dr. Chaos (USA) + cheat + description:Infinite life + code:ddc4/e5/24 + cheat + description:Take minimal damage + code:ddc4/e5/e9+ddc5/74/01 + cheat + description:Infinite Gun ammo on pick-up + code:f800/ce/2c + cheat + description:More invincibility time + code:dddc/14/40 + cheat + description:Less invincibility time + code:dddc/14/04 + cheat + description:Take more damage and Shield Suit has no effect + code:dd9d/46/66+dd9c/07/00 + cheat + description:Mega-jump + code:ca83/03/08 + cheat + description:Start with Shield Suit + code:c95d/00/01+c95f/43/52 + cheat + description:Start with 99 life + code:c94e/32/63 + cheat + description:Start with less health + code:c94e/32/19 + 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 + name:Dr. Jekyll and Mr. Hyde (USA) + cheat + description:Infinite life + code:e42e/ce/2c+e526/ce/2c + cheat + description:Multi-jump + code:cff6/c3/cf+cff8/c9/29+cff9/04/01+cffa/d0/f0+cffd/00/01+cfff/c3/b9 + cheat + description:Keep coins from previous games + code:bef4/8d/2c + cheat + description:Instant game restart + code:d0fa/99/af + cheat + description:Start with 16 coins + code:bef4/8d/8c + +cartridge sha256:01d303a8c0ed6f374586d3a2562065b77f627e8dbf071bd919877e3b48dbdb57 + name:Dr. Mario (Japan, USA) + cheat + description:Vitamin capsules don't fall (press down) + code:8d7e/e6/24 + cheat + description:5 in a row needed to complete a vertical line instead of 4 + code:94a7/03/04 + cheat + description:6 in a row needed to complete a vertical line instead of 4 + code:94a7/03/05 + cheat + description:7 in a row needed to complete a vertical line instead of 4 + code:94a7/03/06 + cheat + description:5 in a row needed to complete a horizontal line instead of 4 + code:9241/03/04 + cheat + description:6 in a row needed to complete a horizontal line instead of 4 + code:9241/03/05 + cheat + description:7 in a row needed to complete a horizontal line instead of 4 + code:9241/03/06 + 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:9bef/18/38 + 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:94aa/e6/24+9244/e6/24 + +cartridge sha256:7026334a7e8742b61b450f4b3b182922c6a69fc723d7cd19c83db365f15e45ba + name:Duck Hunt (World) + cheat + description:Infinite ammo + code:d171/c6/a5 + cheat + description:Hit anywhere + code:d22c/f5/00 + cheat + description:Always get the perfect bonus + code:d350/0a/00+d351/d0/30 + cheat + description:Ducks never fly away - Game A + code:ca6c/c6/05 + cheat + description:Enable game "D" (hit select three times) + code:c19e/03/04 + cheat + description:Infinite ammo (alt) + code:00ba/03 + +cartridge sha256:262c1fcacd30a7f3018bd33ea6cf3fb86f8d9a77273d4f822268bff2c7deeb9a + name:Duck Maze (Australia) (Unl) + cheat + description:Invincibility + code:bbbe/20/ad + cheat + description:No breaking eggs from falling + code:bb88/2a/00 + +cartridge sha256:8ba8baed01a9fbaf1e9ff29e0c9825db1963ac2aff211d6f1f3bcfd3839e2013 + name:DuckTales (USA) + cheat + description:Invincibility + code:e35a/f0/d0+800c/f0/d0 + cheat + description:Infinite health + code:eb6a/a0/60 + cheat + description:Infinite health (alt) + code:eb7d/01/00 + cheat + description:Infinite lives + code:dcb0/ce/ad + cheat + description:Infinite time + code:e2b8/e5/e9 + cheat + description:Lose half normal health (in easy game) + code:eb67/01/03 + cheat + description:Double usual time + code:db2c/05/0a+dcf3/b9/ad+d875/bd/ad + cheat + description:Multi-jump + code:e397/3b/b8+e3a8/e6/e3+e3bd/f0/10+e403/3b/87+e691/f0/24 + cheat + description:Walk 2x faster + code:e49f/01/02 + cheat + description:Walk 4x faster + code:e49f/01/04 + cheat + description:Start with 1 life + code:db0b/02/00 + cheat + description:Start with 6 lives + code:db0b/02/05 + cheat + description:Start with 9 lives + code:db0b/02/08 + 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 + name:DuckTales 2 (USA) + cheat + description:Invincibility + code:e896/f0/d0 + cheat + description:Infinite health + code:f21e/85/a5 + cheat + description:Infinite lives + code:c422/c6/24 + cheat + description:Infinite lives (alt) + code:c422/c6/c5 + cheat + description:Multi-jump + code:e1ed/97/f0+e1e9/9e/21+e1ee/e2/92+e1ec/4c/4a + cheat + description:Take more damage + code:f219/08/10 + cheat + description:Take less damage + code:f219/08/04 + cheat + description:Take very little damage + code:f219/08/02 + cheat + description:Have lots of money + code:d229/00/01 + cheat + description:$5,000 cash from small diamonds + code:d3c9/01/05 + cheat + description:$9,000 cash from small diamonds + code:d3c9/01/09 + cheat + description:Start with full energy + code:c0f9/30/50 + cheat + description:Start with a lot less energy + code:c0f9/30/10 + cheat + description:Start with 1 life + code:c108/02/00 + cheat + description:Start with 6 lives + code:c108/02/05 + cheat + description:Start with 9 lives + code:c108/02/08 + +cartridge sha256:12c92261dfae9c01ce0172cd1e7d70192105ceb350b37c3f1cb2c72f9a10a6b9 + name:Dudes with Attitude (USA) (Rev 1) (Unl) + cheat + description:Infinite energy + code:dd3d/d6/b5 + cheat + description:Infinite time + code:d73d/c6/a5 + +cartridge sha256:99bba29bd92942f64d8a0beda7df3d8bff1ddcebcd3172eec16009fcb4a8bd3e + name:Dudes with Attitude (USA) (Unl) + cheat + description:Infinite energy + code:dd3d/d6/b5 + cheat + description:Infinite time + code:d73d/c6/a5 + +cartridge sha256:c613c10e32b93dbc402356273d698efa14814a51b0339d6d7aacdfb639a7acd7 + name:Dungeon Magic - Sword of the Elements (USA) + cheat + description:Take no damage except from scorpions + code:b3e6/85/a5 + cheat + description:Take less damage + code:b3e4/e5/e9+b3e5/3f/02 + cheat + description:Stay at the Inn for free + code:e2d3/41/21+e2d7/40/20 + cheat + description:Items at Grocer's shop are free + code:eeba/41/21+eebe/40/20 + cheat + description:Items at Armory are free + code:f389/41/21+f38d/40/20 + cheat + description:Start with 100 gold pieces + code:d645/00/64 + cheat + description:Start with 512 gold pieces + code:d645/00/02+d64c/40/41 + +cartridge sha256:690ec2de233486d9fdb1e096ca4aa07aa6e764b0d6d6417454d0a770c875078d + name:Dynowarz - Destruction of Spondylus (USA) + cheat + description:Mostly invincible + code:d078/29/09+d076/c6/24 + cheat + description:Infinite shield + code:ecf7/8a/60 + cheat + description:No harm from spikes + code:dc51/a5/60 + cheat + description:No harm from any dinosaur + code:f96e/03/00 + cheat + description:Mega-jump power + code:d3a7/03/07 + cheat + description:Speed up left and right + code:d27d/01/03 + cheat + description:Start on level 2 + code:c123/01/06 + cheat + description:Start on level 3 + code:c123/01/0a + cheat + description:Start on level 4 + code:c123/01/0e + cheat + description:Start on level 5 + code:c123/01/12 + +cartridge sha256:7951287af48ef9f2e2b375934acff99fe1543aea39d2729d2863b38ab498e231 + name:Egypt (Japan) + cheat + description:Infinite power-ups + code:9f82/99/b9 + cheat + description:No steps + code:8be3/e6/a5+8be7/e6/a5 + cheat + description:No rotates + code:8c07/e6/a5+8c03/e6/a5 + +cartridge sha256:e2824a71c74106326013915d9f8a67be22c367599feefd8da6538f62d5e6f5b0 + name:Elevator Action (USA) + cheat + description:Infinite lives - P1 + code:bb89/ce/2c + cheat + description:Can only shoot one bullet + code:e153/06/04 + cheat + description:Slower man + code:d7d0/03/01+d7ba/fd/ff + cheat + description:Faster man + code:d7d0/03/05+d7ba/fd/fa + cheat + description:Faster bullets + code:e163/08/0a+e167/f8/f6 + cheat + description:Slower bullets + code:e163/08/04+e167/f8/fc + cheat + description:Faster enemy + code:f19c/02/04+f1ac/fe/fa + cheat + description:Slower enemy + code:f19c/02/01+f1ac/fe/ff + cheat + description:Start with 1 life - P1 + code:bb37/02/00 + cheat + description:Start with 6 lives - P1 + code:bb37/02/05 + cheat + description:Start with 9 lives - P1 + code:bb37/02/08 + cheat + description:Start with 6 lives - P2 + code:bbeb/02/05 + cheat + description:Start with 9 lives - P2 + code:bbeb/02/08 + +cartridge sha256:9d0396286f2c027367422b8347216a309200a21b019939f08a7c457c7c4c918d + name:Eliminator Boat Duel (USA) + cheat + description:Almost infinite nitros - no on buoy stage + code:df6e/de/ad + cheat + description:Boat starts with full turbo, steering, hull, max engine power + code:81ff/01/05 + cheat + description:Have full hull strength + code:c8b1/de/ad + cheat + description:Computer boat goes crazy + code:da05/84 + cheat + description:Start with 0 nitros + code:820a/04/00 + cheat + description:Start with 36 nitros + code:820a/04/25 + +cartridge sha256:d1b51f04a6112d8f75d1bf29a9db5a06cfba308be824dcc9db15b228f8e85bd5 + name:Esper Dream (Japan) (v1.0) [b] + cheat + description:Walk anywhere + code:b9c9/ff/00 + +cartridge sha256:761df2c2e04f9ffec5eec59afd821bd74af3b155546519d649876aad37160c06 + name:Esper Dream 2 - Aratanaru Tatakai (Japan) + cheat + description:Infinite HP + code:d475/85/a5 + cheat + description:Infinite ESP + code:e930/85/a5 + cheat + description:Quick level up + code:d6a7/09/08 + cheat + description:Chests worth lots of gold + code:9ead/01/00 + +cartridge sha256:e9f4c9d1b7c66c6af83f2db5d4f704cf5f4b3c86e26a49c05539237807d8875e + name:Excitebike (Japan, USA) + cheat + description:Never crash + code:de1c/95/a5 + cheat + description:Never crash when holding forward + code:e05d/95/60+e063/95/60+dc6b/95/60 + cheat + description:Never lose speed (even if you crash) + code:ce7d/d6/b5 + cheat + description:Never overheat + code:e3a7/ee/ad + cheat + description:Recover fast after crashes + code:d9a4/0f/07 + cheat + description:Reduced enemy bikes in game B + code:daa0/03/01 + cheat + description:Timer runs at half speed + code:df38/10/08 + cheat + description:Timer runs at quarter speed + code:df38/10/04 + cheat + description:Turbo speed on button A + code:c0bc/18/f0+c0d1/03/04 + cheat + description:Mega turbo speed on button A + code:c0bc/18/e0+c0d1/03/06 + cheat + description:Infinite obstacles in design mode + code:f805/01/00 + cheat + description:Start racing before gate opens + code:ea0a/38/00+cd22/1d/00+da29/3f/00+de39/d0/10 + cheat + description:Press Start to complete current race (uses your race position for the verdict) + code:ca59/03/00+ca58/b1/52 + +cartridge sha256:9e3c5574e31cbf74146808df930a70856d7196ec581e40cae3061743504bfba2 + name:Exodus - Journey to the Promised Land (USA) (v4.0) (Unl) + cheat + description:Infinite lives + code:a834/d6/a5 + cheat + description:Infinite time + code:ddfc/c6/a5 + +cartridge sha256:e9aab85fd91822b9dc7a89997eda3415e45a07fe21580c0df4765ce392e63824 + name:F-1 Race (Japan) + cheat + description:Invincibility + code:e411/e6/60 + cheat + description:Infinite time + code:d13e/c6/85 + cheat + description:Don't lose speed when driving over grass/dirt + code:d2a5/85/a5+d2ab/85/a5 + cheat + description:Don't lose speed when skidding in the road + code:c38f/85/a5 + +cartridge sha256:3fd39ba2cdd6e220b07050d752a2c67d4a0f16a72ea9e519adf7390721cd9bdd + name:F15 City War (USA) (v1.1) (Unl) + cheat + description:Infinite lives + code:00e4/09 + +cartridge sha256:0e3db714b82795111afa386f32534ece968d0f8ccb63dc70189d2010dc77a2a7 + name:F15 City War (USA) (v1.0) (Unl) + cheat + description:Infinite lives + code:00e4/09 + +cartridge sha256:bf4b9f8706814e9164971a3c32535bb2ec718232cf05decda785770fa949d396 + name: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 + name:F-117A - Stealth Fighter (USA) + cheat + description:Invincibility + code:96a8/85/a5 + 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 + name:Family Feud (USA) + cheat + description:Infinite time to answer a question + code:cdc8/ce/ad + cheat + description:10 strikes allowed + code:90dc/03/0a + +cartridge sha256:e0b124ddd8ac7be9e0f0b14679a089c475646fe97425fea36674d75a0f481461 + name:Fantastic Adventures of Dizzy, The (USA) (Unl) + cheat + description:Infinite lives + code:d0e0/c6/a5 + cheat + description:Spiders, bats, ants and rats do no damage + code:f261/08/00 + cheat + description:Play bubble sub-game only + code:a531/0e/7f + cheat + description:Play river sub-game only + code:a531/0e/7e + cheat + description:Play mine sub-game only + code:a531/0e/7d + cheat + description:Play puzzle sub-game ony + code:a531/0e/7a + cheat + description:Start with 10 stars instead of 100 + code:fac6/64/0a + cheat + description:Start with 10 lives + code:8012/02/09 + +cartridge sha256:ad14301747e0ae0f9b941c6002102d69916ca5e87b355156ab79311ce8dd7236 + name:Fantasy Zone (USA) (Unl) + cheat + description:Infinite lives + code:e60f/c6/a9 + cheat + description:Keep bought weapon for a life + code:e881/c6/a9 + cheat + description:Keep bought weapon until next shop visit + code:e881/c6/a9+e618/85/c9 + cheat + description:Autofire on all weapons + code:ee1c/01/00 + cheat + description:Start with 1 life + code:e929/03/01 + cheat + description:Start with 6 lives + code:e929/03/06 + cheat + description:Start with 9 lives + code:e929/03/09 + cheat + description:Start on level 2 + code:e75f/00/01 + cheat + description:Start on level 3 + code:e75f/00/02 + cheat + description:Start on level 4 + code:e75f/00/03 + cheat + description:Start on level 5 + code:e75f/00/04 + cheat + description:Start on level 6 + code:e75f/00/05 + cheat + description:Start on level 7 + code:e75f/00/06 + +cartridge sha256:6f23f245b9edc5af0c07fab9e12f5c0571ea0f52413e4ce6ad36e2f57ddf4097 + name:Faria - A World of Mystery & Danger! (USA) + cheat + description:Infinite HP + code:811c/e5/85+b8b8/e5/85 + cheat + description:Infinite batteries + code:c725/ce/ad + cheat + description:Infinite Bombs + code:b197/ce/ad + cheat + description:Infinite Sede magic + code:85d0/ce/2c + cheat + description:Infinite Saba magic + code:85fa/ce/2c + cheat + description:Get 250 arrows when buying any amount of arrows + code:a965/02/00 + cheat + description:Don't get charged in shops for items you can afford + code:a32a/8d/2c+a32f/8d/2c+a334/8d/2c + +cartridge sha256:58f2ba801354a8e5b32e7d1cbcc740b8dc838e7d48c3d2f3eedea36b49b1a518 + name:Faxanadu (USA) (Rev A) + cheat + description:Infinite P (health) + code:c092/ed/2c+c09b/ed/2c + cheat + description:Infinite M (magic) + code:fa88/02/00 + cheat + description:Infinite Gold + code:f9ab/8d/ad+f9b3/8d/ad+f9bb/8d/ad + cheat + description:Jump in direction you are facing + code:e1ac/a5/60 + cheat + description:Slow mode + code:e030/f9/00+e041/f4/00+e032/01/00 + cheat + description:Start with double P (health) + code:deaf/10/20 + cheat + description:Start with triple P (health) + code:deaf/10/30 + cheat + description:Start with half normal amount of Gold + code:8559/0a/05 + cheat + description:Start with double normal amount of Gold + code:8559/0a/14 + 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 + name:Faxanadu (USA) + cheat + description:Infinite P (health) + code:c092/ed/2c+c09b/ed/2c + cheat + description:Infinite M (magic) + code:fa88/02/00 + cheat + description:Infinite Gold + code:f9ab/8d/ad+f9b3/8d/ad+f9bb/8d/ad + cheat + description:Jump in direction you are facing + code:e1ac/a5/60 + cheat + description:Slow mode + code:e030/f9/00+e041/f4/00+e032/01/00 + cheat + description:Start with double P (health) + code:deaf/10/20 + cheat + description:Start with triple P (health) + code:deaf/10/30 + cheat + description:Start with half normal amount of Gold + code:8559/0a/05 + cheat + description:Start with double normal amount of Gold + code:8559/0a/14 + 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 + name:Felix the Cat (USA) + cheat + description:Infinite time + code:f7fc/9d/bd + cheat + description:Infinite lives + code:f9b4/01/00 + cheat + description:Weapon has longer reach + code:8efa/30/10 + cheat + description:Hearts can't be replenished from bottles + code:880f/02/00 + cheat + description:Bottles replenish more hearts + code:880f/02/04 + cheat + description:Bottles replenish even more hearts + code:880f/02/08 + cheat + description:1 Felix icon gives 2 + code:da19/01/02+da79/19/18 + cheat + description:No sound effects + code:8608/90/b0 + cheat + description:Walk through walls + code:d111/d0/70+d12a/d0/70 + cheat + description:Start with 9 lives + code:c430/12/18 + cheat + description:Start with 6 lives + code:c430/12/15 + cheat + description:Start with 1 life + code:c430/12/10 + 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 + name:Fester's Quest (USA) + cheat + description:Invincibility + code:9c51/70 + cheat + description:Infinite health + code:9c83/ce/ea + cheat + description:Infinite Invisible Potions on pick-up + code:d107/ce/ad + cheat + description:Infinite Missiles on pick-up + code:eb6a/ce/ad + cheat + description:Infinite Money + code:d13f/8d/ad + cheat + description:Infinite Nooses on pick-up + code:d0b6/ce/ad + cheat + description:Infinite Potions on pick-up + code:d0eb/ce/ad + cheat + description:Infinite T.N.T on pick-up + code:d177/ce/ad + cheat + description:Infinite Vice Grips on pick-up + code:d0d6/ce/ad + 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 + name:Fighting Road (Japan) + cheat + description:Infinite health + code:d68b/85/a5 + +cartridge sha256:2ae778c5a59fac650fa97e93d883381dbf96c5a0ad2c1db94fd822663904f7e5 + name:Final Combat (Asia) (PAL) (Unl) + cheat + description:Infinite health + code:a6d0/8d/ad+c794/8d/ad + cheat + description:Infinite lives + code:bb61/d6/a5 + cheat + description:Infinite time + code:9d79/ce/ad + +cartridge sha256:fa456d852372173ea31b192459ba1a2026f779df67793327ba6e132476c1d034 + name:Final Fantasy (USA) + cheat + description:Skip intro screen + code:84d4/29/a9 + cheat + description:Faster dialogue + code:d61c/a5/a9+d61d/1b/5e+d69f/f2/00 + cheat + description:Almost infinite Gold + code:a4d1/ed/2c+a4da/ed/2c + cheat + description:999999+ Gold + code:b01e/00/ff + cheat + description:Gain 65535 EXP from every battle + code:9ed9/01 + cheat + description:Enemies don't attack + code:b323/80 + cheat + description:Non-magic users can use level 1 magic + code:ab0e/f0/b0+c7d0/0c/00+c7d4/08/00 + cheat + description:LIFE spell never uses up Magic Points + code:b035/de/ad + cheat + description:LIF2 spell never uses up Magic Points + code:b06b/de/ad + cheat + description:Magic users start with 6 Magic Points + code:c7d6/02/06 + cheat + description:Magic users start with 9 Magic Points + code:c7d6/02/09 + cheat + description:No random battles (enable at start of game) + code:99e6/91 + cheat + description:Double Fighter's Hit Points (enable at start of game) + code:b041/23/46 + cheat + description:Double Fighter's Hit (enable at start of game) + code:b048/0a/14 + cheat + description:Double Fighter's Evade (enable at start of game) + code:b049/35/6a + cheat + description:Double Fighter's Luck (enable at start of game) + code:b046/05/0a + cheat + description:Double Thief's Hit Points (enable at start of game) + code:b051/1e/3c + cheat + description:Triple Thief's Damage (enable at start of game) + code:b057/02/06 + cheat + description:Double Thief's Hit (enable at start of game) + code:b058/05/0a + cheat + description:Double Thief's Evade (enable at start of game) + code:b059/3a/74 + cheat + description:Double Thief's Luck (enable at start of game) + code:b056/0f/1e + cheat + description:Double Black Belt's Hit Points (enable at start of game) + code:b061/21/42 + cheat + description:Triple Black Belt's Damage (enable at start of game) + code:b067/02/06 + cheat + description:Double Black Belt's Hit (enable at start of game) + code:b068/05/0a + cheat + description:Double Black Belt's Evade (enable at start of game) + code:b069/35/6a + cheat + description:Double Black Belt's Luck (enable at start of game) + code:b066/05/0a + cheat + description:Double Red Mage's Hit Points (enable at start of game) + code:b071/1e/3c + cheat + description:Double Red Mage's Damage (enable at start of game) + code:b077/05/0a + cheat + description:Double Red Mage's Hit (enable at start of game) + code:b078/07/0e + cheat + description:Double Red Mage's Evade (enable at start of game) + code:b079/3a/74 + cheat + description:Double Red Mage's Luck (enable at start of game) + code:b076/05/0a + cheat + description:Double White Mage's Hit Points (enable at start of game) + code:b081/1c/38 + cheat + description:Triple White Mage's Damage (enable at start of game) + code:b087/02/06 + cheat + description:Double White Mage's Hit (enable at start of game) + code:b088/05/0a + cheat + description:Double White Mage's Evade (enable at start of game) + code:b089/35/6a + cheat + description:Double White Mage's Luck (enable at start of game) + code:b086/05/0a + cheat + description:Double Black Mage's Hit Points (enable at start of game) + code:b091/19/32 + cheat + description:Triple Black Mage's Damage (enable at start of game) + code:b097/01/03 + cheat + description:Double Black Mage's Hit (enable at start of game) + code:b098/05/0a + cheat + description:Double Black Mage's Evade (enable at start of game) + code:b099/3a/74 + cheat + description:Double Black Mage's Luck (enable at start of game) + code:b096/0a/14 + cheat + description:Start with 800 Gold + code:b01c/90/20+b01d/01/03 + 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 + name: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:ab9b/8d/ad + cheat + description:All items in shops are free. You must have enough to cover the item, but will not be charged + code:b0b0/e5/ea + cheat + description:Knife casts a FIRE spell when used as a item in battle + code:94f4/7f/31 + cheat + description:Knife casts a FIRE3 spell when used as a item in battle + code:94f4/7f/0e + cheat + description:Knife casts a BOLT3 spell when used as a item in battle + code:94f4/7f/15 + cheat + description:Knife casts a ICE3 spell when used as a item in battle + code:94f4/7f/1d + cheat + description:Knife casts a DEATH spell when used as a item in battle + code:94f4/7f/01 + cheat + description:Knife casts a METEO spell when used as a item in battle + code:94f4/7f/02 + cheat + description:Knife casts a HEAL spell when used as a item in battle + code:94f4/7f/0b + cheat + description:Knife casts a CURE4 spell when used as a item in battle + code:94f4/7f/0a + cheat + description:Dagger casts a FIRE3 spell when used as a item in battle + code:94fc/7f/0e + cheat + description:Dagger casts a BOLT3 spell when used as a item in battle + code:94fc/7f/15 + cheat + description:Dagger casts a ICE3 spell when used as a item in battle + code:94fc/7f/1d + cheat + description:Dagger casts a DEATH spell when used as a item in battle + code:94fc/7f/01 + cheat + description:Dagger casts a METEO spell when used as a item in battle + code:94fc/7f/02 + cheat + description:Dagger casts a HEAL spell when used as a item in battle + code:94fc/7f/0b + cheat + description:Dagger casts a CURE4 spell when used as a item in battle + code:94fc/7f/0a + cheat + description:Long Sword casts a FIRE3 spell when used as a item in battle + code:9524/7f/0e + cheat + description:Long Sword casts a BOLT3 spell when used as a item in battle + code:9524/7f/15 + cheat + description:Long Sword casts a ICE3 spell when used as a item in battle + code:9524/7f/1d + cheat + description:Long Sword casts a DEATH spell when used as a item in battle + code:9524/7f/01 + cheat + description:Long Sword casts a METEO spell when used as a item in battle + code:9524/7f/02 + cheat + description:Long Sword casts a HEAL spell when used as a item in battle + code:9524/7f/0b + cheat + description:Long Sword casts a CURE4 spell when used as a item in battle + code:9524/7f/0a + +cartridge sha256:5f21fadd084947d11224d1f37218a504bd75f7c6f17212f638a6917ba8a96f99 + name:Fire Bam (FDS) + cheat + description:All fire items worth 65,535 + code:9a02/00/ff + cheat + description:Start with 65,534 Fire + code:dfc4/81/fe+dfc5/09/ff + +cartridge sha256:9a0cc935c7d8452eff5b90f591bb6390d04362545ecd66b4be67a875ad63dc73 + name: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 + name:Fire Hawk (USA) (Unl) + cheat + description:Invincibility + code:ae19/d0/a9 + cheat + description:Start with 1 life + code:8019/03/01 + cheat + description:Start with 6 lives + code:8019/03/06 + cheat + description:Start with 9 lives + code:8019/03/09 + cheat + description:Infinite Missiles + code:04da/1f + cheat + description:Infinite ammo + code:04dc/1f + cheat + description:Infinite fuel + code:04f4/26 + +cartridge sha256:db16f0a5cb05dfa9344e0ae459f6c44fac7c28d4a8ecd47d3418053ab16c8a62 + name:Fire 'n Ice (USA) + cheat + description:Automatically finish levels + code:f48f/08/00 + +cartridge sha256:04264565cf33f4bd1b23a3f7a1be1487a548c7f6b85323c68af754b0927b0a56 + name:Fist of the North Star (USA) + cheat + description:Invincibility + code:c5a0/20/ad + cheat + description:Infinite health + code:cc53/85/a5 + cheat + description:Infinite time + code:e65c/c6/a5 + cheat + description:Infinite lives + code:c1cf/c6/a5 + cheat + description:One hit kills you + code:cc51/e5/e9 + cheat + description:Sweep kick damages enemies more + code:b186/01/06 + cheat + description:Straight kick damages enemies more + code:b194/03/08 + cheat + description:Can't be knocked back by big thugs + code:cc3e/04/00 + cheat + description:Pogo stick + code:c953/f0/d0 + cheat + description:Take minimum damage from all enemies + code:cc51/e5/e9+cc52/d9/01 + cheat + description:Any attack mega-damages enemies + code:b19a/e5/e9+b19b/d9/0a + cheat + description:Start with 1 life + code:c0cc/03/01 + cheat + description:Start with 6 lives + code:c0cc/03/06 + cheat + description:Start with 9 lives + code:c0cc/03/09 + 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 + name:Flight of the Intruder (USA) + cheat + description:Infinite radar-guided missiles - bombing/strafing screen + code:973a/c6/24 + cheat + description:Start with 9 radar-guided missiles - bombing/strafing screen + code:8213/06/09 + cheat + description:Infinite missiles - cockpit screen + code:943b/ce/2c + cheat + description:Start each mission with 6 missiles + code:a246/c9/a9+a24c/01/00 + cheat + description:Start on mission 3 + code:cc44/00/04 + cheat + description:Start on mission 6 + code:cc44/00/0a + cheat + description:Start on mission 9 + code:cc44/00/10 + cheat + description:Start on mission 12 + code:cc44/00/16 + +cartridge sha256:3036a59bb7bf16a3b80c94750bccaa35be9ab5cd94f99d68d3979ec53cd42c03 + name:Flintstones, The - The Rescue of Dino & Hoppy (USA) + cheat + description:Invincibility + code:9192/ce/60 + cheat + description:Infinite lives + code:8090/ce/ad + cheat + description:Infinite energy (hearts) + code:e472/ce/ad+9192/ce/ad + cheat + description:15 coins on pick-up + code:e2d2/05/0f + cheat + description:2 coins on pick-up + code:e2d2/05/02 + cheat + description:Slingshot doesn't use up coins + code:8e32/03/00 + cheat + description:Axe doesn't use up coins + code:8e33/03/00 + cheat + description:Bomb doesn't use up coins + code:8e34/0a/00 + cheat + description:Infinite Firepower + code:8dec/00 + cheat + description:Max power charge + code:99c8/01/13+a103/01/13+9183/01/13+923b/01/13 + cheat + description:Start with Slingshot + code:8180/00/01 + cheat + description:Start with Axe + code:8180/00/02 + cheat + description:Start with Bomb + code:8180/00/04 + cheat + description:Start with 1 life + code:8167/02/00 + cheat + description:Start with 6 lives + code:8167/02/05 + cheat + description:Start with 9 lives + code:8167/02/08 + cheat + description:Start with 99 coins + code:817b/0a/63 + 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 + name:Flintstones, The - The Surprise at Dinosaur Peak! (USA) + cheat + description:Invincibility + code:9984/8d/60 + cheat + description:Infinite lives + code:808e/ce/ad + cheat + description:Infinite energy + code:997f/01/00 + cheat + description:Infinite energy (alt) + code:9984/8d/ad + cheat + description:Infinite stone hammers on pick-up + code:9eab/8d/ad + cheat + description:Enemies do more damage (3 hearts) + code:997f/01/03 + cheat + description:Get bowling ball instead of stone hammer + code:8f8b/01/02 + cheat + description:Get mystery item instead of stone hammer + code:8f8b/01/03 + cheat + description:Continue on Level 2 + code:8946/00/01 + cheat + description:Continue on Level 3 + code:8946/00/02 + cheat + description:Continue on Level 4 + code:8946/00/03 + cheat + description:Continue on Level 5 + code:8946/00/04 + cheat + description:Continue on Level 6 + code:8946/00/05 + cheat + description:Continue on Level 7 + code:8946/00/06 + cheat + description:Continue on Level 8 + code:8946/00/07 + cheat + description:Continue on Level 9 + code:8946/00/08 + cheat + description:Continue on Level 10 + code:8946/00/09 + cheat + description:Start with max power + code:8186/0c/14 + cheat + description:Start with 1 heart + code:817b/03/01 + cheat + description:Start with 2 hearts + code:817b/03/02 + cheat + description:Start with 6 hearts + code:817b/03/06 + cheat + description:Start with 9 hearts + code:817b/03/09 + cheat + description:Start with 1 life instead of 3 + code:8153/02/00 + cheat + description:Start with 5 lives + code:8153/02/04 + cheat + description:Start with 9 lives + code:8153/02/08 + cheat + description:Start on level 2 + code:897a/8d/ee + +cartridge sha256:fd7523b5ec5769e4d782a9699a2253bd15d0036111b8ed26195238b35b74257d + name:Flying Dragon - The Secret Scroll (USA) + cheat + description:Start with infinite lives + code:b0c6/a4/86 + cheat + description:Start with infinite time + code:8988/c6/24 + cheat + description:Start with double KO power + code:ab1b/03/06 + cheat + description:Start with 1 life + code:8076/03/01 + cheat + description:Start with 6 lives + code:8076/03/06 + cheat + description:Start with 9 lives + code:8076/03/09 + +cartridge sha256:5e2db0db6b1d3d7fe1630a6bab38a66081e3266070a4dfac9c3ace9edf39375e + name: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 + name:Flying Warriors (USA) + cheat + description:Infinite life + code:c4fd/8d/ad + cheat + description:Infinite lives + code:c964/ce/ad + cheat + description:Infinite KO's + code:a491/8d/ad+c25b/8d/ad + cheat + description:Infnite credits + code:822a/c6/a5 + +cartridge sha256:eedcf3fae4fe66102a1bf1338a1ea3276f5aadb3c3bc5770dd1d260e2fc44bac + name:Formation Z (Japan) + cheat + description:Invincibility + code:a059/8d/ad+a458/8d/ad+abae/8d/ad+9f82/8d/ad+976e/8d/ad+aa9d/8d/ad+afb1/8d/ad+adfc/8d/ad+9629/8d/ad+961e/8d/ad + cheat + description:Infinite fuel + code:96de/c6/25 + +cartridge sha256:758ea7bee928136abf612ba564fab4dd4f3caa951cb685bc8e1d4533c7b0680e + name:Formula One - Built to Win (USA) + cheat + description:Infinite nitro + code:d8b2/ce/ad + cheat + description:Better nitro + code:d84a/20/60 + cheat + description:Psycho speed + code:d869/02/00 + cheat + description:Items cost nothing + code:bb7e/ad/60 + cheat + description:Items for free + code:bb7e/ad/60+bb6c/e5/60 + +cartridge sha256:e9fe69c87a9ab1183ce8492843bacf868e1f8df2fd4e1441403091d13025a619 + name:Fox's Peter Pan & the Pirates - The Revenge of Captain Hook (USA) + cheat + description:Infinite lives + code:c31f/c6/a5 + cheat + description:Infinite flight meter + code:da6a/ce/ad + cheat + description:Slower flight meter + code:da5f/04/0c + cheat + description:Faster flight meter + code:da5f/04/02 + cheat + description:Faster flying left and right + code:da33/01/02+d816/01/02 + cheat + description:Start with 30 units of health + code:c4f2/0a/1e+c32f/0a/1e + cheat + description:Start with 5 units of health + code:c4f2/0a/05+c32f/0a/05 + cheat + description:Start with 1 life + code:c4fb/03/01 + cheat + description:Start with 6 lives + code:c4fb/03/06 + cheat + description:Start with 9 lives + code:c4fb/03/09 + 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 + name:Frankenstein - The Monster Returns (USA) + cheat + description:Invincibility + code:c4eb/00/02 + cheat + description:Invincible after you die once (may get stuck in boss stages) + code:8049/85/a5+c001/85/a5 + cheat + description:Infinite health + code:83cb/85/a5+907f/85/a5+8bc9/85/a5+90ba/85/a5+90bc/85/a5 + cheat + description:Can't collect extra energy + code:8b0b/85/a5 + cheat + description:Die after one hit + code:83c7/b0/80 + cheat + description:Start with 0 continue + code:c197/03/01 + cheat + description:Infinite health (alt) + code:007d/08 + +cartridge sha256:995b57f7d2c68a5689549fc53645dcc44f871c8d172e15deafd7389bc3f6ee0a + name:Freedom Force (USA) + cheat + description:Infinite health + code:8367/85/24 + cheat + description:Infinite ammo + code:e7b3/22/00 + cheat + description:Infinite errors allowed + code:e797/c9/a9 + cheat + description:Fewer errors allowed + code:e798/06/03 + cheat + description:Start with half health + code:e64f/18/0c + cheat + description:Start with half ammo + code:e697/24/12 + cheat + description:Start at level 2 + code:e633/01/02 + cheat + description:Start at level 3 + code:e633/01/03 + cheat + description:Start at level 4 + code:e633/01/04 + cheat + description:Start at level 5 + code:e633/01/05 + 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 + name:Free Fall (USA) (Proto) + cheat + description:Infinite hands + code:ce7d/99/b9 + cheat + description:Freeze time (disable at end of level so counter can decrease) + code:d040/95/b5 + cheat + description:One saved to beat level + code:d46a/a5/a9+d46d/d8/75+d46e/04/01 + cheat + description:No score decrease with loss of men + code:ce13/62/08+ce12/a5/30 + cheat + description:Each dead man, one to score instead of five + code:ce13/62/63 + +cartridge sha256:7e94b4fe8c33439779bb653d007ba4678dd589636ffbc87d1535629578a64d5e + name:Friday the 13th (USA) + cheat + description:Invincibility + code:af0d/20/ad + cheat + description:Infinite health + code:dd0c/8d/ad + cheat + description:Infinite health for active counselor + code:dd06/e5/e9 + cheat + description:Infinite child save time + code:b77c/20/ad + cheat + description:Infinite children + code:b853/ce/ad+b845/78/75 + cheat + description:Hit anywhere + code:dc43/d0/50 + cheat + description:One hit kills + code:dc99/12/00 + cheat + description:Enemies die automatically + code:cad2/22/00 + cheat + description:No enemies + code:cbc4/02/00+daa5/fe/ad + cheat + description:Vitamins heal active counselor better + code:b418/06/2a + cheat + description:Vitamins heal others better + code:eb0a/04/28 + cheat + description:Autofire + code:b2f5/74/75 + cheat + description:Everyone can jump high + code:b50a/00/0c + cheat + description:Turbo running + code:b264/b9/ad+b265/68/1f + cheat + description:Throw rocks straight + code:c285/a5/07 + cheat + description:Start with 55 children + code:8ee7/01/05+8efd/0f/37 + 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 + name:G.I. Joe - A Real American Hero (USA) + cheat + description:Invincibility + code:94ec/f0/d0+94f0/38/ea + cheat + description:Infinite health + code:e477/99/b9 + cheat + description:Infinite ammo + code:aee9/8d/ad + cheat + description:Infinte time + code:83fe/8d/ad + cheat + description:Infinite time (alt) + code:83f6/01/00 + cheat + description:More health - Duke + code:edb4/0d/14 + cheat + description:More health - Blizzard + code:edb5/0c/14 + cheat + description:More health - Snake Eyes + code:edb6/0a/14 + cheat + description:More health - Capt. Grid-Iron + code:edb7/0b/14 + cheat + description:More health - Rock and Roll + code:edb8/09/14 + cheat + description:Less health - Duke + code:edb4/0d/06 + cheat + description:Less health - Blizzard + code:edb5/0c/06 + cheat + description:Less health - Snake Eyes + code:edb6/0a/05 + cheat + description:Less health - Capt. Grid-Iron + code:edb7/0b/05 + cheat + description:Less health - Rock and Roll + code:edb8/09/04 + cheat + description:Shorter immunity + code:e47d/78/30 + cheat + description:Longer immunity + code:e47d/78/ff + cheat + description:Max health on pick-up + code:8139/03/00 + cheat + description:Mega-jump - Duke + code:edfc/17/20 + cheat + description:Mega-jump - Blizzard + code:edfd/12/20 + cheat + description:Mega-jump - Snake Eyes + code:edfe/1c/20 + cheat + description:Mega-jump - Capt. Grid-Iron + code:edff/14/20 + cheat + description:Mega-jump - Rock and Roll + code:ee00/10/20 + +cartridge sha256:9e65e4d55123612c5eb05b332e48fd975a187d706a3fd44b62125e1ae48af028 + name:G.I. Joe - The Atlantis Factor (USA) + cheat + description:Invincibility + code:9a53/f0/d0+9a57/38/ea + cheat + description:Infinite health + code:e5d3/99/b9 + cheat + description:Infinite time + code:855a/01/00 + cheat + description:Infinite Mines + code:9b90/de/bd + cheat + description:Infinite stamina + code:e5d3/99/a5+8595/9d/bd + cheat + description:Infinite bullets after obtaining a power up shell + code:b6da/8d/2c+b6e6/8d/2c + cheat + description:Don't flash after getting hit + code:e5d9/78/00 + cheat + description:Flash about half as long after getting hit + code:e5d9/78/39 + cheat + description:Each Pow worth increases player level by one + code:9721/01/04 + cheat + description:Infinite ammo + code:b6da/8d/ad+b6e6/8d/ad+b6d5/ce/ad+b6e9/8d/ad + cheat + description:Start with all characters + code:83ce/01/3f + cheat + description:Start with 500 bullets + code:840b/01/05 + cheat + description:Start with 1 life + code:effd/05/01 + +cartridge sha256:023ff157d96a8efc847c7d7cbe89574091fe099996e6283c63e3fb58918f3502 + name:Gaiapolis (Asia) (Unl) + cheat + description:Invincibility + code:8e47/f0/d0 + cheat + description:Infinite time + code:c93e/c6/a5 + cheat + description:Infinite credits + code:cea5/ce/ad + cheat + description:Hit anywhere + code:9a34/b0/50+9a35/24/18+9988/b0/50+a486/74/b8+a485/d9/4c+a487/05/a4+9989/58/32 + cheat + description:Get items from anywhere + code:9a72/b0/50+9a73/29/1f + +cartridge sha256:a636a947acf1ef0b50e66d31699b64aa4f3b4865e2f2031385780974fb6d8c91 + name:Galactic Crusader (USA) (Unl) + cheat + description:Invincibility + code:f13e/f0/d0 + cheat + description:Infinite lives + code:debb/c6/a6 + +cartridge sha256:df49cc788fff36881fcf1d1cb22281d305260d4d8fbbe07ca2c4d699fe54843a + name:Galaga - Demons of Death (USA) + cheat + description:Invincibility + code:e87d/a6/60 + cheat + description:Infinite lives + code:cb9e/ca/ea + cheat + description:Play challenge stages only + code:ce99/d0/24 + cheat + description:Can't be caught by tractor beam + code:e1d2/a5/a9+e1d3/79/07 + cheat + description:Press Start for next wave + code:d271/80/94+d272/05/04+d26d/01/00 + cheat + description:Press Start for extra life + code:d26c/a9/4c+d26d/01/a8+d26e/85/cb + cheat + description:Start with twin shots + code:e089/d0/24 + cheat + description:Start with 1 life + code:cd4c/03/01 + cheat + description:Start with 6 lives + code:cd4c/03/06 + cheat + description:Infinite lives (alt) + code:0485/05+0487/05 + +cartridge sha256:e6fe68b9f12578e74ba016ca146aaf8232b20475fb675c7d32e0ea4e47eb1cc8 + name:Galaga (Japan) + cheat + description:Invincibility + code:e904/a9/60 + cheat + description:Infinite lives + code:cb9e/ca/ea + cheat + description:Keep double ship after being destroyed + code:e8f4/a9/60 + cheat + description:Only one part to collect + code:81dc/64/01 + cheat + description:Always get a perfect bonus + code:d0e5/c9/29+d0e6/28/00 + cheat + description:Start with double shot + code:c3e5/80/d5+cd47/95/29 + cheat + description:Infinite lives (alt) + code:0485/05+0487/05 + +cartridge sha256:50178a2856f8ed3574b4e7fd45b9d1ec44c660d51fe9783d0012a19df5892cce + name:Galaxian (Japan) + cheat + description:Infinite lives + code:0042/05 + +cartridge sha256:c019750cc439810de6cbf1c3a895099674df3f397744ad3149ba1b25dd55d0ab + name:Galaxy 5000 (USA) + cheat + description:Infinite time + code:9040/de/bd + cheat + description:Reduce damage free of charge + code:aefd/fd/2c + cheat + description:No damage from falling + code:a9c0/20/ad + cheat + description:Take less damage + code:f9fe/a5/a9+f9ff/1a/01 + cheat + description:More damage from falling + code:a9bd/bd/ad+bf6e/23/30 + cheat + description:More damage from shots + code:948a/e6/0e+948b/fe/bf + 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 + name:Gargoyle's Quest II (USA) + cheat + description:Invincibility (except Doppelganger when it mimics you) + code:88d4/05/89 + cheat + description:Invincible against spikes + code:e3ff/05/e4 + cheat + description:Infinite fight + code:81db/a5/a9 + cheat + description:Walk through walls + code:831c/90/10 + +cartridge sha256:a2039efb5b5b8d4941c31ae0977dacccec5aaa72fe307ae36af2a454d30d9e26 + name:Garry Kitchen's BattleTank (USA) + cheat + description:Infinite energy + code:9090/e6/c5 + cheat + description:Infinite hits + code:9090/e6/a5+b9d7/85/a5 + cheat + description:Infinite fuel + code:87b0/8d/cd + cheat + description:Infinite weapons + code:e820/de/dd+e74d/ce/cd + cheat + description:Infinite ammo + code:e820/de/bd + cheat + description:Start with half 150mm ammo + code:a0e5/32/16 + cheat + description:Start with double 150mm ammo + code:a0e5/32/63 + cheat + description:Start with more wire guided shells + code:a0ee/01/32 + cheat + description:Start with max wire guided shells + code:a0ee/01/63 + cheat + description:Start with more smoke shells + code:a0f8/01/32 + cheat + description:Start with max smoke shells + code:a0f8/01/63 + cheat + description:Start with less 50mm shells + code:a101/96/4b + cheat + description:Start with max 50mm shells + code:a101/96/ff + cheat + description:Start with less 50mm ammo after mission 5 + code:a105/c8/64 + cheat + description:Start with max 50mm ammo after mission 5 + code:a105/c8/ff + +cartridge sha256:fbc976422ca910d9391060898c8b58694f19b6e53a68bd33c457fb38dac1e5c6 + name:Gauntlet (USA) (Unl) + cheat + description:Infinite health + code:8f70/95/b5+9861/95/b5 + cheat + description:Infinite keys + code:ab1e/00/09+ab21/a5/85 + cheat + description:Infinite time in puzzle and treasure rooms + code:989f/c6/ea + 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 + name:Gauntlet (USA) + cheat + description:Infinite health + code:8f70/95/b5+9861/95/b5 + cheat + description:Infinite keys + code:ab1e/00/09+ab21/a5/85 + cheat + description:Infinite time in puzzle and treasure rooms + code:989f/c6/ea + 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 + name:Gauntlet II (USA) + cheat + description:Infinite health + code:df2f/9d/bd+e207/9d/bd + cheat + description:Take less damage + code:df2d/e5/e9+df2e/00/02 + cheat + description:Infinite keys (new game) + code:e01f/00/01+eb60/de/ad + cheat + description:Infinite time in treasure rooms + code:e294/bd/ea + cheat + description:Walk through walls + code:e53e/90/10+e55c/90/b0 + cheat + description:Weaker poison + code:ed6e/64/32 + cheat + description:Stronger poison + code:ed6e/64/c8 + cheat + description:5 super shots on pick-up + code:eb30/0a/05 + cheat + description:20 super shots on pick-up + code:eb30/0a/14 + cheat + description:Invincibility lasts longer + code:eb06/3c/78 + cheat + description:Invincibility doesn't last as long + code:eb06/3c/1b + cheat + description:Repulsiveness lasts longer + code:eaf3/3c/78 + cheat + description:Repulsiveness doesn't last as long + code:eaf3/3c/1b + cheat + description:Invisibility lasts longer + code:eb14/3c/78 + cheat + description:Invisibility doesn't last as long + code:eb14/3c/1b + 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 + name:George Foreman's KO Boxing (USA) + cheat + description:Invincibility + code:fa9c/f0/10+faf5/49/a9 + cheat + description:Infinite health + code:036e/43 + cheat + description:Can always use super punches + code:e766/08/00 + cheat + description:Knock opponent down with 1 super punch + code:f8ed/b1/a9+f8ee/ae/41 + cheat + description:Knock opponent down with 1 punch + code:036f/01 + +cartridge sha256:43221ae8a386e8ddf68251d5870d6fe3d696be14a5e41d9a44c36227894044d8 + name:Ghostbusters (USA) + cheat + description:Infinite fuel + code:a2c0/c6/a5 + cheat + description:Infinite energy during Gozer fight + code:f360/8d/ad + cheat + description:Immune to ghosts on Zuul stairway + code:a99c/c6/a9 + cheat + description:Permanent ghost alarm + code:8c0a/29/09 + cheat + description:Permanent ghost vacuum + code:9153/29/09 + cheat + description:Self-emptying traps + code:8cdd/a5/a9 + cheat + description:Super sprinting up Zuul stairway + code:a881/01/00 + cheat + description:Stay Puft does not climb building during Gozer fight + code:f926/ee/ad + cheat + description:Gozer dies in one hit + code:f332/f0/d0 + cheat + description:No walk up Zuul stairway + code:a629/17/00 + cheat + description:Start with $1,000,000 + code:87ee/5e/60 + +cartridge sha256:1ea36ebd81692d3a3c1db217e0df832f060c1566c69a74fac299aaeb0d8eb82f + name:Ghostbusters II (USA) + cheat + description:Invincibility + code:9f71/f0/d0+9dec/f0/d0 + cheat + description:Infinite lives + code:f3c0/de/bd + cheat + description:Infinite continues + code:9a25/ce/ad + cheat + description:Triple continues + code:c006/02/06 + cheat + description:Rapid-firing proton rifle + code:9a89/1f/0a + cheat + description:All Ghostbusters can mega-jump + code:9a5c/fe/fc + cheat + description:Shield lasts longer - car scenes + code:a1a8/50/ff + cheat + description:Infinite shield - car scenes + code:a71b/ce/ad + cheat + description:Start with 1 life + code:e42c/03/00 + cheat + description:Start with 6 lives + code:e42c/03/05 + cheat + description:Start with 9 lives + code:e42c/03/08 + +cartridge sha256:eea66f7bcc90d1145454da487791be5926473bee4014313af12dfa0f7453ea81 + name:Ghosts'n Goblins (USA) + cheat + description:Invincibility + code:f5ec/01/00 + cheat + description:Infinite armor + code:e3d6/c5 + cheat + description:Infinite lives - both players + code:c907/ce/ad + cheat + description:Infinite time + code:d396/ce/ad + cheat + description:Hit anywhere + code:f607/90/38+f608/01/60+f5c1/99/b9+b6be/99/b9 + cheat + description:Enable stage select (disable after loading stage) + code:d062/0f/00 + cheat + description:Speed up game + code:d243/03/02 + cheat + description:Slow down game + code:d243/03/04 + cheat + description:Start with Axe + code:c5ff/40/36 + cheat + description:Start with Dagger + code:c5ff/40/42 + cheat + description:Start with Fireball + code:c5ff/40/44 + cheat + description:Start with Cross + code:c5ff/40/4f + cheat + description:Start with Blue Sphere + code:c5ff/40/ac + cheat + description:Start with 1 life - both players + code:c609/03/01 + cheat + description:Start with 6 lives - both players + code:c609/03/06 + cheat + description:Start with 9 lives - both players + code:c609/03/09 + cheat + description:Start with 4 lives - P1 + code:c60a/8d/8e + 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 + name:Ghoul School (USA) + cheat + description:Invincibility + code:aa41/20/ad + cheat + description:Infinite health + code:abdd/8d/ad + cheat + description:Infinite lives + code:c68f/ce/ad + 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 + name:Goal! (USA) + cheat + description:CPU score adds to your score + code:c71b/f0/c9+c71f/f0/c9 + +cartridge sha256:7911375ab98da4ac5c628ba4dfffcba8ba4fc13a341901aed120ab967be5e26c + name:Goal! Two (USA) + cheat + description:Infinite time - Italy, P2 + code:f100/c6/a5 + cheat + description:P2 or computer can't score - Italy, P2 + code:87fb/8d/ad + cheat + description:Start with more KP - Italy, P2 + code:d740/09/20 + cheat + description:Start with a lot of KP - Italy, P2 + code:d740/09/50 + cheat + description:Start with mega KP - Italy, P2 + code:d740/09/99 + cheat + description:Start with more TP - Italy, P2 + code:d741/07/20 + cheat + description:Start with a lot of TP - Italy, P2 + code:d741/07/50 + cheat + description:Start with mega TP - Italy, P2 + code:d741/07/99 + +cartridge sha256:c2383e5cd8670c7107d59887026b9001f30045aa5f07be4b687b7a6bc290db1f + name:Godzilla - Monster of Monsters! (USA) + cheat + description:Infinite life (health) + code:018c/30 + cheat + description:Infinite power + code:0178/30 + +cartridge sha256:c41555b61617e52cae950e0a94d4d655646eed4e4ce4c1d26740ddee0a9ae090 + name:Golf (USA) + cheat + description:Ball goes in from anywhere + code:c265/03/00+d367/f0/10+d368/41/3d + +cartridge sha256:af24262bc78865b81b1a42d2842e222553fca27fb841a4eb8fbe26da7eba6163 + name:Golf Grand Slam (USA) + cheat + description:Strokes aren't recorded + code:a784/85/a5 + cheat + description:Some shots can be done more accurately + code:eea0/05/01 + cheat + description:Wind always at 9 + code:d411/25/a9+d412/28/09+a7d2/85/a5 + +cartridge sha256:9f559f83b9b5179137069bae0ca4b8eacf84378892b598044b88ef50681b58bb + name:Golgo 13 - Top Secret Episode (USA) + cheat + description:Infinite health + code:841e/85/a5+e8ca/c6/a9+f9cf/85/a5 + cheat + description:Health does not gradually decrease + code:e8ca/c6/a5 + cheat + description:Infinite bullets in horizontal mode + code:eeba/85/24 + cheat + description:Infinite damage in horizontal mode + code:f9cf/85/24 + cheat + description:Infinite damage in pan/zoom mode + code:841c/e5/24 + cheat + description:Infinite damage in maze + code:b442/e5/24 + cheat + description:Have a health and bullets boost + code:c06d/00/02 + +cartridge sha256:16c7de15b7dc72c567f58172bbf0cd1328d11625f6707814da030df15f95dc92 + name:Goonies II, The (USA) + cheat + description:Invincibility + code:80da/ad/8d + cheat + description:Infinite health + code:be5f/85/a5 + cheat + description:Infinite time + code:9a9b/d6/d5 + cheat + description:Infinite lives + code:cf33/c6/a5 + cheat + description:Infinite Bombs on pick-up + code:8db5/ce/ad + cheat + description:Infinite Molotov Bombs on pick-up + code:8d60/ce/ad + cheat + description:Infinite Sling Shots on pick-up + code:8e78/ce/ad + cheat + description:Super-jump + code:89b1/02/07 + cheat + description:Mega-jump + code:89b1/02/03 + cheat + description:Better Jumping Boots on pick-up + code:89bc/04/05 + cheat + description:Super-speed + code:80d1/01/02 + cheat + description:Walk through walls + code:86d7/c9/10+8752/f0/10+8770/8d/ad + cheat + description:Start with all items + code:d460/01/1f + cheat + description:Start with Boomerang + code:d460/01/05 + cheat + description:Start with 4 health cells + code:d432/02/04+d437/20/40 + cheat + description:Start with 8 health cells + code:d432/02/08+d437/20/80 + cheat + description:Start with 1 life + code:d42a/03/01 + cheat + description:Start with 6 lives + code:d42a/03/06 + cheat + description:Start with 9 lives + code:d42a/03/09 + 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 + cheat + description:View ending (enable then disable) + code:0000/08+0001/00 + +cartridge sha256:15685dee8bc1c588dfa2649b7b5f715aa7b4136454ba09c046d1b17209749d76 + name:Gotcha! - The Sport! (USA) + cheat + description:Infinite time + code:b55e/01/00 + cheat + description:Increase timer to 59 seconds + code:9801/04/05+9806/05/09 + cheat + description:Decrease timer to 25 seconds + code:9801/04/02+9806/05/05 + cheat + description:Start with double rations of ammo + code:980c/01/02 + 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 + name:Gradius (USA) + cheat + description:Infinite lives - both players + code:979f/d6/a5 + cheat + description:Keep power capsules + code:97ab/95/94 + cheat + description:Increase force field protection + code:899c/05/ff + cheat + description:Never lose weapons + code:9b3f/5a/4f+9b43/3d/47 + cheat + description:Hit anywhere + code:c01f/10/00+c02c/03/00 + cheat + description:Start with 1 life - both players + code:82fb/03/00 + cheat + description:Start with 6 lives - both players + code:82fb/03/05 + cheat + description:Start with 9 lives - both players + code:82fb/03/08 + +cartridge sha256:2974ad16b994cfdc9418310ced6c7f4ed64433063d12439a7b37a816f797dd0e + name:Gradius II (Japan) + cheat + description:Invincibility + code:f50c/20/60 + +cartridge sha256:fe3d2f94dadd3b2437e45ed9a38276b8b32af9e25d484de79c3cc7bf60eef386 + name: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:Hit anywhere + code:83ba/1a/00+83cb/b0/a9 + 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 + name:Great Waldo Search, The (USA) + cheat + description:Only need to find Waldo to complete the level + code:de82/80/c0 + cheat + description:Only need to find the magic scroll + code:deaf/40/c0 + cheat + description:Faster timer + code:cec9/01/02 + cheat + description:Much faster timer + code:cec9/01/04 + cheat + description:Play the Super Waldo Challenge + code:d850/e9/a9+d851/03/04 + cheat + description:Extra clocks last forever + code:ced4/c6/a5 + cheat + description:Extra clocks worth nothing + code:df27/e6/a5 + +cartridge sha256:2b77da430b08e6a91a3453fde8ea82692415d44c3e953fdf281aa39352d5289d + name:Gremlins 2 - The New Batch (USA) + cheat + description:Invincibility + code:dd0b/d0/f0 + cheat + description:Infinite health + code:81ca/c6/a5 + cheat + description:Infinite lives + code:807e/ce/ad + cheat + description:Infinite balloons + code:8a2b/ce/ad + cheat + description:Start with 5 lives + code:c800/00/04 + cheat + description:Start with 10 lives + code:c800/00/09 + cheat + description:Start with 3 balloons + code:c805/01/03 + cheat + description:Start with 6 balloons + code:c805/01/06 + cheat + description:Start with only 1 heart + code:c80a/06/02+808b/06/02 + cheat + description:Start with 4 hearts + code:c80a/06/08+808b/06/08 + 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 + name:Guardian Legend, The (USA) + cheat + description:Invincibility + code:d2cb/a5/60 + cheat + description:Infinite health + code:e325/ff/00 + cheat + description:Hit anywhere + code:d357/6f/00+d356/25/c0+d358/f0/d0+d359/05/09 + cheat + description:Use up minimum shots + code:8b94/e5/e9+8b95/10/01 + 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:8b94/e5/24 + cheat + description:Start with less health + code:80e5/40/20 + cheat + description:Start with more health + code:80e5/40/80 + cheat + description:Start on area 1 + code:eb48/00/01 + cheat + description:Start on area 3 + code:eb48/00/03 + cheat + description:Start on area 5 + code:eb48/00/05 + cheat + description:Start on area 7 + code:eb48/00/07 + cheat + description:Start on area 9 + code:eb48/00/09 + 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 + name:Guerrilla War (USA) + cheat + description:Invincibility + code:e454/d0/f0+ec03/f0/d0 + cheat + description:Infinite lives - both players + code:ce69/bd + cheat + description:Infinite lives - both players (alt) + code:ce69/de/ad + cheat + description:Keep weapon after death + code:ebb0/9d/ad + cheat + description:Press Start to complete the level + code:c75f/11/0b + cheat + description:Start a new game to view the ending + code:a0a8/08/09 + cheat + description:Start with 1 life - both players + code:c9b6/00 + cheat + description:Start with 6 lives - both players + code:c9b6/05 + cheat + description:Start with 9 lives - both players + code:c9b6/09 + 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 + name:Gumshoe (USA, Europe) + cheat + description:Gain 1 bullet on pick-up + code:8853/03/01 + cheat + description:Gain 6 bullets on pick-up + code:8853/03/06 + cheat + description:Timer set to 04:00 + code:874c/06/03 + cheat + description:Timer set to 10:00 + code:874c/06/09 + cheat + description:Different attack waves + code:8846/8c/8d + cheat + description:Start with 1 life + code:883f/03/01 + cheat + description:Start with 6 lives + code:883f/03/06 + cheat + description:Start with 9 lives + code:883f/03/09 + cheat + description:Start with 25 bullets + code:8858/50/25 + cheat + description:Start with 150 bullets + code:885c/00/01 + cheat + description:Start with 250 bullets + code:885c/00/02 + +cartridge sha256:d22a0c390dfc47c99226226c98158bf0ca3b4cd07dbd3d46cc50c2f1b9303c22 + name:Gun Nac (USA) + cheat + description:Invincibility + code:a001/50/40+a13c/50/40 + cheat + description:Infinite lives + code:a397/8d/ad + cheat + description:Infinite special weapons + code:a2e6/8d/ad + cheat + description:One hit kills + code:d707/90/d0 + cheat + description:Enemies die automatically + code:a133/18/00+d7d8/18/38+a136/ce/8d + cheat + description:Get items from anywhere + code:d7ed/bc/38+d7ee/18/60 + 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 + name:Gun.Smoke (USA) + cheat + description:Infinite lives + code:f3b6/c6/a5 + cheat + description:Keep weapons after death + code:f3a8/00/01 + cheat + description:Start with all weapons and lots of ammo + code:e736/00/01 + cheat + description:Start with all weapons, lots of ammo, all 4 boots and all 4 rifle icons + code:e736/00/04 + cheat + description:Start with 9 lives + code:e72e/03/09 + cheat + description:Start with 25 lives + code:e72e/03/19 + +cartridge sha256:0d895a031dd38f2661ba2af4a1b3c7b9753632b1530ea28eec936cf3fda8bf54 + name:Gyromite (World) + cheat + description:Invincible against enemies + code:ae34/20/ad + cheat + description:Invincible against upward crushing + code:a91a/a9/60 + cheat + description:Infinite lives + code:85a0/b5 + cheat + description:Climb up through flooring + code:aad6/03/00 + cheat + description:Climb down through flooring + code:aa90/03/00 + cheat + description:Slow down timer + code:8d83/0a + cheat + description:Start with 1 life + code:83b4/05/01 + cheat + description:Start with 10 lives + code:83b4/05/0a + cheat + description:Start with 20 lives + code:83b4/05/14 + +cartridge sha256:c6e275929764f7950ee85806ef5fdab9dda36e27f9f29935101bfc0916bf90a6 + name:Gyruss (USA) + cheat + description:Invincibility + code:a0de/a5/a9 + cheat + description:Infinite lives + code:908d/0a/00 + cheat + description:Never lose twin shots + code:9085/02/04+9087/01/81 + cheat + description:Gain 2 phasers when you die with none + code:9087/01/02 + cheat + description:Gain 4 phasers when you die with none + code:9087/01/04 + cheat + description:Start with 1 ship + code:832c/04/01 + cheat + description:Start with 10 ships + code:832c/04/0a + cheat + description:Start with 4 phasers + code:8648/01/04 + cheat + description:Start with 8 phasers + code:8648/01/08 + cheat + description:Start with twin shots + 1 phaser + code:8648/01/81 + cheat + description:Start with twin shots + 4 phasers + code:8648/01/84 + cheat + description:Start with twin shots + 8 phasers + code:8648/01/88 + +cartridge sha256:bd5c7925e616da879ee63ac4ac2004af26e20ae36a494247e704d41440ac971a + name:Hammerin' Harry (Europe) + cheat + description:Infinite energy (except spikes) + code:bcb3/8d/ad + cheat + description:Infinite lives + code:a944/ce/ad + cheat + description:Invincibility + code:f6d9/f0/d0+f6d6/ad/8d + +cartridge sha256:6e2b0e222eb8dba29c0ca363f1d7d59ed1fa307bafc150b5c8e1dd13638555a6 + name:Happy Pairs (Asia) (PAL) (Unl) + cheat + description:Infinite tries + code:b04a/c6/a5 + cheat + description:Infinite time + code:beaf/c6/a5 + cheat + description:Infinite autos + code:b175/c6/a5 + +cartridge sha256:07bfd5bf6d3e5cea26d0a521e7d599d67a4b794c5efa66e4189877c1361aad47 + name:Harlem Globetrotters (USA) + cheat + description:Slower timer + code:c935/2d/55 + cheat + description:Faster timer + code:c935/2d/1c + cheat + description:Slower shot clock + code:c964/2d/55 + cheat + description:Faster shot clock + code:c964/2d/1c + +cartridge sha256:fd3c19b0339bf2b326d8a0526216b5143f035f68dabb3b3392689c92d6c140d9 + name:Heavy Barrel (USA) + cheat + description:Invincibility + code:bbe8/09/60 + cheat + description:Invincibility and invisibility on second life + code:e81e/ca/ea + cheat + description:Infinite lives + code:ee12/c6/a5 + cheat + description:Infinite Bombs + code:ebee/d6/a5 + cheat + description:Infinite Keys + code:b5ca/95/b5 + cheat + description:Infinite Mace + code:b7fe/69/a9 + cheat + description:Infinite hand weapons on pick-up - both players + code:ebec/d0/f0 + cheat + description:Infinite hand weapons and firearms on pick-up - both players + code:ebee/d6/a9 + cheat + description:Hand weapons last 4x longer + code:ebca/55/00 + cheat + description:Only 1 hand weapon + code:e918/00/02 + cheat + description:Autofire - P1 + code:e6d1/fd/f8 + cheat + description:Autofire - P2 + code:e77d/fd/f8 + cheat + description:Enemies don't fire handguns + code:a8c6/ca/ea + +cartridge sha256:0a23312c8e07b9af753b25c1307f07f8061d6ac4f8427f4660382d925e7a84e2 + name:Heavy Shreddin' (USA) + cheat + description:Infinite penalties + code:95df/c6/a5+9391/c6/a5+93ba/c6/a5 + cheat + description:Select any level + code:83bf/00/ff + cheat + description:Slow timer + code:ae8f/18/38 + cheat + description:Faster left and right movement + code:8bdc/01/02+8bec/01/02 + cheat + description:1 penalty + code:83c1/04/01 + cheat + description:8 penalties + code:83c1/04/08 + cheat + description:16 penalties + code:83c1/04/10 + +cartridge sha256:429c833eb61c0728b0d9335c61f4bd8d3fb19c3bf8a18564917bf75526f104af + name:Heisei Tensai Bakabon (Japan) + cheat + description:Invincibility + code:c5c3/f0/d0 + cheat + description:Infinite health + code:c117/c6/c5 + cheat + description:Infinite time + code:8ac9/85/a5 + +cartridge sha256:1c8e9b6c4c57850d4ab1dea011e0226970034a46fa29fab1d370c01fac90538d + name:Hell Fighter (Asia) (PAL) (Unl) + cheat + description:Infinite lives + code:ad5f/ce/ad+ad62/ce/ad + +cartridge sha256:680a56e038176c7b8deca9fb910b26b097cadd58fa553ea29f3c9836c9a4e11b + name:Hello Kitty no Ohanabatake (Japan) + cheat + description:Invincibility + code:d7db/8d/ad + cheat + description:Infinite lives + code:fc1f/9d/bd + +cartridge sha256:72fa562dfb319bfe982a68053128126e2ed5d579ff1a36f7345bd3fe624e8e92 + name:Heracles no Eikou - Toujin Makyou Den (Japan) + cheat + description:No random battles + code:e2de/20/60 + +cartridge sha256:8e4a04076b6a728a7e65a09737776dcb9defed7922bf0437d9a89bbe8c724b55 + name:Hogan's Alley (World) + cheat + description:Hit anywhere - Game B + code:d01d/f5/00+d429/80/00 + cheat + description:5 misses allowed - Game A + code:cd09/10/05 + cheat + description:20 misses allowed - Game A + code:cd09/10/20 + cheat + description:Infinite misses allowed - all games + code:ce10/01/00 + cheat + description:Each miss counts as 2 - all games + code:ce10/01/02 + cheat + description:Infinite misses allowed - all games (alt) + code:00b3/00 + +cartridge sha256:1c1ad2992f728c7fb6a8f3980b1a0f8e01e5b24a0c43c713300846d87be5987a + name:Holy Diver (Japan) + cheat + description:Invincibility + code:f8f7/8d/60 + cheat + description:Infinite health + code:f8f7/8d/ad + cheat + description:Infinite lives + code:e1ce/ce/ad + +cartridge sha256:3f761f529d40cf42aed60fabc0e60ecfecf528f4165948e6157b552e3bbb4f89 + name:Home Alone 2 - Lost in New York (USA) + cheat + description:Infinite power units/life points + code:fd75/ce/ad + cheat + description:Become almost invincible after losing 1 life point (against most enemies, vacuum cleaner can still kill you) + code:e65b/ce/ad + cheat + description:Infinite lives + code:fe04/ce/ad + cheat + description:Infinite slides on pick-up + code:841b/ce/ad + cheat + description:Infinite darts on pick-up + code:846e/ce/ad + cheat + description:Infinite flying fists on pick-up + code:8450/ce/ad + cheat + description:Every 4 cookies count as 8 + code:fcf6/04/08 + cheat + description:Every 4 cookies count as 12 + code:fcf6/04/0c + cheat + description:Every 4 cookies count as 16 + code:fcf6/04/10 + cheat + description:Every 4 cookies count as 20 (extra life point) + code:fcf6/04/14 + cheat + description:Extra life with 5 pizza slices instead of 6 + code:ec1b/06/05 + cheat + description:Extra life with 4 pizza slices + code:ec1b/06/04 + cheat + description:Extra life with 3 pizza slices + code:ec1b/06/03 + cheat + description:Extra life with 2 pizza slices + code:ec1b/06/02 + cheat + description:Extra life with every pizza slice + code:ec1b/06/01 + cheat + description:Start with 1 life instead of 3 + code:9385/03/01 + cheat + description:Start with 5 lives + code:9385/03/05 + cheat + description:Start with 7 lives + code:9385/03/07 + cheat + description:Start with 9 lives + code:9385/03/09 + cheat + description:Start with 25 lives + code:9385/03/19 + cheat + description:Start with 50 lives + code:9385/03/32 + cheat + description:Start with 75 lives + code:9385/03/4b + cheat + description:Start with 99 lives + code:9385/03/63 + +cartridge sha256:f3ff0c50c05aa5d461c293e306e553152e63564cd09e80ae0b6dcfa97b07d073 + name:Hook (USA) + cheat + description:Infinite health - P1 + code:dd64/e5/24 + cheat + description:Infinite health - P2 + code:dd7f/e5/24 + cheat + description:Infinite lives - P1 + code:f01d/ce/ad + cheat + description:Max health from food - P1 + code:ddf1/05/00 + cheat + description:Max health from food - P2 + code:de07/05/00 + cheat + description:No health from food + code:dde2/2c/60 + cheat + description:Start with 1 life + code:eeaf/02/00 + cheat + description:Start with 6 lives + code:eeaf/02/05 + cheat + description:Start with 9 lives + code:eeaf/02/08 + 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 + name:Hudson Hawk (USA) + cheat + description:Infinite health + code:e784/85/a5 + cheat + description:Infinite lives + code:c75f/c3/a9+c762/f0/a9 + cheat + description:Infinite continues + code:c848/30/a9+c846/c6/a9 + cheat + description:Start with very little health - first life only + code:c6ea/ff/01 + cheat + description:Start with 1/4 health - first life only + code:c6ea/ff/40 + cheat + description:Start with 1/2 health - first life only + code:c6ea/ff/70 + cheat + description:Start with 3/4 health - first life only + code:c6ea/ff/b0 + cheat + description:Start with 1 continue + code:c6d9/03/01 + cheat + description:Start with 5 continues + code:c6d9/03/05 + cheat + description:Start with 9 continues + code:c6d9/03/09 + cheat + description:Start with 1 life + code:c6e6/05/01 + cheat + description:Start with 3 lives + code:c6e6/05/03 + cheat + description:Start with 9 lives + code:c6e6/05/09 + +cartridge sha256:53bfc94fce46a25188f84f102810406f686a7fb13fb5e4ae8f13760106acb969 + name:Hudson's Adventure Island (USA) + cheat + description:Invincibility + code:c05a/a4/60 + cheat + description:Infinite health + code:c0cd/c6/a5 + cheat + description:Immune to rocks + code:c0f3/84/24 + cheat + description:Keep weapons + code:8128/85/24 + cheat + description:Hit anywhere + code:c146/dc/00+c14f/07/00+c152/99/b9 + cheat + description:Multi-jump + code:84e4/d0/24+84e9/d0/24 + cheat + description:Get fruits from anywhere + code:8b39/b0/d0 + cheat + description:Collectable items never disappear + code:8b40/de/60 + cheat + description:Can mega-jump while at rest + code:850d/c0/95 + cheat + description:Can mega-jump while running + code:850e/a9/95 + cheat + description:Multi-mega-maxi-moon jumps + code:8507/01/00+84ea/21/00 + cheat + description:Skateboard doesn't automatically move forward + code:8555/d0/30 + cheat + description:Hudson can moonwalk + code:85c1/01/00+858a/00/01 + cheat + description:Start with infinite lives + code:811c/c6/a5 + cheat + description:Start with 1 life + code:8089/03/01 + cheat + description:Start with 6 lives + code:8089/03/06 + cheat + description:Start with 9 lives + code:8089/03/09 + +cartridge sha256:bafe68d5e6bbebb0d71432d09bed0a482215d4534778a76d471150a3bdd01b08 + name:Hunt for Red October, The (USA) (Rev A) + cheat + description:Infinite lives + code:aa82/c6/a5 + cheat + description:Infinite time + code:b389/ce/ad + cheat + description:Infinite horizontal torpedoes + code:a5bf/ce/ad + cheat + description:Infinite vertical torpedoes + code:a631/ce/ad + cheat + description:Maximum power horizontal torpedoes on pick-up + code:bc08/c9/a9+bc0e/01/00 + cheat + description:Maximum power vertical torpedoes on pick-up + code:bc57/c9/a9+bc5d/01/00 + cheat + description:Start with 10 horizontal torpedoes + code:bc76/19/0a + cheat + description:Start with 50 horizontal torpedoes + code:bc76/19/32 + cheat + description:Start with 99 horizontal torpedoes + code:bc76/19/63 + cheat + description:Start with 5 vertical torpedoes + code:bc7b/0f/05 + cheat + description:Start with 50 vertical torpedoes + code:bc7b/0f/32 + cheat + description:Start with 99 vertical torpedoes + code:bc7b/0f/63 + cheat + description:Start with 5 caterpillars + code:bc85/0a/05 + cheat + description:Start with 50 caterpillars + code:bc85/0a/32 + cheat + description:Start with 99 caterpillars + code:bc85/0a/63 + cheat + description:Start with 5 ECM's + code:bc8a/0a/05 + cheat + description:Start with 50 ECM's + code:bc8a/0a/32 + cheat + description:Start with 99 ECM's + code:bc8a/0a/63 + cheat + description:Start with 1 life + code:b0e7/05/01 + cheat + description:Start with 10 lives + code:b0e7/05/0a + +cartridge sha256:770abf58074764db12aade941ab1a389a818b8ff94d95f4b4b4913912b1f40b5 + name:Hydlide (USA) + cheat + description:Boost strength, life, magic + code:8640/0a/28 + cheat + description:Super boost strength, life, magic + code:8640/0a/64 + cheat + description:Don't take damage from most enemies + code:c7d7/85/a5 + cheat + description:Rapid healing + code:8ebc/0d/00 + cheat + description:Rapid magic healing + code:9a7e/02/00 + 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 + name:Ice Climber (USA, Europe) + cheat + description:Invincibility + code:d348/20/60 + cheat + description:Infinite lives + code:d481/d6/c9 + cheat + description:Super-jump + code:c839/22/1c + cheat + description:Enemies bump you instead of killing you + code:d346/f0/b0 + cheat + description:Double speed + code:cbda/ff/fe+cbdb/01/02 + cheat + description:Triple speed + code:cbda/ff/fd+cbdb/01/03 + cheat + description:Start with 1 life + code:c4ae/03/00 + cheat + description:Start with 6 lives + code:c4ae/03/05 + cheat + description:Start with 9 lives + code:c4ae/03/08 + +cartridge sha256:3775c1184419c0786841c5b4f2694b2a15e181678f92e75fb9b71bfb5668c7b3 + name:Ikari Warriors (USA) (Rev A) + cheat + description:Invincibility + code:f3e0/4c/ad + cheat + description:Invincibility (except against bombs) + code:b7e2/f0/d0 + cheat + description:Invincibility (blinking) + code:e023/80/84 + cheat + description:Infinite lives + code:f6da/d6/a5 + cheat + description:Infinite Missiles for Tank + code:fbae/de/ad + cheat + description:Infinite Bullets + code:f51a/de/ad + cheat + description:Infinite Grenades + code:f582/de/ad + cheat + description:Enemies die automatically + code:b740/73/00+9117/1c/00+b9bd/b0/50+8698/90/24 + cheat + description:Hit anywhere (except tanks and helicopters) + code:b9a9/01/00+b9ab/13/3b+b9a8/29/c9 + cheat + description:Walk and shoot through walls + code:eb20/02/00 + cheat + description:Start with 1 life + code:f631/03/01 + cheat + description:Start with 6 lives + code:f631/03/06 + cheat + description:Start with 9 lives + code:f631/03/09 + cheat + description:Start with 50 Bullets + code:f2fb/63/32 + cheat + description:Start with 99 Grenades + code:f300/32/63 + cheat + description:Start with 25 Grenades + code:f300/32/19 + 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 + name:Ikari Warriors (USA) + cheat + description:Invincibility + code:f3e0/4c/ad + cheat + description:Invincibility (except against bombs) + code:b7e2/f0/d0 + cheat + description:Invincibility (blinking) + code:e023/80/84 + cheat + description:Infinite lives + code:f6da/d6/a5 + cheat + description:Infinite Missiles for Tank + code:fbae/de/ad + cheat + description:Infinite Bullets + code:f51a/de/ad + cheat + description:Infinite Grenades + code:f582/de/ad + cheat + description:Enemies die automatically + code:b740/73/00+9117/1c/00+b9bd/b0/50+8698/90/24 + cheat + description:Hit anywhere (except tanks and helicopters) + code:b9a9/01/00+b9ab/13/3b+b9a8/29/c9 + cheat + description:Start with 1 life + code:f631/03/01 + cheat + description:Start with 6 lives + code:f631/03/06 + cheat + description:Start with 9 lives + code:f631/03/09 + cheat + description:Start with 50 Bullets + code:f2fb/63/32 + cheat + description:Start with 99 Grenades + code:f300/32/63 + cheat + description:Start with 25 Grenades + code:f300/32/19 + 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 + name:Ikari Warriors II - Victory Road (USA) + cheat + description:Infinite health + code:b39d/99/b9 + cheat + description:Don't take damage from most enemies + code:b397/e5/24 + cheat + description:Start with half normal health + code:f7f5/60/30 + cheat + description:Maximum weapon power on pick-up + code:a83e/69/a9+a83f/01/04 + 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 + name:Ikari III - The Rescue (USA) + cheat + description:Invincibility + code:ba43/20/ad + cheat + description:Infinite health + code:b85f/9d/bd + cheat + description:Infinite lives + code:cfb7/01/00 + cheat + description:Infinite lives (alt) + code:cfbc/9d/bd + cheat + description:Immune to most kicks and punches + code:b859/e5/24 + cheat + description:3-way firing, instead of punching + code:ccde/01/07 + cheat + description:Always throw grenades instead of punches + code:ccde/01/09 + cheat + description:1 life after continue + code:c3aa/03/01 + cheat + description:6 lives after continue + code:c3aa/03/06 + cheat + description:9 lives after continue + code:c3aa/03/09 + cheat + description:Start with 1 life + code:c89b/03/01 + cheat + description:Start with 6 lives + code:c89b/03/06 + cheat + description:Start with 9 lives + code:c89b/03/09 + +cartridge sha256:7032a94d140339f9d6603accc9fed2846f5bbb781659cdff869d4b5f137d4e4a + name:Image Fight (USA) + cheat + description:Invincibility + code:a4cf/d0/f0+9193/d0/f0 + cheat + description:Infinite lives - both players + code:a1d6/c6/a5 + cheat + description:Never lose Pods + code:b456/a9/60 + cheat + description:Start with V Cannon + code:b404/00/01 + cheat + description:Start with Reflecting Ball + code:b404/00/02 + cheat + description:Start with Drilling Laser + code:b404/00/03 + cheat + description:Start with Seeking Missile + code:b404/00/04 + cheat + description:Start with Seeking Laser + code:b404/00/05 + cheat + description:Start with 1 life - both players + code:a16b/03/01 + cheat + description:Start with 6 lives - both players + code:a16b/03/06 + cheat + description:Start with 9 lives - both players + code:a16b/03/09 + cheat + description:Start at Combat Simulation Stage 2 + code:a163/00/01 + cheat + description:Start at Combat Simulation Stage 3 + code:a163/00/02 + cheat + description:Start at Combat Simulation Stage 4 + code:a163/00/03 + cheat + description:Start at Combat Simulation Stage 5 + code:a163/00/04 + cheat + description:Start at Real Combat - 1st Target + code:a163/00/05 + cheat + description:Start at Real Combat - 2nd Target + code:a163/00/06 + +cartridge sha256:8bc6a252778c2909a97b3fff185c5ff2a1786afe5e8237098f15fe3eaf23adab + name:Immortal, The (USA) + cheat + description:Enemy's fatigue level doesn't go down + code:b215/ce/2c + cheat + description:Your fatigue level doesn't go down + code:b21d/ce/2c + cheat + description:Your fatigue level goes down faster + code:b20d/7f/3f + cheat + description:Your fatigue level goes down slower + code:b20d/7f/ff + cheat + description:Don't lose energy from fighting + code:b256/ce/ad + cheat + description:Your fatigue level never rises + code:b271/ee/ad + cheat + description:More damage from fireballs + code:d74d/01/02 + 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 + name:Incredible Crash Dummies, The (USA) + cheat + description:Invincibility + code:a73f/f0/d0 + cheat + description:Infinite health + code:c764/8c/ac + cheat + description:Infinite lives + code:c778/8c/ac + cheat + description:Invincibility (blinking) + code:053c/01 + +cartridge sha256:79c03fec3f459ac6e762c27d8f08debe6589b01df21919ef69645870a16723b3 + name:Indiana Jones and the Last Crusade (USA) (UBI Soft) + cheat + description:Infinite health (you can get trapped in certain areas) + code:fa1c/04/fe + cheat + description:Infinite time + code:968f/01/00 + cheat + description:Infinite credits + code:a0ad/ce/ad + cheat + description:Infinite lives + code:ec50/04/fc + cheat + description:Infinite lives on bike section + code:8d38/c6/a5 + cheat + description:More lives on ship section + code:8764/05/09 + cheat + description:Fewer lives on ship section + code:8764/05/01 + cheat + description:More lives on tank section + code:9505/06/09 + cheat + description:Fewer lives on tank section + code:9505/06/01 + cheat + description:More lives on castle section + code:90a6/03/09 + cheat + description:Fewer lives on castle section + code:90a6/03/01 + cheat + description:Heart does nothing (may goof up energy bar) + code:9bc2/01/00 + cheat + description:Super-jump + code:e864/01/05 + cheat + description:Mega-jump + code:e864/01/09 + cheat + description:Continue with 1 life + code:a0b1/03/01 + cheat + description:Continue with 5 lives + code:a0b1/03/05 + cheat + description:Continue with 7 lives + code:a0b1/03/07 + cheat + description:Continue with 9 lives + code:a0b1/03/09 + cheat + description:Start with 1 life + code:c06c/03/01 + cheat + description:Start with 5 lives + code:c06c/03/05 + cheat + description:Start with 7 lives + code:c06c/03/07 + cheat + description:Start with 9 lives + code:c06c/03/09 + cheat + description:Start on level 2 (after completing the level you'll go back to level 1) + code:c071/00/01 + cheat + description:Start on level 3 (after completing the level you'll go back to level 1) + code:c071/00/02 + cheat + description:Start on level 4 (after completing the level you'll go back to level 1) + code:c071/00/03 + cheat + description:Start on level 5 (after completing the level you'll go back to level 1) + code:c071/00/04 + cheat + description:Start on level 6 (after completing the level you'll go back to level 1) + code:c071/00/05 + +cartridge sha256:5348f7f88695867de428b38eb6a7f724f5f97110c383567d7e4d1f5a2d8b612f + name:Indiana Jones and the Last Crusade (USA) (Taito) + cheat + description:Infinite health + code:911b/0d/8d + +cartridge sha256:884765e5df86042211191f7e7e4653255425e3da70a9dec6f4a9336c07b5f258 + name:Indiana Jones and the Temple of Doom (USA) (Rev A) + cheat + description:Infinite lives + code:ac09/ce/ad + cheat + description:Infinite time + code:a020/ce/ad + cheat + description:Always keep Sword + code:a354/ce/ad + cheat + description:Always keep Gun + code:a63a/ce/ad + cheat + description:Start with less time + code:bc4a/63/3c+ab8b/3c/63+ac1e/3c/63 + cheat + description:Start with 1 life + code:bbc3/04/00 + cheat + description:Start with 10 lives + code:bbc3/04/09 + cheat + description:Start with 15 lives + code:bbc3/04/0e + cheat + description:Start on level 2 + code:bc40/0f/11 + cheat + description:Start on level 4 + code:bc40/0f/15 + cheat + description:Start on level 6 + code:bc40/0f/19 + cheat + description:Start on level 8 + code:bc40/0f/1d + cheat + description:0 Maps left + code:012f/00 + cheat + description:Have all 3 Keys + code:011d/b0 + +cartridge sha256:8125d69b66dd7784246156bb669542924f1c2b7f53b8d325ffcbaa74746d14ff + name:Indiana Jones and the Temple of Doom (USA) + cheat + description:Infinite lives + code:ac09/ce/ad + cheat + description:Infinite time + code:a020/ce/ad + cheat + description:Always keep Sword + code:a354/ce/ad + cheat + description:Always keep Gun + code:a63a/ce/ad + cheat + description:Start with less time + code:bc4a/63/3c+ab8b/3c/63+ac1e/3c/63 + cheat + description:Start with 1 life + code:bbc3/04/00 + cheat + description:Start with 10 lives + code:bbc3/04/09 + cheat + description:Start with 15 lives + code:bbc3/04/0e + cheat + description:Start on level 2 + code:bc40/0f/11 + cheat + description:Start on level 4 + code:bc40/0f/15 + cheat + description:Start on level 6 + code:bc40/0f/19 + cheat + description:Start on level 8 + code:bc40/0f/1d + cheat + description:0 Maps left + code:012f/00 + cheat + description:Have all 3 Keys + code:011d/b0 + +cartridge sha256:0bb401bbd0cae2758b2bd355cd3cac3cc26a01950859c830b3b122bd379f2463 + name:Infiltrator (USA) + cheat + description:Infinite time + code:b445/ce/ad + cheat + description:Never lose Grenades outside buildings + code:adca/c6/a5 + cheat + description:Never lose Grenades inside buildings + code:c568/c6/a5 + cheat + description:Never lose Spray outside buildings + code:adbc/c6/a5 + cheat + description:Never lose Spray inside buildings + code:c53f/c6/a5 + cheat + description:Start with less time + code:b21b/39/35 + cheat + description:Start with more Grenades + code:b251/0a/12 + cheat + description:Start with fewer Grenades + code:b251/0a/05 + cheat + description:Start with no Grenades + code:b251/0a/00 + cheat + description:Start with less Spray + code:b24d/26/13 + cheat + description:Start with no Spray + code:b24d/26/00 + +cartridge sha256:0f406a7c853b919ed880868420808b945855146db9817ebc3102f08da13fa703 + name: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 + name:Iron Tank - The Invasion of Normandy (USA) + cheat + description:Infinite health + code:e83c/9d/bd + cheat + description:Infinite lives + code:c515/01/d1+c4be/ce/ad + cheat + description:Start with 1 life + code:c515/01/d1+c43c/02/00 + cheat + description:Start with 6 lives + code:c515/01/d1+c43c/02/05 + cheat + description:Start with 9 lives + code:c515/01/d1+c43c/02/08 + cheat + description:Infinite health (alt) + code:0306/ff + cheat + description:Infinite lives (alt) + code:01d1/09 + +cartridge sha256:aab5e0ecc46e575b1b396bd63d8fa4f3bd740061f3157a1d4afdf9f7f2dabd88 + name:IronSword - Wizards & Warriors II (USA) + cheat + description:Infinite lives + code:88a7/c6/a9 + cheat + description:Infinite continues + code:8932/c6/a9 + cheat + description:Infinite spells + code:dcaf/de/2c + cheat + description:Infinite money + code:dc98/00/02 + cheat + description:Infinite keys once one is obtained + code:959e/a5/85 + cheat + description:Super-jump + code:d334/e5/e9+d335/86/09 + cheat + description:Food gives full health + code:9888/02/00 + cheat + description:Drink gives full health + code:9917/02/00 + cheat + description:Fleet foot jumping + code:d157/03/00 + cheat + description:Fleet foot running + code:d3cf/29/a9 + cheat + description:Start with Axe and Helmet + code:8aea/00/03 + cheat + description:Start with Shield + code:8ae6/ff/02 + cheat + description:Start with Ironsword + code:8314/0c/00 + cheat + description:Start on wind level + code:8289/00/0b + cheat + description:Start on tree level + code:8289/00/14 + cheat + description:Start on water level + code:8289/00/16 + cheat + description:Start on outer fire level + code:8289/00/15 + cheat + description:Start on lower earth level + code:8289/00/33 + cheat + description:Start on lower icefire mountain + code:8289/00/31 + cheat + description:Start a new game with full magic + code:8b06/00/ff + cheat + description:Start with 1 life + code:8af0/03/01+89da/03/01 + cheat + description:Start with 6 lives + code:8af0/03/06+89da/03/06 + 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 + name:Isolated Warrior (USA) + cheat + description:Invincibility + code:9a94/30/a9+9a96/a5/85+e7c0/a2/e3 + cheat + description:Infinite health + code:d46c/26/ea + cheat + description:Infinite lives + code:e039/c6/a5 + cheat + description:Infinite Bombs + code:9d2a/ce/ad + cheat + description:More health restored on pick-up + code:8790/02/06 + cheat + description:Less health restored on pick-up + code:8790/02/01 + cheat + description:Start with maximum health and Bombs + code:e25e/09/00 + cheat + description:Start with 1 life + code:e225/03/01 + cheat + description:Start with 6 lives + code:e225/03/06 + cheat + description:Start with 9 lives + code:e225/03/09 + cheat + description:Start on Scene 2 + code:807c/00/01+807f/8d/8e+8082/8d/8e + cheat + description:Start on Scene 3 + code:807c/00/02+807f/8d/8e+8082/8d/8e + cheat + description:Start on Scene 4 + code:807c/00/03+807f/8d/8e+8082/8d/8e + cheat + description:Start on Scene 5 + code:807c/00/04+807f/8d/8e+8082/8d/8e + cheat + description:Start on Scene 6 + code:807c/00/05+807f/8d/8e+8082/8d/8e + 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 + name:Ivan 'Ironman' Stewart's Super Off Road (USA) + cheat + description:Infinite money + code:e434/b1/4c+e435/60/4c+e436/38/e4 + cheat + description:Infinite nitro boosts + code:d9c5/01/00 + cheat + description:Lots of money and full equipment + code:e4c7/00/06 + cheat + description:Computer starts with no nitro boosts + code:803d/19/00 + cheat + description:Computer starts with double nitro boosts + code:803d/19/32 + cheat + description:Start with double nitro boosts + code:e50a/19/32 + cheat + description:Start with 1 life + code:e4f7/03/01 + 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 + name:Jackal (USA) + cheat + description:Invincibility - both players + code:e5ba/d0/50 + cheat + description:Infinite lives - both players + code:ed15/a5 + cheat + description:Keep weapons after death + code:eca5/24 + cheat + description:Full weapons after death + code:eca4/03 + cheat + description:Start with 1 life - both players + code:ca1a/01 + cheat + description:Start with 9 lives - both players + code:ca1a/09 + 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 + name:Jackie Chan's Action Kung Fu (USA) + cheat + description:Invincibility + code:dbd7/f0/d0 + cheat + description:Infinite health + code:ca82/8d/ae + cheat + description:Infinite special attacks + code:cad8/ce/ad + cheat + description:Take less damage + code:dc78/69 + cheat + description:Hit anywhere + code:82c8/c5/4c+82c9/09/e1+82ca/90/82 + cheat + description:Multi-jump + code:e596/04/00 + cheat + description:9 Tornado Attacks on pick-up + code:dfd4/07/09 + cheat + description:9 360o Spin Kicks on pick-up + code:dfd6/07/09 + cheat + description:9 Sky Attacks on pick-up + code:dfd7/07/09 + cheat + description:0 Tornado Attacks on pick-up + code:dfd4/07/00 + cheat + description:0 180o Spin Kicks on pick-up + code:dfd5/09/00 + cheat + description:0 360o Spin Kicks on pick-up + code:dfd6/07/00 + cheat + description:0 Sky Attacks on pick-up + code:dfd7/07/00 + cheat + description:Max health from Energy Bowl + code:ca62/02/06 + cheat + description:Less health from Energy Bowl + code:ca62/02/01 + 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 + name:James Bond Jr (USA) + cheat + description:Invincibility + code:b177/f0/d0+b17f/d0/f0 + cheat + description:Infinite health + code:f570/9d/ad + cheat + description:Infinite weapons (Bombs, Flares, Nukes, Bullets) + code:fb7d/01/00 + cheat + description:Immune to most damage + code:f561/e5/24 + cheat + description:Infinite lives + code:c98d/ce/ad + cheat + description:Slow down rate of air loss (scuba mode) + code:9fd8/1f/3f + cheat + description:Speed up rate of air loss + code:9fd8/1f/0f + cheat + description:Shield doesn't take damage from bullets + code:f532/e5/24 + cheat + description:Start with some weapons + code:e090/8a/ea + cheat + description:Start with 2 lives + code:e076/06/01 + cheat + description:Start with 15 lives + code:e076/06/0e + 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 + name:Jaws (USA) + cheat + description:Infinite lives + code:8556/ce/ad + cheat + description:Infinite shells + code:876f/8d/ad + cheat + description:Jaws has no health + code:85c9/14/00+82dc/14/00+854d/8d/ad + cheat + description:Hit anywhere + code:9918/15/00 + cheat + description:Hit anywhere - bonus stages + code:d3a3/90/50+d3c6/b0/24+d3c2/d0/24 + cheat + description:Don't lose shells on dying + code:855b/4e/ad + cheat + description:Don't lose power on dying + code:855e/ce/ad + cheat + description:Collect Crabs from anywhere + code:a5fb/1e/00 + cheat + description:Collect Shells from anywhere + code:a671/26/00 + cheat + description:Collect Stars from anywhere + code:a6e6/2a/00 + cheat + description:99 Shells on pick-up + code:a685/05/00 + cheat + description:Start with 1 life + code:8294/03/01 + cheat + description:Start with double lives + code:8294/03/06 + 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 + name:Jetsons, The - Cogswell's Caper (USA) + cheat + description:Infinite lives + code:be52/ce/ad + cheat + description:Infinite hearts + code:830b/ce/ad + cheat + description:Better start (more lives and hearts) + code:9581/03/05 + cheat + description:Don't lose extra hearts on dying + code:bee0/ce/2c + cheat + description:2 power packs on pick-up + code:83ea/01/02 + cheat + description:5 power packs on pick-up + code:83ea/01/05 + cheat + description:Small hearts gives full health + code:8445/06/00 + cheat + description:Defenses don't use up powerpacks + code:88bf/8d/2c + cheat + description:Shield uses fewer powerpacks + code:8834/20/05 + cheat + description:Flashlight uses fewer powerpacks + code:87fd/10/02 + cheat + description:Start with 30 powerpacks + code:958c/10/30 + cheat + description:Start with 50 powerpacks + code:958c/10/50 + 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 + name:Jimmy Connors Tennis (USA) + cheat + description:Only need 15 points to win game + code:e1e5/03/00 + cheat + description:Only need 30 points to win game + code:e1e5/03/01 + cheat + description:Only need 40 points to win game + code:e1e5/03/02 + cheat + description:Only need 1 game to win set instead of 6 + code:e288/06/00 + cheat + description:Only need 2 games to win set + code:e288/06/01 + cheat + description:Only need 3 games to win set + code:e288/06/02 + cheat + description:Only need 4 games to win set + code:e288/06/04 + cheat + description:Only need 5 games to win set + code:e288/06/05 + cheat + description:Must get 2 points after 40 to win and no deuces (always shows advantage after 40) + code:e1ed/d0/80 + cheat + description:Don't need to win by 2 to win tiebreaker + code:e1cc/02/01 + cheat + description:2 points needed to win tiebreaker instead of 7 + code:e1bd/07/02 + cheat + description:3 points needed to win tiebreaker + code:e1bd/07/03 + cheat + description:4 points needed to win tiebreaker + code:e1bd/07/04 + cheat + description:5 points needed to win tiebreaker + code:e1bd/07/05 + cheat + description:6 points needed to win tiebreaker + code:e1bd/07/06 + cheat + description:10 points needed to win tiebreaker + code:e1bd/07/0a + +cartridge sha256:509f04b745d11b8d83afb42f084179a6f2ebc87f647927432a647f0e7ee51bb5 + name:Joe & Mac (USA) + cheat + description:Invincibility + code:d6a2/f0/d0+d6ac/d0/f0 + cheat + description:Infinite health + code:ec49/ce/ad + cheat + description:Infinite lives - both players + code:a07e/ce/ad + cheat + description:Protection from most enemy hits + code:ec49/ce/ad + cheat + description:Protection from water + code:e6bf/ce/ad + cheat + description:Stone axe and flint do more damage to bosses + code:b848/01/08 + cheat + description:Stone axe and flint do a lot more damage to bosses + code:b848/01/0f + cheat + description:Stone wheel and boomerang do more damage to bosses + code:b851/02/08 + cheat + description:Stone wheel and boomerang do a lot more damage to bosses + code:b851/02/10 + cheat + description:Fire does more damage to bosses + code:b856/04/10 + cheat + description:Fire does a lot more damage to bosses + code:b856/04/20 + cheat + description:Apple and hamburger worth nothing + code:eb64/8d/ad + cheat + description:Apple and hamburger restore health to 1/2 + code:eb63/10/08 + cheat + description:Start with 1/2 health (die when bar is 1/2 empty) + code:a3a4/10/08 + cheat + description:Start with stone wheel instead of stone axe - P1 + code:a0ba/e0/e1 + cheat + description:Start with flint instead of stone axe - P1 + code:a0ba/e0/e2 + cheat + description:Start with fire instead of stone axe - P1 + code:a0ba/e0/e3 + cheat + description:Start with boomerang instead of stone axe - P1 + code:a0ba/e0/e4 + cheat + description:Start with 1 life instead of 3 - P1 + code:a0bf/03/01 + cheat + description:Start with 5 lives - P1 + code:a0bf/03/05 + cheat + description:Start with 7 lives - P1 + code:a0bf/03/07 + cheat + description:Start with 9 lives - P1 + code:a0bf/03/09 + cheat + description:Start somewhere in level 2 + code:a0c4/00/02 + cheat + description:Infinite health (alt) + code:0499/0f + cheat + description:One hit kills on bosses + code:064d/00 + +cartridge sha256:ec54ed32302aaeb2fa6e0d7e2ca3ea2d8df888e77859e158298ecb2fa322178e + name: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 + name: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 + name:Journey to Silius (USA) + cheat + description:Invincibility + code:e825/20/ad+e8b4/20/ad + cheat + description:Invincibility after first hit (blinking) + code:8011/c6/a5 + cheat + description:Infinite health + code:ea3b/85/a5 + cheat + description:Infinite weapon power + code:8e33/85/a5 + cheat + description:Infinite lives + code:c3f7/c6/a5 + cheat + description:Protection against most aliens + code:ea39/e5/e9 + cheat + description:Hit anywhere + code:ad58/b0/a9+e761/b0/a9+e782/9d/ad+ad70/9d/ad + cheat + description:Multi-jump + code:818d/04/00+81c9/cc/ac + cheat + description:Some aliens are tougher + code:e824/02/08 + cheat + description:Some aliens are weaker + code:e824/02/01 + cheat + description:Mega-jump + code:819e/0b/16 + cheat + description:Speed jump + code:8163/01/20+80ff/ff/e0 + cheat + description:Super speed + code:815f/04/13+80fb/fc/ec + cheat + description:1 life after continue + code:dbe3/03/01 + cheat + description:6 lives after continue + code:dbe3/03/06 + cheat + description:9 lives after continue + code:dbe3/03/09 + cheat + description:Start with all six weapons + code:dcc9/02/1f + cheat + description:Start with Machine Gun + code:dcc9/02/01 + cheat + description:Start with Laser Gun + code:dcc9/02/04 + cheat + description:Start with Homing Missiles + code:dcc9/02/08 + cheat + description:Start with Grenade Launcher + code:dcc9/02/10 + cheat + description:Start with Machine Gun and Laser Gun + code:dcc9/02/05 + cheat + description:Start with 1 life + code:de19/03/01 + cheat + description:Start with 6 lives + code:de19/03/06 + cheat + description:Start with 9 lives + code:de19/03/09 + 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:4b00fa0ae20030af3406e95eb08f42ec473ec03d9063798ccd6c249648409af3 + name:Journey to the West (Asia) (Unl) + cheat + description:Hit anywhere + code:b445/4c/00+b42c/65/00 + cheat + description:Climb anywhere (except in boss fights) + code:a55c/29/a9+a552/60/ea + +cartridge sha256:8471a6b7c7c7d6c7be0ee278778e2d25dc91462db22643395787eaaeb6e320c1 + name:Joust (USA) + cheat + description:Infinite lives + code:caac/d6/a5 + cheat + description:Turbo flying + code:cc54/00/01 + cheat + description:Heavens above? + code:cae9/95/24 + cheat + description:Start with 1 life + code:c093/05/01 + cheat + description:Start with 9 lives + code:c093/05/0a + cheat + description:Start on last level reached + code:c0de/85/24+c0dc/85/24+c0e4/85/24 + +cartridge sha256:8d36c0923103f370eb9fab5caeb2a8307cd1c7a30030db69bd5bc4f5ca46b1d2 + name:Jovial Race (Asia) (PAL) (Unl) + cheat + description:Infinite lives + code:9c7b/ce/ad + cheat + description:Start with 5 lives + code:836a/03/05 + cheat + description:Start with 10 lives + code:836a/03/0a + cheat + description:Sart with 100 lives + code:836a/03/64 + +cartridge sha256:a7bf6adcd838f055405963741dd3368730b0f9dc125ae7071832a9305a4c7292 + name:Jovial Race (Unknown) (Unl) + cheat + description:Infinite lives + code:9c7b/ce/ad + cheat + description:Start with 5 lives + code:836a/03/05 + cheat + description:Start with 10 lives + code:836a/03/0a + cheat + description:Sart with 100 lives + code:836a/03/64 + +cartridge sha256:e5bcb8838f567f485c6f872e9695d2e3ef676f4bcda1c32d51d56008efb96e7a + name:Jungle Book, The (USA) + cheat + description:Infinite lives + code:8d69/8d/2c + cheat + description:Infinite time + code:8f68/01/00 + cheat + description:Infinite weapons + code:8df8/00/01 + cheat + description:Need 2 gems to finish levels 1, 3, 4, 7, 9 + code:cbcb/10/02+f4ab/b9/ad + cheat + description:Need 4 gems to finish levels 1, 3, 4, 7, 9 + code:cbcb/10/04+f4ab/b9/ad + cheat + description:Need 8 gems to finish levels 1, 3, 4, 7, 9 + code:cbcb/10/08+f4ab/b9/ad + cheat + description:Start practice level with 1 life + code:cc06/06/01 + cheat + description:Start practice level with 3 lives + code:cc06/06/03 + cheat + description:Start practice level with 9 lives + code:cc06/06/09 + cheat + description:Start normal level with 1 life + code:cc07/05/01 + cheat + description:Start normal level with 3 lives + code:cc07/05/03 + cheat + description:Start normal level with 9 lives + code:cc07/05/09 + cheat + description:Start with 5 of each weapon + code:f362/00/05 + cheat + description:Start with 10 of each weapon + code:f362/00/10 + cheat + description:Start with 20 of each weapon + code:f362/00/20 + cheat + description:Start with 30 of each weapon + code:f362/00/30 + cheat + description:Start with 90 of each weapon + code:f362/00/90 + +cartridge sha256:49fe0c49cd0a2841ae9c8ae5aa19f710d187ee6931a1e531d3bff19772ca4af0 + name:Jurassic Park (USA) + cheat + description:Invincibility + code:a833/f0/d0 + cheat + description:Infinite health + code:c162/8d/ad + cheat + description:Immune to most attacks + code:c162/8d/60 + cheat + description:Infinite lives (first two levels only) + code:b10b/ce/2c + cheat + description:Infinite ammo on pick-up + code:ac3a/de/2c + cheat + description:More bullets picked up from small dinosaurs + code:9460/02/09 + cheat + description:Fewer bullets picked up from small dinosaurs + code:9460/02/01 + cheat + description:3-ball bolas picked up (from small dinosaurs instead of normal bullets) + code:88a5/85/86+88b2/85/86 + cheat + description:Explosive multi-shots (from small dinosaurs instead of normal bullets) + code:88a5/85/87+88b2/85/87 + +cartridge sha256:f40341cf7e76480465ba8ab2d09e44644c3e3af7d647dc04c8b38357b26e014a + name:Just Breed (Japan) + cheat + description:No health - all enemies + code:69da/00+69db/00+69dc/00+69dd/00+69de/00+69df/00+69e0/00+69e1/00+69e2/00+69e3/00+69e4/00+69e5/00+69e6/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 + name:Kabuki - Quantum Fighter (USA) + cheat + description:Invincibility + code:b1ba/a5/60+a0b4/f0/d0 + cheat + description:Infinite health + code:cf77/8d/ae + cheat + description:Infinite chip power + code:b088/bd/ad + cheat + description:Infinite lives + code:cf65/8d/ad + cheat + description:Don't lose a life from health loss + code:cf64/01/00 + cheat + description:Don't lose a life from timer + code:d058/01/00 + cheat + description:1 continue + code:bbfa/02/01 + cheat + description:6 continues + code:bbfa/02/05 + cheat + description:9 continues + code:bbfa/02/08 + cheat + description:Slower timer + code:d022/3f/ff + cheat + description:Faster timer + code:d022/3f/2f + cheat + description:Special weapons use minimum chip power + code:b088/bd/ad+b089/0f/10 + cheat + description:Start with maximum health + code:bbff/0a/0f+b3a3/0a/0f + cheat + description:Start with less health + code:bbff/0a/05+b3a3/0a/05 + cheat + description:Start with 1 life + code:bbf5/02/00 + cheat + description:Start with 6 lives + code:bbf5/02/05 + cheat + description:Start with 9 lives + code:bbf5/02/08 + 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:67123fe28cf5fbadeafc77400a0812f0135ab36706ec7d1267f84931d044e71d + name:Kai no Bouken - The Quest of Ki (Japan) + cheat + description:Exit always open + code:0053/01 + +cartridge sha256:204b5eb443dc8f599d54e242352ba299c05015e5571f74307d78748af3d5f960 + name:Kame no Ongaeshi - Urashima Densetsu (Japan) + cheat + description:Invincibility + code:c3f7/f0/a9+c3f9/ce/8d + +cartridge sha256:d67817e44f3a421a78ce4217a0660ee375ea162f1465a28da77659dfa46f8f7c + name: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 + name:Karate Champ (USA) + cheat + description:One hit wins round + code:0069/20 + cheat + description:One hit wins stage + code:005d/02 + +cartridge sha256:8aa5c70100080adf0f6d8945ea10382f3986b99d41e010c356991dfe061eaa8d + name:Karate Kid, The (USA) + cheat + description:Infinite health + code:b25f/85/a5 + cheat + description:Infinite chances (lives) + code:881c/c6/a5 + cheat + description:Infinite Crane Kicks + code:a78b/c6/a5 + cheat + description:Infinite Drum Punches on pick-up + code:a778/c6/a5 + cheat + description:Hit anywhere + code:98ec/b0/50+98ed/03/24 + cheat + description:Prevent girl from moving in final stage + code:ac39/01/00 + cheat + description:Win tournament rounds automatically + code:8895/d7/00 + cheat + description:Start with 1 chance + code:86fa/03/01 + cheat + description:Start with 6 chances + code:86fa/03/06 + cheat + description:Start with 9 chances + code:86fa/03/09 + cheat + description:Start with 8 Crane Kicks - 1P game + code:ec4b/04/08 + cheat + description:Start with 8 Crane Kicks - 2P game + code:ec4c/04/08 + cheat + description:Start with 5 Crane Kicks - P1, one on one game + code:ec4d/00/05 + cheat + description:Start on stage 2 - 1P game + code:ec4e/01/02 + cheat + description:Start on stage 2 - 2P game + code:ec4f/01/02 + cheat + description:Start on stage 3 - 1P game + code:ec4e/01/03 + cheat + description:Start on stage 3 - 2P game + code:ec4f/01/03 + cheat + description:Start on stage 4 - 1P game + code:ec4e/01/04 + cheat + description:Start on stage 4 - 2P game + code:ec4f/01/04 + 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 + name:Karnov (USA) + cheat + description:Invincibility after one hit + code:f28f/d0/50 + cheat + description:Invincibility + code:cb6f/85/a5+cb82/85/a5+cb73/85/a5 + cheat + description:Infinite lives + code:dac5/ce/ad + cheat + description:Infinite time + code:ad67/c6/24 + cheat + description:Hit anywhere + code:ccdb/09/00+ccd1/b0/a9+cd4f/95/a5 + cheat + description:Jump higher + code:f5be/2a + cheat + description:Gain 3 of most items + code:cf81/01/03 + cheat + description:Gain 97 of most items + code:cf81/01/97 + cheat + description:Never lose most items + code:cf9d/01/00 + cheat + description:Start with 1 life + code:d01d/02/00+ded6/02/00 + cheat + description:Start with 6 lives + code:d01d/02/05+ded6/02/05 + cheat + description:Start with 9 lives + code:d01d/02/08+ded6/02/08 + cheat + description:Start on stage 2 + code:d038/00/01 + cheat + description:Start on stage 3 + code:d038/00/02 + cheat + description:Start on stage 4 + code:d038/00/03 + cheat + description:Start on stage 5 + code:d038/00/04 + cheat + description:Start on stage 6 + code:d038/00/05 + cheat + description:Start on stage 7 + code:d038/00/06 + cheat + description:Start on stage 8 + code:d038/00/07 + cheat + description:Start on stage 9 + code:d038/00/08 + 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 + name:Kekkyoku Nankyoku Daibouken (Japan) + cheat + description:Infinite time + code:f348/e6/a5 + +cartridge sha256:07e1b14777f8f04d4bd7c85c74a6f9e0f5c43b8c31aa7b3214e53a659fd5a2d9 + name:Kero Kero Keroppi no Daibouken 2 - Donuts Ike wa Oosawagi! (Japan) + cheat + description:Multi-jump + code:8899/3b/00 + +cartridge sha256:23bf669afb3125d72f352848628e201607b4cece974cce86f2558a1812056ece + name:Kick Master (USA) + cheat + description:Invincibility + code:de1a/85/10+de11/8d/ad+de1b/d2/06 + cheat + description:Invincibility after one hit + code:ab61/f0/a9 + cheat + description:Infinite health + code:de11/8d/ad + cheat + description:Infinite magic points + code:bd81/95/b5 + cheat + description:Infinite lives + code:b3b7/ce/ad+d3ba/f0/a9 + cheat + description:Hit anywhere + code:a1bf/90/d0 + cheat + description:Quick level up + code:a6e7/03/00 + cheat + description:Don't flash at all after getting hit + code:de19/3c/00 + cheat + description:Barely flash at all after getting hit + code:de19/3c/05 + cheat + description:Don't flash as long after getting hit + code:de19/3c/15 + cheat + description:Start with more EXP and magic points + code:d33b/60/65 + cheat + description:Start with twice as much health + code:fde0/40/80 + cheat + description:Start with half health + code:fde0/40/20 + cheat + description:Start with very little health + code:fde0/40/03 + cheat + description:Start with 1 life + code:d32c/03/01 + cheat + description:Start with 5 lives + code:d32c/03/05 + cheat + description:Start with 9 lives + code:d32c/03/09 + +cartridge sha256:4a9544bb41869e88ec0610a799b5ce9c7d89bf9a48198923ea7ba22f385ea349 + name:Kickle Cubicle (USA) + cheat + description:Invincibility + code:a089/b1/85+a178/b1/85 + cheat + description:Infinite lives + code:8680/c6/a5 + cheat + description:Infinite time + code:cef5/ce/ad + cheat + description:Infinite time (alt) + code:ceee/70 + cheat + description:Faster timer + code:cefa/0a/07 + cheat + description:Slower timer + code:cefa/0a/0f + cheat + description:Win level now + code:83d6/f0/d0 + cheat + description:Start on land 2 + code:8246/8d/2c+d935/8d/2c+d931/00/01 + cheat + description:Start on land 3 + code:8246/8d/2c+d935/8d/2c+d931/00/02 + cheat + description:Start on land 4 + code:8246/8d/2c+d935/8d/2c+d931/00/03 + +cartridge sha256:56f1fe3a7881b2e9d69cd33a0971b2f26247e964c3c7dd4a6019715425ff2256 + name:Kid Icarus (USA, Europe) + cheat + description:Invincibility + code:db2e/f1/e9 + cheat + description:No ordinary damage + code:db34/85/a5 + cheat + description:No damage from floor hazards + code:cfa3/c6/c5 + cheat + description:No damage from Medusa + code:b150/85/a5 + cheat + description:Lava restores health + code:cfa3/c6/e6 + cheat + description:Immune to becoming an eggplant + code:883e/01/00 + cheat + description:Hit anywhere + code:d971/11/00+d980/02/18+d97f/b0/ea + cheat + description:99 Hammers on pick-up + code:ead0/a9/90+ead1/01/f4 + cheat + description:Small hearts worth 2 + code:de4a/01/02 + cheat + description:Small hearts worth 5 + code:de4a/01/05 + cheat + description:Small hearts worth 135 + code:de4a/01/87 + cheat + description:Big hearts worth 20 + code:de4d/0a/14 + cheat + description:Big hearts worth 255 + code:de4d/0a/f7 + cheat + description:Get best ending with 8uuuuu uuuuuu uuuuuu uuuuuu code + code:818a/00/01 + +cartridge sha256:a11eec5762a029c95a5d496c0671b73e663225be50a5b1e89f16f380637b6665 + name:Kid Klown in Night Mayor World (USA) + cheat + description:Invincibility + code:af76/d0/f0 + cheat + description:Infinite health + code:8849/8d/ad + cheat + description:Infinite lives + code:8873/01/00 + cheat + description:Full health from hearts + code:8c03/03/00 + cheat + description:Less health from hearts + code:8bf7/05/02 + cheat + description:More health from hearts + code:8bf7/05/0a + cheat + description:Mega-jump (don't hold jump down too long or you might get stuck) + code:a687/ee/2c + cheat + description:Infinite chances in sub-game (press Start to re-enter the main game) + code:875d/c6/24 + 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 + name:Kid Kool and the Quest for the Seven Wonder Herbs (USA) + cheat + description:Invincibility + code:d1e3/a5/85 + cheat + description:Infinite time + code:8c19/e6/a6 + cheat + description:Infinite lives + code:cd4a/c6/a5 + cheat + description:Press Start to complete the level + code:c8a3/33/0c+c8a5/33/0b+c8a2/45/a9 + cheat + description:Hit anywhere - throwing + code:c82c/ad/b0+c82d/07/56 + cheat + description:Multi-jump when falling + code:92a2/f0/d0+92a3/d4/9c+929f/a1/c9+92a1/cd/01+92a0/d0/29 + cheat + description:One life after continue + code:cd59/03/01 + cheat + description:Start with one life + code:c065/03/01 + cheat + description:Start with double lives + code:c065/03/06 + cheat + description:Start with triple lives + code:c065/03/09 + cheat + description:Invincibility (alt) + code:0031/09 + cheat + description:Infinite lives (alt) + code:0015/09 + +cartridge sha256:81a77623adf819f10548052075555998c1ec1ef5f4dc4bf6ff6b6c3fa3541c1b + name:Kid Niki - Radical Ninja (USA) (Rev A) + cheat + description:Invincibility (glitchy) + code:8e0d/85/a5+8deb/85/a5 + cheat + description:Infinite lives + code:9ddc/c6/24 + cheat + description:Infinite time + code:bcd8/01/00 + cheat + description:Hit anywhere + code:8db0/8a/18+c21e/fd/60+8db1/48/60 + cheat + description:Higher jump + code:893a/e8/ff + cheat + description:Multi-jump + code:9a7e/10/00+9a84/0a/00+9a9b/2d/00+ff02/ff/10+ff0b/ff/60+ff08/ff/20+ff03/ff/04+ff00/ff/24+ff09/ff/2d+ff05/ff/ec+9a9c/89/ff+ff0a/ff/89+ff04/ff/a9+ff07/ff/19+ff06/ff/85+ff01/ff/57 + cheat + description:Less time + code:823b/06/04+9e81/06/04 + cheat + description:Start with 1 life + code:8216/03/01 + cheat + description:Start with 6 lives + code:8216/03/06 + cheat + description:Start on round 2 + code:81e7/00/01+81be/00/01 + cheat + description:Start on round 3 + code:81e7/00/02+81be/00/02 + cheat + description:Start on round 4 + code:81e7/00/03+81be/00/03 + cheat + description:Start on round 5 + code:81e7/00/04+81be/00/04 + cheat + description:Start on round 6 + code:81e7/00/05+81be/00/05 + 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 + name:Kid Niki - Radical Ninja (USA) + cheat + description:Invincibility + code:81c9/00/80 + cheat + description:Hit anywhere + code:8d9f/8a/18+c23b/fd/60+8da0/48/60 + cheat + description:Multi-jump + code:9a72/1b/00+ff02/ff/10+ff0b/ff/60+ff08/ff/20+ff03/ff/04+ff00/ff/24+9a5a/f0/24+9a54/f0/24+ff05/ff/ec+ff09/ff/1b+9a73/89/ff+ff0a/ff/89+ff04/ff/a9+ff07/ff/19+ff06/ff/85+ff01/ff/57 + 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 + name:King Kong 2 - Ikari no Megaton Punch (Japan) + cheat + description:Infinite health and lives + code:f156/95/b5 + cheat + description:Infinite Rocks + code:8569/8d/ad + cheat + description:Start with max health + code:e0d8/01/09+e0d7/00/99 + cheat + description:Start with 9 lives + code:e929/02/09 + +cartridge sha256:6cc3a973288a4c3c96a967bdf1be74eee909d3f5eb16ce0b405f20ce565c66cc + name:King Neptune's Adventure (USA) (Unl) + cheat + description:Infinite health + code:d6ae/ce/ad+d4b3/ce/ad+d675/8d/ad + cheat + description:Infinite lives + code:ce5e/ce/ad + cheat + description:Infinite Bubble Bombs + code:f9a5/c6/a5 + cheat + description:Start with all treasures (removes all items from level) + code:c4b3/f8/00 + cheat + description:Start with 99 Bubble Bombs and Money + code:c4bc/00/63 + cheat + description:Start with 99 Seahorses and Keys + code:cd3d/00/63 + +cartridge sha256:3249d267ca17098077bb94eee437f354066971bc03c0d06eada05efd92b0fa52 + name:King of Kings, The (USA) (v5.0) (Unl) + cheat + description:Infinite health + code:0512/06 + +cartridge sha256:dc6859332ca69a8361bb3eb8ba1ff638f4bbbc7837a3a9f8a474e05f6bc379ea + name:King of Kings, The (USA) (v1.3) (Unl) + cheat + description:Infinite health + code:0512/06 + +cartridge sha256:9ae715b6f2400d21f5d1ec426ecf310aa68ca46f3b37b37d5ae115f34049676b + name:King of Kings, The (USA) (v1.2) (Unl) + cheat + description:Infinite health + code:0512/06 + +cartridge sha256:d1002d407b544d70b4ddf4515665f6e18ac9c8ee2efd4be184e5240119fd6f70 + name:King of Kings, The (USA) (v1.1) (Unl) + cheat + description:Infinite health + code:0512/06 + +cartridge sha256:be97bca71e1bf099ef0f6ff91aed506df7b0506433c76e5deccea7b130e3a20f + name:King's Knight (USA) + cheat + description:Infinite health + code:a16e/85/24 + cheat + description:Only lose 1 HP when hit + code:a168/e5/e9+a169/10/01 + cheat + description:Start with double usual health + code:b1d8/0c/18 + cheat + description:Start with half usual health + code:b1d8/0c/06 + cheat + description:Start with a better character + code:b1de/00/01 + cheat + description:Start with the best character normally possible + code:b1de/00/02 + cheat + description:Start with a super character, better than normally Possible + code:b1de/00/05 + cheat + description:Infinite health (alt) + code:009a/0c + +cartridge sha256:1250a80faf865aa5ee5585ad7639e5ef2b3fa541554effda5fad2cc5dc2acef5 + name:Kirby's Adventure (USA) (Rev A) + cheat + description:Invincibility + code:847b/f0/d0 + cheat + description:Infinite health + code:9e05/8d/ad + cheat + description:Infinite lives + code:e4c1/ce/a5 + cheat + description:Hit anywhere (spitting) + code:819d/e9/18+819e/07/18+807a/60/80+8078/fd/4c+81cd/b0/24+8079/74/c6 + cheat + description:Inhale from anywhere + code:825b/42/00+827f/90/50+827c/ed/ad + cheat + description:Less health from 'pep drinks' + code:b243/08/02 + cheat + description:More health from 'pep drinks' + code:b243/08/10 + cheat + description:Full health from 'pep drinks' + code:b243/08/2f + cheat + description:Start with less health + code:a7f2/2f/1f + cheat + description:Start with more health + code:a7f2/2f/4f + cheat + description:Start with 2 lives + code:a7ed/04/01 + cheat + description:Start with 9 lives + code:a7ed/04/08 + cheat + description:Start with 17 lives + code:a7ed/04/10 + 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 + name:Kirby's Adventure (USA) + cheat + description:Invincibility + code:847b/f0/d0 + cheat + description:Infinite health + code:9e05/8d/ad + cheat + description:Infinite lives + code:e4c1/ce/a5 + cheat + description:Hit anywhere (spitting) + code:80c5/0d/00+81a5/36/00+8094/e9/18+8095/07/18+81cd/b0/24 + cheat + description:Inhale from anywhere + code:825b/42/00+8284/b0/24 + cheat + description:Less health from 'pep drinks' + code:b243/08/02 + cheat + description:More health from 'pep drinks' + code:b243/08/10 + cheat + description:Full health from 'pep drinks' + code:b243/08/2f + cheat + description:Start with less health + code:a7f2/2f/1f + cheat + description:Start with more health + code:a7f2/2f/4f + cheat + description:Start with 2 lives + code:a7ed/04/01 + cheat + description:Start with 9 lives + code:a7ed/04/08 + cheat + description:Start with 17 lives + code:a7ed/04/10 + 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 + name:Kiwi Kraze - A Bird-Brained Adventure! (USA) + cheat + description:Invincibility + code:c53c/f0/d0 + cheat + description:Super-jump + code:e545/fc/fa + cheat + description:Infinite lives + code:c7db/d6/b5 + cheat + description:Infinite time + code:a015/c6/a5 + cheat + description:Infinite time underwater + code:c640/c6/a5 + cheat + description:Infinite continues + code:c90a/d6/2c + cheat + description:1 life after continue + code:c907/02/00 + cheat + description:6 lives after continue + code:c907/02/05 + cheat + description:9 lives after continue + code:c907/02/08 + cheat + description:Start with 1 life (and 1 continue) + code:c373/02/00 + cheat + description:Start with 6 lives (and 6 continues) + code:c373/02/05 + cheat + description:Start with 9 lives (and 9 continues) + code:c373/02/08 + cheat + description:Start on level 2 + code:c368/8d/2c+c367/00/04 + cheat + description:Start on level 3 + code:c368/8d/2c+c367/00/08 + cheat + description:Start on level 4 + code:c368/8d/2c+c367/00/0c + cheat + description:Start on level 5 + code:c368/8d/2c+c367/00/11 + +cartridge sha256:ef63df6bcbc7e13dace53f106a247485a09409799b99c8415e934ba532cdaa53 + name:KlashBall (USA) + cheat + description:Very little team stamina - select the middle team + code:b939/28/05 + cheat + description:More team stamina - select the middle team + code:b939/28/40 + cheat + description:Mega team stamina - select the middle team + code:b939/28/99 + cheat + description:Power is doubled for the whole team - select the middle team + code:b93c/02/04 + cheat + description:Power is tripled for the whole team - select the middle team + code:b93c/02/06 + cheat + description:Mega power for the whole team - select the middle team + code:b93c/02/09 + cheat + description:Never lose stamina - select the middle team + code:a680/9d/2c + cheat + description:Computer can't score - select the middle team + code:845a/e6/a5 + cheat + description:Everyone including computer has 255 skill - select the middle team + code:a05e/38/2c+a05e/fd/2c + +cartridge sha256:28b3f1dde1488dd83422da47300d2e31ffce811bf2be37bf6d510019c2289f40 + name:Klax (USA) (Unl) + cheat + description:Infinite drops + code:bca3/e6/a5 + cheat + description:When starting on level 6, 0 drops allowed + code:8c7f/04/01 + cheat + description:When starting on level 6, 5 drops allowed + code:8c7f/04/05 + cheat + description:When starting on level 11, 0 drops allowed + code:8c92/05/01 + cheat + description:When starting on level 11, 3 drops allowed + code:8c92/05/03 + cheat + description:Start with 0 drops allowed + code:8c6d/03/01 + cheat + description:Start with 5 drops allowed + code:8c6d/03/05 + cheat + description:Level select + code:0000/00 + +cartridge sha256:b66538543d3c4c74448e896130081c39112b14898beffbe95137a410394e5dc9 + name:Knight Rider (USA) + cheat + description:Infinite shield + code:d62f/85/a5 + cheat + description:Infinite missiles + code:af0b/ce/ad + cheat + description:Infinite laser + code:aea5/ce/2c + cheat + description:Infinite lives + code:80ac/ce/ad+80cd/ce/ad + cheat + description:Start with 1 life after continue + code:80e3/02/00 + cheat + description:Start with 6 lives after continue + code:80e3/02/05 + cheat + description:Start with 9 lives after continue + code:80e3/02/08 + cheat + description:Start with 1 life + code:c879/02/00+c87d/8d/ee + cheat + description:Start with 6 lives + code:c879/02/05+c87d/8d/ee + cheat + description:Start with 99 missiles + code:a147/bd/ad+a148/6e/73 + cheat + description:Start with 99 lasers + code:a153/bd/ad+a154/74/79 + cheat + description:Start with full gasoline + code:a130/bd/ad+a131/66/68 + cheat + description:Start with full shield + code:a13c/bd/ad+a13d/6a/6d + +cartridge sha256:e5673075301b0c84137d24aff0ffbfa0565d33c960968d9843d7bc57f1107417 + name:Krion Conquest, The (USA) + cheat + description:Infinite health + code:dbf6/85/a5 + cheat + description:Infinite lives + code:bde1/c6/a5 + cheat + description:Float spell + code:c69f/16/00 + cheat + description:Quicker supershot + code:cde1/04/01 + cheat + description:Less energy used for fire spell + code:f0a3/08/04+f096/09/05 + cheat + description:Start with 1 life + code:8140/02/00 + cheat + description:Start with 6 lives + code:8140/02/05 + cheat + description:Start with 9 lives + code:8140/02/08 + cheat + description:Start on stage 2 + code:812a/00/01+8129/a9/a0+812d/85/84 + cheat + description:Start on stage 3 + code:812a/00/02+8129/a9/a0+812d/85/84 + cheat + description:Start on stage 4 + code:812a/00/03+8129/a9/a0+812d/85/84 + 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 + name:Krusty's Fun House (USA) + cheat + description:Infinite health + code:a038/0a/00 + cheat + description:Infinite pies - first life only + code:a4c1/ce/2c + cheat + description:Pick-up Super Balls instead of Custard Pies + code:ab9d/01/00 + cheat + description:Start with 1 life + code:8046/03/01 + cheat + description:Start with 6 lives + code:8046/03/06 + cheat + description:Start with 9 lives + code:8046/03/09 + cheat + description:Start with 6 pies + code:804b/09/06 + cheat + description:Start with 18 pies + code:804b/09/12 + +cartridge sha256:0ba5e69962f6576d3729aa967092a7e8c98d00213cd98026dee343bff67b4177 + name:Kung Fu (Japan, USA) + cheat + description:Infinite health + code:ace0/06/30+ace1/ad/8e + cheat + description:Infinite health and one hit kills + code:c466/14+c47e/eb + cheat + description:Infinite time + code:8831/20/ad + cheat + description:Infinite lives - both players + code:8882/b5 + cheat + description:Invincibility against knives + code:bfd6/d0/24 + cheat + description:Don't die when time runs out + code:c76d/85/24+c76f/4c/60 + cheat + description:Hit anywhere + code:c257/c9/00 + cheat + description:Enemies die when trying to grab you + code:a5c6/d0/24+a5c9/4d/ec+a5ca/a6/a5+a793/4c/60 + cheat + description:Enemies easier to shrug off + code:a5eb/69/00 + cheat + description:Enemies harder to shrug off + code:a5e9/04/0a + cheat + description:Give P2 an advantage + code:84ac/85 + cheat + description:Knife thrower harder to beat + code:ab38/4a/fa + cheat + description:Normal enemies do more damage + code:af8d/01/03 + cheat + description:Walk 2X faster + code:9b7f/ff/fe+9b7e/01/02 + cheat + description:Walk 4X faster + code:9b7e/01/04+9b7f/ff/fc + cheat + description:Start at last level reached - P1 + code:8436/24 + cheat + description:Start at last level reached - P2 + code:8439/24 + cheat + description:Start with 1 life - both players + code:84ab/01 + cheat + description:Start with 9 lives - both players + code:84ab/09 + 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 + name:Kung-Fu Heroes (USA) + cheat + description:Invincibility + code:c127/0a/00+d6b9/bd/60 + cheat + description:Infinite lives + code:b3d2/01/00 + cheat + description:Infinite Miracle Kicks + code:d0e9/01/00 + cheat + description:Hit anywhere (most enemies) + code:d3f0/20/ad + cheat + description:2 E-balls for an extra life + code:bc28/05/02 + cheat + description:Use with warp to start with 1 life + code:a957/03/01 + cheat + description:Use with warp to start with 6 lives + code:a957/03/06 + cheat + description:Use with warp to start with 9 lives + code:a957/03/09 + cheat + description:Mega-jumps left and right + code:cc19/01/04+cc21/ff/fc + cheat + description:Start with 20 Miracle Kicks + code:a962/00/14 + cheat + description:Start with 1 life + code:a95d/05/01 + cheat + description:Start with 9 lives + code:a95d/05/09 + cheat + description:Start on Castle 2 + code:a952/a5/a9+a953/cd/04 + cheat + description:Start on Castle 3 + code:a952/a5/a9+a953/cd/08 + cheat + description:Start on Castle 4 + code:a952/a5/a9+a953/cd/0c + cheat + description:Start on Castle 5 + code:a952/a5/a9+a953/cd/10 + cheat + description:Start on Castle 6 + code:a952/a5/a9+a953/cd/14 + cheat + description:Start on Castle 7 + code:a952/a5/a9+a953/cd/18 + cheat + description:Start on Castle 8 + code:a952/a5/a9+a953/cd/1c + +cartridge sha256:f4b7d8d31c5bbfee69c117332fa3878d04dc3b6e693d1a343d3ef2f20b10a85e + name:Last Action Hero (USA) + cheat + description:Infinite health + code:bc95/46/a5 + cheat + description:One hit kills on bosses + code:a0a3/f0/d0 + cheat + description:Infinite lives + code:bca1/c6/a5 + cheat + description:Infinite continues + code:e50a/c6/a5 + cheat + description:Red hearts worth nothing + code:8f50/e6/a6 + cheat + description:Continue with 1 life + code:e550/03/00 + cheat + description:Continue with 2 lives + code:e550/03/01 + cheat + description:Continue with 3 lives + code:e550/03/02 + cheat + description:Start with 1 life + code:ee3d/03/00 + cheat + description:Start with 7 lives + code:ee3d/03/06 + cheat + description:Start with 10 lives + code:ee3d/03/09 + cheat + description:Start with 0 continues + code:ee41/02/00 + cheat + description:Start with 5 continues + code:ee41/02/05 + cheat + description:Start with 9 continues + code:ee41/02/09 + cheat + description:Start on stage 2 - Hamlet + code:e0f0/00/02 + cheat + description:Start on stage 3 - The House + code:e0f0/00/04 + cheat + description:Start on stage 4 - The Freeway + code:e0f0/00/05 + cheat + description:Start on stage 5 - The Office block + code:e0f0/00/06 + cheat + description:Start on stage 6 - The Helicopter + code:e0f0/00/07 + cheat + description:Start on stage 7 - The Film Premiere + code:e0f0/00/08 + cheat + description:Start on Stage 8 - The Cinema + code:e0f0/00/09 + cheat + description:Start on the end-of-level bad guy + code:e0f0/00/0a + 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:333d9de968973202f641714d746012237dc9d65fb592aac10c6146ed1f2fdaeb + name:Last Armageddon (Japan) + cheat + description:No random battles + code:fe93/c9/a9 + cheat + description:Walk anywhere + code:9a57/80/00 + +cartridge sha256:f15382be46e474c596566c5a726ae39dadfa18289722bac2da44b6493bbabfec + name:Last Ninja, The (USA) + cheat + description:Infinite health + code:8ad8/85/a5 + cheat + description:Press Select on controller 2 to skip to next level, A for next screen, B for previous screen + code:e507/d0/f0 + cheat + description:Infinite lives + code:007d/09 + cheat + description:Infinite time (seconds) + code:0369/00 + +cartridge sha256:54dd62754f48e39af39c3e8d645897af25aaba31523267bc41d4c95f2b0348d5 + name:Last Starfighter, The (USA) + cheat + description:Infinite lives - both players + code:9660/c6/a5 + cheat + description:Stop irritating shake + code:94b3/85/24 + cheat + description:Start with 1 life - both players + code:8b7f/05/01 + cheat + description:Start with 6 lives - both players + code:8b7f/05/06 + cheat + description:Start with 9 lives - both players + code:8b7f/05/09 + cheat + description:Start with 1 life - P2 + code:8b86/85/84 + cheat + description:Start on level 5 - P1 + code:8b6c/00/04+8b6f/85/24+8b71/85/24 + cheat + description:Start on level 10 - P1 + code:8b6c/00/09+8b6f/85/24+8b71/85/24 + cheat + description:Start on level 14 - P1 + code:8b6c/00/0d+8b6f/85/24+8b71/85/24 + +cartridge sha256:53923dcb59afac40fbfed4aa2298be156b5b9763ec43956757ec44092ba799c5 + name:Layla (Japan) + cheat + description:Infinite energy + code:e1d6/c6/a5 + cheat + description:Infinite Machine Gun ammo + code:d4e1/c6/a5 + cheat + description:Infinite Dynamite Sticks + code:d5e9/c6/a5 + cheat + description:Infinite Grenades + code:d51f/c6/a5 + +cartridge sha256:203dc9486ba58e65f9a4289da476dc15ff34d6fd39d355b438ae4db2d182746d + name:Legacy of the Wizard (USA) + cheat + description:Infinitel ife + code:e7e2/85/24 + cheat + description:Infinite magic + code:e7f7/c6/24 + cheat + description:Never lose items + code:e4db/d6/24 + cheat + description:Shopkeeper forgets to charge + code:e84b/85/24 + cheat + description:No enemies + code:e99f/91/b1 + cheat + description:Walk through walls + code:dd99/4c + cheat + description:Lyll's strength tripled + code:ffb4/01/03 + cheat + description:Lyll's jumping improved + code:ffb3/1a/30 + cheat + description:Roas' strength tripled + code:ffb0/01/03 + cheat + description:Roas' jumping improved + code:ffaf/14/2a + cheat + description:Xemn's strength tripled + code:ffa8/03/09 + cheat + description:Xemn's jumping improved + code:ffa7/12/20 + cheat + description:Menya's strength tripled + code:ffac/02/06 + cheat + description:Menya's jumping improved + code:ffab/14/20 + +cartridge sha256:d2a585ff6febf59447f9bd9fbb387ae4985385d6f6f61a70e145a5ee69523018 + name:Legendary Wings (USA) + cheat + description:Almost infinite health + code:830c/01/00+8586/01/00 + cheat + description:Hit anywhere + code:8b88/f2/00+8358/ef/00+843a/ec/00+8b98/e2/00+8b90/ea/00+8382/99/ad+839a/99/ad + cheat + description:Gain double powers on pick-up + code:8275/01/02+85e1/01/02 + cheat + description:Gain triple powers on pick-up + code:8275/01/03+82e1/01/02 + cheat + description:Start with 1 life - P1 + code:8783/03/01 + cheat + description:Start with 6 lives - P1 + code:8783/03/06 + cheat + description:Start with 9 lives - P1 + code:8783/03/09 + cheat + description:Start with 1 life - both players + code:8778/03/01 + cheat + description:Start with 6 lives - both players + code:8778/03/06 + cheat + description:Start with 9 lives - both players + code:8778/03/09 + 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 + name:Legends of the Diamond - The Baseball Championship Game (USA) + cheat + description:Balls are considered strikes + code:b53a/29/a9 + cheat + description:1 ball and you walk + code:b5c0/04/01 + cheat + description:2 balls and you walk + code:b5c0/04/02 + cheat + description:6 balls to walk + code:b5c0/04/06 + cheat + description:1 strike and you're out (fouls don't count as strikes) + code:b55c/03/01 + cheat + description:2 strikes and you're out (fouls don't count as strikes) + code:b55c/03/02 + cheat + description:5 strikes and you're out (fouls don't count as strikes) + code:b55c/03/05 + +cartridge sha256:9d83796d8feba9713fa5a1354fd9253cda5cb33ab5bc6f1c6f97d5eb90aef6c3 + name:Legend of Kage, The (USA) + cheat + description:Invincibility + code:9b76/85/a5 + cheat + description:Infinite lives - both players + code:82e3/c6/a5 + cheat + description:Hit anywhere with Shurikens + code:acdf/0a/00+acd3/16/00+acaf/6b/00 + cheat + description:Hit anywhere with Sword + code:ad06/14/00+ad12/08/00+acaf/6b/00 + cheat + description:Kill the white boss (you do not need to kill the butterfly) + code:acaf/6b/00 + cheat + description:Super-ninja-power running ability + code:8b51/02/04 + cheat + description:Super-ninja-power jumping ability + code:a14f/04/0f+a150/04/0f+a151/04/0f + cheat + description:Start with 28 lives - both players + code:8096/86/84 + cheat + description:Infinite lives - P1 + code:002b/63 + +cartridge sha256:1849bb687d038a43971651b13392481768ea0bc15f3d04b6898f052bbfa356e5 + name:Legend of the Ghost Lion (USA) + cheat + description:Infinite Courage points + code:9f37/8d/ad + cheat + description:Infinite Dream points + code:c5ae/8d/ad + cheat + description:Buy items for free in most shops (must have enough rubies to purchase item) + code:c4db/8d/ad + 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 + name:Legend of Zelda, The (USA) (Rev A) + cheat + description:Invincibility (blinking) + code:ec7d/b9 + cheat + description:Infinite life + code:b3e0/ad/60 + cheat + description:Have the Pink Ring (infinite life) + code:9e55/15/62 + cheat + description:Have Blue Ring effect + code:b3cd/06/d0 + cheat + description:Have Red Ring effect + code:b3cd/06/d1 + cheat + description:All items are free + code:a568/ce/ad+88ee/43/00 + cheat + description:Fewer enemies + code:8897/c0/00 + cheat + description:No dark rooms + code:b68f/f0/10 + cheat + description:No Zolas + code:86e6/08/00 + cheat + description:Reset counter to zero + code:a532/01 + cheat + description:Speed writing + code:8818/91 + cheat + description:Skip text + code:8873/05/00+885d/1b/00 + cheat + description:Walk faster + code:b387/a5/a9+b388/00/b0 + cheat + description:Walk through walls in dungeons + code:91a9/85/a5+914b/f0/60 + cheat + description:Create character with 8 life hearts + code:9f41/22/77 + cheat + description:Create character with 16 life hearts + code:9f41/22/ff + cheat + description:Invincibility + code:7b3a/60 + cheat + description:Invincibility (blinking) (alt) + code:04f0/09 + cheat + description:Infinite life (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 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 Bombs + code:0658/10 + 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 + name:Legend of Zelda, The (USA) + cheat + description:Invincibility (blinking) + code:ec7d/b9 + cheat + description:Infinite life + code:b3e0/ad/60 + cheat + description:Have the Pink Ring (infinite life) + code:9e59/15/62 + cheat + description:All items are free + code:a568/ce/ad+88ee/43/00 + cheat + description:Almost no enemies in Overworld + code:9325/04/00+9326/05/00+9327/06/00 + cheat + description:Fewer enemies + code:8897/c0/00 + cheat + description:No dark rooms + code:b68f/f0/10 + cheat + description:No Zolas + code:86e6/08/00 + cheat + description:Reset counter to zero + code:a532/01 + cheat + description:Speed writing + code:8818/91 + cheat + description:Skip text + code:8873/05/00+885d/1b/00 + cheat + description:Walk faster + code:b387/a5/a9+b388/00/b0 + cheat + description:Walk through walls in dungeons + code:919f/85/a5+9141/f0/60 + cheat + description:Create character with 8 life hearts + code:9f41/22/77 + cheat + description:Create character with 16 life hearts + code:9f41/22/ff + cheat + description:Invincibility + code:7b3a/60 + cheat + description:Invincibility (blinking) (alt) + code:04f0/09 + cheat + description:Infinite life (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 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 Bombs + code:0658/10 + 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 + name:Lemmings (USA) + cheat + description:Infinite time + code:e0b3/c6/a5 + cheat + description:Infinite climbers + code:e16e/c6/a5 + cheat + description:Infinite floaters + code:e198/c6/a5 + cheat + description:Infinite bombers + code:e1c7/c6/a5 + cheat + description:Infinite blockers + code:e211/c6/a5 + cheat + description:Infinite builders + code:e261/c6/a5 + cheat + description:Infinite bashers + code:e2ab/c6/a5 + cheat + description:Infinite miners + code:e304/c6/a5 + cheat + description:Infinite diggers + code:e357/c6/a5 + +cartridge sha256:97c67809c952bc25060a01dca224eedc5ed76cc770bac44452c92cd3a1d4a418 + name:Lethal Weapon (USA) + cheat + description:Infinite ammo when shooting on the ground + code:d55c/99/b9 + cheat + description:Infinite ammo when shooting in the air + code:d5dd/99/b9+d5a1/99/b9 + cheat + description:E restores health completely + code:d8e2/10/40 + cheat + description:E worth nothing + code:d8e2/10/00 + cheat + description:Extra ammo restores ammo completely + code:d8c8/10/40 + cheat + description:Extra ammo worth nothing (if you run out of ammo you can't use gun till next stage) + code:d8c8/10/00 + cheat + description:No health lost when falling off screen + code:f8b2/20/00 + cheat + description:Falling off screen is fatal + code:f8b2/20/40 + cheat + description:Bullet proof vest lasts longer + code:d8f5/30/ff + cheat + description:Bullet proof vest lasts until end of stage, except when you die from punches or falling off screen + code:c9b9/ca/ea + cheat + description:Bullet proof vest does not last as long + code:d8f5/30/0a+d8f5/30/10 + cheat + description:Start on Level 2 + code:c236/ca/ea + cheat + description:Start on Level 3 + code:c233/be/a2+c234/97/03+c235/c0/ea + 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 + name:Life Force (USA) + cheat + description:Infinite lives + code:c345/d6/24 + cheat + description:Keep pods after death + code:c653/95/24 + cheat + description:Hit anywhere + code:d231/1e/00+d23e/0d/00+d273/a9/60+d24a/90/d0 + cheat + description:One hit kills most enemies + code:d299/e9/a9 + cheat + description:Press Start to finish the level + code:fd96/24/4e+fd94/01/02 + cheat + description:Start with Speed + code:c6c1/00/01 + cheat + description:Start with Missile + code:c6c1/00/02 + cheat + description:Start with Ripple + code:c6c1/00/03 + cheat + description:Start with Laser + code:c6c1/00/04 + cheat + description:Start with Option + code:c6c1/00/05 + cheat + description:Start with Force Field + code:c6c1/00/06 + cheat + description:Start at the volcanic stage + code:eeb5/00/01 + cheat + description:Start at the prominence stage + code:eeb5/00/02 + cheat + description:Start at cell stage 2 + code:eeb5/00/03 + cheat + description:Start at the temple stage + code:eeb5/00/04 + cheat + description:Start at the mechanical city stage + code:eeb5/00/05 + cheat + description:Start with 1 life + code:eecf/03/01 + cheat + description:Start with 6 lives + code:eecf/03/06 + 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 + name:Lightgun Game 2 in 1 - Cosmocop + Cyber Monster (Asia) (Unl) + cheat + description:Cosmo Cop - Infinite lives + code:cbaf/ce/ad + cheat + description:Cosmo Cop - Infinite ammo + code:cb22/8d/ad + cheat + description:Cosmo Cop - Infinite energy + code:cb68/ce/ad+cb6b/ce/ad + cheat + description:Cyber Monster - Infinite misses + code:9550/ce/60 + +cartridge sha256:745164dee8e4af6a7150d21e9ef082f56a51b01c5c32f28cdf4cd211bed3714d + name:Lightgun Game 2 in 1 - Tough Cop + Super Tough Cop (Asia) (Unl) + cheat + description:Infinite health + code:037a/06 + +cartridge sha256:cecc797ffc82c5764e89038262c00b325f44afc0d9fc4b5bef295ea227e1dd22 + name:Lion King, The (Europe) + cheat + description:Invincibility + code:837d/f0/d0+b467/f0/d0 + cheat + description:Infinite lives + code:84f8/ce/ad + +cartridge sha256:475c35c18b5e958122473bcca52d54438e1734b1b74dc295492eba6d29927193 + name:Little League Baseball - Championship Series (USA) + cheat + description:Balls are considered strikes + code:d336/f0/a9 + cheat + description:Always hit a homerun (press B while the ball is in play) + code:b311/df/40+b30f/c1/93 + +cartridge sha256:68e98b1b8dc5da610321f92718b4b4c2b2b71b6c752ff25ca6926e26cd91c57f + name:Little Mermaid, The (USA) + cheat + description:Invincibility + code:c9d5/f0/d0+818b/f0/d0 + cheat + description:Invincibility after one hit + code:c9d7/c6/a5 + cheat + description:Infinite lives + code:d359/c6/a5 + cheat + description:Keep red pearls after dying + code:d353/85/24 + cheat + description:Keep green pearls after dying + code:d355/85/24 + cheat + description:Get all pearls after dying + code:d352/00/03 + cheat + description:Start with all red pearls + code:c64c/00/03+c64e/e9/3d + cheat + description:Start with all green pearls + code:c64c/00/03+c64e/e9/3e + cheat + description:Start with 1 heart + code:c654/03/01+c720/03/01 + cheat + description:Start with 5 hearts + code:c654/03/05+c720/03/05 + cheat + description:Start with 1 life + code:c650/02/00 + cheat + description:Start with 6 lives + code:c650/02/05 + cheat + description:Start with 9 lives + code:c650/02/08 + cheat + description:Start on Ursula stage + code:c64c/00/05 + cheat + description:Start on stage 2 + code:c64c/00/01 + cheat + description:Start on stage 3 + code:c64c/00/02 + cheat + description:Start on stage 4 + code:c64c/00/03 + cheat + description:Start on stage 5 + code:c64c/00/04 + +cartridge sha256:e95d3557fa60bacabe7a0b65277cdf2f084b6f58b55784d3d631ab030def0a91 + name:Little Nemo - The Dream Master (USA) + cheat + description:Infinite life + code:e0c4/ce/ad + cheat + description:Infinite lives + code:cb1d/c6/a5 + cheat + description:Mega-jump + code:afc4/0a/16 + cheat + description:Speed jumps + code:b1d7/01/04+b13d/fe/fb + cheat + description:Super speed + code:b1a3/01/02+b109/fe/fd + cheat + description:Start with 1 life + code:cacd/03/01 + cheat + description:Start with 6 lives + code:cacd/03/06 + cheat + description:Start with 9 lives + code:cacd/03/09 + cheat + description:Start on stage 2 + code:cab9/00/01 + cheat + description:Start on stage 3 + code:cab9/00/02 + cheat + description:Start on stage 4 + code:cab9/00/03 + cheat + description:Start on stage 5 + code:cab9/00/04 + cheat + description:Start on stage 6 + code:cab9/00/05 + cheat + description:Start on stage 7 + code:cab9/00/06 + cheat + description:Start on stage 8 + code:cab9/00/07 + 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 + name:Little Ninja Brothers (USA) + cheat + description:Invincibility + code:b132/d0/50 + cheat + description:Invincibility to water + code:afd2/5e/ad + cheat + description:Infinite Life + code:b148/99/b9 + cheat + description:Infinite Dragon Kicks + code:b4bf/0d/00 + cheat + description:Infinite money + code:d9d1/ad/60 + cheat + description:Mighty Ball always available + code:9a8c/01/00 + cheat + description:T-Star always available + code:9b3d/ad/60 + cheat + description:All T-Stars + code:9b2f/29/a9 + cheat + description:Max money after fights + code:d99c/02/00 + cheat + description:Quick level up + code:d926/1a/00 + cheat + description:Start with 255 Life + code:da3c/0a/ff + cheat + description:Start with 50 Attack + code:da3d/01/32 + 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 + name:Little Samson (USA) + cheat + description:Invincibility against enemies + code:825b/d0/10 + cheat + description:Infinite health + code:8269/fd/2c + cheat + description:Infinite lives + code:e498/c6/24 + cheat + description:Hit anywhere + code:8435/b0/30 + cheat + description:Collectable items never disappear + code:aacd/de/60 + cheat + description:Increase health gauge - Little Samson + code:e5c1/08/18 + cheat + description:Increase health gauge - Kikira the Dragon + code:e5c2/08/18 + cheat + description:Increase health gauge - Gamm the Golem + code:e5c3/10/20 + cheat + description:Increase health gauge - K.O. the Mouse + code:e5c4/04/10 + cheat + description:Increase health - Little Samson + code:e5c5/08/18 + cheat + description:Increase health - Kikira the Dragon + code:e5c6/08/18 + cheat + description:Increase health - Gamm the Golem + code:e5c7/10/20 + cheat + description:Increase health - K.O. the Mouse + code:e5c8/04/10 + cheat + description:Crystal ball adds 4 units to health gauge + code:aa30/04/08 + cheat + description:Small hearts give 4 health units + code:a9de/02/08 + cheat + description:Infinite health - Little Samson + code:0097/08 + cheat + description:Infinite health - Kikira the Dragon + code:0098/08 + cheat + description:Infinite health - Gamm the Golem + code:0099/0f + cheat + description:Infinite health - K.O. the Mouse + code:009a/04 + +cartridge sha256:33c362ea3dbce2ac449e0d877d85904c26fcaf4b197e27b23efe9cbe67f20e15 + name: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 + name:Lode Runner (USA) + cheat + description:Invincibility + code:c49d/f0/24+c496/f0/24+c473/f0/24 + cheat + description:Infinite lives + code:c577/c6/24 + cheat + description:Moonwalk + code:d114/30/10 + cheat + description:Heavy gravity + code:cc36/07/04+cc40/04/00 + cheat + description:Start with 1 life + code:c65b/05/01 + cheat + description:Start with 10 lives + code:c65b/05/0a + +cartridge sha256:622ef597b328a204fafcef55c9aef0de08489a43898a6c9adaa9d39971e06f69 + name:Lone Ranger, The (USA) + cheat + description:Infinite health - side views only + code:c14f/85/24 + cheat + description:Infinite regular and silver bullets + code:a85b/01/00 + cheat + description:Items are free + code:a50f/e5/60 + cheat + description:Cheaper silver bullets + code:a7b6/0a/05 + cheat + description:Cheaper standard bullets + code:a7b5/05/02 + cheat + description:Don't lose money when shooting bystanders + code:a857/46/24+a859/66/24 + cheat + description:Walk anywhere - Overworld + code:a9d4/85/a5 + cheat + description:Start with 255 dollars + code:f5ce/64/ff + cheat + description:Start with 10 silver bullet rounds + code:f5d6/05/0a + cheat + description:Start with 15 silver bullet rounds + code:f5d6/05/0f + cheat + description:Start with 15 standard bullet rounds + code:f5d2/0a/0f + cheat + description:Start with 30 standard bullet rounds + code:f5d2/0a/1e + 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:fbf9426155adf3b8a57b9123760c88f2c61f33fb2f6c5b21c894d5d83dd19138 + name:Loopz (USA) + cheat + description:Infinite time to place blocks + code:0090/ff + cheat + description:Level modifier + code:0086/00 + +cartridge sha256:4fb6c5c8359dcbabcb4d05cf36192c790e68a509ef8666c20ebdb81541df3243 + name:Low G Man - The Low Gravity Man (USA) + cheat + description:Invincibility + code:a11e/f0/60+a45e/2a/27 + cheat + description:Infinite life (blinking) + code:880f/8d/ad + cheat + description:Infinite ammo - secondary weapon + code:8bbc/de/ad + cheat + description:Infinite vehicle fuel + code:d96c/ce/ad + cheat + description:Infinite time + code:d947/ce/2c + cheat + description:Infinite lives + code:d870/ce/ad + cheat + description:Hit anywhere + code:a0aa/1b/00+a0e3/20/ad + cheat + description:Get items from anywhere + code:a19b/0a/00 + cheat + description:Full life gained from capsules + code:a600/02/08 + cheat + description:Less life gained from capsules + code:a600/02/01 + cheat + description:Full EMDP on a new life + code:d86c/01/03 + cheat + description:Full AGM on a new life + code:d864/00/02 + cheat + description:10 Boomerangs on pick-up + code:a692/03/0a + cheat + description:10 Fireballs on pick-up + code:a66c/03/0a + cheat + description:10 Bombs on pick-up + code:a6b8/03/0a + cheat + description:10 Waves on pick-up + code:a6de/03/0a + cheat + description:1 life after continue + code:d89c/03/01 + cheat + description:6 lives after continue + code:d89c/03/06 + cheat + description:9 lives after continue + code:d89c/03/09 + cheat + description:Start with 1 life + code:d6a2/03/01 + cheat + description:Start with 6 lives + code:d6a2/03/06 + cheat + description:Start with 9 lives + code:d6a2/03/09 + 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:9cdcac614a14e0aefe34d6333bc23ef3e08986144d2dacd322835aad8ec62add + name:Lunar Pool (USA) + cheat + description:Infinite Balls + code:01c3/63 + +cartridge sha256:52812b55986f96fa77eb24a76e795dc8d79977eec7488c7b5b84ac3b47d60366 + name:M.C. Kids (USA) + cheat + description:Infinite lives + code:d9cb/8d/2c + cheat + description:Infinite hearts + code:e607/05/c0 + cheat + description:Don't lose Golden Arches when hit + code:e5ff/05/c0 + cheat + description:Multi-jump + code:812d/c0/3c+812c/ad/a9+812e/04/ea + cheat + description:Super-jump + code:86ec/04/18+86e9/03/00 + cheat + description:1 heart per life + code:d748/02/00+d9cf/02/00 + cheat + description:8 hearts per life + code:d748/02/07+d9cf/02/07 + cheat + description:Always find all cards in level + code:f66d/0c/00+f669/ad/a9+f66a/19/01+f66b/04/ea + cheat + description:Access any level on the map + code:84a3/01/00 + cheat + description:Start with 2 lives + code:d743/03/01 + cheat + description:Start with 7 lives + code:d743/03/06 + cheat + description:Start with 10 lives + code:d743/03/09 + +cartridge sha256:345fe1e466b3e8d7a8b7f01f545808793b120ad17ed8497ddc306e205b2589a3 + name:M.U.L.E. (USA) + cheat + description:4 'months' for beginner game + code:86c3/06/04 + cheat + description:9 'months' for beginner game + code:86c3/06/09 + cheat + description:6 'months' for standard game + code:86a5/0c/06 + cheat + description:20 'months' for standard game + code:86a5/0c/14 + cheat + description:Humanoids start with $400 + code:8719/58/90+871e/02/01 + cheat + description:Humanoids start with $800 + code:8719/58/20+871e/02/03 + cheat + description:Flappers start with $1300 + code:8730/40/14+8735/06/05 + cheat + description:Flappers start with $2000 + code:8730/40/d0+8735/06/07 + +cartridge sha256:d10e4280b6ca868142061ab731aeb378c983334b89a1727a524c57c241812d13 + name:M.U.S.C.L.E. - Tag Team Match (USA) + cheat + description:Invincibility - P1 team + code:8239/a5/a9+823a/4f/63 + cheat + description:Set bout length timer to 20 + code:81db/03/02 + cheat + description:Set bout length timer to 60 + code:81db/03/06 + cheat + description:Set bout length timer to 90 + code:81db/03/09 + cheat + description:Computer controlled players jump faster + code:99bb/01/02 + cheat + description:Computer controlled players speed up + code:a058/01/02 + +cartridge sha256:944105c6dcc57314968d53a2e0dcdfc0e2b60678a53839ba25925416a7ac0e8c + name:Mach Rider (Japan, USA) (Rev A) + cheat + description:Infinite energy + code:ac87/c4+bfea/83 + cheat + description:Infinite lives + code:d35a/a6 + cheat + description:Infinite time - solo and endurance courses + code:ac65/a5 + cheat + description:Infinite Shots + code:ca64/b6 + cheat + description:Bike Never Explode + code:bfc2/e4 + cheat + description:Never lose bike abilities (color) + code:bfc8/65 + cheat + description:Super Speed + code:83ad/a5+83b3/a5 + cheat + description:No winter + code:c677/ad + +cartridge sha256:ef238662a27934d6dbe1692e822786a74a9a2c8bc58c38aa0fd5cfb3e2f1abce + name:Mach Rider (Japan, USA) + cheat + description:Infinite energy + code:ac87/c4+bfea/83 + cheat + description:Infinite lives + code:d35a/a6 + cheat + description:Infinite time - solo and endurance courses + code:ac65/a5 + cheat + description:Infinite Shots + code:ca64/b6 + cheat + description:Bike Never Explode + code:bfc2/e4 + cheat + description:Never lose bike abilities (color) + code:bfc8/65 + cheat + description:Super Speed + code:83ad/a5+83b3/a5 + cheat + description:No winter + code:c677/ad + +cartridge sha256:80757aa85fe4001123cb839db0fc72fc7e06020ecba5c89abb049b8490fd3d0b + name:Mad Max (USA) + cheat + description:Infinite ammo + code:8ee0/ce/ad + cheat + description:No damage done to car + code:87f9/10/00 + cheat + description:Less damage done to car + code:87f9/10/04 + cheat + description:More damage done to car + code:87f9/10/20 + cheat + description:No damage done to you + code:8833/08/00 + cheat + description:Less damage done to you + code:8833/08/04 + cheat + description:More damage done to you + code:8833/08/10 + cheat + description:A better tune-up + code:e1cb/20/60 + cheat + description:Dynamite is free + code:8279/01/00 + cheat + description:Ammo is free + code:826c/01/00 + cheat + description:Cheaper arena pass + code:8286/07/04+824b/37/34 + cheat + description:Start with full food and water + code:ff06/20/ff + cheat + description:Start with less ammo + code:ff13/80/40 + +cartridge sha256:ab0a43bc7c33f0cdd8acf15c4da967ba2af56431de1a598b9767bd10e78cc8fa + name:Mafat Conspiracy, The (USA) + cheat + description:Infinite bullets + code:c292/c6/24 + cheat + description:Infinite time + code:da76/ca/ea + cheat + description:Immune to physical damage + code:ce71/f1/24 + cheat + description:Immune to weapon damage + code:cd1d/f9/2c + cheat + description:Immune to damage in maze + code:c1f1/fd/2c + cheat + description:Fewer bullets on pick-up + code:cd53/0a/05 + cheat + description:More bullets on pick-up + code:cd53/0a/14 + cheat + description:Faster timer + code:da70/3c/20 + cheat + description:Slower timer + code:da70/3c/70+da65/3c/70 + +cartridge sha256:2eee5b14a90458088ac18c36352ab605ae4fe452a59f2675937acee0d15e94b6 + name:Magic Carpet 1001 (Unl) + cheat + description:Invincibility + code:8487/38/60 + +cartridge sha256:9a5d7367891f4d929fe5e3be5fe2988e3e6c0b0d70b7cd401976f16b3b5f0a9d + name:Magic Jewelry (Asia) (Unl) + cheat + description:Bypass checksum check + code:e7b0/d0/24+e7a8/d0/24 + cheat + description:Speed never increases + code:ec87/6d/00+ec86/a6/a2 + cheat + description:Disable Game Over + code:e7bf/90/24 + +cartridge sha256:caae56599689d4297c3be1afdc77d5bfc510d47d6e668244c308b9732eb41dea + name: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 + name:Magic of Scheherazade, The (USA) + cheat + description:Invincibility + code:f4b2/29/a9 + cheat + description:Infinite HP + code:a45b/e5/e9 + cheat + description:Infinite lives + code:e389/c6/a5 + cheat + description:Hit anywhere + code:f487/03/00+f47d/90/30+f47b/c5/a5+f47e/09/26+f47c/09/cb + cheat + description:Never lose Mashroobs + code:8c00/ce/ad + cheat + description:Get coins from anywhere + code:8ba2/03/06 + cheat + description:Less energy gained from Bread + code:8ac1/32/19 + cheat + description:Less magic gained from Mashroobs + code:8c0a/05/02 + cheat + description:Start with only 20 Gold Coins + code:e230/05/02 + cheat + description:Start with 1 life + code:e240/03/01 + cheat + description:Start with 6 lives + code:e240/03/06 + cheat + description:Start with 9 lives + code:e240/03/09 + 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 + name:Magmax (USA) + cheat + description:Infinite lives - 1P game + code:e66f/c6/a5 + cheat + description:Infinite lives - 2P game + code:e68d/01/00 + cheat + description:Start with 1 life - both players + code:cbc4/02/00 + cheat + description:Start with 6 lives - both players + code:cbc4/02/05 + cheat + description:Start with 9 lives - both players + code:cbc4/02/08 + 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 + name:Maniac Mansion (USA) + cheat + description:All codes start out as 0000 + code:c8a4/a5/85 + +cartridge sha256:6bc8f71a1d19cab1a1364c7e2988eaec25b2694aa29670360cab6c513f1c47ac + name:Mappy (Japan) + cheat + description:Invincibility + code:dada/d0/50+da81/f0/24 + cheat + description:Disable Hurry! timer + code:f30a/e6/24 + cheat + description:Infinite time - Bonus stages + code:ca0b/c6/24 + cheat + description:Press Start to complete stage + code:c22d/05/60+c228/45/a9+c22c/f0/01+c22a/85/8d+c22b/23/3e+c229/23/86 + cheat + description:Ropes don't change color when jumping on them + code:dc1f/de/ad+e21a/de/ad + cheat + description:Disable trap floors + code:f0c6/99/ad + cheat + description:Collect items from anywhere - normal stages + code:f1ce/d0/24+f1d9/b0/24 + cheat + description:Collect Red Balloons from anywhere - Bonus stages + code:f1ce/d0/24+f1d9/b0/24 + +cartridge sha256:7d07d335a873205964299b2735c14fe06170329523341a651f275cdf3ed96f18 + name:Mappy-Land (USA) + cheat + description:Infinite lives + code:a64d/c6/a5 + cheat + description:Start with 1 toy + code:a3d8/03/01 + cheat + description:Start with coins, not toys + code:a3d0/00/03 + cheat + description:Start with fish, not toys + code:a3d0/00/01 + cheat + description:Start with pots, not toys + code:a3d0/00/02 + cheat + description:Start with 1 life + code:a0ae/02/00 + cheat + description:Start with 6 lives + code:a0ae/02/05 + cheat + description:Start with 6 toys + code:a3d8/03/06 + +cartridge sha256:d77ed527cf081019dc8e1cad72872ef3bd640114221b89f030e0c03229c54ddc + name:Marble Madness (USA) + cheat + description:Infinite time + code:a2eb/d6/a9 + cheat + description:Don't break from falling + code:c370/d0/f0 + cheat + description:Cannot fall into bottomless pits + code:c147/a9+880b/a5+c201/a9/ad + cheat + description:Extra 20 seconds to complete beginner race + code:a391/00/14 + cheat + description:Extra 40 seconds to complete beginner race + code:a391/00/28 + cheat + description:Bonus time not added + code:a38e/b0/24 + cheat + description:Infinite time (alt) + code:0044/3c + cheat + description:Max score - P1 + code:004a/63+004b/63+004c/63 + +cartridge sha256:0cc334007d3eae698cdcd034d12ec9bab2b5266e85bc703cf24ccb4e2d63b654 + name:Mario Bros. (World) + cheat + description:Invincibility + code:dce0/d6/60 + cheat + description:Infinite time - bonus rounds + code:e371/ce/de + cheat + description:Infinite time - bonus rounds (alt) + code:e371/ce/ad + cheat + description:Infinite power blocks + code:d2f5/c6/a5 + cheat + description:Infinite lives + code:dce0/a5 + cheat + description:Stops green fireball from appearing + code:e795/ad/60 + cheat + description:Stops red fireball from appearing + code:ea82/01/00 + cheat + description:Move faster + code:c8f5/00/01 + cheat + description:Move much faster + code:c8f5/00/02 + cheat + description:Enemies move faster + code:c908/a4/a0+c909/c7/02 + cheat + description:Enemies move much faster + code:c908/a4/a0+c909/c7/03 + cheat + description:Mega-jump + code:f350/fc/f6+f351/fc/f6 + cheat + description:Coins kill you + code:dcb3/40/00 + cheat + description:Start with 1 life + code:d359/00 + cheat + description:Start with 6 lives + code:d359/05 + cheat + description:Start with 9 lives + code:d359/08 + cheat + description:Infinite lives - P1 + code:0048/04 + cheat + description:Infinite lives - P2 + code:004c/04 + +cartridge sha256:c9348c4e30ef0bc62c4fd119b5e38d85af493a1eb436c6c229b7a6a52af42681 + name:Mario's Time Machine (USA) + cheat + description:Get an item after killing one Koopa + code:b7bc/00/02 + +cartridge sha256:a385f0bed8d9afd110e649b73084191d80f41728139494f8fcb92d4815cd5197 + name:Master Chu and the Drunkard Hu (USA) (Unl) + cheat + description:Invinicibility + code:90ed/fe/bd + cheat + description:Infinite health + code:9730/de/bd + cheat + description:Infinite lives + code:972e/d6/b5 + cheat + description:Start on round 2 + code:8103/01/02 + cheat + description:Start on round 3 + code:8103/01/03 + cheat + description:Start on round 4 + code:8103/01/04 + cheat + description:Start on round 5 + code:8103/01/05 + cheat + description:Start on round 6 + code:8103/01/06 + cheat + description:Start on round 7 + code:8103/01/07 + +cartridge sha256:c8486cd1a35950007a3ba671a128097d780084182a854d6115ddec7dad56e806 + name:Mechanized Attack (USA) + cheat + description:Infinite lives + code:f0b9/ce/ad + cheat + description:Infinite grenades + code:f13e/ce/ad + cheat + description:Infinite bullets + code:f105/ce/ad + cheat + description:Reduce damage by half + code:91e8/03/00 + cheat + description:Magazine holds half normal amount of bullets after first magazine used + code:f118/28/14+f003/28/14 + cheat + description:Start with only 1 life + code:c01d/a2/a0+c01e/00/01+c079/8e/8c + cheat + description:Start with 6 lives + code:c01d/a2/a0+c01e/00/06+c079/8e/8c + cheat + description:Start with 9 lives + code:c01d/a2/a0+c01e/00/09+c079/8e/8c + cheat + description:Start with only 1 magazine + code:c01d/a2/a0+c01e/00/00+c07e/8e/8c + cheat + description:Start with 8 magazines + code:c01d/a2/a0+c01e/00/07+c07e/8e/8c + cheat + description:Start with only 1 grenade + code:c01d/a2/a0+c01e/00/01+c082/8e/8c + cheat + description:Start with 8 grenades + code:c01d/a2/a0+c01e/00/08+c082/8e/8c + +cartridge sha256:5314ad0c406161195b6bb100ee11304bab8af121bba85992be896d5cb26b109e + name:Mega Man (USA) + cheat + description:Infinite health + code:a244/85/a5 + cheat + description:Invincibility (except against bosses) + code:a1eb/a5/60 + cheat + description:Infinite weapons on pick-up + code:a8d2/fd/0d + cheat + description:Infinite weapons on pick-up (alt) + code:a8d5/95/b5 + cheat + description:Infinite lives + code:c259/c6/a9 + cheat + description:One hit kills + code:c915/0b/00+bedf/90/d0 + cheat + description:One hit kills on bosses + code:f3a4/30 + cheat + description:Have all weapons + code:b41b/29/00+b2b6/ee/00+b1a1/52/00+b2a1/f0/a9 + cheat + description:Collectable items never disappear + code:b6b6/fe/bd + cheat + description:Climb up ladders faster + code:97f8/00/01 + cheat + description:Climb down ladders faster + code:982a/ff/fe + cheat + description:Disable boss invulnerability after hit + code:c968/85/24 + cheat + description:Maximum points for shooting enemies + code:b8d0/69/a9+b8d1/28/30 + cheat + description:Mega-jump + code:961f/04/06 + cheat + description:Multi-jump + code:95be/18/14+9cc6/b0/24+9583/29/bd+9584/96/95 + cheat + description:Enemies always drop extra lives + code:bf19/3b/41+bf21/c8/ea + cheat + description:Enemies always drop large health refill + code:bf19/3b/40+bf21/c8/ea + cheat + description:Enemies always drop large weapon refill + code:bf21/c8/ea+bf19/3b/3f + cheat + description:Start with half energy + code:912d/1c/0e + cheat + description:Start with 1 life + code:9053/02/00 + cheat + description:Start with 6 lives + code:9053/02/05 + cheat + description:Start with 9 lives + code:9053/02/08 + 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 + name:Mega Man 2 (USA) + cheat + description:Invincibility + code:ce36/f0/d0 + cheat + description:Invincibility (alt) + code:ce36/f0/50+ce34/a5/85 + cheat + description:Infinite health + code:e5a1/8d/ad + cheat + description:Infinite lives + code:c1b6/c6/a5 + cheat + description:Infinite Heat Man + code:ddd9/85/a5 + cheat + description:Infinite Air Man + code:dadf/85/a5 + cheat + description:Infinite Wood Man + code:df63/85/a5 + cheat + description:Infinite Bubble Man + code:db34/c6/a5 + cheat + description:Infinite Quick Man + code:db6f/c6/a5 + cheat + description:Infinite Metal Man + code:dbc9/c6/a5 + cheat + description:Infinite Clash Man + code:db8c/c6/a5 + cheat + description:Infinite 1 + code:dc76/c6/a5 + cheat + description:Infinite 2 + code:e224/c6/a5 + cheat + description:Infinite 3 + code:e340/c6/a5 + cheat + description:Hit anywhere (except bosses) + code:e632/90/d0+e686/b0/24+e659/d0/24+e664/f0/24+e621/b0/24 + cheat + description:One hit kills + code:e686/b0/24+a634/b0/24 + cheat + description:Burst-fire from normal weapon + code:da6d/27/23 + cheat + description:Maximum weapon energy on pick-up + code:834f/30/24 + cheat + description:Collectable items never disappear + code:bcf7/de/dd + cheat + description:Have all weapons + code:925b/25/a9+926e/25/a9+93e4/99/ad+9434/90/a9+9493/90/a9 + cheat + description:Main weapon can destroy Crash Blocks and Turrets + code:e664/f0/a9 + cheat + description:Power-jumps + code:8a71/04/06 + cheat + description:Super power-jumps + code:8a71/04/08 + cheat + description:Mega power-jumps + code:8a71/04/10 + cheat + description:Multi-jump + code:8b83/ad/20+858f/27/23+8b85/04/85+8b84/a0/8e + cheat + description:Moonwalking + code:8904/29/49 + cheat + description:Enemies always drop extra lives + code:f2ba/90/50+f2bb/cc/dd + cheat + description:Enemies always drop large health refill + code:f2ba/90/50+f2bb/cc/d9 + cheat + description:Enemies always drop large weapon refill + code:f2ba/90/50+f2bb/cc/d5 + cheat + description:Special items re-appear after being collected + code:e5e8/99/b9 + cheat + description:Can access already defeated boss stages + code:80e2/dc/00 + cheat + description:Stop Quick Man's stage beams + code:da09/04/ff + cheat + description:Start with half health + code:80c5/1c/0e + cheat + description:Start with 1 life + code:8073/03/01 + cheat + description:Start with 6 lives + code:8073/03/06 + cheat + description:Start with 9 lives + code:8073/03/09 + 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 + name:Mega Man 3 (USA) + cheat + description:Invincibility + code:80ae/d0/f0 + cheat + description:Infinite health + code:80e0/85/24 + cheat + description:Infinite health (alt) + code:80e0/85/a5 + cheat + description:Infinite lives + code:cb82/01/00 + cheat + description:Infinite weapons (except Top Man) + code:def6/99/b9 + cheat + description:Infinite Top Man + code:8292/85/a5 + cheat + description:Hit anywhere + code:fbd2/38/18+fbd3/bd/60 + cheat + description:One hit kills + code:81ca/02/00 + cheat + description:Mega-jump + code:ceb9/04/07 + cheat + description:Multi-jump + code:cd9b/07/36+cdb1/d0/ce+ce39/90/24 + cheat + description:Longer slides + code:d3ae/14/50 + cheat + description:Faster slides + code:d3c0/80/ff + cheat + description:Move faster + code:cd42/4c/ff + cheat + description:Move mega-fast + code:cd47/01/02 + cheat + description:Collectable items never disappear + code:be3f/de/dd + cheat + description:Enemies always drop extra lives + code:bf72/90/a0+bf73/09/05+bf76/f8/06 + cheat + description:Enemies always drop large health refill + code:bf72/90/a0+bf73/09/03+bf76/f8/06 + cheat + description:Enemies always drop large weapon refill + code:bf72/90/a0+bf73/09/01+bf76/f8/06 + cheat + description:Special items re-appear after being collected + code:9caa/d4/00 + cheat + description:Able to access already defeated boss stages + code:931c/d5/00 + cheat + description:Start with 1 life + code:c8fc/02/00 + cheat + description:Start with 6 lives + code:c8fc/02/05 + cheat + description:Start with 9 lives + code:c8fc/02/08 + cheat + description:Start with 1 life after continue + code:991f/02/01 + cheat + description:Start with 6 lives after continue + code:991f/02/05 + cheat + description:Start with 9 lives after continue + code:991f/02/08 + 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 + name:Mega Man 4 (USA) (Rev A) + cheat + description:Infinite health + code:81ed/85/24 + cheat + description:Infinite health (alt) + code:81ed/85/a5 + cheat + description:Infinite weapons + code:fd88/99/b9 + cheat + description:Infinite weapon power + code:fd88/99/2c + cheat + description:Always have 10 E-Tanks + code:98f8/a5/86 + cheat + description:Infinite lives + code:c833/c6/a5 + cheat + description:Infinite energy pods on pick-up + code:96f2/c6/24 + cheat + description:Instant full Mega Buster + code:8095/09/00 + cheat + description:Instant full Mega Buster (alt) + code:8ccd/18/23 + cheat + description:Hit anywhere + code:fa44/b9/18+fa45/28/60 + cheat + description:Hit anywhere continually + code:fa44/b9/18+fa45/28/60+fa42/f0/24 + cheat + description:Longer slides + code:8185/1a/2f + cheat + description:Shorter slides + code:8185/1a/12 + cheat + description:Faster slides + code:8194/02/04 + cheat + description:Mega-jump + code:814f/05/08 + cheat + description:Multi-jump + code:80fb/c8/30+810f/82/81+8133/90/24 + cheat + description:Move faster + code:c679/01/02+83e3/01/02 + cheat + description:Cosack can't hurt you + code:8880/85/a5 + cheat + description:Collectable items never disappear + code:be3f/de/dd + cheat + description:Enemies always drop extra lives + code:bb97/06/00+bb9a/f8/03 + cheat + description:Enemies always drop large health refill + code:bb97/06/00+bb9a/f8/03+bb90/04/02 + cheat + description:Enemies always drop large weapon refill + code:bb97/06/00+bb9a/f8/03+bb90/04/05 + cheat + description:Special items re-appear after being collected + code:9caa/d4/00 + cheat + description:Start with 1 life + code:c53a/02/00 + cheat + description:Start with 6 lives + code:c53a/02/05 + cheat + description:Start with 79 lives + code:c53a/02/08 + 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 + name:Mega Man 4 (USA) + cheat + description:Infinite health + code:81ed/85/24 + cheat + description:Infinite health (alt) + code:81ed/85/a5 + cheat + description:Infinite weapons + code:fd88/99/b9 + cheat + description:Infinite weapon power + code:fd88/99/2c + cheat + description:Always have 10 E-Tanks + code:98f8/a5/86 + cheat + description:Infinite lives + code:c833/c6/a5 + cheat + description:Infinite energy pods on pick-up + code:96f2/c6/24 + cheat + description:Instant full Mega Buster + code:8095/09/00 + cheat + description:Instant full Mega Buster (alt) + code:8ccd/18/23 + cheat + description:Hit anywhere + code:fa44/b9/18+fa45/28/60 + cheat + description:Hit anywhere continually + code:fa44/b9/18+fa45/28/60+fa42/f0/24 + cheat + description:Longer slides + code:8185/1a/2f + cheat + description:Shorter slides + code:8185/1a/12 + cheat + description:Faster slides + code:8194/02/04 + cheat + description:Mega-jump + code:814f/05/08 + cheat + description:Multi-jump + code:80fb/c8/30+810f/82/81+8133/90/24 + cheat + description:Move faster + code:c679/01/02+83e3/01/02 + cheat + description:Collectable items never disappear + code:be3f/de/dd + cheat + description:Enemies always drop extra lives + code:bb97/06/00+bb9a/f8/03 + cheat + description:Enemies always drop large health refill + code:bb97/06/00+bb9a/f8/03+bb90/04/02 + cheat + description:Enemies always drop large weapon refill + code:bb97/06/00+bb9a/f8/03+bb90/04/05 + cheat + description:Special items re-appear after being collected + code:9caa/d4/00 + cheat + description:Start with 1 life + code:c53a/02/00 + cheat + description:Start with 6 lives + code:c53a/02/05 + cheat + description:Start with 9 lives + code:c53a/02/08 + 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 + name:Mega Man 5 (USA) + cheat + description:Infinite health + code:82df/85/24 + cheat + description:Invincible against spikes + code:804a/05/85 + cheat + description:Infinite lives + code:85a0/c6/24 + cheat + description:Infinite weapons + code:954f/99/b9+b5fa/99/b9+8254/85/a5 + cheat + description:Infinite energy for most weapons + code:b5f2/e5/e9+9547/e5/e9 + cheat + description:Infinite mega-tanks on pick-up + code:82d9/c6/24 + cheat + description:Infinite energy tanks on pick-up + code:8156/c6/24 + cheat + description:Hit anywhere + code:f017/b9/18+f018/28/60 + cheat + description:Hit anywhere continually + code:f017/b9/18+f018/28/60+f015/f0/24 + cheat + description:One hit kills + code:81b2/2d/00 + cheat + description:Starting weapons use less energy + code:b1e3/04/01 + cheat + description:Super-jump + code:80ae/05/07+80bb/fb/f9 + cheat + description:Mega-jump + code:80ae/05/01+80bb/fb/f7 + cheat + description:Multi-jump + code:8046/15/8d+806a/82/80+8090/90/24 + cheat + description:Collectable items never disappear + code:ae49/de/60 + cheat + description:Enemies always drop extra lives + code:ae86/90/50+ae80/04/03 + cheat + description:Enemies always drop large health refill + code:ae86/90/50+ae80/04/01 + cheat + description:Enemies always drop large weapon refill + code:ae86/90/50 + cheat + description:Special items re-appear after being collected + code:99be/d5/00 + cheat + description:Start with at least 2 energy tanks + code:de4b/80/82 + cheat + description:Start with at least 6 energy tanks + code:de4b/80/86 + cheat + description:Start with at least 2 mega-tanks + code:de51/80/82 + cheat + description:Start with at least 6 mega-tanks + code:de51/80/86 + 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 + name:Mega Man 6 (USA) + cheat + description:Invincibility + code:8ea4/f0/d0 + cheat + description:Infinite health + code:8f86/8d/ad + cheat + description:Infinite health (except fires, falling into pits and spikes) + code:8f84/e5/24 + cheat + description:Infinite weapons + code:9ea2/99/b9 + cheat + description:Infinite Rush Jet + code:8265/c6/a5 + cheat + description:Infinite lives (can sometimes die and go to another part of the game) + code:8e8a/c6/a5 + cheat + description:Normal shots do more damage + code:8c9c/11/13 + cheat + description:Mega shots do more damage + code:8ccf/13/16 + cheat + description:Hit anywhere and shoot to pick-up items + code:ecef/05/03 + cheat + description:One hit kills + code:ebeb/0a/00+ebea/b1/a9 + cheat + description:Multi-jump + code:810f/0f/40+8111/c8/80+8112/05/d0+8110/ad/29+810e/d0/a5+8113/30/ca+8114/0a/ea + cheat + description:Collectable items never disappear + code:92ae/de/c3 + cheat + description:Enemies always drop extra lives + code:81f5/19/00+821c/49/37+821b/4a/37+8219/39/37+821a/38/37 + cheat + description:Enemies always drop large health refill + code:81f5/19/00+821c/49/39+821d/37/39+821b/4a/39+821a/38/39 + cheat + description:Enemies always drop large weapon refill + code:81f5/19/00+821c/49/4a+821d/37/4a+8219/39/4a+821a/38/4a + cheat + description:Start with 9 lives + code:cd3e/02/08 + cheat + description:Start with 6 lives + code:cd3e/02/05 + cheat + description:Start with 1 life + code:cd3e/02/00 + 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 + name:Menace Beach (USA) (Unl) + cheat + description:Infinite health and one hit kills (levels 1-9, 11, 12 only) + code:e169/38/e0+e16b/11/f0+e16c/b0/06+e16d/02/ea+e16a/e5/00 + cheat + description:Infinite health and one hit kills (level 10 only) + code:e169/38/e0+e16b/11/f0+e16c/b0/06+e16d/02/ea+e16a/e5/01 + cheat + description:Multi-jump + code:f441/a5/a9+f442/62/82 + +cartridge sha256:1152961edf8d484f0e33294ae19fbcac8ab85099e6c8a59f1732c5f17b622885 + name:Mendel Palace (USA) + cheat + description:Infinite lives + code:da52/de/bd + cheat + description:More stars on pick-up + code:d5a0/01/05 + cheat + description:P1 gains P2's speed-ups + code:d931/bd/ad+d938/fe/ee + cheat + description:More lives - P1 + code:bca2/8d/8c + cheat + description:More lives - P2 + code:bca5/8d/8c + cheat + description:Start with 1 life + code:a163/02/00 + cheat + description:Start with 5 lives + code:a163/02/05 + cheat + description:Start with 9 lives + code:a163/02/08 + cheat + description:Automatically finish level + code:051b/00 + +cartridge sha256:25f5359a73cac2d16ed98940f0b537f0392f232554d457ed476e21a5979419ff + name:Metal Force (K) + cheat + description:Invincibility + code:e7a6/d0/f0+e772/d0/f0+e817/d0/f0 + cheat + description:Invincible against spikes + code:e851/d0/f0 + cheat + description:Infinite energy + code:97f6/00/10+97fb/02/1c + cheat + description:Infinite lives + code:e6e2/8d/ad + cheat + description:Keep whatever weapon you started the level with + code:d2b6/8d/ad + cheat + description:Start with max weapon power + code:8391/00/02 + cheat + description:Start on Mission 7 + code:8396/01/07 + +cartridge sha256:f6d29afbd7ddad33672852232791a396695de2e77dccb83088a8d6b139d8c9cb + name:Metal Gear (USA) + cheat + description:Infinite life + code:eae2/c6/a5+f231/c6/a5 + cheat + description:Invincible against Gas + code:b487/c6/a5 + cheat + description:Invincible against Electric Floors + code:ba5e/c6/a5 + cheat + description:Infinite Rations + code:aea8/c6/a5 + cheat + description:Infinite Handgun ammo + code:ef5e/c6/a5 + cheat + description:Infinite Mines + code:ee8b/84/a4 + cheat + description:Infinite Explosives + code:eea8/86/a6 + cheat + description:Infinite Missiles + code:eeec/86/a6 + cheat + description:Infinite Machine Gun ammo + code:ef4a/c6/a5 + cheat + description:Infinite Grenades + code:ef0a/84/a4 + cheat + description:Infinite Rockets + code:eecf/86/a6 + cheat + description:Have all weapons + code:ac5c/a2/a9+ac5d/00/ff+ac5e/a5/85 + cheat + description:Enemies never attack or chase you + code:dc73/95/b5 + cheat + description:Hit anywhere - Punch + code:e305/eb/00+e311/df/00+e319/d7/00+e2ef/90/50 + cheat + description:Hit anywhere - Weapons except Grenade Launcher + code:f25f/f0/50 + cheat + description:Start with a life boost + code:d768/a6/a2+d769/6e/01+d7ca/05/08 + cheat + description:Start with a super life boost + code:d768/a6/a2+d769/6e/01+d7ca/05/0c + cheat + description:Start at mystery location 1 + code:d753/01/02 + cheat + description:Start at mystery location 2 + code:d753/01/04 + 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 + name:Metal Mech - Man & Machine (USA) + cheat + description:Invincibility + code:8f32/20/ad + cheat + description:Infinite health + code:97f7/8d/ad+9868/8d/ad + cheat + description:Infinite lives - Tony + code:f600/ce/ad + cheat + description:Infinite Smart Bombs + code:f565/ce/ad + cheat + description:Super-jumping Tony + code:a0fe/ff/fe + cheat + description:Super-speeding Tony + code:a08c/05/02 + cheat + description:Mega-speeding Tony + code:a08c/05/01 + cheat + description:Start with 1 life and 1 Smart Bomb + code:d3cd/03/01 + cheat + description:Start with 6 lives and 6 Smart Bombs + code:d3cd/03/06 + cheat + description:Start with 9 lives and 9 Smart Bombs + code:d3cd/03/09 + cheat + description:Start on level 2 + code:d3d8/ff/00 + cheat + description:Start on level 3 + code:d3d8/ff/01 + cheat + description:Start on level 4 + code:d3d8/ff/02 + cheat + description:Start on level 5 + code:d3d8/ff/03 + cheat + description:Start on level 6 + code:d3d8/ff/04 + cheat + description:Infinite health (alt) + code:05dd/1f + +cartridge sha256:2fbbc465fc239b483cb89582f75451b21276d97868d67f3d8d89c2269fec5e37 + name:Metal Storm (USA) + cheat + description:Invincibility + code:e674/85/a5+b71d/85/a5 + cheat + description:Infinite time + code:f5c8/c6/a5 + cheat + description:Infinite lives + code:975f/01/00 + cheat + description:Slower timer + code:f5c1/3c/60 + cheat + description:Faster timer + code:f5c1/3c/20 + cheat + description:Permanent Fireball + code:ead4/0c/00 + cheat + description:Permanent Shield + code:afda/7c/00 + cheat + description:Start with extra weapons + code:bbf1/00/ff + cheat + description:Start with 6 lives + code:bbaf/02/06 + cheat + description:Start with 9 lives + code:bbaf/02/09 + +cartridge sha256:649db8035018f2512ccea70aca6606c3b3a6988cd9ed43953b38dc5103dec7bb + name:Metroid (USA) + cheat + description:Invincibility + code:fc44/9c/10+9e03/ad/60+fec2/20/60+f295/bd/60+f2b6/20/60+f2ef/20/60+fc43/20/90+e27b/84/90+9987/c9/a9+e27c/72/29 + cheat + description:Infinite health and Missiles, have all items + code:c934/30 + cheat + description:Infinite health + code:cea2/03/00 + cheat + description:Minimum energy of 30 + code:ced7/8d/ad + cheat + description:Always have Screw Attack effect + code:cd9c/38/18+cda0/88/60 + cheat + description:Infinite Missiles on pick-up + code:d333/ce/ad + cheat + description:Hit anywhere + code:f343/03/00+f2ca/b0/24+f53f/20/ff+f2d2/20/ad + cheat + description:Enemies die automatically + code:f541/29/00 + cheat + description:Beam has longer range + code:d505/55 + cheat + description:Easier bomb jumping + code:d679/14/00+d164/32/00 + cheat + description:Get items from anywhere + code:dbaf/46/00+f488/f0/24 + cheat + description:Gain 10 Missiles on pick-up + code:dbfa/05/0a + cheat + description:Gain 15 Missiles on pick-up + code:dbfa/05/0f + cheat + description:Gain 255 Missiles on pick-up + code:dbfa/05/ff + cheat + description:High-jump without High Jump Boots + code:cff4/18/12 + cheat + description:Mega-jump without High Jump Boots + code:cff4/18/0c + cheat + description:Mega-jump with High Jump Boots + code:cffd/12/0c + cheat + description:Multi-jump + code:d030/f0/24+cd10/f0/24 + cheat + description:Break any block + code:d61e/25 + cheat + description:No enemies + code:eb61/88 + cheat + description:Fall through the floor + code:e4a3/30 + cheat + description:Roll through walls, but loses energy (glitchy) + code:8588/d5 + cheat + description:Start with 70 energy + code:c926/03/07 + cheat + description:Infinite health and Missiles, have all items (alt) + code:69b2/01 + cheat + description:Have all items + code:6878/ff + cheat + description:Have Bombs + code:6878/3f + cheat + description:Have Ice Beam + code:6878/80 + cheat + description:Have Maru Mari (Morphing Ball) + code:6878/10 + cheat + description:Have Long Beam + code:6878/14 + cheat + description:Have Wave Beam + code:6878/40 + +cartridge sha256:77c9100f4d3f291dd751098d3291b14e824cc367696c9167d01051041e08b5cb + name:Michael Andretti's World GP (USA) + cheat + description:Infinite time + code:0565/01 + +cartridge sha256:2d40d51736c2fa22f0cccf686e92efee3a7ebb8fa4eee5032206bab099a5aaf6 + name:Mickey Mania 7 (Unl) + cheat + description:Infinite health + code:9186/ce/ad + cheat + description:Infinite lives + code:9507/ce/ad + cheat + description:Infinite Apples + code:9641/ce/ad + +cartridge sha256:826ace604eb7a657acedd98cd3479dbe1d3ebb087dd7a1b2ad299ab854c0d519 + name:Mickey Mouse 3 - Yume Fuusen (Japan) + cheat + description:Invincibility + code:af79/d0/f0 + cheat + description:Infinite health (life) + code:8849/8d/ad + cheat + description:Infinite lives + code:8874/8d/ad + +cartridge sha256:989243c99d6e58c4fbcc6999473e48a389eba22cf1d3cb95dbe4c8b1f3ce15d7 + name:Mickey Mousecapade (USA) + cheat + description:Invincibility + code:9a84/f0/d0+9ae7/f0/d0 + cheat + description:Infinite health + code:9691/e5/e9 + cheat + description:Infinite lives + code:9259/c6/a5 + cheat + description:Mickey and Minnie can shoot on any level + code:de50/0c/1c+de6e/02/03 + cheat + description:Start with 2 lives + code:91dd/04/01 + cheat + description:Start with 6 lives + code:91dd/04/05 + cheat + description:Start with 9 lives + code:91dd/04/08 + +cartridge sha256:1df64e9554fb9997ceeab9954b2b7f8aa6206509a15e09298014ba765d87c094 + name:Micro Machines (USA) (Unl) + cheat + description:Infinite lives + code:a6d2/ce/2c + cheat + description:Qualify every race + code:fac5/02/04 + cheat + description:Play with 9 lives + code:f7c8/03/09 + cheat + description:Ruff Trux after every race + code:fab2/03/01 + cheat + description:Kid out of game after every race + code:f857/03/01 + cheat + description:Win Championship race + code:fad1/01/04 + cheat + description:Faster Boat acceleration + code:801d/05/00 + cheat + description:Faster Sports Car acceleration + code:801c/05/00 + cheat + description:Faster Formula 1 acceleration + code:801e/05/00 + cheat + description:Faster Turbo Wheels(tm) acceleration + code:801f/05/00 + cheat + description:Faster 4x4 acceleration + code:8020/05/00 + cheat + description:Faster Tank acceleration + code:8022/02/00 + cheat + description:Faster Chopper acceleration + code:8023/05/00 + cheat + description:Quicker Boat deceleration + code:8026/09/00 + cheat + description:Quicker Sports Car deceleration + code:8025/09/00 + cheat + description:Quicker Formula 1 deceleration + code:8027/09/00 + cheat + description:Quicker Turbo Wheels deceleration + code:8028/09/00 + cheat + description:Quicker 4x4 deceleration + code:8029/09/00 + cheat + description:Quicker Tank deceleration + code:802b/02/00 + cheat + description:Quicker Chopper deceleration + code:802c/0f/00 + cheat + description:Higher bounce for Boats + code:8002/01/07 + cheat + description:Higher bounce for Sports cars + code:8001/01/05 + cheat + description:Higher bounce for Formula 1's + code:8003/01/07 + cheat + description:Higher bounce for Turbo Wheels + code:8004/01/07 + cheat + description:Higher bounce for 4x4's + code:8005/01/07 + cheat + description:Higher bounce for Tanks + code:8007/01/07 + cheat + description:Drive through vehicles + code:8dbd/19 + cheat + description:Start on race 5 + code:f7cd/00/04 + cheat + description:Start on race 10 + code:f7cd/00/09 + cheat + description:Start on race 15 + code:f7cd/00/0e + cheat + description:Start on race 20 + code:f7cd/00/13 + cheat + description:Start on race 25 (Final Race) + code:f7cd/00/18 + +cartridge sha256:31b8afd6e571d3ce8ddea49b813ceda2d350df3c84ceb5d8dd2c7a3a6de5ba88 + name:Micro Machines (USA) (Aladdin Compact Cartridge) (Unl) + cheat + description:Infinite lives + code:a67c/ce/2c + cheat + description:Qualify every race + code:fa25/02/04 + cheat + description:Play with 9 lives + code:f728/03/09 + cheat + description:Ruff Trux after every race + code:fa12/03/01 + cheat + description:Kid out of game after every race + code:f7b7/03/01 + cheat + description:Win Championship race + code:fa31/01/04 + cheat + description:Faster Boat acceleration + code:801d/05/00 + cheat + description:Faster Sports Car acceleration + code:801c/05/00 + cheat + description:Faster Formula 1 acceleration + code:801e/05/00 + cheat + description:Faster Turbo Wheels(tm) acceleration + code:801f/05/00 + cheat + description:Faster 4x4 acceleration + code:8020/05/00 + cheat + description:Faster Tank acceleration + code:8022/02/00 + cheat + description:Faster Chopper acceleration + code:8023/05/00 + cheat + description:Quicker Boat deceleration + code:8026/09/00 + cheat + description:Quicker Sports Car deceleration + code:8025/09/00 + cheat + description:Quicker Formula 1 deceleration + code:8027/09/00 + cheat + description:Quicker Turbo Wheels deceleration + code:8028/09/00 + cheat + description:Quicker 4x4 deceleration + code:8029/09/00 + cheat + description:Quicker Tank deceleration + code:802b/02/00 + cheat + description:Quicker Chopper deceleration + code:802c/0f/00 + cheat + description:Higher bounce for Boats + code:8002/01/07 + cheat + description:Higher bounce for Sports cars + code:8001/01/05 + cheat + description:Higher bounce for Formula 1's + code:8003/01/07 + cheat + description:Higher bounce for Turbo Wheels + code:8004/01/07 + cheat + description:Higher bounce for 4x4's + code:8005/01/07 + cheat + description:Higher bounce for Tanks + code:8007/01/07 + cheat + description:Drive through vehicles + code:8dbd/19 + cheat + description:Start on race 5 + code:f72d/00/04 + cheat + description:Start on race 10 + code:f72d/00/09 + cheat + description:Start on race 15 + code:f72d/00/0e + cheat + description:Start on race 20 + code:f72d/00/13 + cheat + description:Start on race 25 (Final Race) + code:f72d/00/18 + +cartridge sha256:a2b4b0fd54028f1bbbdef152d8f2a172270b60162802d298accd0c698d258c3d + name:Mighty Bomb Jack (USA) + cheat + description:Invincibility + code:979f/29/a9 + cheat + description:Invincibility (alt) + code:97b1/8d/ad+9b0a/8d/ad + cheat + description:Infinite lives + code:873a/ce/ae + cheat + description:Infinite time + code:87a3/ce/ad + cheat + description:Less time in game + code:879c/60/40 + cheat + description:More time in game + code:879c/60/80 + cheat + description:Enemies don't return from coin transformation + code:889d/ce/ad + cheat + description:Power coins are not used up + code:8b0a/ce/ad + cheat + description:Disable torture room + code:9ed7/03/81 + cheat + description:Jump through walls + code:98bb/01/02 + cheat + description:Start with 1 life + code:821a/03/01 + cheat + description:Start with 6 lives + code:821a/03/06 + cheat + description:Start with 9 lives + code:821a/03/09 + 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 + name:Mighty Bomb Jack (Japan) + cheat + description:Invincibility + code:9875/29/09 + cheat + description:Invincibility (alt) + code:9887/8d/ad+9be5/8d/ad + +cartridge sha256:ef8ccb38760604f5122e034ae0c4591362364632fe2dc2fa10f2660e15bd368f + name:Mighty Final Fight (USA) + cheat + description:Invincibility + code:cf2f/00/80 + cheat + description:Infinite lives + code:dd4f/c6/a5 + cheat + description:Infinite credits + code:941b/c6/a5 + cheat + description:Protection from most hazards + code:f92b/85/a5 + cheat + description:Cody is weaker + code:8638/b9/ad + cheat + description:Cody is stronger + code:85df/a4/a0+85e0/6b/05 + cheat + description:Cody is stronger and has a super-powerful normal punch + code:85df/a4/a0+85e0/6b/05+8885/0b/40 + cheat + description:Cody is much stronger + code:8638/b9/a9+8639/d6/40+863a/87/ea + cheat + description:Guy is weaker + code:8656/b9/ad + cheat + description:Guy is stronger + code:8607/a4/a0+8608/6b/05 + cheat + description:Guy is stronger and has a super-powerful normal punch + code:8607/a4/a0+8608/6b/05+8934/02/40 + cheat + description:Guy is much stronger + code:8656/b9/a9+8657/a8/40+8658/88/ea + cheat + description:Haggar is weaker + code:8674/b9/ad + cheat + description:Haggar is stronger + code:8627/a4/a0+8628/6b/03 + cheat + description:Haggar is stronger and has a super-powerful normal punch + code:8627/a4/a0+8628/6b/03+89cb/0d/40 + cheat + description:Haggar is much stronger + code:8674/b9/a9+8675/57/40+8676/89/ea + cheat + description:Gain EXP faster (10 pts at a time) (may be displayed incorrectly) + code:8ac2/a5/a9+8ac3/05/10 + cheat + description:Gain EXP much faster (20 pts at a time) (may be displayed incorrectly) + code:8ac2/a5/a9+8ac3/05/20 + cheat + description:Cody starts with 3/4 health (1st life only) + code:c841/40/30 + cheat + description:Cody starts with 1/2 health (1st life only) + code:c841/40/20 + cheat + description:Cody starts with 1/4 health (1st life only) + code:c841/40/10 + cheat + description:Cody starts with 3/4 health (after 1st life) + code:de4c/40/30 + cheat + description:Cody starts with 1/2 health (after 1st life) + code:de4c/40/20 + cheat + description:Cody starts with 1/4 health (after 1st life) + code:de4c/40/10 + cheat + description:Guy starts with 3/4 health (1st life only) + code:c842/30/24 + cheat + description:Guy starts with 1/2 health (1st life only) + code:c842/30/18 + cheat + description:Guy starts with 1/4 health (1st life only) + code:c842/30/0c + cheat + description:Guy starts with 3/4 health (after 1st life) + code:de52/30/24 + cheat + description:Guy starts with 1/2 health (after 1st life) + code:de52/30/18 + cheat + description:Guy starts with 1/4 health (after 1st life) + code:de52/30/0c + cheat + description:Haggar starts with 3/4 health (1st life only) + code:c843/50/3c + cheat + description:Haggar starts with 1/2 health (1st life only) + code:c843/50/28 + cheat + description:Haggar starts with 1/4 health (1st life only) + code:c843/50/14 + cheat + description:Haggar starts with 3/4 health (after 1st life) + code:de58/50/3c + cheat + description:Haggar starts with 1/2 health (after 1st life) + code:de58/50/28 + cheat + description:Haggar starts with 1/4 health (after 1st life) + code:de58/50/14 + cheat + description:Start with 2 lives (doesn't work on continues) + code:c7ee/05/01 + cheat + description:Start with 4 lives (doesn't work on continues) + code:c7ee/05/03 + cheat + description:Start with 8 lives (doesn't work on continues) + code:c7ee/05/07 + cheat + description:Start with 10 lives (doesn't work on continues) + code:c7ee/05/09 + cheat + description:Start with 1 credit + code:c7f2/03/01 + cheat + description:Start with 5 credits + code:c7f2/03/05 + cheat + description:Start with 7 credits + code:c7f2/03/07 + cheat + description:Start with 9 credits + code:c7f2/03/09 + 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 + name:MiG 29 - Soviet Fighter (USA) (Unl) + cheat + description:Keep weapon after death + code:db59/c6/a5 + cheat + description:Start with best weapon + code:c179/00/03 + cheat + description:More time to refuel + code:908a/00/ff + cheat + description:Less time to refuel + code:908a/00/03 + cheat + description:Start with 1 life + code:c174/03/00 + cheat + description:Start with 6 lives + code:c174/03/05 + cheat + description:Start with 9 lives + code:c174/03/08 + cheat + description:Start with 255 lives + code:c174/03/fe + cheat + description:Start on mission 2 + code:911f/a5/a9+9120/15/01+9122/51/da + cheat + description:Start on mission 3 + code:911f/a5/a9+9120/15/02+9122/51/da + cheat + description:Start on mission 4 + code:911f/a5/a9+9120/15/03+9122/51/da + cheat + description:Start on mission 5 + code:911f/a5/a9+9120/15/04+9122/51/da + cheat + description:Start on mission 6 + code:911f/a5/a9+9120/15/05+9122/51/da + +cartridge sha256:2ebab487204c42b0d9cf19c37bdc395e396226ca3eaa664907bf7f8216b3c4d3 + name:Mike Tyson's Punch-Out!! (Japan, USA) (Rev A) + cheat + description:Invincibility + code:8080/e5/00+82b5/f5/75 + cheat + description:Infinite health + code:8503/a2/60 + cheat + description:Infinite hearts + code:892b/00/09 + cheat + description:Infinite hearts (alt) + code:844e/e5/24 + cheat + description:Infinite stars + code:8168/1e/00 + cheat + description:Infinite stars once obtained + code:897e/f0/30 + cheat + description:Infinite time + code:87ab/8e/a2+87de/9d/bd + cheat + description:Infinite time (alt) + code:87de/9d/bd + cheat + description:Opponent cannot block punches + code:82b5/f5/75 + cheat + description:No health for opponent + code:881a/8d/60+84c7/8d/ad + cheat + description:No health replenishment for opponent + code:815b/20/ad + cheat + description:Take less damage + code:8160/6d/ad + cheat + description:Take even less damage + code:8163/20/ad + cheat + description:Normal punches do more damage + code:836e/04/00 + cheat + description:Instant win + code:9d3d/2f + cheat + description:Instant loss + code:9d3d/ab + cheat + description:First knockdown will be a TKO + code:9ddf/28 + cheat + description:Skip intro + code:a290/01/f8 + cheat + description:Start with and have infinite stars + code:8167/f0/30 + cheat + description:Start each round with 3 stars + code:8950/00/03 + 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 + name:Mike Tyson's Punch-Out!! (Japan, USA) + cheat + description:Invincibility + code:8080/e5/00+82b5/f5/75 + cheat + description:Infinite health + code:8503/a2/60 + cheat + description:Infinite hearts + code:892b/00/09 + cheat + description:Infinite hearts (alt) + code:844e/e5/24 + cheat + description:Infinite stars + code:8168/1e/00 + cheat + description:Infinite stars once obtained + code:897e/f0/30 + cheat + description:Infinite time + code:87ab/8e/a2+87de/9d/bd + cheat + description:Infinite time (alt) + code:87de/9d/bd + cheat + description:Opponent cannot block punches + code:82b5/f5/75 + cheat + description:No health for opponent + code:881a/8d/60+84c7/8d/ad + cheat + description:No health replenishment for opponent + code:815b/20/ad + cheat + description:Take less damage + code:8160/6d/ad + cheat + description:Take even less damage + code:8163/20/ad + cheat + description:Normal punches do more damage + code:836e/04/00 + cheat + description:Skip intro + code:a290/01/f8 + cheat + description:Start with and have infinite stars + code:8167/f0/30 + cheat + description:Start each round with 3 stars + code:8950/00/03 + 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 + name:Millipede (USA) + cheat + description:Infinite lives - both players + code:cec0/d6/b5 + cheat + description:Increase territory to half screen + code:d58d/a0/50 + cheat + description:Increase territory to full screen + code:d58d/a0/20 + cheat + description:Shrink territory + code:d58d/a0/c7 + cheat + description:Player's bullets move faster + code:dfba/06/0a + cheat + description:Player's bullets move slower + code:dfba/06/03 + cheat + description:Start with 1 life - P1 + code:c96d/04/01 + cheat + description:Start with 10 lives - P1 + code:c96d/04/0a + cheat + description:Invincibility + code:0071/00 + +cartridge sha256:6eea421f6c0738ff3abfd6e059e91c3409eedd2150093d3e01d49dfaad4dbf80 + name:Milon's Secret Castle (USA) + cheat + description:Infinite health + code:d27b/85/a5 + cheat + description:More health on pick-up + code:cac7/08/18 + cheat + description:No health on pick-up + code:cac7/08/00 + cheat + description:Max power bubbles + code:a782/d0/50 + cheat + description:Hit anywhere + code:d1b4/c9/d0+d1b5/08/24 + cheat + description:Floating Milon + code:9af6/03/50 + cheat + description:Start with more health + code:8a58/20/40 + cheat + description:Start with a bigger health bar + code:8a51/38/50 + 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 + name:Mission Cobra (USA) (Unl) + cheat + description:Infinite health + code:f17a/64/00+dd0e/64/00+db21/64/00 + cheat + description:Infinite health (alt) + code:009a/63 + +cartridge sha256:6b04b87ab30e885974844ad693cc39ba8c87e7e650e1f9cf22a054e0a385df4e + name:Mission Impossible (USA) + cheat + description:Infinite Type B weapons for all + code:9235/01/00 + cheat + description:Take less damage + code:86be/b9/ad + cheat + description:Take more damage + code:86fe/01/02 + cheat + description:2 Type B weapons for Nicholas + code:bcb2/05/02 + cheat + description:9 Type B weapons for Nicholas + code:bcb2/05/09 + cheat + description:5 Type B weapons for Max and Grant + code:bcaa/0a/05 + cheat + description:15 Type B weapons for Max and Grant + code:bcaa/0a/0f + cheat + description:Longer disguise time + code:8996/ad/ce+9309/01/04 + cheat + description:Start with less health + code:bc9f/0c/06 + cheat + description:Start with more health + code:bc9f/0c/10 + 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 + name:Mitsume ga Tooru (Japan) + cheat + description:Hit anywhere + code:bab2/03/00 + cheat + description:One hit kills + code:bad3/01/ff+bad2/e9/a9 + cheat + description:Collect money from anywhere + code:8423/b0/50+8d69/b0/30 + cheat + description:Increase projectile limit to 13 + code:d68e/03/0d + cheat + description:Start a new game for hidden debug TEST MODE menu + code:8341/04/03 + cheat + description:Start a new game to view the ending + code:8341/04/07 + +cartridge sha256:f997fe34edf1d998694aa979c81fe0063480274b4284498f230fffe694fe87ac + name:Monopoly (USA) + cheat + description:Collect $300 as you pass Go + code:db59/31/3f + cheat + description:Collect $100 as you pass Go + code:db59/31/1d + cheat + description:Pay $0 to get out of jail + code:a864/17/00 + cheat + description:Pay $100 to get out of jail + code:a864/17/1d + cheat + description:Pay $30 for luxury tax + code:8c96/1a/13 + cheat + description:Pay $100 for luxury tax + code:8c96/1a/1d + cheat + description:Pay $200 for luxury tax + code:8c96/1a/31 + cheat + description:Pay $0 for income tax + code:8cd6/31/00 + cheat + description:Pay $30 for income tax + code:8cd6/31/13 + cheat + description:Pay $100 for income tax + code:8cd6/31/1d + cheat + description:Pay $300 for income tax + code:8cd6/31/3f + cheat + description:$300 to buy Boardwalk + code:d41b/4b/3f + cheat + description:$600 to buy Boardwalk + code:d41b/4b/53 + cheat + description:$200 to buy Park Place + code:d412/45/31 + cheat + description:$400 to buy Park Place + code:d412/45/4b + cheat + description:$600 to buy Park Place + code:d412/45/53 + cheat + description:Houses on Park Place cost $100 + code:d41a/31/1d + cheat + description:Houses on Park Place cost $300 + code:d41a/31/3f + cheat + description:Houses on Boardwalk cost $100 + code:d423/31/1d + cheat + description:Houses on Boardwalk cost $300 + code:d423/31/3f + cheat + description:Go Back 7 spaces instead of 3 on Chance + code:8315/03/07 + cheat + description:Infinite money - P1 + code:03c5/09+03c6/09+03c7/09+03c8/09+03c9/09 + cheat + description:Infinite money - P2 + code:03ca/09+03cb/09+03cc/09+03cd/09+03ce/09 + cheat + description:Infinite money - P3 + code:03cf/09+03d0/09+03d1/09+03d2/09+03d3/09 + cheat + description:Infinite money - P4 + code:03d4/09+03d5/09+03d6/09+03d7/09+03d8/09 + cheat + description:Infinite money - P5 + code:03c9/09+03da/09+03db/09+03dc/09+03dd/09 + cheat + description:Infinite money - P6 + code:03de/09+03df/09+03e0/09+03e1/09+03e2/09 + cheat + description:Infinite money - P7 + code:03e3/09+03e4/09+03e5/09+03e6/09+03e7/09 + cheat + description:Infinite money - P8 + code:03e8/09+03e9/09+03ea/09+03eb/09+03ec/09 + +cartridge sha256:08615e9e339bd2df713cdb15f6426895ba643fbd8f383758f7f5c06ebf7ac10b + name:Monster in My Pocket (USA) + cheat + description:Invincibility after first hit + code:85c9/de/bd+86e1/90/91 + cheat + description:Infinite energy + code:86dd/de/bd + cheat + description:Infinite lives + code:8550/de/bd + +cartridge sha256:219c94a1f0801ee255f4c8df6d7d1120bdcfd882fcaecba2c858b1e4c66d060b + name:Monster Party (USA) + cheat + description:Invincibility + code:879a/a5/60 + cheat + description:Infinite life against normal enemies + code:87a7/c6/a5 + cheat + description:Infinite life against Guardians + code:87a5/c6/e6 + cheat + description:One hit kills normal enemies + code:850d/b0/f0 + cheat + description:One hit kills Guardians + code:8d3b/02/00 + cheat + description:Walk twice as fast + code:82ce/ff/fe+82b8/01/02 + cheat + description:Jump twice as far + code:84f2/ff/fe+84df/01/02 + cheat + description:Start with double life + code:9532/0c/18+94c6/0c/18 + cheat + description:Start with full life + code:9532/0c/2c+94c6/0c/2c + cheat + description:Start on level 2 + code:954a/00/01 + cheat + description:Start on level 3 + code:954a/00/02 + cheat + description:Start on level 4 + code:954a/00/03 + cheat + description:Start on level 5 + code:954a/00/04 + cheat + description:Start on level 6 + code:954a/00/05 + cheat + description:Start on level 7 + code:954a/00/06 + cheat + description:Start on level 8 + code:954a/00/07 + +cartridge sha256:ce493dcb4ba133d9a31e234a4c446a365bcf98c5f99c13968f1e1c777747ac29 + name:Moon Crystal (Japan) + cheat + description:Multi-jump + code:96dc/06/60+96d6/1c/04+96dd/98/97+977b/8d/ad + +cartridge sha256:66cb74efa264a285a541277b935d4b6cc9c49a18653bce90b65f0de98b05aec0 + name:Moon Ranger (USA) (Unl) + cheat + description:Infinite lives + code:d6bc/ce/ad + +cartridge sha256:aa0fe1b0b1e0c3a0a01695f1914fbb5e92649db33b74a9bdcb51be1481221f49 + name:Mother (Japan) + cheat + description:Start a new game with $1024 + code:be11/00/04 + cheat + description:Start a new game with $16,384 + code:be11/00/40 + +cartridge sha256:ed219a1b03be92e3ac4a2229e3e7663fd126eca6332f0564e5d3a12ec56f2142 + name:MotorCity Patrol (USA) + cheat + description:Don't take damage + code:a68c/01/00 + cheat + description:Slow down timer + code:819d/3c/70 + cheat + description:Speed up timer + code:819d/3c/1f + cheat + description:Free equipment + code:8cbd/ce/2c+8c33/d0/10 + cheat + description:Start with 5 merits + code:a31d/00/05 + +cartridge sha256:3264e4c57ffaf64df816cc97b1d6d278042545a4be248f5c195d82037f0a9bfd + name:Mr. Gimmick (Europe) + cheat + description:Invincibility + code:8410/f0/d0+8412/ce/ee + cheat + description:Infinite health + code:8c98/ce/cd + cheat + description:Infinite lives + code:e5e6/ce/cd + cheat + description:Start with 3 Bombs + code:e0e5/00/03 + cheat + description:Start with 3 Fireballs + code:e0e5/00/02 + cheat + description:Start with 3 Potions + code:e0e5/00/01 + 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 + name: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 + name:Ms. Pac-Man (USA) (Unl) + cheat + description:Infinite lives for both players in alternating type games + code:82fe/c6/a5 + cheat + description:Infinite lives for P2 only, in other type games + code:8303/ce/ad + cheat + description:Super fast turbo speed + code:f79d/4a/ea + cheat + description:Pinky out of game + code:863a/02/00 + cheat + description:Sue out of game + code:865a/02/00 + cheat + description:Start with 1 life - both players + code:86b7/02/00 + cheat + description:Start with 6 lives - both players + code:86b7/02/05 + cheat + description:Start with 9 lives - both players + code:86b7/02/08 + cheat + description:Start with 1 life for P2 in 2P cooperative and competitive games + code:86ba/8d/8c + 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:Ghosts stay blue until eaten + code:00c5/01 + 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 + name:Muppet Adventure - Chaos at the Carnival (USA) + cheat + description:Infinite power + code:8a47/c6/a5 + +cartridge sha256:ac2374bd4a5f7c87a7bd51e296f79800f84ea6c91a35e0c79dd9a3b2f923ef37 + name:Mutant Virus, The - Crisis in a Computer World (USA) + cheat + description:Invincibility + code:cc8a/c6/a5 + cheat + description:Infinite health + code:cb47/8d/ad + cheat + description:Infinite time + code:d486/8e/ae + cheat + description:Infinite lives + code:d486/8e/ea + cheat + description:Don't flash after getting hit + code:d48a/ff/00 + cheat + description:Flash 1/2 as long after getting hit + code:d48a/ff/63 + cheat + description:Start with 1 life + code:c096/05/00 + cheat + description:Start with 3 lives + code:c096/05/02 + cheat + description:Start with 7 lives + code:c096/05/85 + cheat + description:Start with 10 lives + code:c096/05/09 + cheat + description:Infinite health (alt) + code:0119/0c + cheat + description:Infinite lives (alt) + code:0110/06 + +cartridge sha256:61cb18d11771cffa08f79fd6973f634c8351703a2fe0f79858171d72a5a46582 + name:Mystery Quest (USA) + cheat + description:Invincibility + code:90f7/c6/24 + cheat + description:Infinite vitality + code:90f7/c6/a5 + cheat + description:Immune to monster attacks + code:90ac/f8/00 + cheat + description:Immune to shallow water + code:90b8/ff/00 + cheat + description:Never lose Key + code:9fe9/85/24 + cheat + description:Never lose Raft + code:96f9/00/01 + cheat + description:Start with more vitality + code:8f5b/40/60 + cheat + description:Start with less vitality + code:8f5b/40/20 + cheat + description:Start with Raft and Key + code:99bc/00/01 + +cartridge sha256:dc71dadc3f4eae03f26ac4afec8ef044e7874ad8fdee1567a9b9b9e2c112669e + name:NARC (USA) + cheat + description:Invincibility (blinking) - both players + code:a1f9/0e/00 + cheat + description:Infinite health - both players + code:e3ac/f6/ea + cheat + description:Infinite Bullets + code:d91b/01/00 + cheat + description:Infinite Missiles + code:d483/01/00 + cheat + description:Infinite lives + code:e3ce/d6/b5 + cheat + description:Enemies die automatically + code:dfbf/f0/50+dfc0/f3/51 + cheat + description:Hit anywhere - P1 + code:e150/03/00+dfc1/a4/50+dfc2/56/4f + cheat + description:More missiles + code:80e4/35/39 + cheat + description:1 Missile on pick-up + code:a2b1/05/01 + cheat + description:9 Missiles on pick-up + code:a2b1/05/09 + cheat + description:45 Bullets on pick-up + code:9356/02/04 + cheat + description:Start with 1 life + code:8132/02/00 + cheat + description:Start with 6 lives + code:8132/02/05 + cheat + description:Start with 9 lives + code:8132/02/08 + +cartridge sha256:55efed163edb02abc2a344aba79edc5ad873a77ed92378ad0c3e62f1e1816d3e + name:NES Open Tournament Golf (USA) + cheat + description:Always on first shot + code:86b4/9d/01 + cheat + description:No wind + code:da47/85/a5 + +cartridge sha256:4b382baa70cbc52977fd766f49a3c7c9a3239f0d9581cd961b8b26700c53247d + name:NES Play Action Football (USA) + cheat + description:30-minute quarters + code:f4c3/0f/1e + cheat + description:10-minute quarters + code:f4c3/0f/0a + cheat + description:No timeouts - P2 + code:bfc3/8d/8c + cheat + description:6 timeouts per half (ignore display) + code:bfbf/03/06 + cheat + description:1 timeout per half + code:bfbf/03/01 + +cartridge sha256:c03ffd0d5fb5439eb35f22f09df3cbd8f81f5cf3eb9b6718a4d7afb67c75c543 + name:Nigel Mansell's World Championship Challenge (USA) + cheat + description:Almost no tire wear + code:e053/ce/ad+f87a/ce/ad + cheat + description:Only need 1 lap on all tracks + code:ca7a/07/02+c8fd/bd/ad + cheat + description:Accelerate faster + code:f1dd/7d/6d + cheat + description:Accelerate a lot faster + code:f1dd/7d/6d+f348/04/08 + cheat + description:No extra time in the pits + code:b15b/ee/2c + cheat + description:Less tire wear + code:e053/ce/ad + cheat + description:Only need 3 laps in South Africa instead of 6 + code:ca7a/07/04 + cheat + description:Only need 3 laps in Mexico instead of 6 + code:ca7b/07/04 + cheat + description:Only need 3 laps in Brazil instead of 5 + code:ca7c/06/04 + cheat + description:Only need 3 laps in Spain instead of 4 + code:ca7d/05/04 + cheat + description:Only need 3 laps in San Marino instead of 6 + code:ca7e/07/04 + cheat + description:Only need 3 laps in Monaco instead of 5 + code:ca7f/06/04 + cheat + description:Only need 3 laps in Canada instead of 6 + code:ca80/07/04 + cheat + description:Only need 3 laps in France instead of 4 + code:ca81/05/04 + cheat + description:Only need 3 laps in Great Britian instead of 5 + code:ca82/06/04 + cheat + description:Only need 3 laps in Germany instead of 5 + code:ca83/06/04 + cheat + description:Only need 3 laps in Hungary instead of 5 + code:ca84/06/04 + cheat + description:Only need 3 laps in Belgium instead of 5 + code:ca85/06/04 + cheat + description:Only need 3 laps in Italy instead of 6 + code:ca86/07/04 + cheat + description:Only need 3 laps in Portugal instead of 4 + code:ca87/05/04 + cheat + description:Only need 3 laps in Japan instead of 5 + code:ca88/06/04 + cheat + description:Only need 3 laps in Australia instead of 5 + code:ca89/06/04 + cheat + description:Full season ends after South Africa + code:aa99/10/01 + cheat + description:Full season ends after Mexico + code:aa99/10/02 + cheat + description:Full season ends after Brazil + code:aa99/10/03 + cheat + description:Full season ends after Spain + code:aa99/10/04 + cheat + description:Full season ends after San Marino + code:aa99/10/05 + cheat + description:Full season ends after Monaco + code:aa99/10/06 + cheat + description:Full season ends after Canada + code:aa99/10/07 + cheat + description:Full season ends after France + code:aa99/10/08 + cheat + description:Full season ends after Great Britian + code:aa99/10/09 + cheat + description:Full season ends after Germany + code:aa99/10/0a + cheat + description:Full season ends after Hungary + code:aa99/10/0b + cheat + description:Full season ends after Belgium + code:aa99/10/0c + cheat + description:Full season ends after Italy + code:aa99/10/0d + cheat + description:Full season ends after Portugal + code:aa99/10/0e + cheat + description:Full season ends after Japan + code:aa99/10/0f + cheat + description:Start with 1/2 normal tire tread + code:c88a/10/08 + +cartridge sha256:58be6a811ee3370882160115253b610581e8b4af7228669eb3fbd56e7a13117c + name:Nightmare on Elm Street, A (USA) + cheat + description:Invincibility + code:b315/f0/d0 + cheat + description:Infinite health + code:bfbc/fe/bd + cheat + description:Infinite lives + code:bb85/de/bd + cheat + description:Infinite 'zzz' + code:9031/de/ad + cheat + description:Have all characters + code:b9e7/f0/d0+b9d9/d0/f0 + cheat + description:Hit anywhere + code:cf18/0d/00+cf20/f0/10+cefc/f0/50 + cheat + description:One hit kills + code:cf6c/f0/d0 + cheat + description:No enemies + code:a198/05/00+a197/ad/a9+a199/01/ea + cheat + description:Always able to switch characters + code:b9ce/f0/30 + cheat + description:Freddy will not show up in Nightmare World + code:e0f1/ce/ad + cheat + description:Mega-jumping teenagers + code:b4b5/03/05 + cheat + description:Don't lose 'zzz' when hit + code:d0db/80/00 + cheat + description:Don't lose 'zzz' when standing still + code:902b/01/00 + cheat + description:Lose 'zzz' quicker + code:902b/01/02 + cheat + description:Start with 1 continue + code:ea38/03/01 + cheat + description:Start with 6 continues + code:ea38/03/06 + cheat + description:Start with 9 continues + code:ea38/03/09 + +cartridge sha256:02caaf66cc43a4c5a8d54252fca7bcb929dad91c71f127eabe37f29ef9199105 + name:Nightshade (USA) + cheat + description:Invincible in fights + code:d6dc/46 + cheat + description:Invincible out of fights + code:d5d8/46 + +cartridge sha256:590e508b47eb6d6c0088dffd83fe2436edd0d75e74faba7a9da2008770fb1986 + name:Niji no Silk Road (Japan) + cheat + description:Walk anywhere + code:8187/36/89+8188/82/81 + +cartridge sha256:b1c2ae757c5ec76f488893f130f0f7f1aacf36a25467b9012ca3a11ab52204ce + name:Ninja Crusaders (USA) + cheat + description:Invincibility + code:c05f/d0/f0 + cheat + description:Infinite lives + code:c148/de/bd + cheat + description:Hit anywhere + code:ce7f/f0/4c+ce80/1b/d1+ce81/b9/ce + cheat + description:Collect items from anywhere + code:a61b/b0/24+a62e/b0/24 + cheat + description:Multi-jump + code:ae58/f0/24 + cheat + description:Mega-jump + code:ae7f/12/25 + cheat + description:Super speed + code:8b2d/fe/fd+8b2b/01/02 + cheat + description:Start with 1 life + code:a890/03/01 + cheat + description:Start with 6 lives + code:a890/03/06 + cheat + description:Start with 9 lives + code:a890/03/09 + cheat + description:Start on stage 1-2 + code:9406/00/01 + cheat + description:Start on stage 2-1 + code:9406/00/02 + cheat + description:Start on stage 2-2 + code:9406/00/03 + cheat + description:Start on stage 3-1 + code:9406/00/04 + cheat + description:Start on stage 3-2 + code:9406/00/05 + cheat + description:Start on stage 4-1 + code:9406/00/06 + cheat + description:Start on stage 4-2 + code:9406/00/07 + cheat + description:Start on stage 5-1 + code:9406/00/08 + +cartridge sha256:6799437d4122b81c86ae35cefe5b6ae6e10e6f9a9c7b3140dd569f717ba32b3d + name:Ninja Gaiden (USA) + cheat + description:Invincibility + code:e162/a9 + cheat + description:Invincibility (alt) + code:e177/a9/60 + cheat + description:Infinite health + code:e1af/85/a5 + cheat + description:Infinite lives + code:e401/c6/a5 + cheat + description:Hit anywhere + code:ded5/00+dee3/00+deeb/00+def3/10+def7/d0 + cheat + description:Enemies die instantly + code:ddf2/03/00+ded5/24/00+dee3/15/00+deeb/09/00+def3/90/10+def7/90/d0 + cheat + description:Multi-jump + code:eb8d/80/00+ed92/1d/00+eced/d0/24+ee35/d0/24+eef6/85/a5 + cheat + description:Use windmill throwing-star without losing spiritual strength + code:efae/05/00 + cheat + description:Use fire-wheel without losing spiritual strength + code:ef03/05/00 + cheat + description:Use shuriken without losing spiritual strength + code:ef67/03/00 + cheat + description:Maximum strength regained from restorer + code:dc04/06/10 + cheat + description:Sound Test - hold down and press Start at Tecmo Presents screen + code:805e/e6/04 + cheat + description:Start with 9 lives + code:e53b/02/08 + cheat + description:Start with 6 lives + code:e53b/02/05 + cheat + description:Start with 1 life + code:e53b/02/00 + 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 + name:Ninja Gaiden II - The Dark Sword of Chaos (USA) + cheat + description:Invincibility + code:cc34/50/a5 + cheat + description:Invincibility (alt) + code:ca1b/cb/91 + cheat + description:Infinite health + code:cc74/85/80 + cheat + description:Infinite health (alt) + code:cc74/85/a5 + cheat + description:Infinite Ninja power + code:9a8d/a6/a2+9a8e/7d/13+9a9d/4b/39 + cheat + description:Infinite time + code:c6eb/c6/a5 + cheat + description:Infinite lives + code:c8a2/c6/a5 + cheat + description:Hit anywhere + code:ca6a/d3/00+ca81/bc/00+ca92/0d/00+ca9c/b0/f0 + cheat + description:Multi-jump + code:c150/10/80+c157/d0/24+c14e/1f/13+c152/06/1b+d908/8d/ad+c14d/f0/a5+d97a/8d/ad+d7dd/86/a6 + cheat + description:Half-energy from medicine + code:98bd/06/03 + cheat + description:Double energy from medicine + code:98bd/06/0c + cheat + description:Never lose Ninja power item + code:cdcb/86/24 + cheat + description:Fast running Ryu + code:c0a7/01/02+c08f/fe/fd + cheat + description:Mega-fast running Ryu + code:c0a7/01/03+c08f/fe/fc + cheat + description:Half-energy from Blue Ninja power + code:983f/0a/05+9849/0a/05 + cheat + description:Double energy from Blue Ninja power + code:983f/0a/14+9849/0a/14 + cheat + description:Double maximum Ninja power from scroll + code:9881/0a/14+9898/01/02 + cheat + description:All powers use up only 5 points + code:9a92/fd/ed+9a9c/fd/ed+9aaa/fd/ed + cheat + description:Less enemies + code:e32f/00 + cheat + description:Start every life with two shadow ninjas + code:d117/09/0f + cheat + description:Start with 1 life + code:cec6/02/00 + cheat + description:Start with 6 lives + code:cec6/02/05+cecc/95/85 + cheat + description:Start with 9 lives + code:cec6/02/08+cecc/95/85 + 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 + name:Ninja Gaiden III - The Ancient Ship of Doom (USA) + cheat + description:Invincibility + code:9fe7/03/00 + cheat + description:Infinite lives + code:cb8e/c6/a5 + cheat + description:Infinite health + code:a30d/85/a5 + cheat + description:Infinite time (timer will still countdown) + code:a565/c6/a5 + cheat + description:Infinite continues + code:cba7/c6/a5 + cheat + description:Multi-jump and infinite time + code:a8f9/14/00+a55c/32/20+a55a/8b/90+93b2/b0/24+a55b/d0/03+a558/bf/13+a55e/cf/a9+a57d/c6/a5+a55d/c6/da+a559/05/0a + cheat + description:Less time + code:cc42/fa/96 + cheat + description:One hit kills + code:a0ce/0f/00 + cheat + description:Sword hits several areas of the screen at once (sword upgrade negates the effect) + code:cc28/10/7f+cc2c/07/7f + cheat + description:No power required for Windmill Throwing Star + code:9fd4/01/00+9fca/0a/00 + cheat + description:No power required for Fire Wheel Art + code:9fcb/08/00+9fd0/08/00 + cheat + description:No power required for Invincible Fire Wheel + code:9fce/14/00+9fd8/02/00 + cheat + description:No power required for Fire Dragon Balls + code:9fcc/08/00+9fd1/08/00 + cheat + description:No power required for Vacuum Wave Art + code:9fcd/0a/00+9fd7/01/00 + cheat + description:Start with upgraded sword + code:cc24/00/01+cc28/10/18+cc2c/07/10 + cheat + description:Start with 5 lives + code:cc06/02/04 + cheat + description:Invincibility (alt) + code:00ad/14 + cheat + description:Infinite health (alt) + code:00a7/0a + +cartridge sha256:648cf7ac553517573cc9b3955ab50566a91974b2348154910bfa53ef15d55b56 + name:Ninja Jajamaru - Ginga Daisakusen (Japan) + cheat + description:Invincibility + code:9674/20/ad + cheat + description:Infinite lives + code:946c/de/dd + +cartridge sha256:bf546b0ce7fc60d89020ff7c0fadc7369925ba68a84d25b03de4190a91c46a95 + name:Ninja Jajamaru-kun (Japan) + cheat + description:Infinite time + code:002a/78 + cheat + description:Hit anywhere + code:9a70/06/00+9a60/21/00+9aa2/8d/ad + +cartridge sha256:622c62d48aa244fb2427ce8d0cf45e5fc57d94ad82e47a3b5b45a0dd643c9cd7 + name:Ninja Kid (USA) + cheat + description:Infinite Feathers + code:a913/c6/a5 + cheat + description:Infinite Stars + code:a62d/c6/a5 + cheat + description:Infinite Boomerangs + code:94fc/c6/a5 + cheat + description:Infinite Fireflames + code:a7b2/c6/a5 + cheat + description:More Invincibility time + code:d703/0f/28 + cheat + description:Less Invincibility time + code:d703/0f/07 + cheat + description:1 Feather on pick-up + code:d82a/03/01 + cheat + description:6 Feathers on pick-up + code:d82a/03/06 + cheat + description:10 Stars on pick-up + code:d82b/14/0a + cheat + description:40 Stars on pick-up + code:d82b/14/28 + cheat + description:1 Boomerang on pick-up + code:d82c/04/02 + cheat + description:10 Fireflames on pick-up + code:d82d/14/0a + cheat + description:40 Fireflames on pick-up + code:d82d/14/28 + cheat + description:Start with 1 life + code:806a/02/00 + cheat + description:Start with 6 lives + code:806a/02/05 + cheat + description:Start with 9 lives + code:806a/02/08 + +cartridge sha256:b0e4d88db0b21db4a84e3c21d51898c686e9031dc138b2939877ecad20dd2350 + name:Nintendo World Cup (USA) + cheat + description:1 minute in tournament mode + code:ea3c/03/00 + cheat + description:6 minutes in tournament mode + code:ea3c/03/05 + cheat + description:9 minutes in tournament mode + code:ea3c/03/08 + cheat + description:6 minutes in match mode + code:ea42/09/05 + cheat + description:3 minutes in match mode + code:ea42/09/02 + cheat + description:1 minutes in match mode + code:ea42/09/00 + cheat + description:Faster players + code:bda3/00/01 + cheat + description:More powerful 'normal' shots + code:aa2f/38/70 + +cartridge sha256:6157c99fe7a214025c65fd3649e4afe9cd2d38c333e65af028b935e49fbeb500 + name:Noah's Ark (Europe) + cheat + description:Invincibility + code:b83f/20/ad + cheat + description:Invincible against spikes + code:cf8b/20/ad + cheat + description:Infinite lives + code:83fc/ce/cd+88d6/ce/cd + cheat + description:Infinite health + code:bc4b/85/a5 + cheat + description:Infinite time + code:e10a/ce/cd + +cartridge sha256:55c2d10ae1b034b39533f780f6205f736735df1954c0eca6d147cfc13a224f82 + name:North and South (USA) + cheat + description:Cannon has 5 shots + code:81b6/09/05 + cheat + description:Cannon has 15 shots + code:81b6/09/0f + cheat + description:Cannon has infinite shots + code:9327/de/ad + cheat + description:No cannons allowed + code:81a6/9d/2c + cheat + description:Only 2 daggers in the fortress + code:8134/04/02 + cheat + description:Infinite daggers in the fortress + code:94a3/de/2c + cheat + description:2 men in the fortress + code:813e/0a/02 + cheat + description:5 men in the fortress + code:813e/0a/05 + cheat + description:2 men on the train + code:8154/0a/02 + cheat + description:5 men on the train + code:8154/0a/05 + +cartridge sha256:106a9cd2acc3373bf2fae05158bdf7587d5f645402ba8073aaee65cb8b7b11cd + name:Operation Secret Storm (USA) (Unl) + cheat + description:Infinite lives + code:e33a/99/b9 + cheat + description:Infinite Gun ammo + code:e54f/99/bd + cheat + description:Infinite health + code:0520/17 + +cartridge sha256:36666e3314ee9e0a340b04ea8427aaefb6df8937425a016e78c26fb1fa77b017 + name:Operation Wolf (USA) (Rev 0A) + cheat + description:Infinite continues + code:bdef/09/05 + cheat + description:Never die + code:d2db/36/00 + cheat + description:Infinite magazines + code:d56d/01/00 + cheat + description:Infinite grenades + code:d600/01/00 + cheat + description:Double bullets in each magazine + code:d577/02/04 + cheat + description:Heal completely between levels + code:d08a/03/ff + cheat + description:Grenades inflict double damage + code:b27b/02/04 + cheat + description:Super power drinks + code:b104/05/0a + cheat + description:Increase magazines + code:cfee/07/09+d56d/05/09 + cheat + description:Increase grenades + code:cff2/05/09+d56d/03/09 + cheat + description:Start on mission 2 + code:a4d5/00/01 + cheat + description:Start on mission 3 + code:a4d5/00/02 + cheat + description:Start on mission 4 + code:a4d5/00/03 + cheat + description:Start on mission 5 + code:a4d5/00/04 + cheat + description:Start on mission 6 + code:a4d5/00/05 + +cartridge sha256:4d2b5339703d2300539348e3aad055fd00828afcbd9f3a97565e37725221fc0a + name: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:6d310d9f2249932c7187130ebd696c42ff05f678c3086ac727ee6a27fdad4f43 + name:Otaku no Seiza - An Adventure in the Otaku Galaxy (Japan) + cheat + description:No random battles + code:dc82/a9/60 + cheat + description:Walk anywhere + code:dd70/2d/00 + +cartridge sha256:d50327afa539f4a5ccfd6e10f685326eb0f01915ccf305f752deae2bf17385a6 + name:Over Horizon (Europe) + cheat + description:Invincibility (blinking) + code:def0/c6/a5 + cheat + description:Infinite lives + code:bdb0/ce/ad + cheat + description:Enable alternate graphics + code:d685/00/01 + +cartridge sha256:b3a798ab7f2f237c7bd3c3e8b36cc752d850d10a8597e43771c82dcd654d5dae + name:Overlord (USA) + cheat + description:Food not decreased + code:8101/0d/1c + cheat + description:Hover tanks never decrease in battle + code:beac/ce/ad + cheat + description:Ballistic Missiles never decrease in battle + code:9149/ce/ad + cheat + description:Homing Missiles never decrease in battle + code:9154/ce/ad + cheat + description:Enemy starts with 0 Missiles + code:bf6c/9f/a7 + cheat + description:Constantly get 9999999 cash on all planets with 1% or higher tax + code:81c3/b0/d0 + cheat + description:View a planet's stats for high food + code:b725/00/7f+b729/b9/99 + cheat + description:View a planet's stats for high people + code:b810/00/7f+b814/b9/99 + cheat + description:View a planet's stats for high energy + code:b7cf/00/7f+b7d3/b9/99 + cheat + description:View a planet's stats for high fuel + code:b78e/00/7f+b792/b9/99 + +cartridge sha256:ae2dddda1f90b8f8e3a990a2247ab4e373f69e6599f4e63f531d3a541b54bd85 + name:P.O.W. - Prisoners of War (USA) + cheat + description:Invincibility + code:ba6b/85/60 + cheat + description:Infinite lives + code:d1fb/01/00 + cheat + description:Infinite bullets + code:ce61/01/00 + cheat + description:One hit kills + code:b90d/bd/b9 + cheat + description:Hit anywhere + code:b8df/23/00+b8de/b0/4c+b8e0/c8/b9 + cheat + description:Take less damage when hit from behind + code:bb11/f9/ed + cheat + description:Keep weapons after dying + code:bb3f/8d/2c+bd51/8d/2c + cheat + description:Start with half health + code:c341/20/10+d20f/20/10 + cheat + description:Start with 1 life + code:82bd/02/00 + cheat + description:Start with 6 lives + code:82bd/02/05 + cheat + description:Start with 9 lives + code:82bd/02/08 + cheat + description:Start with 99 lives + code:82bd/02/63 + 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 + name:Pac-Man (USA) (Namco) + cheat + description:Invincibility + code:d307/f0/24 + cheat + description:Get 8000+ points for eating ghosts + code:d31b/a4/a0+d31c/d9/06+d327/e6/a5 + cheat + description:Power Pill effect always active + code:0088/0f + cheat + description:Infinite lives + code:0067/03 + +cartridge sha256:1e60a181e1f89f2249a3e0d44a7765c2cdd9e0446f1671c63bf2c6f6df562d4c + name:Pac-Man (USA) (Tengen) + cheat + description:Invincibility + code:d2c6/f0/24 + cheat + description:Walk through walls + code:d36f/18/00+d43a/d0/50+d473/f0/50+d46a/f0/70 + cheat + description:Get 8000+ points for eating ghosts + code:d2da/a4/a0+d2db/d9/06+d2e6/e6/a5 + cheat + description:Ghosts are re-eatable until Power Pill wears off + code:d648/85/a5 + cheat + description:Power pills last longer + code:d166/3c/70 + cheat + description:Power pills last extra long + code:d166/3c/ff + cheat + description:Power pills don't last as long + code:d166/3c/20 + cheat + description:Power pills don't work + code:e022/a5/60 + cheat + description:Only 3 ghosts are edible + code:e02f/0f/0d + cheat + description:Only 2 ghosts are edible + code:e02f/0f/09 + cheat + description:Pac-Man moves manually + code:d35b/35/af + cheat + description:Power Pill effect always active + code:0088/15 + cheat + description:Infinite lives + code:0067/03 + +cartridge sha256:25506ac6d6413a73249d3ce6a4ecc40048982596e01d778eddb71baca084efa6 + name:Pac-Man (USA) (Tengen) (Unl) + cheat + description:Invincibility + code:d2c6/f0/24 + cheat + description:Get 8000+ points for eating ghosts + code:d2da/a4/a0+d2db/d9/06+d2e6/e6/a5 + cheat + description:Ghosts are re-eatable until Power Pill wears off + code:d648/85/a5 + cheat + description:Power pills last longer + code:d166/3c/70 + cheat + description:Power pills last extra long + code:d166/3c/ff + cheat + description:Power pills don't last as long + code:d166/3c/20 + cheat + description:Power pills don't work + code:e022/a5/60 + cheat + description:Only 3 ghosts are edible + code:e02f/0f/0d + cheat + description:Only 2 ghosts are edible + code:e02f/0f/09 + cheat + description:Power Pill effect always active + code:0088/15 + cheat + description:Infinite lives + code:0067/03 + +cartridge sha256:acc561f57cfd0490fdce649deb16fa9df309bba1695608213a0ff8066d662492 + name:Pac-Mania (USA) (Unl) + cheat + description:Infinite lives + code:d941/c6/a5 + cheat + description:Trapped ghosts + code:cfe3/78 + cheat + description:Go through ghosts + code:d8b6/95 + cheat + description:Ghosts worth 3200 points + code:d88f/01 + +cartridge sha256:6c47c73eb510fb0f71eeb2a3f5cca7c25eca8678ffe060aa17df6534dbd10ef1 + name:Panic Restaurant (USA) + cheat + description:Invincibility + code:90b1/d0/f0 + cheat + description:Infinite health - except when you fall on spikes + code:90e1/c6/a9 + cheat + description:Infinite health (alt) + code:90e1/c6/a5 + cheat + description:Infinite time + code:c26c/c6/a9 + cheat + description:Infinite time (alt) + code:c26c/c6/c5 + cheat + description:Infinite lives + code:d418/c6/85 + cheat + description:Infinite lives (alt) + code:d418/c6/a5 + cheat + description:Hit anywhere + code:92c7/be/00+92e4/a1/00 + cheat + description:Moon-jump + code:c303/29/00 + cheat + description:Start with 4 hearts + code:f452/02/04 + cheat + description:Start with 2 lives + code:ad17/02/01 + cheat + description:Start with 5 lives + code:ad17/02/05 + cheat + description:Start with 6 hearts (heart meter will be distorted) + code:f452/02/06 + cheat + description:Start with 10 hearts (heart meter will be distorted) + code:f452/02/0a + cheat + description:Start with 10 lives (meter will display 9) + code:ad17/02/0a + cheat + description:Start with 15 lives (meter will display 9) + code:ad17/02/0f + cheat + description:Start with 80 on timer (1st level only) + code:f464/63/50+cf6a/63/50 + cheat + description:Start with 70 on timer (1st level only) + code:f464/63/46+cf6a/63/46 + cheat + description:Start with 60 on timer (1st level only) + code:f464/63/3c+cf6a/63/3c + +cartridge sha256:73f0f7b9150fb080541426cedc87bf528c63393e6112812112e8c1339d9bfbf5 + name:Panda Prince, The (Shin-Shin) (Unl) + cheat + description:Infinite lives + code:979b/85/a5 + +cartridge sha256:f1c9c4723190d6be5f1f683ad5fd8cc123abd70d42f486c175a25f1237db6199 + name:Paperboy (USA) + cheat + description:Invincibility against moving objects + code:8a79/90/18+8a7a/04/60 + cheat + description:Invincibility against non-moving objects + code:9c45/06/00 + cheat + description:Infinite lives + code:8ade/c6/a5 + cheat + description:Infinite papers + code:987c/c6/a9 + cheat + description:Infinite time in training course + code:982b/8d/ad + cheat + description:Broken windows count as deliveries + code:9943/02/01 + cheat + description:Can deliver to houses with broken windows + code:9944/99/ad + cheat + description:Deliver from anywhere (must be within range of house) + code:98d9/f0/50+98da/50/77 + cheat + description:Hold down to stop moving + code:8fc3/3f/00+8fc1/06/0d + cheat + description:Gain 20 papers on pick-up + code:9b3f/0a/14 + cheat + description:Start with 1 life + code:9d38/04/01 + cheat + description:Start with 6 lives + code:9d38/04/06 + cheat + description:Start with 20 papers + code:89a3/0a/14 + +cartridge sha256:dec09033f68850bd25cf3e8bf0e05a44970301c4aaac2cbc27b8f9e96392b409 + name:Paperboy 2 (USA) + cheat + description:Infinite lives + code:834a/01/00 + cheat + description:Infinite papers + code:9be7/01/00 + cheat + description:5 papers on pick-up + code:8990/0a/05 + cheat + description:15 papers on pick-up + code:8990/0a/0f + cheat + description:20 papers on pick-up + code:8990/0a/14 + cheat + description:Start with 1 life - Paperboy only + code:b49f/05/01 + cheat + description:Start with 3 lives - Paperboy only + code:b49f/05/03 + cheat + description:Start with 10 lives - Paperboy only + code:b49f/05/0a + cheat + description:Start with 15 papers + code:b604/0a/0f + cheat + description:Start with 20 papers + code:b604/0a/14 + +cartridge sha256:25ae9f90412612715a254973006f0056016a840efc8af1fbdb6fc2eb7cd5eb7c + name: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 + name:Parodius (Europe) + cheat + description:Enemies die automatically + code:008b/02 + cheat + description:Infinite Shield on pick-up + code:64d0/0f + +cartridge sha256:f1762c9f40e6e45a123b73a035841768e0132fa82c92f9d066a8718a7f99b6cc + name:Pesterminator (USA) (Unl) + cheat + description:Infinite health + code:d799/ce/e6 + cheat + description:Infinite lives + code:d0f5/ce/ae + +cartridge sha256:1c598fe0b58811b1bedfc6f2cda05f0960b4a6e2770c8a2f73cd6da370ed2448 + name:Phantom Fighter (USA) + cheat + description:Infinite health + code:a3d3/8d/ad + cheat + description:Take less damage when attacked + code:a3d1/e5/e9+a3d2/00/01 + cheat + description:Start with Sacred Sword + code:cc68/85/e6+cc69/87/84 + cheat + description:Start with Bell + code:cc68/85/e6+cc69/87/85 + cheat + description:Start with Tonten + code:cc68/85/e6+cc69/87/83 + cheat + description:Start with Talisman + code:cc68/85/e6+cc69/87/82 + cheat + description:Start with 3 Scrolls + code:cc5f/00/03+cc69/87/86 + cheat + description:Start with 6 Scrolls + code:cc5f/00/06+cc69/87/86 + 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 + name:Pictionary - The Game of Video Quick Draw (USA) + cheat + description:Infinite time + code:0084/20 + +cartridge sha256:f4ddb0f1a02f823ebed30b55547344de3c8fb9d87254ff993584373ecadd9141 + name:Pin Bot (USA) + cheat + description:Infinite balls + code:e26f/e6/a9 + cheat + description:Start with only 1 ball + code:e274/03/01 + cheat + description:Start with 6 balls + code:e274/03/06 + cheat + description:Start with 9 balls + code:e274/03/09 + +cartridge sha256:910ba4505b46a99b3779d84fd22ba8b18f3a649b0c1a11706c4609d06ce0bc18 + name:Pinball (World) + cheat + description:Infinite balls + code:c0ab/de/bd + cheat + description:Start with lots of balls + code:c051/03/2f + cheat + description:Start with 1 ball + code:c051/03/01 + cheat + description:Start with 6 balls + code:c051/03/06 + cheat + description:Start with 9 balls + code:c051/03/09 + +cartridge sha256:836a6df9f6885b2b09d9daf3cecd67a4e5f36ae0b278a32c296779f067c8694f + name:Pinball Quest (USA) + cheat + description:Infinite Balls - Mini Games - P1 + code:8000/00/00 + cheat + description:Infinite Balls - Mini Games - P2 + code:06f9/63 + cheat + description:Infinite Balls - Mini Games - P3 + code:06fa/63 + cheat + description:Infinite Balls - Mini Games - P4 + code:06fb/63 + cheat + description:Max Attack Power - RPG mode + code:00c0/0c + cheat + description:Infinite Gold - RPG mode (1 of 3) + code:0082/63 + cheat + description:Infinite Gold - RPG mode (2 of 3) + code:0083/63 + cheat + description:Infinite Gold - RPG mode (3 of 3) + code:0084/63 + +cartridge sha256:7dd47bac196af9874181e86f64402035e255814739828d5d00c03bac8689d40a + name: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 + name:Pipe Dream (USA) + cheat + description:Infinite wrenches + code:e341/ce/ad + cheat + description:One-way pipes from level 1 + code:c212/05/00 + cheat + description:One-way pipes from level 5 + code:c210/03/05 + cheat + description:One-way pipes from level 10 + code:c219/03/0a + cheat + description:Tunnels galore + code:8eb3/8d/8c + cheat + description:Pumps instead of reservoirs + code:dc40/12/14 + cheat + description:Pumps before reservoirs + code:dc40/12/14+dc47/14/12 + cheat + description:Start with 1 wrench + code:8113/03/01 + cheat + description:Start with 6 wrenches + code:8113/03/06 + cheat + description:Start with 9 wrenches + code:8113/03/09 + +cartridge sha256:ac1215af2a3315f8bbff01987f24a85e9c1fe984287c05fc21246b0a66fd5dfd + name:Platoon (USA) (Rev A) + cheat + description:Stage 1 - Infinite grenades + code:91ca/c6/a5 + cheat + description:Stage 1 - Start with double capacity magazine + code:9057/c6/a5 + cheat + description:Stage 1 - Double hits + code:8fcd/04/08 + cheat + description:Stage 1 - Don't take damage + code:8fc3/e6/a5 + cheat + description:Stage 2 - Don't take damage + code:8e62/e6/a5 + cheat + description:Stage 4 - Infinite time + code:8acb/c6/a5 + cheat + description:Stage 4 - Play with more time + code:89e9/03/05 + cheat + description:Stage 4 - Double hits + code:914d/05/09 + cheat + description:Stage 4 - Halve hits + code:914d/05/02 + cheat + description:Stage 4 - Start with double ammo + code:89ab/06/0c + cheat + description:Start on stage 2 + code:8148/05/04 + cheat + description:Start on stage 3 + code:c004/06/03 + +cartridge sha256:61ac77e84b4aa089115a682a2e8cfaa6811ba83b567ae1f13d8b644e0c42a2bf + name:Platoon (USA) + cheat + description:Stage 1 - Infinite grenades + code:91ca/c6/a5 + cheat + description:Stage 1 - Start with double capacity magazine + code:9057/c6/a5 + cheat + description:Stage 1 - Double hits + code:8fcd/04/08 + cheat + description:Stage 1 - Don't take damage + code:8fc3/e6/a5 + cheat + description:Stage 2 - Don't take damage + code:8e62/e6/a5 + cheat + description:Stage 4 - Infinite time + code:8acb/c6/a5 + cheat + description:Stage 4 - Play with more time + code:89e9/03/05 + cheat + description:Stage 4 - Double hits + code:914d/05/09 + cheat + description:Stage 4 - Halve hits + code:914d/05/02 + cheat + description:Stage 4 - Start with double ammo + code:89ab/06/0c + cheat + description:Start on stage 2 + code:8148/05/04 + cheat + description:Start on stage 3 + code:c004/06/03 + +cartridge sha256:97f56ee3bcb0542996401a65c63a0e91c1c9c71da07f0619975e910946f9540d + name:Popeye (World) (Rev A) + cheat + description:Invincibility against enemy + code:d147/60 + cheat + description:Invincibility against shots + code:d35e/60 + cheat + description:Start with 1 life + code:c81f/01 + cheat + description:Start with 6 lives + code:c81f/06 + cheat + description:Start with 9 lives + code:c81f/09 + +cartridge sha256:23e457d854d5ce2bb8b81cef9fbbff0164171505a4d2d9e28ecbc2d062c81517 + name: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 + name:Power Blade (USA) + cheat + description:Infinite health + code:8a4d/e5/e9 + cheat + description:Infinite lives + code:d050/c6/a5 + cheat + description:Hit anywhere + code:8c97/22/00+8c8b/90/f0 + cheat + description:Take minimum damage + code:8a44/b9/ad + cheat + description:Mega-jump + code:d628/38/28 + cheat + description:Don't lose boomerang strength when you die + code:d036/c6/24+d066/85/24 + cheat + description:Don't lose multi-boomerangs when you die + code:d03c/c6/24+d06a/85/24 + cheat + description:Press Start to finish the level (don't use on Protect level) + code:d181/01/08+d183/4d/18+d184/a9/60 + cheat + description:Start a new game to view the ending + code:f67b/02/07 + cheat + description:Start with 1 life + code:f722/02/00 + cheat + description:Start with 6 lives + code:f722/02/05 + cheat + description:Start with 9 lives + code:f722/02/08 + 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 + cheat + description:Infinite Bombs + code:005a/09 + cheat + description:Infinite health refills + code:005b/09 + cheat + description:Powered up Boomerang + code:005e/03 + cheat + description:Triple Boomerangs + code:0099/02 + cheat + description:One hit kills on bosses + code:04ba/00 + cheat + description:Moon jump (Can cause you to die in areas with no ceiling) + code:051d/c0 + cheat + description:Have Suit + code:009c/03 + cheat + description:Start on last stage + code:0059/3f + +cartridge sha256:6c462c3fa07aab70759376fe6b59e9c91e808f79fae2960f869bafc9cf20dca2 + name:Power Blade 2 (USA) + cheat + description:Infinite health - except for spikes + code:b3d2/e5/e9 + cheat + description:Infinite lives + code:d053/c6/24 + cheat + description:Infinite time + code:ca4a/a5/60 + cheat + description:Infinite life tanks + code:ee8a/c6/24 + cheat + description:Infinite energy tanks + code:d301/c6/24 + cheat + description:Speed up timer + code:ca47/3f/1f + cheat + description:Slow down timer + code:ca47/3f/7f + cheat + description:Throw meter doesn't decrease when boomerang is thrown + code:d24a/a5/85 + cheat + description:Take minimal damage + code:b3d2/e5/e9+b3d3/00/01 + cheat + description:Maximum throwing ability on pick-up + code:b56b/c9/a9+b572/e6/85 + cheat + description:Start a new game to view the ending + code:ee27/03/07 + cheat + description:Start with 1 life + code:86c9/02/00 + cheat + description:Start with 6 lives + code:86c9/02/05 + cheat + description:Start with 9 lives + code:86c9/02/08 + 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 + name:Power Punch II (USA) + cheat + description:Infinite health + code:fc02/85/a5 + 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 + name:Predator (USA) + cheat + description:Invincibility (normal mode) + code:8851/85/86+cc4f/c6/c9 + cheat + description:Infinite health (big mode) + code:8be2/ce/ee + cheat + description:Infinite health in jungle mode + code:ccb6/85/60 + cheat + description:Infinite lives in jungle mode + code:c274/ce/ad + cheat + description:Infinite lives in big mode + code:c1a2/ce/ad + cheat + description:Hit anywhere + code:ed08/a5/60+ed60/a5/60+ed21/a5/60+ecf4/a5/60+ed9d/a5/60 + cheat + description:Mega-jumps in jungle mode + code:819e/09/08 + cheat + description:Don't die if you fall down holes + code:880f/0c/ef+8810/a9/60 + cheat + description:Start each life with Laser Rifle + code:8859/0b/03+885b/ae/ba + cheat + description:Start with double lives + code:c16c/04/08 + cheat + description:Invincibility + code:0010/02 + cheat + description:Infinite lives + code:0504/09 + +cartridge sha256:7b0899bfde9661d1af5c2d88c46a8a70f1623729bf52db654fb40cda4554820b + name:Prince of Persia (USA) + cheat + description:Infinite health + code:8725/9d/bd + cheat + description:Infinite time + code:b245/8d/ad + 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 + name:Princess Tomato in the Salad Kingdom (USA) + cheat + description:Infinite gold coins + code:03cb/09 + +cartridge sha256:3910ae7495a71e6a55f70ed31eb345d28d6e9d524fe88679719d831f8f2553ce + name:Pro Sport Hockey (USA) + cheat + description:P1 goals worth 2 + code:b7da/01/02 + cheat + description:P1 goals worth 3 + code:b7da/01/03 + cheat + description:P1 goals worth 4 + code:b7da/01/04 + cheat + description:P1 goals worth 5 + code:b7da/01/05 + cheat + description:P1 goals worth 6 + code:b7da/01/06 + cheat + description:P1 goals worth 7 + code:b7da/01/07 + cheat + description:P1 goals worth 8 + code:b7da/01/08 + cheat + description:P2 goals worth 2 + code:b7f2/01/02 + cheat + description:P2 goals worth 3 + code:b7f2/01/03 + cheat + description:P2 goals worth 4 + code:b7f2/01/04 + cheat + description:P2 goals worth 5 + code:b7f2/01/05 + cheat + description:P2 goals worth 6 + code:b7f2/01/06 + cheat + description:P2 goals worth 7 + code:b7f2/01/07 + cheat + description:P2 goals worth 8 + code:b7f2/01/08 + cheat + description:P1 starts with 1 point + code:91f6/8d/ee + cheat + description:P2 starts with 1 point + code:91f9/8d/ee + cheat + description:P1 starts with 2 points + code:91f5/00/02+91fa/e7/e6 + cheat + description:P1 starts with 4 points + code:91f5/00/04+91fa/e7/e6 + cheat + description:P1 starts with 6 points + code:91f5/00/06+91fa/e7/e6 + cheat + description:P1 starts with 8 points + code:91f5/00/08+91fa/e7/e6 + cheat + description:P1 starts with 10 points + code:91f5/00/0a+91fa/e7/e6 + cheat + description:P2 starts with 2 points + code:91f5/00/02+91f7/e6/e7 + cheat + description:P2 starts with 4 points + code:91f5/00/04+91f7/e6/e7 + cheat + description:P2 starts with 6 points + code:91f5/00/06+91f7/e6/e7 + cheat + description:P2 starts with 8 points + code:91f5/00/08+91f7/e6/e7 + cheat + description:P2 starts with 10 points + code:91f5/00/0a+91f7/e6/e7 + +cartridge sha256:e144020f37416f80f1a0da47aa9b3fbda338c61fcd175e8b2dc98df181e24b85 + name:Pro Wrestling (USA) (Rev A) + cheat + description:Infinite health and time + code:e655/0b/ef+e654/d6/a9+e656/f0/85+e657/0a/67 + cheat + description:Only have 5 seconds to get back into ring + code:e286/14/05 + cheat + description:Only have 10 seconds to get back into ring + code:e286/14/0a + cheat + description:Have 30 seconds to get back into ring + code:e286/14/1e + cheat + description:Rounds are only 1 minute + code:dfa4/05/01 + cheat + description:Rounds are only 3 minutes + code:dfa4/05/03 + cheat + description:Rounds are 8 minutes + code:dfa4/05/08 + cheat + description:Rounds are 10 minutes + code:dfa4/05/0a + cheat + description:2-second pin count + code:e46e/03/02 + cheat + description:5-second pin count + code:e46e/03/05 + cheat + description:7-second pin count + code:e46e/03/07 + 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 + name:Pro Wrestling (USA) + cheat + description:Infinite health and time + code:e655/0b/ef+e654/d6/a9+e656/f0/85+e657/0a/67 + cheat + description:Only have 5 seconds to get back into ring + code:e286/14/05 + cheat + description:Only have 10 seconds to get back into ring + code:e286/14/0a + cheat + description:Have 30 seconds to get back into ring + code:e286/14/1e + cheat + description:Rounds are only 1 minute + code:dfa4/05/01 + cheat + description:Rounds are only 3 minutes + code:dfa4/05/03 + cheat + description:Rounds are 8 minutes + code:dfa4/05/08 + cheat + description:Rounds are 10 minutes + code:dfa4/05/0a + cheat + description:2-second pin count + code:e46e/03/02 + cheat + description:5-second pin count + code:e46e/03/05 + cheat + description:7-second pin count + code:e46e/03/07 + 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 + name: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 + name:Punisher, The (USA) + cheat + description:Invincibility (blinking) + code:e4c4/f0/d0+e4c6/ca/e8 + cheat + description:Infinite health + code:a974/8d/ad+a631/8d/ad+a947/8e/ae + cheat + description:Infinite Grenades + code:ef5d/ca/ea + cheat + description:Infinite bullets and Rockets + code:f1d0/01/00 + cheat + description:Never lose a life against normal enemy + code:e29c/ca/ea + cheat + description:Never lose a life against end of level enemy + code:899a/ca/ea + cheat + description:Hit anywhere + code:a274/28/00+a21f/0d/00+a428/09/00+a12a/32/00 + cheat + description:Faster Punisher + code:b5bf/02/04 + cheat + description:Stage scrolls 2x as fast + code:e47c/00/01 + cheat + description:Stage scrolls 3x as fast + code:e47c/00/02 + cheat + description:Stage scrolls 4x as fast + code:e47c/00/03 + cheat + description:150 Machine Gun bullets on pick-up + code:fbb7/00/01 + cheat + description:150 Assault Rifle bullets on pick-up + code:fbba/00/01 + cheat + description:Less energy on pick-up + code:b90b/10/08 + cheat + description:More energy on pick-up + code:b90b/10/18 + cheat + description:Start with 1 life + code:e697/05/01 + cheat + description:Start with 10 lives + code:e697/05/0a + +cartridge sha256:691ef0807cacd7032c52ff65ab1718c28be45c7220afcc13f20c645dfb40d4ed + name:Puss n Boots - Pero's Great Adventure (USA) + cheat + description:Infinite health + code:cd71/85/a5 + cheat + description:Infinite lives + code:c21a/c6/a5 + cheat + description:Auto-fire and auto-jump + code:e81f/ff/00 + cheat + description:Mega-jump + code:cb27/09/00 + cheat + description:Start with less health + code:ebd7/38/1c + cheat + description:Start with 1 life + code:c092/03/01 + cheat + description:Start with 6 lives + code:c092/03/06 + cheat + description:Start with 9 lives + code:c092/03/09 + cheat + description:Start on stage 1 + code:c500/00/04 + cheat + description:Start on stage 2 + code:c500/00/09 + cheat + description:Start on stage 3 + code:c500/00/0e + cheat + description:Infinite health (alt) + code:0092/38 + cheat + description:Infinite lives (alt) + code:000a/09 + +cartridge sha256:0cf2fc17a59a0932ce43e6b2e9ea4e2570f03139784b5c9df429a499e734b92e + name:Puzznic (USA) + cheat + description:Press A to destroy blocks (no need to match blocks) + code:a639/94/00+a63d/05/00 + cheat + description:Slower timer + code:d241/3c/65 + cheat + description:Faster timer + code:d241/3c/1e + cheat + description:Start on level 2-1 + code:81b5/00/0a + cheat + description:Start on level 3-1 + code:81b5/00/14 + cheat + description:Start on level 4-1 + code:81b5/00/1e + cheat + description:Start on level 5-1 + code:81b5/00/28 + cheat + description:Start on level 6-1 + code:81b5/00/32 + cheat + description:Start on level 7-1 + code:81b5/00/3c + cheat + description:Start on level 8-1 + code:81b5/00/46 + cheat + description:Start on level 9-1 + code:81b5/00/50 + +cartridge sha256:5fa346174b6b5a9dc2b5fe113ef8d8ac013a32b26dde6d5dfc9ed631d5e9af25 + name:Q-bert (USA) + cheat + description:Infinite lives + code:a1d4/c6/a5 + cheat + description:Clear level automatically + code:c142/a5/a9 + cheat + description:Start with 1 life + code:9cb9/05/01+a323/05/01 + cheat + description:Start with 10 lives + code:a323/05/0a+9cb9/05/0a + cheat + description:Start on level 3 + code:9cd6/00/08 + cheat + description:Start on level 6 + code:9cd6/00/14 + cheat + description:Start on level 9 + code:9cd6/00/20 + 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 + name:Q Boy (Asia) (Unl) + cheat + description:Infinite lives + code:8f54/ce/ad + cheat + description:Infinite life + code:a9f2/ce/ad + cheat + description:Invincibility after first hit + code:95a7/c6/60 + cheat + description:Infinite Breath Power + code:aa8e/ce/ad+aa91/ce/ad + cheat + description:Infinite Lift Power + code:ab22/ce/ad+ab25/ce/ad + +cartridge sha256:745050dec23a692e1e759eb3e291f58ad7739fadb3a1308ec8d60085fefaec69 + name:QIX (USA) + cheat + description:1 life - P1 + code:8281/04/01 + cheat + description:1 life - P2 + code:8288/04/01 + cheat + description:Start on Level 5 - 1P game + code:8272/01/05 + cheat + description:Start on Level 10 - 1P game + code:8272/01/0a + cheat + description:Start on Level 20 - 1P game + code:8272/01/14 + cheat + description:Start on Level 5 - 2P game + code:828c/01/05 + cheat + description:Start on Level 10 - 2P game + code:828c/01/0a + cheat + description:Start on Level 20 - 2P game + code:828c/01/14 + +cartridge sha256:5dcea6d649f5ab79cf43dde76b92fb53b056fe92c6b49fd41f5158d9af0e9c32 + name:Quattro Adventure (USA) (Unl) + cheat + description:Boomerang Kid - Infinite lives + code:ce12/ce/ad + cheat + description:Boomerang Kid - Start with 6 lives + code:c611/03/06 + cheat + description:Linus Spacehead - Increase oxygen + code:c749/18/20 + cheat + description:Linus Spacehead - Never lose oxygen + code:b5b2/01/00 + cheat + description:Linus Spacehead - Never lose life in the water + code:c783/c6/a5 + cheat + description:Linus Spacehead - Never lose life in the land + code:d325/c6/a5 + cheat + description:Linus Spacehead - Start with 9 lives + code:c3c4/03/09 + cheat + description:Super Robin Hood - Invincibility + code:f59d/49/60 + cheat + description:Super Robin Hood - Infinite lives + code:c5fa/c6/a5 + cheat + description:Super Robin Hood - 9 energy hearts, you may lose some hearts when you pick up new ones + code:c603/03/09 + cheat + description:Super Robin Hood - Start with 1 life + code:c365/03/01 + cheat + description:Super Robin Hood - Start with 6 lives + code:c365/03/06 + cheat + description:Super Robin Hood - Start with 9 lives + code:c365/03/09 + 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:d7aa/00/01 + cheat + description:Treasure Island Dizzy - Walk backwards + code:e874/a5/a9 + cheat + description:Treasure Island Dizzy - Start with snorkel + code:d7bf/00/01 + cheat + description:Treasure Island Dizzy - Start with axe + code:d7bf/00/01+f2cd/12/01 + cheat + description:Treasure Island Dizzy - Start with dynamite + code:d7bf/00/01+f2cd/12/02 + cheat + description:Treasure Island Dizzy - Start with heavy weight + code:d7bf/00/01+f2cd/12/05 + +cartridge sha256:a537916d210a97e41e669c77f3ebcccb681dc44db4d8b758c2109baf8590d918 + name:Quattro Arcade (USA) (Unl) + cheat + description:Go! Dizzy Go! - Always kill monsters + code:dbe5/ea+dbe6/ea + cheat + description:Go! Dizzy Go! - Walk through walls + code:d3e3/ea + cheat + description:Go! Dizzy Go! - Start with 1 life + code:c562/03/01 + cheat + description:Go! Dizzy Go! - Start with 6 lives + code:c562/03/06 + cheat + description:Go! Dizzy Go! - Start with 9 lives + code:c562/03/09 + cheat + description:Go! Dizzy Go! - Start on world 1, stage 3 + code:c58c/01/02 + cheat + description:Go! Dizzy Go! - Start on world 1, stage 5 + code:c58c/01/04 + cheat + description:Go! Dizzy Go! - Start on world 2, stage 2 + code:c58c/01/06 + cheat + description:Go! Dizzy Go! - Start on world 2, stage 4 + code:c58c/01/08 + cheat + description:Go! Dizzy Go! - Start on world 4, stage 2 + code:c58c/01/10 + cheat + description:Go! Dizzy Go! - Start on world 4, stage 4 + code:c58c/01/12 + cheat + description:Go! Dizzy Go! - Start on world 5, stage 1 + code:c58c/01/14 + cheat + description:Go! Dizzy Go! - Start on world 5, stage 3 + code:c58c/01/16 + cheat + description:Go! Dizzy Go! - Start on world 5, stage 5 + code:c58c/01/18 + cheat + description:Sunt Buggies - Infinite lives + code:a09a/ce/ad + cheat + description:Sunt Buggies - Start with 1 life + code:ec4a/03/01 + cheat + description:Sunt Buggies - Start with 6 lives + code:ec4a/03/06 + cheat + description:Sunt Buggies - Start with 9 lives + code:ec4a/03/09 + cheat + description:F-16 Renegade - Start with 2 lives - 1P game + code:c8b0/03/01 + cheat + description:F-16 Renegade - Start with 7 lives - 1P game + code:c8b0/03/06 + cheat + description:F-16 Renegade - Start with 10 lives - 1P game + code:c8b0/03/09 + cheat + description:F-16 Renegade - Start on level 3 + code:c8b5/01/03+c8c2/00/01 + cheat + description:F-16 Renegade - Start on level 5 + code:c8b5/01/05+c8c2/00/02 + cheat + description:F-16 Renegade - Start on level 7 + code:c8b5/01/07+c8c2/00/03 + cheat + description:F-16 Renegade - Start on level 9 + code:c8b5/01/09+c8c2/00/04 + cheat + description:C.J.'s Elephant Antics - Infinite lives + code:e3c2/de/bd + cheat + description:C.J.'s Elephant Antics - Start in Switzerland + code:f801/00/01 + cheat + description:C.J.'s Elephant Antics - Start in Egypt + code:f801/00/02 + cheat + description:C.J.'s Elephant Antics - Start in Africa + code:f801/00/03 + cheat + description:C.J.'s Elephant Antics - Always run fast after losing all lives + code:f31d/00/01 + cheat + description:C.J.'s Elephant Antics - Super C.J. after losing all lives + code:f31d/00/0f + cheat + description:C.J.'s Elephant Antics - Start with 1 life + code:ee55/09/01 + cheat + description:C.J.'s Elephant Antics - Start with 5 lives + code:ee55/09/05 + cheat + description:C.J.'s Elephant Antics - Start with 15 lives + code:ee55/09/0f + cheat + description:C.J.'s Elephant Antics - Start with 20 lives + code:ee55/09/14 + +cartridge sha256:d4f1650059a011455577561ea607993a5046d452ba987b1c7381cad56550be0a + name:R.B.I. Baseball (USA) + cheat + description:Auto fielding + code:fada/09/00+fa1a/30/f0+fa1b/13/0f + cheat + description:Perfectly straight pitches - both players + code:bad3/36/80+bad2/71/a9 + cheat + description:Super slow pitches - both players + code:baac/36/00+baab/b1/a9 + cheat + description:Slow pitches - both players + code:baac/36/03+baab/b1/a9 + cheat + description:Fast pitches - both players + code:baab/b1/a9+baac/36/07 + cheat + description:Super fast pitches - both players + code:baab/b1/a9+baac/36/0f + cheat + description:All missed pitches are strikes - both players + code:bbe5/d0/10 + +cartridge sha256:0df01b1d7b6efe38c98f2f0b131707d833c87874938d5722bf0a9a488c2e41c0 + name:R.B.I. Baseball 2 (USA) (Unl) + cheat + description:Auto fielding + code:fac6/09/00+a703/30/f0+a704/13/0f + +cartridge sha256:3f9e3d3b48a897d94003df004ab4b332d749f85ea5d0e1a1b29b6d4f5634049a + name:R.C. Pro-Am (USA) (Rev A) + cheat + description:Infinite continues + code:d101/01/00 + cheat + description:Max turbo on first pick-up + code:c1b0/01/04 + cheat + description:Max tires on first pick-up + code:c1cc/01/04 + cheat + description:Max speed on first pick-up + code:c165/01/04 + cheat + description:Double turbo on first pick-up + code:c1b0/01/02 + cheat + description:Double tires on first pick-up + code:c1cc/01/02 + cheat + description:Double speed on first pick-up + code:c165/01/02 + cheat + description:Computer cars go crazy + code:b2e4/40/ad + 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 + name:R.C. Pro-Am (USA) + cheat + description:Infinite continues + code:d853/01/00 + cheat + description:Max turbo on first pick-up + code:c811/01/04 + cheat + description:Max tires on first pick-up + code:c82d/01/04 + cheat + description:Max speed on first pick-up + code:c7c6/01/04 + cheat + description:Double turbo on first pick-up + code:c811/01/02 + cheat + description:Double tires on first pick-up + code:c82d/01/02 + cheat + description:Double speed on first pick-up + code:c7c6/01/02 + cheat + description:Computer cars go crazy + code:b941/40/ad + 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 + name:R.C. Pro-Am II (USA) + cheat + description:Infinite credits + code:828c/de/bd + cheat + description:Infinite Lazers on purchase + code:e6cb/de/ad + cheat + description:Infinite Bombs on purchase + code:e4d2/de/ad + cheat + description:Infinite Freezes on purchase + code:e69c/de/ad + cheat + description:Infinite Buckshot on purchase + code:e52c/de/ad + cheat + description:Infinite Missiles on purchase + code:e556/de/ad + cheat + description:Items in the Model Shop are free if you have enough money + code:a43f/a5/60 + cheat + description:Buckshot costs 10 instead of 2,000 + code:e980/c8/01 + cheat + description:Mega Pulse costs 2,080 instead of 20,000 + code:e98b/07/00 + cheat + description:Scoopers costs 2,200 instead of 15,000 + code:e975/05/00 + cheat + description:Dynafit tires costs 2,320 instead of 10,000 + code:e973/03/00 + cheat + description:Mega Motor costs 1,360 instead of 50,000 + code:e96b/13/00 + cheat + description:Hyper Motor costs 1,840 instead of 30,000 + code:e969/0b/00 + cheat + description:Freeze costs 2,200 instead of 15,000 + code:e989/05/00 + cheat + description:Lazer costs 1,200 instead of 14,000 + code:e987/05/00 + cheat + description:Bombs costs 1,760 instead of 12,000 + code:e985/04/00 + cheat + description:Nobbies costs 1,880 instead of 7,000 + code:e971/02/00 + cheat + description:Missile costs 2,320 instead of 10,000 + code:e983/03/00 + cheat + description:Nitro costs 10 instead of 1000 + code:e97c/64/01 + cheat + description:Oil slicks costs 10 instead of 500 + code:e97a/32/01 + cheat + description:Skinny tires costs 10 instead of 2,000 + code:e96e/c8/01 + cheat + description:Gold Motor costs 10 instead of 16,000 + code:e967/06/00+e966/40/01 + cheat + description:Start with 1 credit instead of 3 + code:90db/02/00 + cheat + description:Start with 5 credits + code:90db/02/04 + cheat + description:Start with 7 credits + code:90db/02/06 + cheat + description:Start with 9 credits + code:90db/02/08 + cheat + description:Start on Track 02 + code:ce97/00/01 + cheat + description:Start on Track 03 + code:ce97/00/02 + cheat + description:Start on Track 04 + code:ce97/00/03 + cheat + description:Start on Track 05 + code:ce97/00/04 + cheat + description:Start on Track 06 + code:ce97/00/05 + cheat + description:Start on Track 07 + code:ce97/00/06 + cheat + description:Start on Track 08 + code:ce97/00/07 + cheat + description:Start on Track 09 + code:ce97/00/09 + cheat + description:Start on Track 10 + code:ce97/00/0a + cheat + description:Start on Track 11 + code:ce97/00/0b + cheat + description:Start on Track 12 + code:ce97/00/0c + cheat + description:Start on Track 13 + code:ce97/00/0d + cheat + description:Start on Track 14 + code:ce97/00/0e + cheat + description:Start on Track 15 + code:ce97/00/0f + cheat + description:Start on Track 16 + code:ce97/00/10 + cheat + description:Start on Track 17 + code:ce97/00/12 + cheat + description:Start on Track 18 + code:ce97/00/13 + cheat + description:Start on Track 19 + code:ce97/00/14 + cheat + description:Start on Track 20 + code:ce97/00/15 + cheat + description:Start on Track 21 + code:ce97/00/16 + cheat + description:Start on Track 22 + code:ce97/00/17 + cheat + description:Start on Track 23 + code:ce97/00/18 + cheat + description:Start on Track 24 + code:ce97/00/19 + cheat + description:Start on Track 25 + code:ce97/00/1b + cheat + description:Start on Track 26 + code:ce97/00/1c + cheat + description:Start on Track 27 + code:ce97/00/1d + cheat + description:Start on Track 28 + code:ce97/00/1e + cheat + description:Start on Track 29 + code:ce97/00/1f + cheat + description:Start on first Tug-O-Truck Challenge + code:ce97/00/08 + cheat + description:Start on Drag Race + code:ce97/00/11 + cheat + description:Start on second Tug-O-Truck Challenge + code:ce97/00/1a + cheat + description:Infinite continues + code:0771/09 + cheat + description:Infinite time at continue screen + code:0431/63 + +cartridge sha256:5cb8d03a90732d01737a401e8dc87a3d594ab2f901970f309fe551c0013ac5da + name:Race America (USA) + cheat + description:Can't down shift + code:b35c/d6/c5 + cheat + description:Cars only have 4 gears + code:b36d/07/05+a548/07/05 + cheat + description:Go super fast in 6th gear + code:9078/f0/a9+9079/05/ff+9224/e6/85 + +cartridge sha256:2e14f4481b5b762ba1ff0e7a25b07f316f7bdef0574a1704856f92823874f4e6 + name:Rad Racer (USA) + cheat + description:Infinite time + code:de27/ff + cheat + description:Never crash from things outside of the road + code:d54f/01/00 + cheat + description:Less time to finish each stage + code:de23/2d/24 + cheat + description:More time to finish each stage + code:de23/2d/3c + cheat + description:Turbo acceleration + code:c520/00/30 + cheat + description:Super Turbo acceleration + code:c53c/30/7f + cheat + description:Ultra Turbo acceleration + code:c581/00/01 + cheat + description:Start on stage 2 + code:c029/00/01+cec4/85/24 + cheat + description:Start on stage 3 + code:c029/00/02+cec4/85/24 + cheat + description:Start on stage 4 + code:c029/00/03+cec4/85/24 + cheat + description:Start on stage 5 + code:c029/00/04+cec4/85/24 + cheat + description:Start on stage 6 + code:c029/00/05+cec4/85/24 + cheat + description:Start on stage 7 + code:c029/00/06+cec4/85/24 + cheat + description:Start on stage 8 + code:c029/00/07+cec4/85/24 + 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 + name: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 + name:Radia Senki - Reimei Hen (Japan) + cheat + description:No random battles + code:fab5/85/a5 + +cartridge sha256:5d9f7deb09c9de8725c293366c943e6fef0a505a72bb1bc92be7a7a055cde464 + name:Raf World (Japan) + cheat + description:Invincibility + code:ea0a/29/09+ea18/29/09 + cheat + description:Infinite energy + code:ea3b/85/a5 + cheat + description:Infinite weapons + code:8e33/85/a5 + cheat + description:Infinite lives + code:c3f7/c6/c5 + cheat + description:Double-jump + code:81cd/a9/60 + +cartridge sha256:d79be89ff83550ba185d19fb586d2b5f988ad6743125b5233ab3bfe2cb814c94 + name:Raid 2020 (USA) (Unl) + cheat + description:Infinite health + code:ddd8/ce/ad+dd4e/ce/ad + cheat + description:Infinite lives + code:d6ed/ce/ad + +cartridge sha256:b7b5fdf2b31c4b8c5340f93f166fb56aecf598f7c43a24b4334502bb81065143 + name:Raid on Bungeling Bay (USA) + cheat + description:Infinite Damage + code:e5e9/20/ad + cheat + description:Infinite Bombs + code:d5d0/ce/ad + cheat + description:Can only carry 5 Bombs + code:d015/2c/28 + cheat + description:Start with 9 lives + code:c7f2/05/09 + cheat + description:Start with 1 life + code:c7f2/05/01 + cheat + description:Start on round 3 + code:c7ee/01/03 + cheat + description:Start on round 6 + code:c7ee/01/06 + cheat + description:Start on round 9 + code:c7ee/01/09 + cheat + description:Infinite Bombs (alt) + code:0254/2c + cheat + description:0 Damage + code:024d/23+024e/23 + +cartridge sha256:9866b51b16b503aa515967929060eb100ae4cbd851229a3125ecf3ee7c88346e + name:Rally Bike (USA) + cheat + description:Infinite gas + code:c33b/ee/dd + cheat + description:Infinite lives - 1P game + code:d406/ee/ad + cheat + description:Infinite lives - 2P game, both players + code:d41d/fe/ad + cheat + description:Start with 1 life - 1P game + code:de34/05/01 + cheat + description:Start with 10 lives - 1P game + code:de34/05/0a + cheat + description:Start with 1 life - 2P game, both players + code:dd34/06/01+d42e/06/02 + cheat + description:Start with 10 lives - 2P game, both players + code:de34/05/0a+d42e/05/0b + +cartridge sha256:2596cf1e1a9b09dac24aeffea708807173ec81fa7093b2a729f1539aec3b5764 + name:Rambo (USA) (Rev A) + cheat + description:Invincibility + code:dd1a/b5/60 + cheat + description:Infinite weapons + code:ec9a/de/ad + cheat + description:Gain double amount on pick-up + code:e2a2/0a/14 + cheat + description:Gain maximum amount on pick-up + code:e2a2/0a/74 + cheat + description:Hit anywhere + code:d9ef/3a/00 + cheat + description:Start with 2 Medicine Bottles + code:868d/05/02 + cheat + description:Start with 9 Medicine Bottles + code:868d/05/62 + cheat + description:Start with Hand Grenades + code:867d/11/15+8683/11/15 + 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 + name:Rambo (USA) + cheat + description:Invincibility + code:dd1a/b5/60 + cheat + description:Infinite weapons + code:ec9a/de/ad + cheat + description:Gain double amount on pick-up + code:e2a2/0a/14 + cheat + description:Gain maximum amount on pick-up + code:e2a2/0a/74 + cheat + description:Hit anywhere + code:d9ef/3a/00 + cheat + description:Start with 2 Medicine Bottles + code:868d/05/02 + cheat + description:Start with 9 Medicine Bottles + code:868d/05/62 + cheat + description:Start with hand grenades + code:867d/11/15+8683/11/15 + 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 + name:Rampage (USA) + cheat + description:No harm from attacks or bad food + code:b3a0/91/24 + cheat + description:No harm from falling + code:b4a1/10/00 + cheat + description:No harm from water + code:b919/01/00+b955/01/00 + cheat + description:Buildings collapse automatically + code:e5b1/b0/50 + cheat + description:Buildings collapse faster + code:a6d4/f0/50+aa93/0d/15 + cheat + description:One hit destroys buildings + code:a1cf/05/80 + cheat + description:More health - P1 + code:c353/7f/ff + cheat + description:More health - P2 + code:c36e/7f/ff + cheat + description:Less health - P1 + code:c353/7f/3f + cheat + description:Less health - P2 + code:c36e/7f/3f + cheat + description:More health after continue - both players + code:cff4/7f/ff + cheat + description:Less health after continue - both players + code:cff4/7f/3f + cheat + description:More damage done from falling + code:b4a1/10/20 + cheat + description:Double health from food + code:b3b3/05/04 + cheat + description:Half health from food + code:b3b3/05/00+b3b6/0a/4a + +cartridge sha256:501e921616931e4796c44b1e80c7112c881eb1e9a3190d0e6a3b4b199ee368e3 + name:Ren & Stimpy Show, The - Buckeroo$! (USA) + cheat + description:Infinite health + code:fb12/07/ff + cheat + description:Infinite lives + code:ea39/06/ff + cheat + description:Infinite collectibles + code:8a82/99/b9 + cheat + description:Shorter invincibility after getting hit + code:fb01/3c/1f + cheat + description:Longer invincibility after getting hit + code:fb01/3c/65 + cheat + description:2 custard pies on pick-up + code:f229/05/02 + cheat + description:9 custard pies on pick-up + code:f229/05/09 + cheat + description:Start with $11 instead of 0 + code:85ab/9d/fe + cheat + description:Start with 2 lives + code:82b1/03/01 + cheat + description:Start with 6 lives + code:82b1/03/05 + cheat + description:Start with 8 lives + code:82b1/03/07 + cheat + description:Start with 10 lives + code:82b1/03/09 + cheat + description:Start on Rescue the Maiden level + code:8709/d0/a9+870a/22/01 + cheat + description:Start on Out West level + code:8709/d0/a9+870a/22/01+870b/ee/8d + cheat + description:Start on Robin Hoek level + code:8709/d0/a9+870a/22/02+870b/ee/8d + +cartridge sha256:b4856061c9310015101c461aef744e9dcf3b158bd13d5d9cb4a76d3ca18a6864 + name:Renegade (USA) + cheat + description:Infinite lives + code:deb1/c6/a5 + cheat + description:Timer runs faster + code:ead9/3e/1e + cheat + description:Timer runs slower + code:ead9/3e/a0 + cheat + description:Start with a super energy boost + code:933a/28/50 + cheat + description:Start with 1 life - both players + code:d79b/02/00 + cheat + description:Start with 6 lives - both players + code:d79b/02/05 + cheat + description:Start with 9 lives - both players + code:d79b/02/08 + cheat + description:Start on mission 2 + code:d7af/00/01 + cheat + description:Start on mission 3 + code:d7af/00/02 + cheat + description:Start on mission 4 + code:d7af/00/03 + cheat + description:Infinite time + code:0472/59 + cheat + description:Enemies have no health + code:007e/00+007f/00+0080/00 + +cartridge sha256:f17df83a3e714c9f839dcd428d31a0b8b3cdb5fe1a78f24f43f158cb379720c1 + name:Ring King (USA) + cheat + description:Infinite power points - 1P game + code:d601/ce/2c + cheat + description:Don't lose stamina from fighting + code:afc2/91/24 + cheat + description:Rounds are 30 seconds + code:d79b/06/03 + cheat + description:Rounds are 90 seconds + code:d79b/06/09 + cheat + description:Players can't hurt each other + code:ad91/91/24 + 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 + name:River City Ransom (USA) + cheat + description:Infinite lives + code:8cfb/9d/bd + cheat + description:Start with max stats + code:f6d8/0f/63 + cheat + description:Infinite money + code:9ac9/9d/bd+9ad0/9d/bd+9ad7/9d/bd + cheat + description:Coins worth max amount of money + code:ec22/13/23 + cheat + description:Infinite Stamina + code:bb86/b9/99+bbee/e9/a9 + cheat + description:Infinite Will Power + code:af1f/9d/bd + cheat + description:Max Punch + code:936d/3f/7f + cheat + description:Max Kick + code:936e/3f/7f + cheat + description:Max Weapon + code:936f/3f/7f + cheat + description:Max Throw + code:9370/3f/7f + cheat + description:Max Agility + code:9371/3f/7f + cheat + description:Max Defense + code:9372/3f/7f + cheat + description:Max Strength + code:9373/3f/7f + cheat + description:Max Will Power + code:9374/3f/7f + cheat + description:Max Stamina + code:9376/7f/ff + cheat + description:View the credits + code:f2e2/d0/f0 + cheat + description:Start with double every attribute + code:f6d8/0f/1e + cheat + description:Start with 127 of all stats + code:f6d8/0f/7f + cheat + description:Start with 99 Stamina + code:f6f5/3f/63 + cheat + description:Start with double money - P1 + code:f708/20/40 + cheat + description:Start with double money - P2 + code:f717/20/40 + cheat + description:Start with $100 extra - P1 + code:f70d/00/01 + cheat + description:Start with $100 extra - P2 + code:f71c/00/01 + +cartridge sha256:46361c5b4007e6ef855430934b5a205aa19c885857a7eb31072646753d06e321 + name:RoadBlasters (USA) + cheat + description:Infinite credits + code:d004/ce/ad + cheat + description:Double credits + code:be63/02/04 + cheat + description:Extend lifetime of UZ Cannon + code:8d80/05/09 + cheat + description:Extend lifetime of Nitro Injector + code:8dd9/80/ff + cheat + description:Reduce lifetime of Nitro Injector + code:8dd9/80/40 + cheat + description:Infinite Cruise missiles + code:8dec/ce/ad+8d1f/1e/e0 + cheat + description:Infinite UZ Cannon + code:8d78/a5/60+8d1f/1e/2b + cheat + description:Infinite Nitro Injectors + code:8ddc/ce/60+8d1f/1e/8d+8dc9/f0/24 + cheat + description:Infinite Electro Shield + code:8e5c/ce/ad+8d1f/1e/51+8d20/8d/8e + 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 + name:Road Runner (USA) (Unl) + cheat + description:Infinite lives + code:eb1b/ce/ad + cheat + description:Never lose seed + code:c1b0/c8/ea+eba5/c8/ea + cheat + description:Start with 1 life + code:e40e/05/00 + cheat + description:Start with 12 lives + code:e40e/05/0b + cheat + description:Start with 18 lives + code:e40e/05/11 + cheat + description:Start on level 5 + code:e413/01/05 + cheat + description:Start on level 10 + code:e413/01/0a + cheat + description:Start on level 15 + code:e413/01/0f + cheat + description:Start on level 20 + code:e413/01/14 + cheat + description:Start on level 25 + code:e413/01/19 + cheat + description:Start on level 30 + code:e413/01/1e + +cartridge sha256:687e4129be3b8e224a9748cba9687b8c10e5feb234a727bdf2dcb8d3c8c47097 + name:Robin Hood - Prince of Thieves (USA) (Rev A) + cheat + description:Infinite HP for Robin in main combat + code:8b29/85/86 + cheat + description:Infinite HP for Robin in dueling combat + code:8921/30/f0 + cheat + description:Infinite Arrows + code:9255/01/00 + cheat + description:Bandages give more HP back + code:b7a3/08/14 + cheat + description:Food gives more HP back - Except the Leg of meat + code:b3b5/08/18 + 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 + name:Robin Hood - Prince of Thieves (USA) + cheat + description:Infinite HP for Robin in main combat + code:8b29/85/86 + cheat + description:Infinite HP for Robin in dueling combat + code:8921/30/f0 + cheat + description:Infinite Arrows + code:9255/01/00 + cheat + description:Bandages give more HP back + code:b7a3/08/14 + cheat + description:Food gives more HP back - Except the Leg of meat + code:b3b5/08/18 + 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 + name:Robo Warrior (USA) + cheat + description:No damage from bomb blast + code:f23f/4e/2c + cheat + description:No damage from monsters and no power drain + code:f27d/4e/2c + cheat + description:Infinite Barrier after pick-up + code:c924/e6/ea + cheat + description:Infinite Mega Bombs after pick-up + code:ddaf/d6/b5 + cheat + description:Infinite Super Bombs + code:e147/c6/a5 + cheat + description:Walk through walls + code:cbf0/10/90 + cheat + description:5 Super Bombs on pick-up + code:e561/0a/05 + cheat + description:20 Super Bombs on pick-up + code:e561/0a/14 + cheat + description:Set firing range to 5 + code:c170/01/05 + cheat + description:Set firing range to 10 + code:c170/01/0a + cheat + description:Start with 5 of everything + code:c1eb/00/05 + cheat + description:Start with 10 of everything + code:c1eb/00/0a + cheat + description:Start with defense level at 5 + code:c1e5/01/05 + cheat + description:Start with defense level at 8 + code:c1e5/01/08 + cheat + description:Always have 99 Medals + code:0058/63 + cheat + description:Always have 99 Super Boots + code:0061/63 + cheat + description:Always have 99 Clocks + code:0062/63 + cheat + description:Always have 99 Flash + code:0063/63 + cheat + description:Always have 99 CrossFires + code:0064/63 + cheat + description:Always have 99 Candles + code:0065/63 + cheat + description:Always have 99 Energy Capsule + code:0066/63 + cheat + description:Always have 99 Missles + code:0067/63 + cheat + description:Always have 99 Megaton Bombs + code:004d/63 + cheat + description:Always have 99 Life Vest + code:004e/63 + cheat + description:Always have 99 Lanterns + code:004f/63 + +cartridge sha256:100c394264b40c17f635a6356c884135558bf2aee1a7f60c9ce43441e48a06cb + name:Robocco Wars (Japan) + cheat + description:Start on level 5 + code:a831/00/3c + +cartridge sha256:d04b445ac57cccb3a31a3bf83d002dc9a9765f15313e96f67be077b6114d2411 + name:RoboCop (USA) + cheat + description:Invincibility + code:e276/35/3b+b62f/20/bd + cheat + description:Infinite time + code:a5cf/e6/a5 + cheat + description:Infinite ammunition + code:eb14/05/c5 + cheat + description:No damage from touching enemies + code:ee49/85/a5 + cheat + description:No damage from enemy bullets + code:ef6e/85/a5 + cheat + description:Bosses die automatically + code:a29d/3b/00 + cheat + description:Can't harm civilian at the end of level 1 + code:a7c3/bd/9d + cheat + description:Triple normal power on power food pick-up + code:fd17/03/09 + cheat + description:Triple normal time on battery pick-up + code:fd28/03/09 + cheat + description:Max time on battery pick-up + code:fd28/03/16 + cheat + description:Full power on power food pick-up + code:fd17/03/16 + cheat + description:Use with COP Code 2 to start with machine gun and Cobra gun + code:d128/01/0f + cheat + description:Press Start to finish the level (may cause graphical glitches in later levels) + code:d224/0e/0f + cheat + description:Start on level 2 + code:d10a/00/01+d10b/95/85+d10c/85/66 + cheat + description:Start on level 3 + code:d10a/00/02+d10b/95/85+d10c/85/66 + cheat + description:Start on level 4 + code:d10a/00/03+d10b/95/85+d10c/85/66 + cheat + description:Start on level 5 + code:d10a/00/04+d10b/95/85+d10c/85/66 + cheat + description:Start on level 6 + code:d10a/00/05+d10b/95/85+d10c/85/66 + cheat + description:Infinite health + code:006e/00 + cheat + description:Infinite time (alt) + code:0082/00 + +cartridge sha256:8ed3cb0046caecbefdc6c6b3ad8dae013442136f6a65c1a21b54586b0275e615 + name:RoboCop 2 (USA) (Rev A) + cheat + description:Invincibility + code:8feb/d0/f0 + cheat + description:Infinite health + code:e7c1/99/60 + cheat + description:Infinite lives + code:c17d/d6/d5 + cheat + description:Infinite time + code:e704/c6/c5+e6fc/c6/c5 + cheat + description:No enemies + code:8b72/f0/d0 + cheat + description:Each N (Nuke) is worth 10 + code:e80c/03/00 + 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 + name:RoboCop 2 (USA) + cheat + description:Invincibility + code:8feb/d0/f0 + cheat + description:Infinite lives + code:c17d/d6/d5 + cheat + description:No enemies + code:8b72/f0/d0 + 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 + name:RoboCop 3 (USA) + cheat + description:Infinite efficiency + code:f19b/e5/a9+f19c/e2/19 + cheat + description:Infinite efficiency (alt) + code:f1a1/9d/b9 + cheat + description:One hit kills + code:f0b8/fc/7c + cheat + description:Hit anywhere + code:f088/eb/00 + cheat + description:Lots of repair icons + code:c0c3/06/ee + cheat + description:Start with 2x health + code:c265/19/32 + cheat + description:Start with 1/2 health + code:c265/19/0c + 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 + name:RoboCop versus The Terminator (USA) (Proto) + cheat + description:Infinite lives + code:d442/8d/ad + cheat + description:Infinite health + code:e10c/8d/ad + cheat + description:Infinite health (alt) + code:04ee/0a + +cartridge sha256:d0e5899cf6b756d697be9ad6700d1f612b1604496374da9606478d5cdbceebf1 + name:Robodemons (USA) (Unl) + cheat + description:Infinite health + code:051b/14 + +cartridge sha256:e1a3d949b9bf258b4d2c92104cedd7957a311f142dc2cb32eb92ce559837377f + name:Rocketeer, The (USA) + cheat + description:Infinite health + code:d75d/ed/2c + cheat + description:Have all weapons with infinite ammo + code:bd64/05/00 + cheat + description:1/2 normal bullets on pick-up + code:a212/0a/05 + cheat + description:2x normal bullets on pick-up + code:a212/0a/14 + cheat + description:3x normal bullets on pick-up + code:a212/0a/1e + cheat + description:1/2 silver bullets on pick-up + code:a204/14/0a + cheat + description:2x silver bullets on pick-up + code:a204/14/28 + cheat + description:3x silver bullets on pick-up + code:a204/14/3c + cheat + description:Start with 1/2 health + code:bcd7/08/04 + cheat + description:Start with 2x health + code:bcd7/08/10 + cheat + description:Start with 3x health + code:bcd7/08/18 + 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 + name:Rocket Ranger (USA) + cheat + description:Double amount of Lunarium in storage + code:cf95/01/02 + cheat + description:Triple amount of Lunarium in storage + code:cf95/01/03 + cheat + description:Lunarium level in backpack at 99 + code:cf9a/3c/63 + cheat + description:Never lose Lunarium in backpack + code:c351/8d/ad + cheat + description:Half amount of Lunarium in storage + code:cf95/01/00+cf9f/00/32 + +cartridge sha256:683c49e4ea3f4b179065deccecd3e4a86a4e355e13924872571e7b7c79205d0c + name:Rockin' Kats (USA) + cheat + description:Invincibility + code:e628/f0/d0 + cheat + description:Infinite health + code:e6ca/8d/ad + cheat + description:Infinite lives + code:cd99/ce/cd + cheat + description:Hit anywhere + code:e6f6/16/00 + cheat + description:Can select any item (you will not be able to see it) + code:829f/d1/00 + cheat + description:Can always select channel 5 + code:8ba8/10/00 + cheat + description:Can always buy items + code:8f89/a5/a9 + 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 + name:Rock 'n' Ball (USA) + cheat + description:Infinite balls + code:a07f/de/bd + +cartridge sha256:9fdbaa2877363948b466a6e3e11a1bce02d2a6490cb90808be4d788fe4630eba + name:Rod Land (Europe) + cheat + description:Infinite lives + code:9911/5e/bd + cheat + description:Infinite time in extra game + code:e490/c6/a5 + cheat + description:Start with invincibility + code:dbe8/f0/d0 + cheat + description:Start on scene 31 + code:c5df/00/1e + +cartridge sha256:1a35607e218d68106367e7b87735aa9f10bf330c3a71f607a21de2d7fc763ef8 + name:Roger Clemens' MVP Baseball (USA) + cheat + description:Infinite balls (balls are not called) + code:d3f0/00/91 + cheat + description:Infinite balls and strikes + code:8173/f6/b5 + cheat + description:Strikes are not called when batter doesn't swing + code:d3eb/01/91 + cheat + description:Strikes are not called when batter swings + code:8170/02/04 + cheat + description:2 strikes and you're out + code:8178/03/02+b19f/03/02+c1ec/03/02 + cheat + description:1 strike and you're out + code:8178/03/01+b19f/03/01+c1ec/03/01 + cheat + description:1 ball for a walk + code:c1fb/04/01 + cheat + description:2 balls for a walk + code:c1fb/04/02 + cheat + description:3 balls for walk + code:c1fb/04/03 + +cartridge sha256:942c802c34627c969c49dae94fb8b48c7b1e873a65803caad559324e2a54b4c8 + name:Rollerblade Racer (USA) + cheat + description:Infinite lives + code:d7e8/c6/a9 + cheat + description:1 fall and you're dead + code:d7e1/04/01 + cheat + description:6 falls and you're dead + code:d7e1/04/06 + cheat + description:8 falls and you're dead + code:d7e1/04/08 + cheat + description:Start on the City Street + code:ca3f/00/02 + cheat + description:Start with 1 life + code:ca3b/03/01 + cheat + description:Start with 6 lives + code:ca3b/03/06 + cheat + description:Start with 9 lives + code:ca3b/03/09 + cheat + description:Start on Hit the Beach + code:ca3f/00/04 + cheat + description:Start on Panic Park + code:ca3f/00/06 + +cartridge sha256:7ddc56bf2b8d8f3f980837bbc48284fd7241e111a9f51599c6e358518d3469dc + name:Rollergames (USA) + cheat + description:Infinite lives + code:f788/c6/a5 + cheat + description:Infinite special moves + code:92e0/c6/24 + cheat + description:9 special moves + code:8052/03/09 + cheat + description:6 special moves + code:8052/03/06 + cheat + description:Mega-jump + code:8440/00/09 + cheat + description:Infinite time + code:8d1f/85/24 + cheat + description:Faster timer + code:8d13/3f/1f + cheat + description:Slower timer + code:8d13/3f/7f + cheat + description:Start with less energy + code:8056/0c/06 + cheat + description:Start with more energy + code:8056/0c/18 + 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 + name:Rolling Thunder (USA) (Unl) + cheat + description:Infinite health + code:a654/8d/ad + cheat + description:Infinite lives + code:eb73/c6/a5+eb53/c6/a5 + cheat + description:Infinite time + code:e20f/c6/a5 + cheat + description:Hit anywhere + code:a7d0/b8/40+d733/d0/60+a7d1/a8/a9 + cheat + description:200 Machine Gun bullets on pick-up + code:e8d0/64/c8 + cheat + description:300 Machine Gun bullets and 300 bullets on pick-up + code:a291/de/bd + cheat + description:Gain fewer bullets on pick-up + code:e8cf/32/14 + cheat + description:Self-replenishing bullets + code:d766/01/32 + cheat + description:Start with 200 bullets + code:e0aa/32/c8 + cheat + description:Start with 200 bullets on each new life + code:eb4c/32/c8 + cheat + description:Start with loads of ammunition + code:e0a2/00/03+eb44/00/03 + cheat + description:Start with 1 life + code:e09b/03/01 + cheat + description:Start with 6 lives + code:e09b/03/06 + cheat + description:Start with 9 lives + code:e09b/03/09 + cheat + description:Start with 1 life after continue + code:9257/03/01 + cheat + description:Start with 6 lives after continue + code:9257/03/06 + cheat + description:Start with 9 lives after continue + code:9257/03/09 + cheat + description:Start with increased life meter + code:e88d/02/08 + cheat + description:Start on story 1 area 02 + code:8f6b/00/01+8f6d/b1/30 + cheat + description:Start on story 1 area 03 + code:8f6b/00/02+8f6d/b1/30 + cheat + description:Start on story 1 area 04 + code:8f6b/00/03+8f6d/b1/30 + cheat + description:Start on story 1 area 05 + code:8f6b/00/04+8f6d/b1/30 + cheat + description:Start on story 2 area 06 + code:8f6b/00/05+8f6d/b1/30 + cheat + description:Start on story 2 area 07 + code:8f6b/00/06+8f6d/b1/30 + cheat + description:Start on story 2 area 08 + code:8f6b/00/07+8f6d/b1/30 + cheat + description:Start on story 2 area 09 + code:8f6b/00/08+8f6d/b1/30 + cheat + description:Start on story 2 area 10 + code:8f6b/00/09+8f6d/b1/30 + cheat + description:Start on story 3 area 01 + code:8dca/00/01 + 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 + name:Roundball - 2-on-2 Challenge (USA) + cheat + description:Start with 1 ball - all players + code:c175/03/01 + cheat + description:Infinite balls - all players + code:c241/de/ad + +cartridge sha256:fade44d9c76173afe098fbe02d859735e06b2c509fd80da08b1cc85bfc01a556 + name:Rush'n Attack (USA) + cheat + description:Invincibility (star effect) + code:8724/05/84+872f/05/84 + cheat + description:Invincibility (except vs bullets) + code:8131/d0/50 + cheat + description:Infinite POW + code:8df5/01/00 + cheat + description:Always have 255 POW + code:df6f/ad/8d + cheat + description:Hit anywhere + code:82cb/b0/50+8520/b0/4c+82cc/6b/3b+8522/b9/85+8521/5c/37 + cheat + description:Infinite lives - P1 + code:8718/c6/24 + cheat + description:Infinite lives - P2 + code:871d/c6/24 + cheat + description:Multi-jump + code:af33/ff/08+af3c/ff/60+87d3/f1/30+af39/ff/20+af36/ff/20+af34/ff/f0+af37/ff/f8+af31/ff/04+af35/ff/03+87d4/8b/af+af38/ff/89+af3a/ff/f1+af32/ff/29+af30/ff/a5+af3b/ff/8b + cheat + description:Start with 1 life - P1 + code:d16e/05/01 + cheat + description:Start with 1 life - P2 + code:d176/05/01 + cheat + description:Start with 10 lives - P1 + code:d16e/05/0a + cheat + description:Start with 10 lives - P2 + code:d176/05/0a + 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 + name:Rygar (USA) (Rev A) + cheat + description:Invincibility + code:ae01/84/60 + cheat + description:Infinite health + code:aeb2/85/a5 + cheat + description:Infinite Mind points + code:822a/00 + cheat + description:Have first three items after pressing B once + code:a3c1/25/05 + cheat + description:Hit anywhere + code:ad1c/b0/30+ad33/b0/30+ad22/b0/30+ad39/b0/f0 + cheat + description:One hit kills + code:afae/85/11 + cheat + description:Pits aren't fatal (side view) + code:a013/08/00 + cheat + description:Walk on water (side view) + code:9cdd/d0/50 + cheat + description:Enemies always drop a health potion + code:b557/b0/90+b57f/07/03+b57e/29/a9 + cheat + description:Enemies always drop a Mind unit + code:b557/b0/90+b57f/07/04+b57e/29/a9 + cheat + description:Don't be pushed after being hit + code:ae9e/05/60 + cheat + description:Jump higher + code:966b/04/03 + cheat + description:Multi-jump + code:ad4d/f0/10+a016/a9/60+ad4a/04/28+ad51/05/04+ad4b/29/25+ad4f/ad/8d+ad49/92/a5+ad50/32/c2+ad48/ad/ea+ad4c/20/2a + cheat + description:Grappling Hook continues until it finds something + code:9931/ce/ad+a22c/85/a5 + cheat + description:Start with 12 units of health + code:c0b1/06/18+c0b2/06/18 + 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 + name:Rygar (USA) + cheat + description:Invincibility + code:ae01/84/60 + cheat + description:Infinite health + code:aeb2/85/a5 + cheat + description:Infinite Mind points + code:822a/00 + cheat + description:Have first three items after pressing B once + code:a3c1/25/05 + cheat + description:Hit anywhere + code:ad1c/b0/30+ad33/b0/30+ad22/b0/30+ad39/b0/f0 + cheat + description:One hit kills + code:afae/85/11 + cheat + description:Pits aren't fatal (side view) + code:a013/08/00 + cheat + description:Walk on water (side view) + code:9cdd/d0/50 + cheat + description:Enemies always drop a health potion + code:b557/b0/90+b57f/07/03+b57e/29/a9 + cheat + description:Enemies always drop a Mind unit + code:b557/b0/90+b57f/07/04+b57e/29/a9 + cheat + description:Don't be pushed after being hit + code:ae9e/05/60 + cheat + description:Jump higher + code:966b/04/03 + cheat + description:Multi-jump + code:ad4d/f0/10+a016/a9/60+ad4a/04/28+ad51/05/04+ad4b/29/25+ad4f/ad/8d+ad49/92/a5+ad50/32/c2+ad48/ad/ea+ad4c/20/2a + cheat + description:Grappling Hook continues until it finds something + code:9931/ce/ad+a22c/85/a5 + cheat + description:Start with 12 units of health + code:c0b1/06/18+c0b2/06/18 + 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 + name:S.C.A.T. - Special Cybernetic Attack Team (USA) + cheat + description:Infinite health + code:dc7b/01/00 + cheat + description:More energy on pick-up + code:ec7f/03/0a + cheat + description:Don't lose speed-ups when hit + code:dc8e/08/00 + cheat + description:Longer immunity + code:dc84/40/ff + cheat + description:Shorter immunity + code:dc48/40/10 + cheat + description:Faster maximum speed-up + code:de04/06/09+de05/fa/f7 + cheat + description:Faster normal speed-up + code:ddf4/04/06+ddf5/fc/fa + cheat + description:Start with more health + code:cea4/06/32 + cheat + description:Infinite health - P1 + code:001c/09 + +cartridge sha256:4d6e58f232dc1a592583889f858eac230b8e8921e715276e580073ab2dd18546 + name: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 + name: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 + name: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 + name:Secret Scout in the Temple of Demise (USA) (Unl) + cheat + description:Infinite lives + code:e4a7/99/b9 + cheat + description:View the ending + code:d5e7/00/58 + +cartridge sha256:c33611fb6b3ced6cf0ab4cd8e6795be44dc164efd453a69bad404c95837ec420 + name:Secret Ties (USA) (Proto) + cheat + description:Invincibility + code:c8fb/cc/cd + cheat + description:Infinite health + code:c960/85/a5 + cheat + description:Infinite lives + code:faec/c6/c5 + cheat + description:Infinite Gun + code:c763/c6/a5 + cheat + description:Infinite Shield + code:c91d/c6/a5 + cheat + description:Super-jump + code:c5f0/05/1f+c4e7/06/20 + cheat + description:Allways able to use Gun + code:ef22/d0/50 + cheat + description:Allways able to use Shield + code:ef1c/d0/50 + cheat + description:Start with 99 lives + code:e1e0/03/64 + cheat + description:Start with double health + code:e1f9/05/0a + 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 + name:Section-Z (USA) + cheat + description:Infinite lives + code:9d93/c6/a5 + cheat + description:Energy tube gives full energy boost + code:fa3b/00/0a + cheat + description:Autofiring capability + code:9efb/f5/f7 + cheat + description:Autofire without having to hold the button down + code:9efb/f5/ff + cheat + description:Press Start to complete current mission (do not use past sector 40) + code:d395/07/00+d391/49/a9+d394/fd/39+d392/01/02 + cheat + description:Start a new game to view the ending + code:8702/01/03 + cheat + description:Start with 1 life + code:d2ad/03/01 + cheat + description:Start with 6 lives + code:d2ad/03/06 + cheat + description:Start with 9 lives + code:d2ad/03/09 + cheat + description:Infinite energy + code:005b/09+005a/09 + +cartridge sha256:afc7ce7262cc03039481b9338a94db35a1f4e9e54ee3dd34f979a7921d4a5e29 + name:Seicross (USA) + cheat + description:Infinite lives + code:8ae8/bd + cheat + description:Slow motion + code:8ccb/01 + cheat + description:Start with 1 life + code:80b4/01 + cheat + description:Start with 6 lives + code:80b4/06 + cheat + description:Start with 9 lives + code:80b4/09 + cheat + description:Infinite health - P1 + code:0078/bd + cheat + description:Infinite lives - P1 + code:0615/99 + +cartridge sha256:2395a8a102bfc403bb2c474f77035483792ec15bce37695c9f2d96d62bc8fe10 + name:Shadow of the Ninja (USA) + cheat + description:Infinite continues + code:f55d/c6/a5 + cheat + description:Don't lose energy from enemy attacks + code:ac6d/9d/2c + cheat + description:Don't lose energy from falling + code:9564/04/00 + cheat + description:Maximum energy gained from potion + code:8c19/04/10 + cheat + description:Less energy gained from potion + code:8c19/04/01 + cheat + description:Mega-jump + code:96c0/fe/ea + cheat + description:40 Throwing Stars on pick-up + code:8c31/14/28 + cheat + description:20 Bombs on pick-up + code:8c46/05/14 + cheat + description:Some enemies can't move left or right + code:a12b/9d/ea + cheat + description:9 continues + code:e08a/05/09 + cheat + description:1 continue + code:e08a/05/01 + +cartridge sha256:fbc69cdaf7c1419906d8cf2a74ab70d11520b2f3877387b8fd70460b6e6dd542 + name:Shadowgate (USA) + cheat + description:Infinite torches + code:d78a/ce/ea + +cartridge sha256:c3f361c4a1441101d6a3eb42f5776073c712198e7ed45d6ab5350816ea15aee4 + name:Shatterhand (USA) + cheat + description:Hit anywhere + code:8519/b0/50+84f3/b0/24+84ff/90/24+84db/90/24 + cheat + description:Power-ups don't use up gold + code:c94d/01/00 + cheat + description:Big coins worth double + code:82a2/14/28 + cheat + description:Big coins worth half + code:82a2/14/0a + cheat + description:Small coins worth triple + code:8287/05/0f + cheat + description:Start with less health + code:f5fa/08/04 + cheat + description:Start with 1 life + code:f5e8/02/00 + cheat + description:Start with 6 lives + code:f5e8/02/05 + cheat + description:Start with 9 lives + code:f5e8/02/08 + cheat + description:Invincibility - Robot Suit + code:05c2/7e + cheat + description:Powered up - Red Vest + code:05c8/03 + +cartridge sha256:2b85e6411f42597ceab01f5eb3ba9fd362b07340c0665fd533a3c3d5f2b1e972 + name:Shinobi (USA) (Unl) + cheat + description:Infinite life + code:d771/ce/ad + cheat + description:Infinite lives + code:920b/ce/ad + cheat + description:Turbo running + code:9dcf/03/05 + cheat + description:Start with double life + code:902e/06/0c+91f4/06/0c + cheat + description:Start with 1 life + code:907b/02/00 + cheat + description:Start with 6 lives + code:907b/02/05 + cheat + description:Start with 9 lives + code:907b/02/08 + +cartridge sha256:0df6a7a16af6cffc9a54a3de1ab14225f2ce5d5a269a691f16a22d3fd42b942b + name:Shinsenden (Japan) + cheat + description:No random battles + code:b029/30/60 + +cartridge sha256:6c705f7980a08b7a7a5d74ddfd175155492168248f65c7d9e3cef1a6b14a2886 + name:Shooting Range (USA) + cheat + description:Double bonus time for hourglasses + code:9801/32/64 + cheat + description:Half bonus time for hourglasses + code:9801/32/19 + cheat + description:More time for level 1 + code:83c5/03/04+860e/03/04 + cheat + description:Less time for level 1 + code:83c5/03/02+860e/03/02 + cheat + description:More time for level 2 + code:8610/02/04+8611/32/00 + cheat + description:Less time for level 2 + code:8610/02/01+8611/32/32 + cheat + description:More time for level 3 + code:8612/02/04+8613/00/32 + cheat + description:Less time for level 3 + code:8612/02/01+8613/00/00 + cheat + description:Double usual shots per round + code:86b5/28/50+9aae/28/50+99ef/b9/ad + cheat + description:Triple usual shots per round + code:86b5/28/50+9aae/28/78+99ef/b9/ad + cheat + description:Quadruple usual shots per round + code:86b5/28/50+9aae/28/a0+99ef/b9/ad + +cartridge sha256:648f68ae58f3420096e052a68255d8e453ae1fc09a4214adbeaa66ff841aaa33 + name:Side Pocket (USA) + cheat + description:Infinite turns - P1 + code:abcf/85/a5 + +cartridge sha256:69399633df5ea1baf37d3e47087257e245fca1f260cac0f539e8e4437ddf2a28 + name:Silent Assault (USA) (Unl) + cheat + description:Infinite lives + code:002e/08 + cheat + description:Infinite Grenades + code:00d9/04 + +cartridge sha256:37a5cfb1aacd9bb42746f20923441b5f613971d4dc99de68c216b10a8d7bcbfc + name:Silent Service (USA) + cheat + description:Infinite deck gun shells + code:e929/c6/a5 + cheat + description:Infinite bow torpedoes + code:e95b/c6/a5 + cheat + description:Infinite aft torpedoes + code:e983/c6/a5 + cheat + description:Start with 50 deck gun shells + code:9d01/50/32 + cheat + description:Start with 99 deck gun shells + code:9d01/50/63 + +cartridge sha256:28f0444e178830edf654eb72e54c7920296156524295b5a4f4418fc4d33f42fd + name:Silk Worm (USA) + cheat + description:Infinite lives using helicopter + code:e2dd/c6/a5 + cheat + description:Infinite lives using jeep + code:e66c/c6/a5 + cheat + description:Keep firepower and speed-ups for helicopter + code:e302/85/a5 + cheat + description:Keep firepower and speed-ups for jeep + code:e691/85/a5 + cheat + description:Restrict movement area for helicopter + code:e39f/d8/80 + cheat + description:Restrict movement area for jeep + code:e79c/e0/88 + cheat + description:1 life using helicopter after continue + code:c985/03/01 + cheat + description:6 lives using helicopter after continue + code:c985/03/06 + cheat + description:9 lives using helicopter after continue + code:c985/03/09 + cheat + description:1 life using jeep after continue + code:c99f/03/01 + cheat + description:6 lives using jeep after continue + code:c99f/03/06 + cheat + description:9 lives using jeep after continue + code:c99f/03/09 + cheat + description:Start with 1 life + code:c822/03/01 + cheat + description:Start with 6 lives + code:c822/03/06 + cheat + description:Start with 9 lives + code:c822/03/09 + cheat + description:Start at stage 2 + code:c828/00/01 + cheat + description:Start at stage 3 + code:c828/00/02 + cheat + description:Start at stage 4 + code:c828/00/03 + cheat + description:Start at stage 5 + code:c828/00/04 + cheat + description:Start at stage 6 + code:c828/00/05 + cheat + description:Start at stage 7 + code:c828/00/06 + +cartridge sha256:718dce0398dba4f8968969fe3e078f55ea0a5b3cff91895fd9ac0225fe4c437e + name:Silver Surfer (USA) + cheat + description:Infinite lives - both players + code:cf8d/ce/ad + cheat + description:Infinite Smart Bombs - both players + code:e663/1c/ff + cheat + description:Keep cosmic weapons after losing a life + code:d586/8d/2c + cheat + description:Keep Orbs after losing a life + code:d583/8d/2c+dbc1/8d/2c + cheat + description:Have 5 Smart Bombs on a new life + code:d58d/01/05 + cheat + description:Start with 1 life - P1 + code:d513/05/01 + cheat + description:Start with 1 life - P2 + code:d54c/05/01 + cheat + description:Start with 5 Smart Bombs - P1 + code:d52c/01/05 + cheat + description:Start with 5 Smart Bombs - P2 + code:d565/01/05 + cheat + description:Infinite lives + code:05e6/09 + +cartridge sha256:ce1fd1fcf89d2d6334cc3d96101c7b995ff4959257ed04df92f0afad711d08da + name:Simpsons, The - Bartman Meets Radioactive Man (USA) + cheat + description:Invincibility + code:f3a9/20/ad + cheat + description:Infinite health + code:f731/04/00 + cheat + description:Infinite health (alt) + code:f732/8d/ad + cheat + description:Infinite Eyes on pick-up + code:f8fe/ce/cd + cheat + description:Infinite Eyes on pick-up (alt) + code:f8fe/ce/ad + cheat + description:Infinite Cold on pick-up + code:f944/01/00 + cheat + description:Infinite lives + code:f260/91/b1 + cheat + description:Infinite credits + code:f80f/ce/ad + cheat + description:Eyes worth more on pick-up + code:eae1/20/50 + cheat + description:Cold worth more on pick-up + code:eabd/05/20 + cheat + description:Start with 2 lives and 2 credits + code:8767/03/01 + cheat + description:Start with 6 lives and 6 credits + code:8767/03/05 + cheat + description:Start with 8 lives and 8 credits + code:8767/03/07 + cheat + description:Start with 10 lives and 10 credits + code:8767/03/09 + cheat + description:Start in chapter 1 level 2 + code:a730/00/02 + cheat + description:Start in chapter 1 level 3 + code:a730/00/05 + 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:0789/99 + +cartridge sha256:7e8a3accbd57c9fea4f86fb9f99d9adc579bacec52fc68d547125067f8e50816 + name:Simpsons, The - Bart vs. the Space Mutants (USA) (Rev A) + cheat + description:Infinite time + code:f293/ca/ea + cheat + description:Slow down time + code:f27d/3c/78 + cheat + description:Speed up time + code:f27d/3c/20 + cheat + description:Gain 2 coins for every 1 collected + code:f70c/00/01 + cheat + description:Only 10 coins needed to get an extra life + code:f712/0e/09 + cheat + description:Buy items for free + code:a29d/ce/2c+b0a5/ce/2c + cheat + description:Super-jump + code:fb36/0c/15 + 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 + name:Simpsons, The - Bart vs. the Space Mutants (USA) + cheat + description:Invincibility + code:d997/f0/d0 + cheat + description:Infinite health + code:ed10/ce/ad + cheat + description:Infinite time + code:f29f/ca/ea + cheat + description:Slow down time + code:f289/3c/78 + cheat + description:Speed up time + code:f289/3c/20 + cheat + description:Gain 2 coins for every 1 collected + code:f718/00/01 + cheat + description:Only 10 coins needed to get an extra life + code:f71e/0e/09 + cheat + description:Buy items for free + code:a1a2/ce/2c+b0ab/ce/2c + cheat + description:Get all items by selecting them (be sure to get the Paint Can in level 1 and Gun in the Museum) + code:e043/bd/9d + cheat + description:Super-jump + code:fb42/0c/15 + 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 + name:Simpsons, The - Bart vs. the World (USA) + cheat + description:Invincibility + code:e3ac/05/1a + cheat + description:Infinite health + code:ec68/ce/ad + cheat + description:Infinite lives + code:f11d/e5/a5 + cheat + description:Infinite Firecracker Balls + code:f139/91/b1 + cheat + description:Infinite tries for the card match game + code:a071/ce/ad + cheat + description:Bart flies + code:b87c/b4 + cheat + description:Lose lives more easily + code:ec5f/f0/d0 + cheat + description:Start with 99 Firecracker Balls + code:a001/00/09 + cheat + description:Start with 9 lives + code:ac2e/03/09 + 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 + name:Skate or Die (USA) + cheat + description:Snowball Blast - More snowballs picked up + code:a6fe/01/02 + cheat + description:Snowball Blast - Start with more time + code:9886/60/99 + cheat + description:Snowball Blast - Start with less time + code:9886/60/40 + cheat + description:Snowball Blast - More time gained + code:a6cd/10/15 + cheat + description:Snowball Blast - Less time gained + code:a6cd/10/05 + cheat + description:Snowball Blast - Start with more ammo + code:9836/02/04 + cheat + description:Snowball Blast - Start with less ammo + code:9836/02/01 + cheat + description:Acro Aerials - More jumps allowed + code:ed6f/03/05+efd0/03/05 + +cartridge sha256:3626bb5ce3035b39d70ed5f2941b69801c1a95629609f1ebd90a5a6a9e16794f + name:Skate or Die 2 - The Search for Double Trouble (USA) + cheat + description:Adventure Game - Infinite health + code:a1ba/c6/a5 + cheat + description:Adventure Game - Infinite Paint Clips + code:96e6/ce/ad + cheat + description:Adventure Game - Infinite Eggs + code:9172/01/00+932a/01/00 + cheat + description:Adventure Game - Infinite M-80's + code:9366/01/00+9188/01/00 + cheat + description:Adventure Game - Skate at any speed + code:d088/41/00+8046/41/00 + cheat + description:Stunt Ramp - Only 1 skateboard + code:f333/03/01 + cheat + description:Stunt Ramp - 6 skateboards + code:f333/03/06 + cheat + description:Stunt Ramp - 9 skateboards + code:f333/03/09 + cheat + description:Stunt Ramp - More time + code:f31d/03/06 + cheat + description:Stunt Ramp - Less time + code:f31d/03/02 + cheat + description:Stunt Ramp - Infinite time + code:8a34/c6/a5 + cheat + description:Stunt Ramp - Super speed + code:9acc/05/06 + cheat + description:Stunt Ramp - Infinite skateboards + code:9fc6/c6/a5+a0b4/c6/a5 + +cartridge sha256:a29461c583ec03909c1dbc4e7d783de0aaf2f391ae8329b3d8bf06e06cfdd2fa + name:Ski or Die (USA) + cheat + description:Snowball Blast - More snowballs picked up + code:a6fe/01/02 + cheat + description:Snowball Blast - Start with more time + code:9886/60/99 + cheat + description:Snowball Blast - Start with less time + code:9886/60/40 + cheat + description:Snowball Blast - More time gained + code:a6cd/10/15 + cheat + description:Snowball Blast - Less time gained + code:a6cd/10/05 + cheat + description:Snowball Blast - Start with more ammo + code:9836/02/04 + cheat + description:Snowball Blast - Start with less ammo + code:9836/02/01 + cheat + description:Acro Aerials - More jumps allowed + code:efd0/03/05+ed6f/03/05 + +cartridge sha256:06fddd300a6d1cbe1be92e851e3d5d2defcc7e682903b569bc9fe71a26addd74 + name:Skull & Crossbones (USA) (Unl) + cheat + description:Infinite continues + code:977e/ce/ad + cheat + description:Infinite weapons + code:869d/de/bd + cheat + description:Infinite time + code:f21c/ce/ad + cheat + description:Faster timer + code:f218/3c/20 + cheat + description:Slower timer + code:f218/3c/70 + cheat + description:Half energy for Red Dog and One Eye + code:97e3/32/19+9782/32/19 + cheat + description:Double energy for Red Dog and One Eye + code:97e3/32/63+9782/32/19 + cheat + description:Better super-jump + code:87ef/c8/b8+87e4/c8/b8 + cheat + description:1 continue + code:97a6/05/01 + cheat + description:9 continues + code:97a6/05/09 + +cartridge sha256:51958d12a19e7c573fab26b85fe81d57330ff6668d630c6bc95c7c563c441e93 + name:Sky Kid (USA) + cheat + description:Infinite lives + code:c28c/d6/a5 + cheat + description:P1 has more lives than P2 + code:fa7e/85/86 + cheat + description:Shoot more bullets + code:c21d/01/00 + cheat + description:Start with 1 life - both players + code:fa77/03/01 + cheat + description:Start with 6 lives - both players + code:fa77/03/06 + cheat + description:Start with 9 lives - both players + code:fa77/03/09 + cheat + description:Start on level 5 + code:fa6f/01/05+fa6b/00/04 + cheat + description:Start on level 10 + code:fa6f/01/0a+fa6b/00/09 + cheat + description:Start on level 15 + code:fa6f/01/10+fa6b/00/0f + cheat + description:Start on level 20 + code:fa6f/01/14+fa6b/00/13 + cheat + description:Invincibility - P1 + code:00bb/00 + cheat + description:Invincibility - P2 + code:00cb/00 + +cartridge sha256:f845ee19cbe21f5b463073f3716659f9c82ef6342a20879165ed21f219f6653b + name:Sky Shark (USA) (Rev 0A) + cheat + description:Infinite lives + code:8078/d6/a9 + cheat + description:Infinite Bombs + code:83b8/d6/24 + cheat + description:Infinite credits + code:817d/de/2c + cheat + description:Autofire + code:810b/5c/00 + cheat + description:Double Bombs + code:9e65/03/06 + cheat + description:Double credits + code:8037/03/06 + cheat + description:1 life after continue - both players + code:817a/04/00 + cheat + description:9 lives after continue - both players + code:817a/04/08 + cheat + description:Start with maximum firepower + code:8121/a4/a0+8122/3d/06 + cheat + description:Start with 1 life - P1 + code:8026/a9/24 + cheat + description:Start with 1 life - P2 + code:8033/04/00 + cheat + description:Start with 9 lives - P1 + code:802a/a2/06+802b/ff/21 + cheat + description:Start with 9 lives - P2 + code:8033/04/08 + +cartridge sha256:f7f6d714c7758f679db8f0c7869ef19353fdcc49c267494bb41bfefda0f152d6 + name:Slalom (USA) + cheat + description:Ski super fast + code:b21b/00/01 + cheat + description:No track obstacles + code:9503/01/00 + cheat + description:Timer at 5 minutes for all tracks + code:9620/a6/a2+9621/79/09 + +cartridge sha256:6dde1137253e7e41972dd04e09dc736efee82cc7f41f8deac8d0dcb111301616 + name:Smash T.V. (USA) + cheat + description:Infinite lives + code:f264/de/db + cheat + description:Touch and kill most enemies + code:a211/f0/80 + cheat + description:Infinite Grenades + code:bfab/d6/a9 + cheat + description:Get a lot more Grenades + code:ae7e/06/99 + +cartridge sha256:8df9c1a7a3806873db908604bb99749673241ccd58e1b32a6d7bf2fafc97d9d4 + name:Smurfs, The (Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:8b00/f0/d0+a3f9/f0/d0 + cheat + description:Infinite health + code:96c3/ce/ad + cheat + description:Infinite lives + code:bb92/8d/ad + cheat + description:Infinite time + code:99c5/9d/bd + +cartridge sha256:c85ed147e6da0da5ef02c930cc52621ae38d66971a332d168bf31126a3a740ce + name:Snake's Revenge (USA) + cheat + description:Invincibility + code:e908/85/a5 + cheat + description:Infinite health + code:e8cc/85/a5 + cheat + description:Infinite ammo for all weapons + code:e672/88/ea + cheat + description:Infinite Beretta ammo + code:8b09/8d/ad + cheat + description:Infinite Shotgun ammo + code:8c95/8d/ad + cheat + description:Infinite Grenades + code:8c44/8d/ad + cheat + description:Infinite Missiles + code:8ce9/8d/ad + cheat + description:Reduce your injuries by up to 50% + code:e8b9/07/00 + cheat + description:Play with less health + code:f3b6/0a/ea+ac42/0a/ea + cheat + description:Infinite time for Metal Gear battle + code:a0d6/ce/ad + cheat + description:One hit defeats Metal Gear + code:83a3/f0/d0 + cheat + description:Start a new game to view the ending + code:c530/0e/11 + cheat + description:Start with half bullets for Beretta M92 + code:e7ac/40/20 + cheat + description:Start with double bullets for Beretta M92 + code:e7ac/40/80 + cheat + description:Start with Machine Gun instead of Beretta + code:e798/01/02+e7ae/c0/c2 + cheat + description:Start with Shotgun instead of Beretta + code:e798/01/04+e7ae/c0/c4 + cheat + description:Start with Grenades instead of Beretta + code:e798/01/20+e7ae/c0/c6 + cheat + description:Start with Missiles instead of Beretta + code:e798/01/80+e7ae/c0/c8 + +cartridge sha256:98691aea357072f901095e47db056a01887083fd81710d425b9171db1cd1ad1b + name:Snake Rattle n Roll (USA) + cheat + description:Infinite lives - both players + code:be1d/de/bd + cheat + description:Infinite time + code:fa81/c6/a5 + cheat + description:Faster timer + code:fa7e/6e/40 + cheat + description:Slower timer + code:fa7e/6e/90 + cheat + description:Super-jump + code:9c2d/01/02 + cheat + description:Mega-jump + code:9c2d/01/03 + cheat + description:1 life - both players + code:82a7/02/00 + cheat + description:6 lives - both players + code:82a7/02/05 + cheat + description:9 lives - both players + code:82a7/02/08 + cheat + description:1 life - both players, after continue + code:8eb0/02/00 + cheat + description:6 lives - both players, after continue + code:8eb0/02/05 + cheat + description:9 lives - both players, after continue + code:8eb0/02/08 + cheat + description:Start on level 2 + code:82bc/ff/01 + cheat + description:Start on level 3 + code:82bc/ff/02 + cheat + description:Start on level 4 + code:82bc/ff/03 + cheat + description:Start on level 5 + code:82bc/ff/04 + cheat + description:Start on level 6 + code:82bc/ff/05 + cheat + description:Start on level 7 + code:82bc/ff/06 + 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 + name:Snow Brothers (USA) + cheat + description:Invincibility + code:8eb6/de/bd + cheat + description:Infinite number of chances + code:8ffb/d6/a5 + cheat + description:Always get 10 chances after a continue (count restarts at 9) + code:8317/02/09 + cheat + description:Always get 1 chance after a continue (count restarts at 0) + code:8317/02/00 + cheat + description:Don't lose super ability after you lose a chance + code:909c/99/b9 + cheat + description:Start with 10 chances instead of 3 (count starts at 9 instead of 2) + code:a329/02/09 + cheat + description:Start with 1 chance (count starts at 0) + code:a329/02/00 + cheat + description:Start with Speed Skates, Power Shots and super snow-throwing + code:800f/00/0f + cheat + description:Start with Speed Skates (don't use with other "start with" codes) + code:800f/00/01 + cheat + description:Start with Power Shots (don't use with other "start with" codes) + code:800f/00/02 + cheat + description:Start with super snow-throwing ability (don't use with other "start with" codes) + code:800f/00/04 + cheat + description:Start on 5th floor + code:a2e6/00/04 + cheat + description:Start on 10th floor + code:a2e6/00/09 + cheat + description:Start on 20th floor + code:a2e6/00/13 + cheat + description:Start on 30th floor + code:a2e6/00/1d + cheat + description:Start on 40th floor + code:a2e6/00/27 + cheat + description:Start on 50th floor + code:a2e6/00/31 + +cartridge sha256:6a0c8be0f6445d9d777080955c7aa8fbff7497633b878a36c8139ec13dabfb8b + name:Soccer (World) + cheat + description:Each half lasts only 10 minutes + code:9a1c/15/10 + cheat + description:Each half lasts for 50 minutes + code:9a1c/15/50 + cheat + description:Start 1 goal up + code:be56/00/01+be59/85/84+be5b/8d/8c + cheat + description:Start 3 goals up + code:be56/00/03+be59/85/84+be5b/8d/8c + +cartridge sha256:45a0fd35f3141c140fb8d1f652876011f28d772b987da123c597aa8c924437b2 + name:Solar Jetman - Hunt for the Golden Warpship (USA) + cheat + description:No damage taken from walls + code:a6a4/fd/00+a6a8/ff/00 + cheat + description:Minimum damage taken from walls + code:a6a8/ff/00 + cheat + description:Infinite lives + code:9d2f/c6/a5 + cheat + description:Weapons use up no energy + code:ce89/f9/ed + cheat + description:Items for free + code:dab1/0f/00+dac9/85/24 + cheat + description:Reversed gravity for planet 1 + code:95d3/0b/fb + cheat + description:Reversed gravity for planet 2 + code:965a/1e/ee + cheat + description:Reversed gravity for planet 3 + code:9690/14/e4 + cheat + description:Reversed gravity for planet 4 + code:95ee/0a/fa + cheat + description:Reversed gravity for planet 5 + code:9624/20/e0 + cheat + description:Reversed gravity for planet 6 + code:963f/29/e9 + cheat + description:Reversed gravity for planet 7 + code:9609/23/e3 + cheat + description:Normal gravity for planet 8 + code:96ab/e8/18 + cheat + description:Start with 1 ship and 1 life + code:d34a/04/01 + cheat + description:Start with 8 ships and 8 lives + code:d34a/04/08 + cheat + description:Start with more money + code:d35a/01/08 + cheat + description:Start on level 3 + code:d35e/00/02 + cheat + description:Start on level 6 + code:d35e/00/05 + cheat + description:Start on level 9 + code:d35e/00/08 + cheat + description:Start on level 11 + code:d35e/00/0a + +cartridge sha256:842478f0d9f01c6c547672a7e4dc4a33ed2c900f92e4b318f4d5941ba548b355 + name:Solomon's Key (USA) + cheat + description:Invincibility + code:8065/20/ad + cheat + description:Infinite life + code:a1a7/91/b1 + cheat + description:Infinite lives + code:c84c/ca/ea + cheat + description:Indestructible fireball + code:a01b/20/2c + cheat + description:Continuous fairies + code:a025/23/00 + cheat + description:Start with 40,000 life points + code:9829/8e/8c + cheat + description:Start on last level reached + code:9136/8d/2c + cheat + description:Start on next level + code:9136/8d/ee + cheat + description:Start on level 10 + code:9139/8d/ad+913b/04/93+9135/00/09 + cheat + description:Start on level 20 + code:9139/8d/ad+913b/04/93+9135/00/13 + cheat + description:Start on level 30 + code:9139/8d/ad+913b/04/93+9135/00/1d + cheat + description:Start on level 40 + code:9139/8d/ad+913b/04/93+9135/00/27 + 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 + name:Solstice - The Quest for the Staff of Demnos (USA) + cheat + description:Infinite lives + code:8a5d/ce/ad + cheat + description:Infinite Potions + code:92d5/de/bd + cheat + description:Multi-jump + code:a4bf/20/ad + cheat + description:1 life after continue + code:812b/03/01 + cheat + description:8 lives after continue + code:812b/03/08 + cheat + description:Start with full flasks of Potions + code:8d1b/02/04 + cheat + description:Start with no Potions + code:8d1b/02/00 + cheat + description:Start with 1 life + code:8d46/04/01 + cheat + description:Start with 8 lives + code:8d46/04/08 + 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:69569bebb916fcd78f904abd28aa4ed69fde0467c050c539c5359409305ca4ea + name:Space Invaders (Japan) + cheat + description:Infinite lives - P1 + code:0029/09 + cheat + description:Infinite lives - P2 + code:002a/09 + +cartridge sha256:cce92c9404d5dd48680b0b505acbbbce279a4f09606167f0aacfb6da991aac4c + name:Space Hunter (Japan) + cheat + description:Infinite energy + code:b714/ce/ad+b697/9d/ad + +cartridge sha256:dbd587ef5a12e03a336cda61cd120b4e8c585f45d82821e144ee8afdea9ee84e + name:Spartan X 2 (Japan) + cheat + description:Infinite health + code:dc82/ce/ad+dc3e/8d/ad + +cartridge sha256:6f58c6fb427cf18b4c28f07909db642abac09fac2d7ae7dc9c99f1cd79263d95 + name:Spelunker (USA) + cheat + description:Invincibility + code:9540/20/60+848f/ff/3e+8491/2d/2c + cheat + description:Infinite lives + code:9599/ce/2d + cheat + description:Invisibility + code:86a7/10/00 + cheat + description:Jump higher + code:8884/fe/fd+8878/00/80 + cheat + description:Start with 1 life + code:8176/02/00 + cheat + description:Start with 6 lives + code:8176/02/05 + cheat + description:Start with 9 lives + code:8176/02/08 + 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 + name:Spider-Man - Return of the Sinister Six (USA) + cheat + description:Invincibility + code:b2fd/20/ad + cheat + description:Infinite health + code:ce9e/8d/ad + +cartridge sha256:3c74b191d7d4cb6c34e6b2d5f76d9c86be63f8ebb61581c49810f0dd58c538c1 + name:Spiritual Warfare (USA) (v6.1) (Unl) + cheat + description:Infinite energy + code:c4e3/85/a5 + cheat + description:Infinite Vial Of God's Wrath + code:cdc2/c6/a5 + cheat + description:Start with all armors, 7 of each fruit, all items, 99 Keys, 255 God's Wrath, 99 Birds + code:b50f/00/ff + cheat + description:Start with max energy + code:b542/06/18 + +cartridge sha256:5a82a1b0386407f1036c3d0ae750741c0835336f062d77480e1dd5b4da507386 + name:Spiritual Warfare (USA) (v6.0) (Unl) + cheat + description:Invincibility + code:ed9a/02/00 + cheat + description:Infinite energy + code:c4bb/85/a5 + cheat + description:Infinite Vial Of God's Wrath + code:b4df/00/ff + cheat + description:Infinite Vials + code:cd9a/c6/a5 + cheat + description:Hit anywhere with fruits + code:cc5c/06/24 + cheat + description:Items are free + code:9161/b0/50 + cheat + description:Any answer is correct + code:929e/4c/ad + cheat + description:Walk through walls (not diagonally) + code:e5d4/c9/60 + cheat + description:Start with all armors, 7 of each fruit, all items, 99 Keys, 255 God's Wrath, 99 Birds + code:b4df/00/ff + cheat + description:Start with max energy + code:b512/06/18 + +cartridge sha256:14a86d409cc9e6ae2428f301e4aaa77290fe38ec3e660d971af9abda772747e2 + name:Spiritual Warfare (USA) (v5.1) (Unl) + cheat + description:Infinite energy + code:c4f9/85/a5 + cheat + description:Infinite Vial Of God's Wrath + code:cdd8/c6/a5 + cheat + description:Start with all armors, 7 of each fruit, all items, 99 Keys, 255 God's Wrath, 99 Birds + code:b525/00/ff + cheat + description:Start with max energy + code:b558/06/18 + +cartridge sha256:387d82471ca5f54e70b3c4d445ae5c692640d99c47b30a6bf67f5a17b6236c85 + name:Splatter House - Wanpaku Graffiti (Japan) + cheat + description:Hit anywhere + code:a14c/03/00+a139/1b/00+a134/b0/24 + cheat + description:Moon-jump + code:c4ab/20/28+c3a5/05/80+c3a4/c9/29+c3a3/8f/67 + cheat + description:Start a new game to view ending + code:aeee/02/05 + +cartridge sha256:17da401495807145c9d4db275d429b7fe94be45dde00edc40aca885911cfd138 + name:Spy Hunter (USA) + cheat + description:Infinite health + code:9ae0/85/a5 + cheat + description:Infinite lives + code:81c7/ce/ad + cheat + description:Infinite lives (alt) + code:bc0d/c6/a5 + cheat + description:Infinite missiles + code:b748/ce/ad + cheat + description:Infinite smoke + code:b686/8d/ae + cheat + description:Hit anywhere + code:9dfc/15/00+9df8/0e/00+abd8/0f/00+9ded/24/00+9dff/85/a5 + cheat + description:Enemies die automatically + code:8538/0e/00+abd8/0f/00+abd2/60/ea + cheat + description:No enemies + code:9ad9/85/a5+9b3e/85/a5 + cheat + description:Double missiles on pick-up + code:a58b/03/06 + cheat + description:Slow down timer + code:ad07/07/0f + cheat + description:Keep special weapons + code:8bd4/8d/2c+8bd7/8d/2c + cheat + description:Start with 2 extra lives + code:ad8c/00/02 + cheat + description:Start with 6 extra lives + code:ad8c/00/06 + +cartridge sha256:91c61066a9b6b5ed169449b175190d75d38834e07da263f637af05801bc2f5ae + name:Spy vs Spy (USA) + cheat + description:Stop black spy's clock + code:8367/ce/ad + cheat + description:Stop white spy's clock + code:83bb/ce/ad + cheat + description:Black spy has 100 seconds in a minute + code:8381/35/39 + cheat + description:White spy has 100 seconds in a minute + code:83d5/35/39 + cheat + description:Black spy has deadly punches + code:a7e7/eb/f1 + cheat + description:White spy has deadly punches + code:a7e3/05/0d + +cartridge sha256:687963e7fd12834543da99c60a533fcdfedacd27f8a67c0c9c4007c1263a79b3 + name:Sqoon (USA) + cheat + description:Infinite lives + code:8580/01/00 + cheat + description:Never lose your special weapon + code:8d09/ce/ad + cheat + description:Never lose humans on dying + code:8c84/8d/2c+b2da/8d/2c + cheat + description:Gain main weapon on rescuing 9 humans + code:9f98/01/02 + cheat + description:Start with 1 life + code:8bbd/02/00 + cheat + description:Start with 6 lives + code:8bbd/02/05 + cheat + description:Start with 9 lives + code:8bbd/02/08 + cheat + description:Start at phase 3 + code:8b5a/01/03 + cheat + description:Start at phase 5 + code:8b5a/01/05 + cheat + description:Start at phase 8 + code:8b5a/01/08 + +cartridge sha256:b2e222df4d50fb75b108eac25e2beb671e37881bb357aa89bde7ef73d8d670f2 + name:Squashed (USA) (Proto) + cheat + description:Invincibility + code:969a/20/ad + cheat + description:Infinite lives + code:9476/de/dd + cheat + description:Infinite time + code:e665/ce/cd + +cartridge sha256:d9a666f7b122bff2db329d346e20d9708ad58471ea80fbd032aa4600e86ad8f1 + name:Stanley - The Search for Dr. Livingston (USA) + cheat + description:Infinite health + code:c307/8d/ad + cheat + description:Infinite time on continue screen + code:af5a/c6/ea + cheat + description:Start a new game with complete map + code:caa6/00/ff + 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 + name:Star Force (USA) + cheat + description:Infinite lives + code:8e4e/c6/a5 + cheat + description:Turbo speed + code:816c/ff/fe + cheat + description:Start with 1 life + code:8db3/02/00 + cheat + description:Start with 6 lives + code:8db3/02/05 + cheat + description:Start with 9 lives + code:8db3/02/08 + +cartridge sha256:7b7ccdcda705c2c3215c646b479c5d5868b72f3cd3eff97291d608756e5f3230 + name:Starship Hector (USA) + cheat + description:Take minimum damage + code:fcb0/e5/e9+fcb1/06/01 + cheat + description:Infinite lives + code:dc41/c6/a5 + cheat + description:Extra health from capsules + code:e5ec/01/04 + cheat + description:Start with 1 life + code:dc79/02/00 + cheat + description:Start with 6 lives + code:dc79/02/05 + cheat + description:Start with 9 lives + code:dc79/02/08 + cheat + description:Start at stage 2 + code:f5f4/00/01 + cheat + description:Start at stage 3 + code:f5f4/00/02 + cheat + description:Start at stage 4 + code:f5f4/00/03 + cheat + description:Start at stage 5 + code:f5f4/00/04 + cheat + description:Infinite health + code:00b0/10 + cheat + description:Play as Bomberking + code:005f/01 + +cartridge sha256:025abe5ae4e1610fac2507296184f64173fd960adfc79d456001adec29c546a5 + name:Star Soldier (USA) + cheat + description:Infinite lives + code:8118/c6/a5 + cheat + description:Infinite shield power + code:9ee2/c6/24 + cheat + description:Double shield power + code:9f19/05/0a+93fc/05/0a + cheat + description:Start with laser + code:8191/00/01 + +cartridge sha256:a3d132f118c0d95590579c6d6b89b6bbe448a93aab93b3a29490f985b821a42c + name:Star Trek - 25th Anniversary (USA) + cheat + description:Kirk has more energy + code:9c9e/07/0b + cheat + description:Kirk has less energy + code:9c9e/07/04 + cheat + description:McCoy has more energy + code:a03f/07/0b + cheat + description:McCoy has less energy + code:a03f/07/04 + cheat + description:Spock has more energy + code:a036/07/0b + cheat + description:Spock has less energy + code:a036/07/04 + cheat + description:Security has more energy + code:a063/07/0b + cheat + description:Geologist has more energy + code:a048/07/0b + cheat + description:Geologist has less energy + code:a048/07/04 + cheat + description:Biologist has more energy + code:a05a/07/0b + cheat + description:Biologist has less energy + code:a05a/07/04 + cheat + description:Historian has more energy + code:a051/07/0b + cheat + description:Historian has less energy + code:a051/07/04 + cheat + description:McCoy gives full energy to injured party + code:b1cf/04/07 + +cartridge sha256:8271542561a71830886e88ac74e6eda309440920b3607e950d5f2cd1a7edd5ca + name:Star Trek - The Next Generation (USA) + cheat + description:All systems are immune to damage - shields down + code:e7a1/91/b1 + cheat + description:Shields are immune to damage - shields up + code:e7be/8d/ad + cheat + description:Quicker damage repair + code:e64e/90/40 + cheat + description:Very quick damage repair + code:e64e/90/10 + cheat + description:Slower damage repair + code:e64e/90/c0 + cheat + description:Enemy does less damage + code:e0fb/0a/4a + cheat + description:Stop game time ticking over + code:e505/ee/60 + cheat + description:Photon Torpedoes always work + code:a031/74/00 + cheat + description:Phasers always work + code:a10e/f7/00 + cheat + description:Phasers fire for longer + code:a119/ec/00 + cheat + description:Damage is repaired immediately + code:e662/3d/00 + cheat + description:Transporter power does not decrease most of the time + code:beed/c6/a5 + cheat + description:Less transporter power required most of the time + code:be7a/20/05 + cheat + description:Stardate does not advance + code:aaf1/65/64 + +cartridge sha256:2e366cb5ebcce2cd7be431b84bbbb401104e2717322b15e5368707b4eddeb11a + name:Star Trek V - The Final Frontier (Unknown) (Proto) + cheat + description:Invincibility (blinking) + code:9a7f/f0/d0 + cheat + description:Infinite health + code:9507/8d/ad+8972/8d/ad + cheat + description:Infinite Phasers + code:9d96/8d/ad + cheat + description:Infinite Bombs + code:a2fb/ce/ad + +cartridge sha256:69de2c7552fa81ca5921da0e457abf1be35f18ffbad159788a76141be59c9f6b + name:StarTropics (USA) + cheat + description:Infinite health + code:a163/ed/ae + cheat + description:Infinite lives + code:e480/ce/ad + cheat + description:Infinite weapons + code:a5a9/de/bd + cheat + description:Hit anywhere + code:b2fc/29/50+b2fd/07/58+b3a0/c9/4c+b3a1/02/ef+b3a2/90/b3 + cheat + description:Enemies can't move + code:d39e/9f + cheat + description:1 star needed to restore health + code:a6af/05/01+a6b3/05/01 + cheat + description:9 stars needed to restore health + code:a6af/05/09+a6b3/05/09 + cheat + description:1 life with a new character + code:e257/03/01 + cheat + description:6 lives with a new character + code:e257/03/06 + cheat + description:1 life after continue + code:e534/03/01 + cheat + description:6 lives after continue + code:e534/03/06 + cheat + description:Gain 50 fire weapons on pick-up + code:b0e2/19/32 + cheat + description:Gain 50 bat weapons on pick-up + code:b0df/1e/32 + cheat + description:Only 3 hearts needed to use shooting-star + code:a7b2/0c/05 + cheat + description:Only 8 hearts needed to use super-nova + code:a791/16/08 + 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 + name:Star Voyager (USA) + cheat + description:Infinite life support pods + code:ae55/c6/24 + cheat + description:Start with double life support pods + code:d540/0a/14 + cheat + description:Start with triple life support pods + code:d540/0a/1e + cheat + description:Barrier won't take damage + code:bb55/03/00 + cheat + description:Radar won't take damage + code:bbc6/d0/10 + cheat + description:Cannon won't take damage + code:bba2/d0/f0 + cheat + description:Engine won't take damage + code:bb2a/03/00 + +cartridge sha256:b9116f11828e39d3e201c878a874f0d88fa0eae9dece0469bf94a7e9c8616775 + name:Star Wars (USA) + cheat + description:Infinite lives + code:8207/ce/ad + cheat + description:Immune to spikes, you can get stuck on them + code:f553/9d/2c + cheat + description:Immune to most bullets + code:b76f/9d/bd + cheat + description:Immune to most collisions + code:b5fa/e5/24+b647/9d/bd + cheat + description:Full energy on big energy pick-ups + code:bc47/02/00 + cheat + description:Less energy on big energy pick-ups + code:bc43/20/08 + cheat + description:More energy on big energy pick-ups + code:bc43/20/40 + cheat + description:Always running + code:cd99/01/02+cdca/01/02 + cheat + description:Start with 1 life + code:8024/02/00 + cheat + description:Start with 6 lives + code:8024/02/05 + cheat + description:Start with 9 lives + code:8024/02/08 + +cartridge sha256:01b1bc93f72286a10ac62869ebe1bf2493ca24b3386e01447b0ccac50acdee94 + name:Star Wars - The Empire Strikes Back (USA) + cheat + description:Don't take damage from most enemies + code:a766/99/2c + cheat + description:9 harpoons - scene 2 + code:a1d7/05/09 + cheat + description:1 harpoons - scene 2 + code:a1d7/05/01 + cheat + description:Infinite harpoons - scene 2 + code:ac66/ce/2c + cheat + description:Infinite energy for ship - scene 2 + code:b5d5/85/24 + cheat + description:Always have Lightsaber + code:9ea8/37/00 + cheat + description:Start with 14 continues + code:b5f4/07/0e + cheat + description:Start on scene 2 + code:cb02/00/01 + cheat + description:Start on scene 3 + code:cb02/00/02 + cheat + description:Start on scene 4 + code:cb02/00/03 + cheat + description:Start on scene 5 + code:cb02/00/04 + cheat + description:Start on scene 6 + code:cb02/00/05 + cheat + description:Start on scene 7 + code:cb02/00/06 + +cartridge sha256:8093144834f1153e95076a76dbc720cec37a31412b422c8adf9f5bcea1b642e8 + name:Stealth ATF (USA) + cheat + description:Infinite missiles + code:ad65/ce/ad + cheat + description:Start with double missiles + code:a8ba/08/10 + cheat + description:No damage taken from enemy's bullets + code:9f62/ee/ad + cheat + description:Start with less fuel + code:a8bf/96/60 + cheat + description:More enemy planes on the screen + code:a3c2/02/08 + +cartridge sha256:5ca7cb3c4168bb021a67b50fa071afe7679f4e79c5c46e229fbe7b88004bf51a + name:Stinger (USA) + cheat + description:Keep weapons after death + code:cb77/95/24 + cheat + description:Infinite lives + code:cb6c/d6/a9 + cheat + description:Skip intro + code:c3db/00/05 + cheat + description:Start with 1 life + code:c429/03/01 + cheat + description:Start with 6 lives + code:c429/03/06 + cheat + description:Start with 9 lives + code:c429/03/09 + cheat + description:Start with Dual Cannons + code:c470/3e/47+c46e/10/01 + cheat + description:Start with Laser + code:c470/3e/47+c46e/10/02 + cheat + description:Start with Shoot Right + code:c470/3e/47+c46e/10/04 + cheat + description:Start with Shoot Left + code:c470/3e/47+c46e/10/08 + cheat + description:Start with Five Direction Firing + code:c470/3e/47+c46e/10/10 + cheat + description:Start with Three Direction Firing + code:c470/3e/47+c46e/10/20 + cheat + description:Start with Force field + code:c470/3e/47+c46e/10/40 + cheat + description:Start at stage 2 (wait for demo game then press start) + code:c415/85/24+c301/01/01 + cheat + description:Start at stage 3 + code:c415/85/24+c301/01/02 + cheat + description:Start at stage 4 + code:c415/85/24+c301/01/03 + cheat + description:Start at stage 5 + code:c415/85/24+c301/01/04 + cheat + description:Start at stage 6 + code:c415/85/24+c301/01/05 + cheat + description:Invincibility + code:0056/50 + cheat + description:Infinite lives (alt) + code:0038/09 + +cartridge sha256:d8a12772ddcb35d66a6518096c8415961cb43ceb9ffb96e5c7f83fe3a8e7f2c1 + name:Street Cop (USA) + cheat + description:Infinite health + code:d28e/e5/24 + cheat + description:Take minimum damage + code:d28e/e5/e9+d28f/10/01 + cheat + description:Infinite time + code:f05e/c6/a5 + cheat + description:Have less time + code:e21e/09/06 + cheat + description:Have more time + code:e21e/09/12 + cheat + description:Start with less health + code:c8f7/30/18 + cheat + description:Start with more health + code:c8f7/30/60 + cheat + description:Start at level 2 + code:e121/00/01 + cheat + description:Start at level 3 + code:e121/00/02 + cheat + description:Start at level 4 + code:e121/00/03 + +cartridge sha256:885cfd4396e0ade5f3abbbdb5055bc48ef166f86207db631bac83c51c0844f08 + name:Street Fighter 2010 - The Final Fight (USA) + cheat + description:Invincibility + code:d45b/d0/f0 + cheat + description:Infinite health + code:d4b1/02/00 + cheat + description:Infinite lives + code:8136/c6/a5 + cheat + description:Infinite time + code:c238/95/b5 + cheat + description:Hit anywhere + code:d57f/11/20+d57e/b0/d0+d57b/d9/ad + cheat + description:Take less damage + code:d4b1/02/01 + cheat + description:Take more damage + code:d4b1/02/03 + cheat + description:Keep power-ups after losing a life + code:8112/85/24 + cheat + description:Keep power-ups when hit + code:d4c7/02/00 + cheat + description:Faster Ken + code:89dd/01/02 + cheat + description:Portal always stays open + code:ebe6/ce/ad + cheat + description:Start with 1 life + code:800e/04/00 + cheat + description:Start with 9 lives + code:800e/04/09 + +cartridge sha256:07401bfb725c61711ce0a1d5eade14e09cd0f1b90991691339077a0b7dea5e58 + name: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 + name:Strider (USA) + cheat + description:Infinite health + code:8cf3/29/a9+8cf6/35/69 + cheat + description:Hit anywhere + code:ea7d/26/00+ea8a/19/00 + cheat + description:More energy from small capsules (10) + code:af38/01/0a + cheat + description:More energy from big capsules (20) + code:af3a/0a/14 + cheat + description:Health from small capsules (10) + code:af3c/01/0a + cheat + description:Health from big capsules (20) + code:af3e/0a/14 + cheat + description:Double health and energy from all capsules + code:af0e/18/0a + 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 + name:Strike Wolf (MGC-014) + cheat + description:Infinite energy + code:bd4f/85/a5 + cheat + description:Infinite ammo + code:985f/ce/ad + cheat + description:Infinite Bombs + code:97a3/ce/ad + +cartridge sha256:f3a140c16012c4e4fb0deda64cbee7d9ebe78d2fb717b80b12a9f938d57b78bb + name:Stunt Kids (USA) (Unl) + cheat + description:Infinite time - P1 + code:927f/de/bd + cheat + description:Infinite time - P2 + code:932f/de/bd + cheat + description:Infinite lives + code:ac55/ce/ad + cheat + description:Always have 9 coins after a race + code:d673/8c/8e + cheat + description:Coins worth nothing on pick-up + code:9948/ee/ad + cheat + description:Start with 1 life instead of 3 + code:cad7/02/00 + cheat + description:Start with 6 lives + code:cad7/02/05 + cheat + description:Start with 9 lives + code:cad7/02/09 + cheat + description:Start with 0 turbos instead of 3 + code:d089/03/00 + cheat + description:Start with 6 turbos + code:d089/03/06 + cheat + description:Start with 9 turbos + code:d089/03/09 + +cartridge sha256:4d16627301ff5def67247039b3a4b1cce4d20fbb867f4c5b7bcab43a8575f59f + name:Sunday Funday - The Ride (USA) (Unl) + cheat + description:Enable level skip (press B then Select) + code:fafb/f0/d0 + +cartridge sha256:a387a17294bb440eb821fa096bfe476f772c7f9f79c5fb251f6b0a50bdeda53d + name:Super Arabian (Japan) + cheat + description:Invincibility + code:a930/ad + cheat + description:Hit anywhere + code:9c8d/07/00+9cba/95/cc + +cartridge sha256:3edd803db1cc88155720625ed8f3e362a5e3c660e7faf3285bbe3a2c6571511c + name:Super C (USA) + cheat + description:Invincibility - both players + code:a13a/3b + cheat + description:Infinite continues + code:ea1a/c6/a5 + cheat + description:Activates 10 lives code + code:e5a8/02/00 + cheat + description:10 lives code give you 30 + code:e5aa/09/1d + cheat + description:Extra life for each enemy killed + code:e6f6/02/00 + cheat + description:Hit anywhere + code:a1ad/0d/11 + cheat + description:One hit kills + code:a201/00 + cheat + description:Enemies die automatically (causes graphical glitches in some levels) + code:bb7d/38/18+a19d/1d/6b+f6ad/a5/a9+84ff/85/86+84fe/eb/1a + cheat + description:Multi-jump - both players + code:86e0/d0/24+86e9/6d/3a + cheat + description:Keep equipped weapon after dying + code:8662/95/24 + cheat + description:Keep weapon after dying + code:e5a0/95/a5+8662/95/a5 + cheat + description:Run faster to the right + code:8870/f0 + cheat + description:Press Start to complete current level + code:ea9f/39/38+ea9d/01/04 + cheat + description:Start a new game to view the ending + code:e4c3/00/08 + cheat + description:Stage select after title screen + code:e4af/d0/f0 + cheat + description:Start with Spray Gun + code:e5b4/57/b8+e5a1/b8/57+e5b2/00/02 + cheat + description:Start with Fireball Gun + code:e5b4/57/b8+e5a1/b8/57+e5b2/00/04 + cheat + description:Start with 1 life - both players + code:e5a3/02/00 + cheat + description:Start with 6 lives - both players + code:e5a3/02/05 + cheat + description:Start with 9 lives - both players + code:e5a3/02/08 + cheat + description:Start with 255 lives - both players + code:e5a3/02/ff + cheat + description:Start with 9 continues + code:e58d/02/06 + cheat + description:Start at area 2 + code:e583/00/01 + cheat + description:Start at area 3 + code:e583/00/02 + cheat + description:Start at area 4 + code:e583/00/03 + cheat + description:Start at area 5 + code:e583/00/04 + cheat + description:Start at area 6 + code:e583/00/05 + cheat + description:Start at area 7 + code:e583/00/06 + 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 + name:Super Mario Bros. (World) + cheat + description:Invincibility + code:eee9/ad/8d+eeec/f0/d0 + cheat + description:Invincibility (Starman effect) + code:d88d/d5 + cheat + description:Infinite time + code:b766/ae + cheat + description:Infinite time (alt) + code:b766/ad + cheat + description:Infinite lives - both players + code:91d9/ad + cheat + description:Infinite lives + code:91d9/ce/cd + cheat + description:Always Big Mario + code:b263/a9+b264/00+d936/ad + cheat + description:Always Fiery Mario + code:b626/22 + cheat + description:Always get 3 fireworks at end of stage + code:d305/1c + cheat + description:Always get 6 fireworks at end of stage + code:d2f6/07/86 + cheat + description:After falling down a hole, you drop from above + code:bff3/95/a9 + cheat + description:Fireballs hit anywhere + code:d721/90/24 + cheat + description:Gain a 1-up when an enemy is killed or power-up is gained + code:84e5/07/00 + cheat + description:Goombas don't walk off ledges + code:e0e6/0b + cheat + description:Mega-jump from a standing start only + code:b424/10 + cheat + description:Mega-jump from running only + code:b426/10 + cheat + description:Mega-jump from turbo running only + code:b428/04 + cheat + description:Moon Gravity from a standing start + code:b42b/07 + cheat + description:Moon Gravity from a running start + code:b42d/07 + cheat + description:Moon Gravity from turbo running only + code:b42f/07 + cheat + description:Multi-jump + code:b48d/10 + cheat + description:Super-jump from a standing start only + code:b424/18 + cheat + description:Super-jump from running only + code:b426/16 + cheat + description:Super-jump from turbo running only + code:b428/14 + cheat + description:Turn all enemies into Toad + code:e8b4/b7 + cheat + description:Can control Mario in demo and title screen + code:82bc/00/01+82be/fc/70+82bf/06/07 + cheat + description:Can control Mario in entrances that lead to underground + code:b08b/f5 + cheat + description:Can move left or right while crouched + code:b123/f0/10 + cheat + description:Can walk through pipes and blocks + code:df56/54 + cheat + description:Small Mario can break bricks + code:bd18/01/00+bcf7/02/00+bd17/d0/a0 + cheat + description:Fireballs can kill Bowser's Fire + code:d794/2e/00 + cheat + description:Fireballs can kill Bullet Bill + code:d78c/36/00 + cheat + description:Fireballs can kill Buzzy Beetle + code:d757/6b/00 + cheat + description:Fireballs can kill Podoboo + code:e02a/04/00+d790/32/00 + cheat + description:World 8-4, wrong pipe will lead to next area + code:9e33/e1/ec+9e23/e1/e7+9e42/65/02 + cheat + description:Enable level select + code:8270/00 + cheat + description:Press Start to finish current world + code:81ba/80/70+81b5/84/24+81b7/49/a9+81b9/09/8d+81bc/05/ea+81bb/d0/07+81b8/01/02 + cheat + description:Start with 1 life - both players + code:906a/00 + cheat + description:Start with 6 lives - both players + code:906a/05 + cheat + description:Start with 9 lives - both players + code:906a/08 + cheat + description:Start P1 with 8 lives and P2 with 3 lives + code:906b/8e + cheat + description:Start on World 2 + code:9089/5f+908a/07+9087/01 + cheat + description:Start on World 3 + code:9089/5f+908a/07+9087/02 + cheat + description:Start on World 4 + code:9089/5f+908a/07+9087/03 + cheat + description:Start on World 5 + code:9089/5f+908a/07+9087/04 + cheat + description:Start on World 6 + code:9089/5f+908a/07+9087/05 + cheat + description:Start on World 7 + code:9089/5f+908a/07+9087/06 + cheat + description:Start on World 8 + code:9089/5f+908a/07+9087/07 + 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 + name:Super Mario Bros. + Duck Hunt (USA) + cheat + description:DH - Infinite ammo + code:d171/c6/a5 + cheat + description:DH - Infinite ammo (alt) + code:00ba/03 + cheat + description:DH - Hit anywhere + code:d22c/f5/00 + cheat + description:DH - Always get the perfect bonus + code:d350/0a/00+d351/d0/30 + cheat + description:DH - Ducks never fly away - Game A + code:ca6c/c6/05 + cheat + description:DH - Enable game "D" (press Select three times) + code:c19e/03/04 + cheat + description:SMB - Invincibility + code:eee9/ad/8d+eeec/f0/d0 + cheat + description:SMB - Invincibility (Starman effect) + code:d88d/d5 + cheat + description:SMB - Infinite time + code:b766/ae + cheat + description:SMB - Infinite time (alt) + code:b766/ad + cheat + description:SMB - Infinite lives - both players + code:91d9/ad + cheat + description:SMB - Infinite lives + code:91d9/ce/cd + cheat + description:SMB - Always Big Mario + code:b263/a9+b264/00+d936/ad + cheat + description:SMB - Always Fiery Mario + code:b626/22 + cheat + description:SMB - Always get 3 fireworks at end of stage + code:d305/1c + cheat + description:SMB - Always get 6 fireworks at end of stage + code:d2f6/07/86 + cheat + description:SMB - After falling down a hole, you drop from above + code:bff3/95/a9 + cheat + description:SMB - Fireballs hit anywhere + code:d721/90/24 + cheat + description:SMB - Gain a 1-up when an enemy is killed or power-up is gained + code:84e5/07/00 + cheat + description:SMB - Goombas don't walk off ledges + code:e0e6/0b + cheat + description:SMB - Mega-jump from a standing start only + code:b424/10 + cheat + description:SMB - Mega-jump from running only + code:b426/10 + cheat + description:SMB - Mega-jump from turbo running only + code:b428/04 + cheat + description:SMB - Moon Gravity from a standing start + code:b42b/07 + cheat + description:SMB - Moon Gravity from a running start + code:b42d/07 + cheat + description:SMB - Moon Gravity from turbo running only + code:b42f/07 + cheat + description:SMB - Multi-jump + code:b48d/10 + cheat + description:SMB - Super-jump from a standing start only + code:b424/18 + cheat + description:SMB - Super-jump from running only + code:b426/16 + cheat + description:SMB - Super-jump from turbo running only + code:b428/14 + cheat + description:SMB - Turn all enemies into Toad + code:e8b4/b7 + cheat + description:SMB - Can control Mario in demo and title screen + code:82bc/00/01+82be/fc/70+82bf/06/07 + cheat + description:SMB - Can control Mario in entrances that lead to underground + code:b08b/f5 + cheat + description:SMB - Can move left or right while crouched + code:b123/f0/10 + cheat + description:SMB - Can walk through pipes and blocks + code:df56/54 + cheat + description:SMB - Small Mario can break bricks + code:bd18/01/00+bcf7/02/00+bd17/d0/a0 + cheat + description:SMB - Fireballs can kill Bowser's Fire + code:d794/2e/00 + cheat + description:SMB - Fireballs can kill Bullet Bill + code:d78c/36/00 + cheat + description:SMB - Fireballs can kill Buzzy Beetle + code:d757/6b/00 + cheat + description:SMB - Fireballs can kill Podoboo + code:e02a/04/00+d790/32/00 + cheat + description:SMB - Enable level select + code:8270/00 + cheat + description:SMB - Press Start to finish current world + code:81ba/80/70+81b5/84/24+81b7/49/a9+81b9/09/8d+81bc/05/ea+81bb/d0/07+81b8/01/02 + cheat + description:SMB - Start with 1 life - both players + code:906a/00 + cheat + description:SMB - Start with 6 lives - both players + code:906a/05 + cheat + description:SMB - Start with 9 lives - both players + code:906a/08 + cheat + description:SMB - Start P1 with 8 lives and P2 with 3 lives + code:906b/8e + cheat + description:SMB - Start on World 2 + code:9089/5f+908a/07+9087/01 + cheat + description:SMB - Start on World 3 + code:9089/5f+908a/07+9087/02 + cheat + description:SMB - Start on World 4 + code:9089/5f+908a/07+9087/03 + cheat + description:SMB - Start on World 5 + code:9089/5f+908a/07+9087/04 + cheat + description:SMB - Start on World 6 + code:9089/5f+908a/07+9087/05 + cheat + description:SMB - Start on World 7 + code:9089/5f+908a/07+9087/06 + cheat + description:SMB - Start on World 8 + code:9089/5f+908a/07+9087/07 + 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 + name:Super Mario Bros. + Duck Hunt + World Class Track Meet (USA) (Rev A) + cheat + description:DH - Infinite ammo + code:d171/c6/a5 + cheat + description:DH - Infinite ammo (alt) + code:00ba/03 + cheat + description:DH - Hit anywhere + code:d22c/f5/00 + cheat + description:DH - Always get the perfect bonus + code:d350/0a/00+d351/d0/30 + cheat + description:DH - Ducks never fly away - Game A + code:ca6c/c6/05 + cheat + description:DH - Enable game "D" (press Select three times) + code:c19e/03/04 + cheat + description:SMB - Invincibility + code:eee9/ad/8d+eeec/f0/d0 + cheat + description:SMB - Invincibility (Starman effect) + code:d88d/d5 + cheat + description:SMB - Infinite time + code:b766/ae + cheat + description:SMB - Infinite time (alt) + code:b766/ad + cheat + description:SMB - Infinite lives - both players + code:91d9/ad + cheat + description:SMB - Infinite lives + code:91d9/ce/cd + cheat + description:SMB - Always Big Mario + code:b263/a9+b264/00+d936/ad + cheat + description:SMB - Always Fiery Mario + code:b626/22 + cheat + description:SMB - Always get 3 fireworks at end of stage + code:d305/1c + cheat + description:SMB - Always get 6 fireworks at end of stage + code:d2f6/07/86 + cheat + description:SMB - After falling down a hole, you drop from above + code:bff3/95/a9 + cheat + description:SMB - Fireballs hit anywhere + code:d721/90/24 + cheat + description:SMB - Gain a 1-up when an enemy is killed or power-up is gained + code:84e5/07/00 + cheat + description:SMB - Goombas don't walk off ledges + code:e0e6/0b + cheat + description:SMB - Mega-jump from a standing start only + code:b424/10 + cheat + description:SMB - Mega-jump from running only + code:b426/10 + cheat + description:SMB - Mega-jump from turbo running only + code:b428/04 + cheat + description:SMB - Moon Gravity from a standing start + code:b42b/07 + cheat + description:SMB - Moon Gravity from a running start + code:b42d/07 + cheat + description:SMB - Moon Gravity from turbo running only + code:b42f/07 + cheat + description:SMB - Multi-jump + code:b48d/10 + cheat + description:SMB - Super-jump from a standing start only + code:b424/18 + cheat + description:SMB - Super-jump from running only + code:b426/16 + cheat + description:SMB - Super-jump from turbo running only + code:b428/14 + cheat + description:SMB - Turn all enemies into Toad + code:e8b4/b7 + cheat + description:SMB - Can control Mario in demo and title screen + code:82bc/00/01+82be/fc/70+82bf/06/07 + cheat + description:SMB - Can control Mario in entrances that lead to underground + code:b08b/f5 + cheat + description:SMB - Can move left or right while crouched + code:b123/f0/10 + cheat + description:SMB - Can walk through pipes and blocks + code:df56/54 + cheat + description:SMB - Small Mario can break bricks + code:bd18/01/00+bcf7/02/00+bd17/d0/a0 + cheat + description:SMB - Fireballs can kill Bowser's Fire + code:d794/2e/00 + cheat + description:SMB - Fireballs can kill Bullet Bill + code:d78c/36/00 + cheat + description:SMB - Fireballs can kill Buzzy Beetle + code:d757/6b/00 + cheat + description:SMB - Fireballs can kill Podoboo + code:e02a/04/00+d790/32/00 + cheat + description:SMB - Enable level select + code:8270/00 + cheat + description:SMB - Press Start to finish current world + code:81ba/80/70+81b5/84/24+81b7/49/a9+81b9/09/8d+81bc/05/ea+81bb/d0/07+81b8/01/02 + cheat + description:SMB - Start with 1 life - both players + code:906a/00 + cheat + description:SMB - Start with 6 lives - both players + code:906a/05 + cheat + description:SMB - Start with 9 lives - both players + code:906a/08 + cheat + description:SMB - Start P1 with 8 lives and P2 with 3 lives + code:906b/8e + cheat + description:SMB - Start on World 2 + code:9089/5f+908a/07+9087/01 + cheat + description:SMB - Start on World 3 + code:9089/5f+908a/07+9087/02 + cheat + description:SMB - Start on World 4 + code:9089/5f+908a/07+9087/03 + cheat + description:SMB - Start on World 5 + code:9089/5f+908a/07+9087/04 + cheat + description:SMB - Start on World 6 + code:9089/5f+908a/07+9087/05 + cheat + description:SMB - Start on World 7 + code:9089/5f+908a/07+9087/06 + cheat + description:SMB - Start on World 8 + code:9089/5f+908a/07+9087/07 + 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 + name:Super Mario Bros. + Duck Hunt + World Class Track Meet (USA) + cheat + description:DH - Infinite ammo + code:d171/c6/a5 + cheat + description:DH - Infinite ammo (alt) + code:00ba/03 + cheat + description:DH - Hit anywhere + code:d22c/f5/00 + cheat + description:DH - Always get the perfect bonus + code:d350/0a/00+d351/d0/30 + cheat + description:DH - Ducks never fly away - Game A + code:ca6c/c6/05 + cheat + description:DH - Enable game "D" (press Select three times) + code:c19e/03/04 + cheat + description:SMB - Invincibility + code:eee9/ad/8d+eeec/f0/d0 + cheat + description:SMB - Invincibility (Starman effect) + code:d88d/d5 + cheat + description:SMB - Infinite time + code:b766/ae + cheat + description:SMB - Infinite time (alt) + code:b766/ad + cheat + description:SMB - Infinite lives - both players + code:91d9/ad + cheat + description:SMB - Infinite lives + code:91d9/ce/cd + cheat + description:SMB - Always Big Mario + code:b263/a9+b264/00+d936/ad + cheat + description:SMB - Always Fiery Mario + code:b626/22 + cheat + description:SMB - Always get 3 fireworks at end of stage + code:d305/1c + cheat + description:SMB - Always get 6 fireworks at end of stage + code:d2f6/07/86 + cheat + description:SMB - After falling down a hole, you drop from above + code:bff3/95/a9 + cheat + description:SMB - Fireballs hit anywhere + code:d721/90/24 + cheat + description:SMB - Gain a 1-up when an enemy is killed or power-up is gained + code:84e5/07/00 + cheat + description:SMB - Goombas don't walk off ledges + code:e0e6/0b + cheat + description:SMB - Mega-jump from a standing start only + code:b424/10 + cheat + description:SMB - Mega-jump from running only + code:b426/10 + cheat + description:SMB - Mega-jump from turbo running only + code:b428/04 + cheat + description:SMB - Moon Gravity from a standing start + code:b42b/07 + cheat + description:SMB - Moon Gravity from a running start + code:b42d/07 + cheat + description:SMB - Moon Gravity from turbo running only + code:b42f/07 + cheat + description:SMB - Multi-jump + code:b48d/10 + cheat + description:SMB - Super-jump from a standing start only + code:b424/18 + cheat + description:SMB - Super-jump from running only + code:b426/16 + cheat + description:SMB - Super-jump from turbo running only + code:b428/14 + cheat + description:SMB - Turn all enemies into Toad + code:e8b4/b7 + cheat + description:SMB - Can control Mario in demo and title screen + code:82bc/00/01+82be/fc/70+82bf/06/07 + cheat + description:SMB - Can control Mario in entrances that lead to underground + code:b08b/f5 + cheat + description:SMB - Can move left or right while crouched + code:b123/f0/10 + cheat + description:SMB - Can walk through pipes and blocks + code:df56/54 + cheat + description:SMB - Small Mario can break bricks + code:bd18/01/00+bcf7/02/00+bd17/d0/a0 + cheat + description:SMB - Fireballs can kill Bowser's Fire + code:d794/2e/00 + cheat + description:SMB - Fireballs can kill Bullet Bill + code:d78c/36/00 + cheat + description:SMB - Fireballs can kill Buzzy Beetle + code:d757/6b/00 + cheat + description:SMB - Fireballs can kill Podoboo + code:e02a/04/00+d790/32/00 + cheat + description:SMB - Enable level select + code:8270/00 + cheat + description:SMB - Press Start to finish current world + code:81ba/80/70+81b5/84/24+81b7/49/a9+81b9/09/8d+81bc/05/ea+81bb/d0/07+81b8/01/02 + cheat + description:SMB - Start with 1 life - both players + code:906a/00 + cheat + description:SMB - Start with 6 lives - both players + code:906a/05 + cheat + description:SMB - Start with 9 lives - both players + code:906a/08 + cheat + description:SMB - Start P1 with 8 lives and P2 with 3 lives + code:906b/8e + cheat + description:SMB - Start on World 2 + code:9089/5f+908a/07+9087/01 + cheat + description:SMB - Start on World 3 + code:9089/5f+908a/07+9087/02 + cheat + description:SMB - Start on World 4 + code:9089/5f+908a/07+9087/03 + cheat + description:SMB - Start on World 5 + code:9089/5f+908a/07+9087/04 + cheat + description:SMB - Start on World 6 + code:9089/5f+908a/07+9087/05 + cheat + description:SMB - Start on World 7 + code:9089/5f+908a/07+9087/06 + cheat + description:SMB - Start on World 8 + code:9089/5f+908a/07+9087/07 + 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 + name:Super Mario Bros. 2 (USA) (Rev A) + cheat + description:Invincibility + code:f324/d0/a9+f326/a5/85 + cheat + description:Infinite health (except if you hit a spike) + code:ba06/8d/2c + cheat + description:Infinite health (alt) + code:ba06/8d/ad + cheat + description:Infinite lives + code:8a7d/ce/ad + cheat + description:Hit anywhere + code:b6a0/04/00+b69f/29/e0+b6a2/4d/44 + cheat + description:All characters can float + code:8cf8/f0/70 + cheat + description:More sub-space time + code:972e/1f + cheat + description:Quick pick-up + code:8ab5/b9/ad + cheat + description:Twice as much time in sub-space + code:95a2/60/ff + cheat + description:Infinite magic carpet time + code:a372/d6/b5 + cheat + description:Jump as high as a squat jump + code:8cbc/3c/00 + cheat + description:Princess has mega-float + code:8d21/00/11 + cheat + description:Princess has mega-float and lunar descent + code:8d21/00/01 + cheat + description:Super moon-jumps - Mario + code:83dc/04/01 + cheat + description:Mega moon-jumps - Luigi + code:840a/01/00 + cheat + description:Super moon-jumps - Toad + code:83f3/04/01 + cheat + description:Super moon-jumps - Princess + code:8421/04/01 + cheat + description:Speed up enemies + code:84a3/02/00 + cheat + description:Super speed enemies + code:85f2/08/20+85f3/f8/e0 + cheat + description:Walk backwards + code:8c87/18/1c+8c88/8c/d3 + cheat + description:Super turbo running + code:8de7/4a/ea+8dfa/6a/ea + cheat + description:Permanent turbo running + code:8de6/05/00+8df8/06/00 + cheat + description:Fast run - Toad + code:83f5/18/28+83f8/e8/d8 + cheat + description:Super fast run - Mario + code:83de/18/28+83e1/e8/d8 + cheat + description:Super fast run - Luigi + code:840c/18/28+840f/e8/d8 + cheat + description:Super fast run - Princess + code:8423/18/28+8426/e8/d8 + cheat + description:Weak Birdo + code:8f6f/02/00 + cheat + description:Strong Birdo + code:8f6f/02/0d + cheat + description:Strong Wart + code:b1d8/06/0f + cheat + description:Birdo spits eggs instead of fireballs (in late levels of the game) + code:9003/20/1e + cheat + description:Start on World 2 + code:9a83/40/01+9a85/00/35+9a86/01/06 + cheat + description:Start on World 3 + code:9a83/40/02+9a85/00/35+9a86/01/06 + cheat + description:Start on World 4 + code:9a83/40/03+9a85/00/35+9a86/01/06 + cheat + description:Start on World 5 + code:9a83/40/04+9a85/00/35+9a86/01/06 + cheat + description:Start on World 6 + code:9a83/40/05+9a85/00/35+9a86/01/06 + cheat + description:Start on World 7 + code:9a83/40/06+9a85/00/35+9a86/01/06 + 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 + name:Super Mario Bros. 2 (USA) + cheat + description:Invincibility + code:f324/d0/a9+f326/a5/85 + cheat + description:Infinite health (except if you hit a spike) + code:ba06/8d/2c + cheat + description:Infinite health (alt) + code:ba06/8d/ad + cheat + description:Infinite lives + code:8a7d/ce/ad + cheat + description:Hit anywhere + code:b6a0/04/00+b69f/29/e0+b6a2/4d/44 + cheat + description:Quick pick-up + code:8ab5/b9/ad + cheat + description:Twice as much time in sub-space + code:95a2/60/ff + cheat + description:Jump as high as a squat jump + code:8cbc/3c/00 + cheat + description:Princess has mega-float + code:8d21/00/11 + cheat + description:Princess has mega-float and lunar descent + code:8d21/00/01 + cheat + description:Super moon-jumps - Mario + code:83dc/04/01 + cheat + description:Mega moon-jumps - Luigi + code:840a/01/00 + cheat + description:Super moon-jumps - Toad + code:83f3/04/01 + cheat + description:Super moon-jumps - Princess + code:8421/04/01 + cheat + description:Speed up enemies + code:84a3/02/00 + cheat + description:Super speed enemies + code:85f2/08/20+85f3/f8/e0 + cheat + description:Walk backwards + code:8c87/18/1c+8c88/8c/d3 + cheat + description:Super turbo running + code:8de7/4a/ea+8dfa/6a/ea + cheat + description:Permanent turbo running + code:8de6/05/00+8df8/06/00 + cheat + description:Fast run - Toad + code:83f5/18/28+83f8/e8/d8 + cheat + description:Super fast run - Mario + code:83de/18/28+83e1/e8/d8 + cheat + description:Super fast run - Luigi + code:840c/18/28+840f/e8/d8 + cheat + description:Super fast run - Princess + code:8423/18/28+8426/e8/d8 + cheat + description:Hawkeye at end of level always open + code:8dbd/f0/24 + cheat + description:Start on World 2 + code:9a83/40/01+9a85/00/35+9a86/01/06 + cheat + description:Start on World 3 + code:9a83/40/02+9a85/00/35+9a86/01/06 + cheat + description:Start on World 4 + code:9a83/40/03+9a85/00/35+9a86/01/06 + cheat + description:Start on World 5 + code:9a83/40/04+9a85/00/35+9a86/01/06 + cheat + description:Start on World 6 + code:9a83/40/05+9a85/00/35+9a86/01/06 + cheat + description:Start on World 7 + code:9a83/40/06+9a85/00/35+9a86/01/06 + 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 + name:Super Mario Brothers 2 (Japan) (FDS) + cheat + description:Start with 50 lives + code:c5e4/31 + cheat + description:Start with 9 lives + code:c5e4/08 + cheat + description:Invincibility (Starman effect) + code:079f/09 + cheat + description:Infinite lives + code:701b/ad + +cartridge sha256:959fdd32c71735d6fb2bd16a646d39f4ee65623273dd035e6a968e991bd13ef8 + name:Super Mario Bros. 3 (USA) (Rev A) + cheat + description:Invincibility (Starman effect) + code:cee0/2a/00 + cheat + description:Invincibility after changing up from Super Mario (Raccoon, Frog, ect.) + code:da44/8d/ad + cheat + description:Invincibility as miniture stone Mario + code:a3cc/05/a0 + cheat + description:Invincibility as Super Mario + code:a3cc/05/ba + cheat + description:Invincibility as Fire Mario + code:a3cc/05/a3 + cheat + description:Invincibility as Raccoon Mario + code:a3cc/05/af + cheat + description:Invincibility as Frog Mario + code:a3cc/05/b9 + cheat + description:Invincibility as Sledgehammer Mario + code:a3cc/05/fa + cheat + description:Infinite lives - both players + code:9123/de/bd + cheat + description:Infinite time + code:afb0/ce/ad + cheat + description:Infinite items - Mario + code:a62b/0c/1f + cheat + description:Infinite tries at card match game + code:d86d/ce/2c + cheat + description:Always win at line up the pictures game (prize is based on the top picture) + code:d1df/20/00 + cheat + description:Fireballs hit anywhere + code:a6a0/cb/00+a6af/4d/00 + cheat + description:Fireballs turn most solid objects into coins + code:a54e/17/00+a560/05/00 + cheat + description:Tail hits anywhere + code:db59/90/24 + cheat + description:1-up for each enemy you stomp + code:c460/52 + cheat + description:1-up for each coin + code:b08b/64/01+b090/64/01 + cheat + description:1-up for each 10 coins + code:b08b/64/0a+b090/64/0a + cheat + description:Change to Super Mario if you fall off screen and die + code:da9d/01/00+a416/00/01 + cheat + description:Change to Fire Mario if you fall off screen and die + code:da9d/01/00+a416/00/02 + cheat + description:Change to Raccoon Mario if you fall off screen and die + code:da9d/01/00+a416/00/03 + cheat + description:Change to Frog Mario if you fall off screen and die + code:da9d/01/00+a416/00/04 + cheat + description:Change to Tanooki Mario if you fall off screen and die + code:da9d/01/00+a416/00/05 + cheat + description:Change to Sledgehammer Mario if you fall off screen and die + code:da9d/01/00+a416/00/06 + cheat + description:Move anywhere on the map + code:d2c1/d1/a9+d348/20/10 + cheat + description:Multi-jump + code:ac85/a9/a5 + cheat + description:Multi-jump (alt) + code:ac85/a9/ad + cheat + description:Multi-jump (alt 2) + code:ac3f/d0/24 + cheat + description:Power-jumps + code:a647/c8/b8 + cheat + description:Super power-jumps + code:a647/c8/a8 + cheat + description:Mega power-jumps + code:a647/c8/88 + cheat + description:Super speed running + code:abc0/a5/a9 + cheat + description:Turbo-charged running + code:abbf/88/ea + cheat + description:Raise P meter while standing still (hold B) + code:ab74/03/00 + cheat + description:Restore powers after playing an action scene + code:8f3a/9d/ad + cheat + description:Card match game always appears after a level + code:ac92/f0/24 + cheat + description:Small white ship level always appears after a level + code:accd/4f/0c+ac92/f0/24+accc/bd/a9+acce/ac/ea + cheat + description:White money ship always appears after a level + code:ac92/f0/24+accd/4f/0b+accc/bd/a9+acce/ac/ea + cheat + description:White toad house always appears after a level + code:ac92/f0/24+accc/bd/a9+acce/ac/ea+accd/4f/0a + cheat + description:Press Start to complete current level (do not use on final ship/castle levels for each map) + code:8e71/03/00+8e70/76/14 + cheat + description:1 life after continue - both players + code:92c6/04/00 + cheat + description:9 lives after continue - both players + code:92c6/04/08 + cheat + description:Start a new game as Fire Mario + code:acbc/00/02 + cheat + description:Start a new game as Raccoon Mario + code:acbc/00/03 + cheat + description:Start a new game as Frog Mario + code:acbc/00/04 + cheat + description:Start a new game as Tanooki Mario + code:acbc/00/05 + cheat + description:Start a new game as Sledgehammer Mario + code:acbc/00/06 + cheat + description:Start a new game to see the ending + code:a9c5/cf + cheat + description:Start on World 2 + code:acb3/00/01 + cheat + description:Start on World 3 + code:acb3/00/02 + cheat + description:Start on World 4 + code:acb3/00/03 + cheat + description:Start on World 5 + code:acb3/00/04 + cheat + description:Start on World 6 + code:acb3/00/05 + cheat + description:Start on World 7 + code:acb3/00/06 + cheat + description:Start on World 8 + code:acb3/00/07 + cheat + description:Unused level - Plains 1 + code:b47c/82/4c+b47d/bb/a7 + cheat + description:Unused level - Plains 2 + code:b47c/82/ac+b47d/bb/a1 + cheat + description:Unused level - Dungeon + code:b428/21/22+b47c/82/54+b47d/bb/b7 + cheat + description:Unused level - Underground 2 + code:b428/21/23+b47c/82/42+b47d/bb/b4 + cheat + description:Unused level - Sky 1 + code:b428/21/24+b47c/82/cd+b47d/bb/ad + cheat + description:Unused level - Sky 3 (level cannot be completed) + code:b428/21/24+b47c/82/c4+b47d/bb/b0 + cheat + description:Unused level - Cloudy 1 + code:b428/21/2d+b47c/82/a9+b47d/bb/ac + cheat + description:Unused level - Pipe level + code:b428/21/28+b47c/82/18+b47d/bb/af + cheat + description:Unused level - Hilly level + code:b428/21/23+b47c/82/dd+b47d/bb/b0 + cheat + description:Unused level - Ice/Water + code:b428/21/2c+b47c/82/ba+b47d/bb/b7 + cheat + description:Unused level - Cloudy (level cannot be completed) + code:b428/21/2d+b47c/82/ab+b47d/bb/ad + 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 + name:Super Mario Bros. 3 (USA) + cheat + description:Invincibility (Starman effect) + code:cee0/2a/00 + cheat + description:Invincibility after changing up from Super Mario (Raccoon, Frog, ect.) + code:da44/8d/ad + cheat + description:Invincibility as miniture stone Mario + code:a3cc/05/a0 + cheat + description:Never die from being hit while little (changes music) + code:daaa/1c + cheat + description:Invincibility as Super Mario + code:a3cc/05/ba + cheat + description:Invincibility as Fire Mario + code:a3cc/05/a3 + cheat + description:Invincibility as Raccoon Mario + code:a3cc/05/af + cheat + description:Invincibility as Frog Mario + code:a3cc/05/b9 + cheat + description:Invincibility as Sledgehammer Mario + code:a3cc/05/fa + cheat + description:Infinite lives - both players + code:9123/de/bd + cheat + description:Infinite time + code:afb0/ce/ad + cheat + description:Infinite items - Mario + code:a62b/0c/1f + cheat + description:Infinite tries at card match game + code:d86d/ce/2c + cheat + description:Always win at line up the pictures game (prize is based on the top picture) + code:d1df/20/00 + cheat + description:Fireballs hit anywhere + code:a6a0/cb/00+a6af/4d/00 + cheat + description:Fireballs turn most solid objects into coins + code:a54e/17/00+a560/05/00 + cheat + description:Tail hits anywhere + code:db59/90/24 + cheat + description:1-up for each enemy you stomp + code:c460/52 + cheat + description:1-up for each coin + code:b08b/64/01+b090/64/01 + cheat + description:1-up for each 10 coins + code:b08b/64/0a+b090/64/0a + cheat + description:Change to Super Mario if you fall off screen and die + code:da9d/01/00+a416/00/01 + cheat + description:Change to Fire Mario if you fall off screen and die + code:da9d/01/00+a416/00/02 + cheat + description:Change to Raccoon Mario if you fall off screen and die + code:da9d/01/00+a416/00/03 + cheat + description:Change to Frog Mario if you fall off screen and die + code:da9d/01/00+a416/00/04 + cheat + description:Change to Tanooki Mario if you fall off screen and die + code:da9d/01/00+a416/00/05 + cheat + description:Change to Sledgehammer Mario if you fall off screen and die + code:da9d/01/00+a416/00/06 + cheat + description:Move anywhere on the map + code:d2c1/d1/a9+d348/20/10 + cheat + description:Multi-jump + code:ac85/a9/a5 + cheat + description:Multi-jump (alt) + code:ac85/a9/ad + cheat + description:Multi-jump (alt 2) + code:ac3f/d0/24 + cheat + description:Power-jumps + code:a647/c8/b8 + cheat + description:Super power-jumps + code:a647/c8/a8 + cheat + description:Mega power-jumps + code:a647/c8/88 + cheat + description:Super speed running + code:abc0/a5/a9 + cheat + description:Turbo-charged running + code:abbf/88/ea + cheat + description:Raise P meter while standing still (hold B) + code:ab74/03/00 + cheat + description:Restore powers after playing an action scene + code:8f3a/9d/ad + cheat + description:Card match game always appears after a level + code:ac92/f0/24 + cheat + description:Small white ship level always appears after a level + code:accd/4f/0c+ac92/f0/24+accc/bd/a9+acce/ac/ea + cheat + description:White money ship always appears after a level + code:ac92/f0/24+accd/4f/0b+accc/bd/a9+acce/ac/ea + cheat + description:White toad house always appears after a level + code:ac92/f0/24+accc/bd/a9+acce/ac/ea+accd/4f/0a + cheat + description:Press Start to complete current level (do not use on final ship/castle levels for each map) + code:8e71/03/00+8e70/76/14 + cheat + description:1 life after continue - both players + code:92c6/04/00 + cheat + description:9 lives after continue - both players + code:92c6/04/08 + cheat + description:Start a new game as Fire Mario + code:acbc/00/02 + cheat + description:Start a new game as Raccoon Mario + code:acbc/00/03 + cheat + description:Start a new game as Frog Mario + code:acbc/00/04 + cheat + description:Start a new game as Tanooki Mario + code:acbc/00/05 + cheat + description:Start a new game as Sledgehammer Mario + code:acbc/00/06 + cheat + description:Start a new game to see the ending + code:a9c5/cf + cheat + description:Start on World 2 + code:acb3/00/01 + cheat + description:Start on World 3 + code:acb3/00/02 + cheat + description:Start on World 4 + code:acb3/00/03 + cheat + description:Start on World 5 + code:acb3/00/04 + cheat + description:Start on World 6 + code:acb3/00/05 + cheat + description:Start on World 7 + code:acb3/00/06 + cheat + description:Start on World 8 + code:acb3/00/07 + cheat + description:Unused level - Plains 1 + code:b47c/82/4c+b47d/bb/a7 + cheat + description:Unused level - Plains 2 + code:b47c/82/ac+b47d/bb/a1 + cheat + description:Unused level - Dungeon + code:b428/21/22+b47c/82/54+b47d/bb/b7 + cheat + description:Unused level - Underground 2 + code:b428/21/23+b47c/82/42+b47d/bb/b4 + cheat + description:Unused level - Sky 1 + code:b428/21/24+b47c/82/cd+b47d/bb/ad + cheat + description:Unused level - Sky 3 (level cannot be completed) + code:b428/21/24+b47c/82/c4+b47d/bb/b0 + cheat + description:Unused level - Cloudy 1 + code:b428/21/2d+b47c/82/a9+b47d/bb/ac + cheat + description:Unused level - Pipe level + code:b428/21/28+b47c/82/18+b47d/bb/af + cheat + description:Unused level - Hilly level + code:b428/21/23+b47c/82/dd+b47d/bb/b0 + cheat + description:Unused level - Ice/Water + code:b428/21/2c+b47c/82/ba+b47d/bb/b7 + cheat + description:Unused level - Cloudy (level cannot be completed) + code:b428/21/2d+b47c/82/ab+b47d/bb/ad + 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 + name:Super Pitfall (USA) + cheat + description:Infinite bullets + code:f395/01/00 + cheat + description:Infinite lives - 1P game + code:d548/ce/ad + cheat + description:Infinite lives - P1 + code:d58e/ce/ad + cheat + description:Infinite lives - P2 + code:d5aa/ce/ad + cheat + description:30 bullets gained on pick-up + code:bbf0/02/03 + cheat + description:10 bullets gained on pick-up + code:bbf0/02/01 + cheat + description:Start with 1 life - both players + code:d061/03/01 + cheat + description:Start with 6 lives - both players + code:d061/03/06 + cheat + description:Start with 9 lives - both players + code:d061/03/09 + cheat + description:Start with 30 bullets + code:cfaf/02/03 + cheat + description:Start with 10 bullets + code:cfaf/02/01 + cheat + description:Invincibility (blinking) - both players + code:00dc/ff + +cartridge sha256:7c14c7e39943e7247c92d907f3362eab09a7306fb606d4a899a918fc6afd356a + name: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 + name:Super Sprint (USA) (Unl) + cheat + description:Infinite continues + code:eb06/ce/ad + cheat + description:6 continues + code:d059/03/07 + cheat + description:No continues + code:d059/03/01 + cheat + description:More obstacles on tracks + code:cecf/00/05+ced3/8d/2c + cheat + description:Even more obstacles on tracks + code:cecf/00/0a+ced3/8d/2c + cheat + description:Lots and lots of obstacles on tracks + code:cecf/00/0f+ced3/8d/2c + +cartridge sha256:7806ee6afcdf88ef6364da23af8b28f359ef7d850fe55224e188b8a01d5ade67 + name:Super Spy Hunter (USA) + cheat + description:Infinite health + code:9ae0/85/a5 + cheat + description:Start with max health gauge + code:bda9/04/0c + cheat + description:Infinite lives + code:0074/05 + cheat + description:Infinite health (alt) + code:007b/40 + +cartridge sha256:639d5b9dad2f4eae48559dadc708d396f50f898a5912631c0a3c1715a5eab729 + name:Super Turrican (Europe) + cheat + description:Infinite health + code:038a/06 + cheat + description:Infinite lives + code:7051/09 + +cartridge sha256:9ffc36dfc772e1020a9648949aecebab687d6b386d6f02526916d1d49973a78a + name:Superman (USA) + cheat + description:Never die when out of super power + code:dd28/80/00 + cheat + description:Never lose super power + code:dcfd/8d/ad + cheat + description:Start with lots of super power + code:e2bf/05/e2 + cheat + description:Double max power of all items at start + code:9d8b/30/60 + cheat + description:Double usual item power on item power crystal pick-up + code:93b7/10/20 + cheat + description:Full item power on item power crystal pick-up + code:93b7/10/a0 + cheat + description:Start at mission 2 + code:9d64/a9/a0+9d65/00/01+9d72/8d/8c + cheat + description:Start at mission 3 + code:9d64/a9/a0+9d65/00/02+9d72/8d/8c + cheat + description:Start at mission 4 + code:9d64/a9/a0+9d65/00/03+9d72/8d/8c + cheat + description:Start at mission 5 + code:9d64/a9/a0+9d65/00/04+9d72/8d/8c + +cartridge sha256:d138aba5eb5c8cf1218abc7b57ad10709041fd68b6a6c47dd30432f8b33470e9 + name:Swamp Thing (USA) + cheat + description:Invincibility + code:94ee/29/09+94ea/f0/d0 + cheat + description:Infinite health + code:e67a/ce/ad + cheat + description:Infinite lives + code:e475/ce/ad + +cartridge sha256:553d6db3959c8ae3e3cfa598a33c57756b06653ce434fddd0de92bafb460cb05 + name:Sword Master (USA) + cheat + description:Invincibility + code:aa46/10/30 + cheat + description:Infinite health + code:cadf/8d/ad+ca57/8d/ad + cheat + description:Infinite continues + code:eb76/8d/ad + cheat + description:Gain a level for every EXP point gained + code:cc04/21/00 + cheat + description:Invincibility (alt) + code:042e/8f + cheat + description:Infinite health (alt) + code:042f/0f + +cartridge sha256:cdd148ebf43ed8918b4cd5d03e685fe0f38b434a59ffb38f0d9ceb2ee7ca9d89 + name:Swords and Serpents (USA) + cheat + description:All characters have Scale Armor + code:ce74/86/8e + cheat + description:Warriors start with a Great Sword + code:ce8d/81/8b + cheat + description:Warriors start with a Great Axe + code:ce8d/81/8c + cheat + description:Magicians start with a Wizard's Wand + code:ce80/85/8d + cheat + description:Magicians start with more spells + code:ce45/03/1f + cheat + description:Magicians have greater spells + code:ce4a/00/03 + cheat + description:Spells use up no magic points + code:f443/f1/24 + cheat + description:Thieves start with a Long Sword + code:ce96/82/8a + cheat + description:Thieves start with an Axe + code:ce96/82/84 + cheat + description:Start with 30 health points each + code:ce27/0a/1e+ce2d/0a/1e + cheat + description:Start with 50 health points each + code:ce27/0a/32+ce2d/0a/32 + +cartridge sha256:f3955370fe7ecc99afc27cdccf3482f75f06e0f431e42823c95982bb553ad6b9 + name:Town & Country Surf Designs - Wood & Water Rage (USA) + cheat + description:Infinite lives for skating + code:a2b2/c6/24 + cheat + description:Infinite lives for surfing + code:c3f8/c6/24 + cheat + description:When surfing lose only 1 symbol + code:c395/02/01 + cheat + description:When skating lose only 1 symbol if you fall into the ocean or a crack + code:a007/03/01 + cheat + description:Infinite time + code:b8c2/c6/24 + cheat + description:Increase time + code:92d4/01/03 + cheat + description:Infinite lives + code:0047/04 + cheat + description:Infinite time (alt) + code:0037/09 + +cartridge sha256:cfa1cc0f40cf139b1ba61794838d52c029b40ea12194b4248178d8ae59c69b7a + name:Town & Country Surf Designs - Thrilla's Surfari (USA) + cheat + description:Infinite lives + code:d752/c6/a9 + cheat + description:Can't collect Coconuts + code:e58d/e6/a9 + cheat + description:Start with 5 Coconuts plus what you've collected in sub-game + code:8133/00/05 + cheat + description:Start with 10 Coconuts plus what you've collected in sub-game + code:8133/00/0a + cheat + description:Start with 15 Coconuts plus what you've collected in sub-game + code:8133/00/0f + cheat + description:Start with less health + code:812d/02/01 + cheat + description:Start with a little more health + code:812d/02/03 + cheat + description:Start with 2x health + code:812d/02/04 + cheat + description:Start with a lot more health + code:812d/02/09 + cheat + description:Start with 1 life + code:8129/03/01 + cheat + description:Start with 5 lives + code:8129/03/05 + cheat + description:Start with 7 lives + code:8129/03/07 + cheat + description:Start with 9 lives + code:8129/03/09 + cheat + description:Start with mega lives + code:8129/03/99 + cheat + description:Start on level 1-3 (can't advance to next level) + code:b6f8/05/02+b6fa/b4/04 + cheat + description:Start on level 1-4 (can't advance to next level) + code:b6f8/05/03+b6fa/b4/04 + cheat + description:Watch the level 2 Cinema (can't advance to next level) + code:b6f8/05/04+b6fa/b4/04 + cheat + description:Start on level 2-2 (can't advance to next level) + code:b6f8/05/06+b6fa/b4/04 + cheat + description:Start on level 2-3 (can't advance to next level) + code:b6f8/05/07+b6fa/b4/04 + cheat + description:Start on level 2-4 (can't advance to next level) + code:b6f8/05/08+b6fa/b4/04 + cheat + description:Have all 8 health slots + code:0006/08 + +cartridge sha256:b002d1ebee16a5fd2bcae480df8ccc7b8dc7a6f96a80f5fac8b76e078e4f42f0 + name:Tag Team Wrestling (USA) + cheat + description:Infinite health (glitchy) + code:d2bb/95/99 + cheat + description:Never give up + code:cefa/d6/b5 + 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 + name:Takahashi Meijin no Bouken-jima IV (Japan) + cheat + description:Invincibility + code:a20f/f0/d0 + cheat + description:Infinite health + code:c2c7/85/a5 + +cartridge sha256:6d10e95fcbf4cd1179293106d526373ea43a0c2b8531e694288b147310d617c6 + name:TaleSpin (USA) + cheat + description:Infinite health + code:812c/06/00 + cheat + description:Infinite continues + code:cbfa/c6/a5 + cheat + description:Infinite lives from getting trapped by obstacles + code:cc47/ce/2c + cheat + description:Add $1,000,000 to end-of-level bonus + code:c863/70/71 + cheat + description:1 life after continue + code:cbf6/73/70 + cheat + description:7 lives after continue + code:cbf6/73/76 + cheat + description:10 lives after continue + code:cbf6/73/79 + cheat + description:1 continue + code:c605/73/71 + cheat + description:6 continues + code:c605/73/76 + cheat + description:9 continues + code:c605/73/79 + cheat + description:Start with 1 life + code:c76a/73/70 + cheat + description:Start with 7 lives + code:c76a/73/76 + cheat + description:Start with 10 lives + code:c76a/73/79 + 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 + name:Target Renegade (USA) + cheat + description:Don't take most damage + code:aee6/85/a5 + cheat + description:Take half damage from bosses + code:9955/14/06 + cheat + description:Infinite time + code:8a01/c6/a5 + cheat + description:Set timer to 5:00 for all levels + code:8286/bd/ad + cheat + description:Hearts replenish health to maximum + code:8acd/02/00 + cheat + description:Set timer to 3:00 for all levels + code:8286/bd/ad+8288/80/cf + cheat + description:Start on level 2 + code:921f/00/01 + cheat + description:Start on level 3 + code:921f/00/02 + cheat + description:Start on level 4 + code:921f/00/03 + cheat + description:Start on level 5 + code:921f/00/04 + cheat + description:Start on level 6 + code:921f/00/05 + cheat + description:Start on level 7 + code:921f/00/06 + cheat + description:Infinite health + code:00da/40+00db/40 + cheat + description:Infinite time (alt) + code:00eb/09 + +cartridge sha256:efb93dcae29f1ff85b58ccb9450c23d528073a019493d88a9abcabe4ca9aca4f + name:Tatakae! Chou Robot Seimeitai Transformers - Convoy no Nazo (Japan) + cheat + description:Invincibility + code:c238/f0/50+c4a1/a5/60 + cheat + description:Hit anywhere (enemies and platforms) + code:c2c7/24/00+c2ea/90/50+c30b/9d/bd + cheat + description:Moon jump + code:910e/2e/00+9102/3a/00+90f8/27/00 + cheat + description:Solve level 9 maze using any path + code:8278/f0/70 + +cartridge sha256:d088f4b91a03dd6a618245fffb492bcda127c7faa6d880596aa5e751fdac0181 + name:Tecmo Bowl (USA) (Rev A) + cheat + description:Instant touchdowns - P1 + code:816b/03/00 + cheat + description:Instant touchdowns - P2 + code:8d0c/03/00 + cheat + description:Always kick with max power - P1 + code:9bac/02/65+9bab/69/a9 + cheat + description:Only 2 downs allowed + code:8527/04/02+912e/04/02 + cheat + description:6 downs allowed + code:8527/04/06+912e/04/06 + 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 + name:Tecmo Bowl (USA) + cheat + description:Instant touchdowns - P1 + code:816b/03/00 + cheat + description:Instant touchdowns - P2 + code:8d0c/03/00 + cheat + description:Always kick with max power - P1 + code:9bac/02/65+9bab/69/a9 + cheat + description:Only 2 downs allowed + code:8527/04/02+912e/04/02 + cheat + description:6 downs allowed + code:8527/04/06+912e/04/06 + 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 + name:Tecmo NBA Basketball (USA) + cheat + description:Infinite timeouts + code:b369/de/bd + cheat + description:2-pt. shots worth 1, 3-pt. shots worth 2 + code:b996/01/00 + cheat + description:2-pt. shots worth 3, 3-pt. shots worth 4 + code:b996/01/02 + cheat + description:2-pt. shots worth 4, 3-pt. shots worth 5 + code:b996/01/03 + cheat + description:2-pt. shots worth 5, 3-pt. shots worth 6 + code:b996/01/04 + cheat + description:2-pt. shots worth 6, 3-pt. shots worth 7 + code:b996/01/05 + cheat + description:3-pt. shots worth 2 pts. + code:b9fe/ee/60 + cheat + description:5-second violations become 10-second violations + code:8a5f/07/ff + cheat + description:No 10-second violations + code:9716/0a/ff + cheat + description:Longer shot clock after getting ball on rebound + code:b895/18/58 + cheat + description:Shorter shot clock after getting ball on rebound + code:b895/18/08 + +cartridge sha256:cd5ad84e6bba35c19098c6f9783b568e4f1218582a12ec0513e5fafbdabb0303 + name:Tecmo Super Bowl (USA) + cheat + description:Infinite time (continuous play) + code:a2f9/c6/a5 + cheat + description:Almost every player has their skill level at 100 + code:dde5/2a + cheat + description:10 minutes per quarter instead of 5 + code:a23b/05/10 + cheat + description:20 minutes per quarter + code:a23b/05/20 + cheat + description:2 minutes per quarter + code:a23b/05/02 + cheat + description:Touchdown scores 0 instead of 6 - P1 + code:8616/06/00 + cheat + description:Touchdown scores 0 - P2 or computer + code:8d9e/06/00 + cheat + description:Touchdown scores 3 - P1 + code:8616/06/03 + cheat + description:Touchdown scores 3 - P2 or computer + code:8d9e/06/03 + cheat + description:Touchdown scores 9 - P1 + code:8616/06/09 + cheat + description:Touchdown scores 9 - P2 or computer + code:8d9e/06/09 + cheat + description:Touchdown scores 12 - P1 + code:8616/06/0c + cheat + description:Touchdown scores 12 - P2 or computer + code:8d9e/06/0c + cheat + description:Extra-point kick scores 0 instead of 1 - P1 + code:8703/01/00 + cheat + description:Extra-point kick scores 0 - P2 or computer + code:8e8b/01/00 + cheat + description:Extra-point kick scores 2 - P1 + code:8703/01/02 + cheat + description:Extra-point kick scores 2 - P2 or computer + code:8e8b/01/02 + cheat + description:Extra-point kick scores 3 - P1 + code:8703/01/03 + cheat + description:Extra-point kick scores 3 - P2 or computer + code:8e8b/01/03 + cheat + description:Extra-point kick scores 6 - P1 + code:8703/01/06 + cheat + description:Extra-point kick scores 6 - P2 or computer + code:8e8b/01/06 + cheat + description:Field goal scores 0 instead of 3 - P1 + code:84c4/03/00 + cheat + description:Field goal scores 0 - P2 or computer + code:8c4c/03/00 + cheat + description:Field goal scores 1 - P1 + code:84c4/03/01 + cheat + description:Field goal scores 1 - P2 or computer + code:8c4c/03/01 + cheat + description:Field goal scores 6 - P1 + code:84c4/03/06 + cheat + description:Field goal scores 6 - P2 or computer + code:8c4c/03/06 + cheat + description:Field goal scores 9 - P1 + code:84c4/03/09 + cheat + description:Field goal scores 9 - P2 or computer + code:8c4c/03/09 + cheat + description:Safety scores 0 instead of 2 - P1 + code:8d55/02/00 + cheat + description:Safety scores 0 - P2 or computer + code:85cd/02/00 + cheat + description:Safety scores 1 - P1 + code:8d55/02/01 + cheat + description:Safety scores 1 - P2 or computer + code:85cd/02/01 + cheat + description:Safety scores 4 - P1 + code:8d55/02/04 + cheat + description:Safety scores 4 - P2 or computer + code:85cd/02/04 + cheat + description:Safety scores 6 - P1 + code:8d55/02/06 + cheat + description:Safety scores 6 - P2 or computer + code:85cd/02/06 + +cartridge sha256:b6adca3680ba28efd41b2216cfcb9af66ed175e4359f0fbd5eda90e6cb6380e8 + name:Tecmo World Cup Soccer (Europe) + cheat + description:Never lose guts + code:86b9/91/a9 + cheat + description:Everyone has more guts + code:ddf0/20/50+ddf1/03/06 + +cartridge sha256:daf07341c80a866333d69c7560f8402123adbb345b15185480393f0db6822b16 + name:Tecmo World Wrestling (USA) + cheat + description:Infinite health - P1 + code:d7c5/85/a5 + cheat + description:Half training time allowed + code:d1be/0a/05 + cheat + description:Double training time allowed + code:d1be/0a/14 + cheat + description:Lose all energy after being on the receiving end of a move + code:d79f/91 + +cartridge sha256:892468d05a1097769d14e0ed4822267760d85dbfc79d83a0235878109f839dd1 + name:Teenage Mutant Ninja Turtles (USA) + cheat + description:Invincibility + code:9591/20/ad + cheat + description:Infinite health + code:98db/e5/10 + cheat + description:Infinite health (alt) + code:98e3/99/b9 + cheat + description:Infinite health (alt 2) + code:98db/e5/24 + cheat + description:10 weapons on pick-up + code:96f8/14/0a + cheat + description:50 weapons on pick-up + code:96f8/14/32 + cheat + description:99 weapons on pick-up + code:96f8/14/63 + cheat + description:20 missiles on pick-up + code:973b/0a/14 + cheat + description:99 missiles on pick-up + code:973b/0a/67 + cheat + description:Don't take damage from non-killing seaweed + code:a5e4/99/ad + cheat + description:Full health boost from pizza slices + code:969c/02/00 + cheat + description:Double rope on pick-up + code:9749/03/06 + cheat + description:Never lose rope + code:a3ee/c6/a5 + cheat + description:Reduce recovery time + code:a696/8d/ad + cheat + description:No sound + code:9150/55 + cheat + description:Start a new game to view the ending + code:c621/02/05 + 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 + name:Teenage Mutant Ninja Turtles II - The Arcade Game (USA) + cheat + description:Invincibility (except grabs from behind) - both players + code:82b9/f0/d0 + cheat + description:Infinite health - both players + code:8ee5/9d/bd+ec01/9d/bd + cheat + description:Infinite lives - both players + code:8b03/01/00 + cheat + description:One hit kills - both players + code:eaaa/d0/10 + cheat + description:Stronger turtle weapon + code:eaa4/02/09 + cheat + description:Stronger jump + attack + code:ea9c/04/09 + cheat + description:Stronger jump + attack + code:ea9c/04/02 + cheat + description:Stronger kick + code:eaa0/03/09 + cheat + description:Weaker kick + code:eaa0/03/01 + cheat + description:In two-turtle mode, when one player is revived the other player's spare life won't get used + code:8281/c6/a5+8237/c6/a5 + cheat + description:Enable stage select and 10 lives code + code:caef/00/81 + cheat + description:Press Start to finish the level + code:d3dc/01/04+d3de/3d/3c + cheat + description:Start with 1 life + code:d190/02/01 + cheat + description:Start with 6 lives + code:d190/02/06 + cheat + description:Start with 9 lives + code:d190/02/09 + 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 + name:Teenage Mutant Ninja Turtles III - The Manhattan Project (USA) + cheat + description:Invincibility (except grabs from behind) + code:cddc/d0/f0 + cheat + description:Infinite health + code:b22e/de/bd+a449/9d/bd + cheat + description:Infinite lives + code:c2fb/01/00 + cheat + description:Infinite continues + code:dcfc/ce/ad + cheat + description:No health loss from using turbo attack + code:d20f/08/00 + cheat + description:Hit anywhere - both players + code:a806/1e/00+aa7f/d7/00+a810/14/00+a822/ab/18+a820/d9/ea+a821/78/ea + cheat + description:High-jump + code:cf36/40/30 + cheat + description:Super-jump + code:cf36/40/28 + cheat + description:Mega-jump + code:cf36/40/20 + cheat + description:1 continue + code:ac31/03/01 + cheat + description:9 continues + code:ac31/03/09 + cheat + description:Start with 1 life instead of 4 + code:8390/03/00 + cheat + description:Start with 6 lives + code:8390/03/05 + cheat + description:Start with 9 lives + code:8390/03/08 + 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 + name:Teenage Mutant Ninja Turtles - Tournament Fighters (USA) + cheat + description:Infinite health + code:ee6e/90/a9+ee6f/1b/b0+ee71/bd/8d + cheat + description:Infinite time + code:eacc/ce/2c + cheat + description:Select ultra strength (ignore strength meter and keep pushing to the right) - both players + code:893d/07/ff + cheat + description:Select any character in story mode + code:8362/04/07 + cheat + description:Infinite continues + code:86ca/c6/c1 + cheat + description:First hit wins round + code:80a4/b0/01 + cheat + description:One round wins match + code:8a79/69/a9+8a7a/01/02 + cheat + description:Start with 1/3 health - both players + code:80a4/b0/30 + cheat + description:Start a new game to view the ending + code:f4a3/02/0b + 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 + name:Terminator, The (USA, Europe) + cheat + description:Infinite health + code:b8f7/8d/ad + cheat + description:Infinite Grenades + code:f0e5/ce/ad + +cartridge sha256:6f66d14e5f17ca244444e74538afe31f8abda8376b5b0205afaeb86075407c45 + name:Terminator 2 - Judgment Day (USA) + cheat + description:Infinite health + code:eae2/20/2c + cheat + description:Take minimal damage + code:eafc/49/a9+eafd/ff/fe + cheat + description:Infinite lives + code:8196/ce/ad + cheat + description:Super-jump + code:99ed/fc/fa + cheat + description:Slower running + code:9a1e/02/01+9a3a/02/01 + cheat + description:Faster running + code:9a1e/02/03+9a3a/02/03 + cheat + description:Faster and longer jumping + code:9cd4/02/03+9ce0/02/03 + cheat + description:Start with 1 life + code:a379/04/01 + cheat + description:Start with 9 lives + code:a379/04/09 + +cartridge sha256:667bcf3ca1ebcf6f71fccd412ced546f4aba3b8cd2fc30d173cf6d3b4c15846a + name:Terra Cresta (USA) + cheat + description:Invincibility + code:d44b/20/e4 + cheat + description:Infinite lives + code:e649/c6/a5 + cheat + description:Infinite "ship formation" splits + code:ebd3/c6/a5 + cheat + description:9 "ship formation" splits + code:e890/03/09+cec0/03/09 + cheat + description:A secret mega-weapon + code:cfef/03/00 + cheat + description:Start with 1 life + code:d449/02/00 + cheat + description:Start with 6 lives + code:d449/02/05 + cheat + description:Start with 9 lives + code:d449/02/08 + +cartridge sha256:2ae5fb18a1bf841077e3872ba05060f030ea0bfc573994b2f8fe2fb570dc7853 + name:Tetris (USA) + cheat + description:Lines are cleared when a piece is dropped + code:9a94/37/00 + cheat + description:Disable Game Over (press start) + code:9d10/03/04+9a15/f0/4c+9a17/a5/9a+9a16/30/47 + cheat + description:999999 score with one piece dropped + code:9c8b/08/00 + cheat + description:Puzzle area doesn't disappear on pause + code:a3b7/16/1e + cheat + description:2P interactive game + code:8783/f7/f8 + cheat + description:Need only complete 10 lines in game B + code:875c/25/10 + cheat + description:Faster forced fall rate + code:8953/01/09 + cheat + description:Must complete 50 lines in game B + code:875c/25/50 + cheat + description:Must complete 80 lines in game B + code:875c/25/80 + cheat + description:Next piece is a T-block + code:00bf/02 + cheat + description:Next piece is a J-block + code:00bf/07 + cheat + description:Next piece is a Z-block + code:00bf/08 + cheat + description:Next piece is a square block + code:00bf/0a + cheat + description:Next piece is a S-block + code:00bf/0b + cheat + description:Next piece is a L-block + code:00bf/0e + cheat + description:Next piece is a straight line block + code:00bf/12 + +cartridge sha256:9daa4bec3013ae7ef498318432f438d70374af294d1dce28edd3c466aaf6b740 + name:Tetris (USA) (Unl) + cheat + description:Lines are cleared when a piece is dropped + code:87ab/2a/00+87af/26/00 + cheat + description:Always get straight pieces + code:9940/f0/a9+9941/f9/01 + cheat + description:Speed stays the same + code:9b24/24/a9+9b25/2f/21 + cheat + description:Press down to stop blocks from falling + code:8109/04 + cheat + description:Press down to rotate block very fast + code:8109/19 + cheat + description:Next piece is a straight line block - P1 + code:0066/01 + cheat + description:Next piece is a T-block - P1 + code:0066/02 + cheat + description:Next piece is a square block - P1 + code:0066/03 + cheat + description:Next piece is a J-block - P1 + code:0066/04 + cheat + description:Next piece is a L-block - P1 + code:0066/05 + cheat + description:Next piece is a S-block - P1 + code:0066/06 + cheat + description:Next piece is a Z-block - P1 + code:0066/07 + cheat + description:Next piece is a straight line block - P2 + code:0067/01 + cheat + description:Next piece is a T-block - P2 + code:0067/02 + cheat + description:Next piece is a square block - P2 + code:0067/03 + cheat + description:Next piece is a J-block - P2 + code:0067/04 + cheat + description:Next piece is a L-block - P2 + code:0067/05 + cheat + description:Next piece is a S-block - P2 + code:0067/06 + cheat + description:Next piece is a Z-block - P2 + code:0067/07 + cheat + description:Start at level 0 + code:042c/30+042d/30 + cheat + description:Start at level 1 + code:042c/30+042d/31 + cheat + description:Start at level 2 + code:042c/30+042d/32 + cheat + description:Start at level 3 + code:042c/30+042d/33 + cheat + description:Start at level 4 + code:042c/30+042d/34 + cheat + description:Start at level 5 + code:042c/30+042d/35 + cheat + description:Start at level 6 + code:042c/30+042d/36 + cheat + description:Start at level 7 + code:042c/30+042d/37 + cheat + description:Start at level 8 + code:042c/30+042d/38 + cheat + description:Start at level 9 + code:042c/30+042d/39 + cheat + description:Start at level 10 + code:042c/31+042d/30 + cheat + description:Start at level 11 + code:042c/31+042d/31 + cheat + description:Start at level 12 + code:042c/31+042d/32 + cheat + description:Start at level 13 + code:042c/31+042d/33 + cheat + description:Start at level 14 + code:042c/31+042d/34 + cheat + description:Start at level 15 + code:042c/31+042d/35 + cheat + description:Start at level 16 + code:042c/31+042d/36 + cheat + description:Start at level 17 + code:042c/31+042d/37 + cheat + description:Max score at 999,999 - P1 + code:0418/39+0419/39+041a/39+041b/39+041c/39+041d/39 + cheat + description:Max score at 999,999 - P2 + code:041e/39+041f/39+0420/39+0421/39+0422/39+0423/39 + +cartridge sha256:dd77dc88d380807990f55d0b1b55c151f78c480a0a0895e91d6edfb945ad71d7 + name:Tetris 2 (USA) + cheat + description:(1P game) Speed doesn't increase + code:8d3b/9d/08 + cheat + description:(1P game) Speed increases much faster + code:8dbb/9d/fe + cheat + description:(1P game) Start and stay at speed of 25 + code:8fa4/01/06 + cheat + description:(1P game) Max speed is 2 + code:8dcd/19/02+8dd1/18/01 + cheat + description:(1P game) Max speed is 10 + code:8dcd/19/0a+8dd1/18/09 + cheat + description:(1P game) Max speed is 15 + code:8dcd/19/0f+8dd1/18/0e + cheat + description:(1P game) Max speed is 20 + code:8dcd/19/14+8dd1/18/13 + cheat + description:(1P vs 2P or 1P vs Com) Every round starts with 4 fixed blocks + code:817e/b1/a9+817f/00/01 + cheat + description:(1P vs 2P or 1P vs Com) Every round starts with 10 fixed blocks + code:817e/b1/a9+817f/00/07 + cheat + description:(1P vs 2P or 1P vs Com) Every round starts with 15 fixed blocks + code:817e/b1/a9+817f/00/0c + cheat + description:(1P vs 2P or 1P vs Com) Every round starts with 20 fixed blocks + code:817e/b1/a9+817f/00/11 + cheat + description:(All game types) Cannot pause game + code:af66/80/00 + cheat + description:(All game types) Don't hide remaining pieces during pause + code:af89/a2/60 + +cartridge sha256:18d41a2dc65d8afce295eaf29c391539a69d7cfe6dd32503713ae13d4495a545 + name:Thexder (Japan) + cheat + description:Infinite health + code:9d85/85/a5 + cheat + description:Infinite shield + code:980c/c6/a5 + cheat + description:Start on last level + code:0074/63 + +cartridge sha256:e3be0290f198fceed633b037d9201aa4b95460617551b3a9fb5bb212b153a2d4 + name:Thunder & Lightning (USA) + cheat + description:Infinite lives - P1 + code:9371/d6/d5 + +cartridge sha256:c0c3d7c2682dd2e0dd2122682e2ae3a9ee7aa3d095bd22a36c759c29b5d05615 + name:Thunderbirds (USA) + cheat + description:Don't lose life points when colliding with enemy + code:eef1/ce/ad + cheat + description:Don't lose life points when hit + code:ef3b/ce/ad + cheat + description:Don't lose energy points when colliding with enemy + code:eefe/ce/ad + cheat + description:Don't lose energy points when hit + code:ef48/ce/ad + cheat + description:81 Days to defeat Hood + code:c68d/3c/51 + cheat + description:30 Days to defeat Hood + code:c68d/3c/1e + cheat + description:Limited forward movement + code:8728/08/60+872c/08/60 + cheat + description:Faster craft + code:86ae/02/04+86aa/02/04 + cheat + description:Full firepower on first pick-up + code:8e30/c0/a0+8e34/c8/ea + +cartridge sha256:c56af43761cb601a068cdc88c2fc36f715921dbae9a8a9d8c10479146c47ccb9 + name:Thundercade (USA) + cheat + description:Infinite lives + code:f2e1/d6/24 + cheat + description:Infinite Missiles + code:f53b/11/00 + cheat + description:Infinite Bombs + code:f622/d6/24 + cheat + description:Autofire + code:f574/0a/02 + cheat + description:Start with double Bombs + code:f2f9/03/06 + cheat + description:Start with triple Bombs + code:f2f9/03/09 + cheat + description:Start with 1 life + code:f515/03/01 + cheat + description:Start with 6 lives + code:f515/03/06 + cheat + description:Start with 9 lives + code:f515/03/09 + +cartridge sha256:e115dbf3de0a4e674ff3f9081d7f97b89f636d81ce524119c0af4ef799490695 + name:Thunder Warrior (Asia) (Unl) + cheat + description:Invincibility + code:b3be/f0/d0+b3c3/f0/d0 + cheat + description:Infinite health + code:93a4/ce/ad + cheat + description:Infinite magic + code:89c0/ce/ad + cheat + description:Infinite lives + code:807d/ce/ad + cheat + description:Keep weapon after losing a life + code:9bd1/8d/60 + cheat + description:Start with 9 lives + code:a438/03/09 + +cartridge sha256:403fe1c4454dc1e23fb272c88f70ba30dd5e860ab48ecff59420a09fc84e9a2d + name:Tiger-Heli (USA) + cheat + description:Invincibility + code:f050/4c/ad + cheat + description:Infinite lives - 1P game + code:b724/de/bd + cheat + description:Infinite lives - both players + code:b7c5/de/bd+b7eb/de/bd + cheat + description:Autofire capability + code:f2c8/0d/06 + cheat + description:Burstfire capability + code:f2c8/0d/02 + cheat + description:Turbo boost + code:f3ea/12/24 + cheat + description:Extra life every 5 bonus blocks + code:fe5e/0a/03 + cheat + description:Start with 2 lives - 1P game + code:b6bf/02/00 + cheat + description:Start with 9 lives - 1P game + code:b6bf/02/08 + cheat + description:Start with 6 lives - P1 in a 2P game + code:b75f/02/05 + cheat + description:Start with 9 lives - P1 in a 2P game + code:b75f/02/08 + cheat + description:Start with 6 lives - P2 + code:b772/02/05 + cheat + description:Start with 9 lives - P2 + code:b772/02/08 + cheat + description:Start with 2 little-helis after dying + code:b863/4a/ea + +cartridge sha256:13353e4e94633eba066e024ea7050b0801a8ccbe4c03bd97656852df4d2f3359 + name:Time Lord (USA) + cheat + description:Infinite health + code:d16b/8d/ad + cheat + description:Infinite lives + code:cc3d/ce/ad + cheat + description:Hit anywhere + code:d789/18/00+fb05/b0/90 + cheat + description:Moonwalking (don't combine with super speed) + code:ce2a/01/00+ce36/00/01 + cheat + description:Super speed (don't combine with moonwalking) + code:ced9/00/01+ce95/00/01 + cheat + description:Start with 1 life + code:c18f/03/01 + cheat + description:Start with 6 lives + code:c18f/03/06 + cheat + description:Start with 9 lives + code:c18f/03/09 + +cartridge sha256:c47a01c9b32642ad3145316804e64b0475a20863e42e81d17c664d03dcdde3c5 + name:Tiny Toon Adventures (USA) + cheat + description:Invincibility + code:814c/d0/f0 + cheat + description:Infinite health after collecting one heart + code:9e1d/ce/ad + cheat + description:Infinite health and one Carrot + code:829f/ac/8d + cheat + description:Infinite time + code:da47/de/dd + cheat + description:Infinite lives + code:9f7b/ce/ad + cheat + description:Slow down timer + code:da22/3b/7f + cheat + description:Speed up timer + code:da22/3b/1f + cheat + description:Multi-jump + code:9651/29/00 + cheat + description:Pick-up more hearts + code:9781/01/00 + cheat + description:Power decreases slower when using Dizzy Devil's spin attack + code:91ed/02/01 + cheat + description:Press Start to finish the level (don't use on 6-3) + code:d9f6/01/0c+d9f8/4d/4c + cheat + description:Start a new game to view the ending + code:cf9d/00/10 + cheat + description:1 life after continue + code:aaa7/02/00 + cheat + description:6 lives after continue + code:aaa7/02/05 + cheat + description:9 lives after continue + code:aaa7/02/08 + cheat + description:Start with 1 life + code:cf2b/02/00 + cheat + description:Start with 6 lives + code:cf2b/02/05 + cheat + description:Start with 9 lives + code:cf2b/02/08 + cheat + description:Start on level 2 + code:cf51/85/86+cf2f/a9/a2+cf30/01/05 + cheat + description:Start on level 3 + code:cf51/85/86+cf2f/a9/a2+cf30/01/0a + cheat + description:Start on level 4 + code:cf51/85/86+cf2f/a9/a2+cf30/01/0f + cheat + description:Start on level 5 + code:cf51/85/86+cf2f/a9/a2+cf30/01/14 + +cartridge sha256:d4a94fd07859485fc2aac73d627933b70e1977c93b744ec3d71b66d4365ab7f7 + name:Tiny Toon Adventures 2 - Trouble in Wackyland (USA) + cheat + description:Invincibility + code:8012/a5/85+8014/f0/d0 + cheat + description:Infinite time + code:f230/20/ad + cheat + description:Protection against hits on log ride + code:aabe/ce/ad + cheat + description:Protection against hits on train + code:8558/ce/ad + cheat + description:Protection against hits on bumper cars + code:9a1b/ce/ad + cheat + description:Protection against hits on roller coaster + code:83c7/ce/ad + cheat + description:Protection against hits in fun house + code:8153/ce/ad + cheat + description:Log ride costs nothing instead of 3 tickets + code:9177/03/00 + cheat + description:Log ride costs 5 tickets + code:9177/03/05 + cheat + description:Train costs nothing instead of 2 tickets + code:9175/02/00 + cheat + description:Train costs 5 tickets + code:9175/02/05 + cheat + description:Roller coaster costs nothing instead of 4 tickets + code:9171/04/00 + cheat + description:Roller coaster costs 6 tickets + code:9171/04/06 + cheat + description:Bumper cars cost nothing instead of 1 ticket + code:9173/01/00 + cheat + description:Bumper cars cost 4 tickets + code:9173/01/04 + cheat + description:Fun house costs nothing instead of 50 normal tickets + code:917a/05/00 + cheat + description:Fun house costs 10 normal tickets + code:917a/05/01 + cheat + description:Fun house costs 90 normal tickets + code:917a/05/09 + cheat + description:Start a new game to view the ending + code:f745/08/09 + cheat + description:Start with 20 tickets instead of 10 + code:f701/01/02 + cheat + description:Start with 50 tickets instead of 10 + code:f701/01/05 + cheat + description:Start with 90 tickets instead of 10 + code:f701/01/09 + cheat + description:Start with 110 tickets instead of 10 + code:f6e8/8d/ee + +cartridge sha256:f80e57788e32f73852d7d2aa4831edfe4c4bd5b8a02a322995263a13597c2f0c + name:Titan Warriors (USA) (Proto) + cheat + description:Invincibility against enemies + code:fc5d/85/a5 + cheat + description:Infinite lives + code:9453/ce/ad + +cartridge sha256:44569cef71a0b859bd0390e0155b19077ddef4a684f6fba6569a5f918910d4a2 + name:To the Earth (USA) + cheat + description:Shots use up no energy + code:be0a/04/00 + cheat + description:Shots use up less energy + code:be0a/04/02 + cheat + description:Shots use up more energy + code:be0a/04/08 + cheat + description:Enemy bombs do no damage + code:efb8/14/00 + cheat + description:Enemy bombs do half damage + code:efb8/14/08 + cheat + description:Enemy bombs do more damage + code:efb8/14/28 + cheat + description:Bonus energy for shooting enemy + code:be88/0a/14 + cheat + description:Less energy for shooting enemy + code:be88/0a/04 + cheat + description:No energy for shooting enemy + code:be88/0a/00 + +cartridge sha256:e580f51b06217b102e56ec98fff7c4ebad5b925fa3a28042d67433cffa8c5cdc + name:Toki (USA) + cheat + description:Infinite health + code:80df/ce/80 + cheat + description:Infinite weapons + code:937c/ee/ad+938b/ee/ad+939a/8d/ad + cheat + description:Infinite time + code:8f4e/01/00 + cheat + description:Infinite lives + code:f5f2/ce/ad + cheat + description:Hit anywhere - normal enemies + code:86de/9d/ad+8681/60/ea + cheat + description:When weapon runs out of ammo it's replaced with the double weapon + code:9396/00/01 + cheat + description:When weapon runs out of ammo it's replaced with the wave weapon + code:9396/00/02 + cheat + description:When weapon runs out of ammo it's replaced with the 3-way weapon + code:9396/00/03 + cheat + description:When weapon runs out of ammo it's replaced with the flame weapon + code:9396/00/04 + cheat + description:When weapon runs out of ammo it's replaced with the fireball weapon + code:9396/00/05 + cheat + description:Start with less time + code:d804/03/01+8044/03/01 + cheat + description:Start with more time + code:d804/03/05+8044/03/05 + cheat + description:Start with even more time + code:d804/03/09+8044/03/09 + cheat + description:Start with one heart - first life only + code:f509/02/01 + cheat + description:Start with one heart - after first life + code:f5f6/02/00 + cheat + description:Start with 1 life + code:ffc2/02/00 + cheat + description:Start with 2 lives + code:ffc2/02/01 + cheat + description:Start with 5 lives + code:ffc2/02/04 + cheat + description:Start with 9 lives + code:ffc2/02/08 + 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 + name:Tom & Jerry - The Ultimate Game of Cat and Mouse! (USA) + cheat + description:Infinite health + code:f0a1/01/00 + cheat + description:Infinite lives + code:f0df/ce/ad + cheat + description:Minimum health (one touch kills) + code:f0a1/01/03 + cheat + description:Start with 1 life + code:fa5e/03/01 + cheat + description:Start with 6 lives + code:fa5e/03/06 + cheat + description:Start with 9 lives + code:fa5e/03/09 + cheat + description:Start on world 2 + code:f9e4/00/08 + cheat + description:Start on world 3 + code:f9e4/00/10 + cheat + description:Start on world 4 + code:f9e4/00/18 + cheat + description:Start on world 5 + code:f9e4/00/20 + +cartridge sha256:fe052f7f6b4b41dcbc009860e0c997c31e2e236eb46d713137ee773cce96105e + name:Toobin' (USA) (Unl) + cheat + description:Infinite lives + code:e5b4/c6/a5 + cheat + description:Infinite cans + code:a502/c6/a5 + cheat + description:Turbo left and right movement + code:a04e/20/30+a06b/20/30 + cheat + description:Start with 2 lives + code:e612/03/01 + cheat + description:Start with 6 lives + code:e612/03/06 + cheat + description:Start with 9 lives + code:e612/03/09 + cheat + description:Start with 18 cans + code:e616/06/12 + cheat + description:Start with 12 cans + code:e616/06/0c + cheat + description:Start with 1 can + code:e616/06/01 + cheat + description:Start on level 2 + code:a810/00/01 + cheat + description:Start on level 4 + code:a810/00/03 + cheat + description:Start on level 6 + code:a810/00/05 + cheat + description:Start on level 8 + code:a810/00/07 + 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 + name:Top Gun (USA) (Rev A) + cheat + description:Immune to Bullets (not Missiles) + code:dbcf/03/00 + cheat + description:Infinite fuel + code:dcbf/c6/24 + cheat + description:Infinite Missiles + code:ddc4/c6/24 + cheat + description:Take off with double Hound Missiles + code:c18e/28/50 + cheat + description:Take off with double Wolf Missiles + code:c18f/14/28 + cheat + description:Take off with double Tiger Missiles + code:c190/0a/14 + cheat + description:Start with half fuel + code:c17b/0a/05 + cheat + description:Start on mission 2 + code:c103/01/02 + cheat + description:Start on mission 3 + code:c103/01/03 + cheat + description:Start on mission 4 + code:c103/01/04 + 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 + name:Top Gun (USA) + cheat + description:Immune to Bullets (not Missiles) + code:dbcf/03/00 + cheat + description:Infinite fuel + code:dcbf/c6/24 + cheat + description:Infinite Missiles + code:ddc4/c6/24 + cheat + description:Always land safely on Aircraft Carrier + code:b725/04/00+b623/85/a5 + cheat + description:Take off with double Hound Missiles + code:c18e/28/50 + cheat + description:Take off with double Wolf Missiles + code:c18f/14/28 + cheat + description:Take off with double Tiger Missiles + code:c190/0a/14 + cheat + description:Start with half fuel + code:c17b/0a/05 + cheat + description:Start on mission 2 + code:c103/01/02 + cheat + description:Start on mission 3 + code:c103/01/03 + cheat + description:Start on mission 4 + code:c103/01/04 + 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 + name:Top Gun - The Second Mission (USA) + cheat + description:Invincibility + code:8b86/f0/50 + cheat + description:Infinite lives + code:f563/c6/a5 + cheat + description:Infinite missiles - 1P game + code:8f4b/01/00 + cheat + description:Infinite missiles - 2P game + code:85f2/01/00 + cheat + description:60 Phoenix missiles - 1P game + code:a5e6/94/bc + cheat + description:20 Phoenix missiles - 2P game + code:a5ee/85/94 + cheat + description:Start with 1 life + code:f350/03/01 + cheat + description:Start with 6 lives + code:f350/03/06 + cheat + description:Start with 9 lives + code:f350/03/09 + +cartridge sha256:45067f85328eabb3b8cb2bceec72192bfa8d73494521660f171b9ed6d151fdea + name:Total Recall (USA) + cheat + description:Infinite health + code:e8f9/a4/60 + cheat + description:Most enemies easier to kill + code:d2b5/9d/2c + cheat + description:Take less damage + code:e8fc/0c/09 + cheat + description:Gain maximum health from canisters + code:eb3f/ea/f2 + cheat + description:Start with less health + code:c978/a5/a9+c979/2b/30 + cheat + description:Start with more health + code:c978/a5/a9+c979/2b/ff + cheat + description:Invincibility + code:007f/03 + cheat + description:Infinite health (alt) + code:02c0/fa + +cartridge sha256:0bd29c5b583570e195e05a4272e69b74257db1f4ff928d59c8eb1022bad871ce + name:Totally Rad (USA) + cheat + description:Infinite health + code:f4ee/f9/ed + cheat + description:Infinite magic + code:84a1/fd/2c + cheat + description:Immune to fire and water + code:8567/c6/a5 + cheat + description:Infinite lives + code:825f/ce/ad + cheat + description:Super-jump + code:8497/10/18 + cheat + description:Mega-jump + code:8497/10/1f + cheat + description:Half a life or half magic give full health or magic + code:988f/03/06 + cheat + description:Start with 1 life + code:aebd/02/00 + cheat + description:Start with 6 lives + code:aebd/02/05 + cheat + description:Start with 9 lives + code:aebd/02/08 + cheat + description:Infinite health (alt) + code:006e/0c + cheat + description:Infinite lives (alt) + code:05d4/63 + +cartridge sha256:5ec7c3e91bfd5800073286ee978b1d152c19f924837788eb72700c7c01261fa4 + name:Tower of Druaga, The (Japan) + cheat + description:Invincibility + code:b6f8/a5/a9+b403/a5/a9 + 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 + name:Toxic Crusaders (USA) + cheat + description:Infinite lives + code:b5c6/84/a4 + cheat + description:Infinite health + code:e4af/85/a5 + cheat + description:Never lose Mop + code:efa2/8d/ad+b850/00/01 + 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 + name:Track & Field (USA) + cheat + description:Almost always qualify in Skeet Shooting and Archery + code:c72e/ec/e7 + cheat + description:You don't have to score any points to qualify for Skeet Shooting, Triple Jump and Archery + code:c4bd/c4/c3 + +cartridge sha256:58d2f6abe4445dadc332f37a34af54e78b6af47a8c0e6313ef898ef6db046f4f + name:Treasure Master (USA) + cheat + description:Invincibility + code:9af3/b8/e4+9af4/05/03 + cheat + description:Infinite health + code:ec45/c6/c5 + cheat + description:Infinite lives + code:808e/c6/a5 + cheat + description:Infinite oxygen + code:a1ef/ce/cd + 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 + name:Trog! (USA) + cheat + description:Infinite lives + code:8126/de/ea + +cartridge sha256:a5ae39359aa5b16961a98a7aaeeb278787382d5282ee80b5b3a2de954283ebb7 + name:Trojan (USA) + cheat + description:Infinite health - both players + code:d26a/ce/ad + cheat + description:Infinite health - both players (alt) + code:a4b4/3f/ff+fc68/3f/ff + cheat + description:Infinite time + code:9484/de/2c + cheat + description:One hit kills + code:d10b/ad/ee + cheat + description:Hit anywhere + code:884f/56/00+f47d/1b/00+a713/25/00+8862/43/00+f489/0f/00+dbf0/18/00+f3bd/db/00+f3b1/e7/00+dbe3/25/00+a71f/b0/24 + cheat + description:Keep High-jump Boots on pick-up + code:eacc/ce/ad + cheat + description:Always have High-jump Boots + code:d3f0/1f/00 + cheat + description:Multi-jump - both players + code:d338/1c/00+d3d2/d8/00+d3c5/f0/24 + cheat + description:Start with a health boost + code:cb53/08/0f + cheat + description:Start with a super health boost + code:cb53/08/1e + cheat + description:Start with half usual health + code:cb53/08/04 + cheat + description:Start with 1 life - P1 + code:c9fa/03/01 + cheat + description:Start with 1 life - P2 + code:ca1f/03/01 + cheat + description:Start with 6 lives - P1 + code:c9fa/03/06 + cheat + description:Start with 6 lives - P2 + code:ca1f/03/06 + cheat + description:Start with 9 lives - P1 + code:c9fa/03/09 + cheat + description:Start with 9 lives - P2 + code:ca1f/03/09 + cheat + description:Start with 187 lives - P1 + code:c9fa/03/f0 + cheat + description:Start with 196 lives - P2 + code:ca1f/03/f0 + cheat + description:Start with 100 seconds + code:cb58/02/01 + cheat + description:Start with 900 seconds + code:cb58/02/09 + cheat + description:Infinite health (alt) + code:0335/08 + cheat + description:Have Key + code:0386/02 + cheat + description:Have High-jump Boots + code:03cb/0e + cheat + description:Have Speed-Up + code:03cc/ff + cheat + description:Have Power-Up + code:03cd/ff + cheat + description:Start on level 2-1 + code:03d1/02 + cheat + description:Start on level 2-2 + code:03d1/03 + cheat + description:Start on level 3-1 + code:03d1/04 + cheat + description:Start on level 3-2 + code:03d1/05 + cheat + description:Start on level 4-1 + code:03d1/06 + cheat + description:Start on level 4-2 + code:03d1/07 + cheat + description:Start on level 5-1 + code:03d1/08 + cheat + description:Start on level 5-2 + code:03d1/09 + cheat + description:Start on level 6-1 + code:03d1/0a + cheat + description:Start on level 6-2 + code:03d1/0b + cheat + description:Start on level 7-1 + code:03d1/0c + +cartridge sha256:5699da9924f31e0f1b7d5cacd05111786881b7a87da38a99aee092fc855ab353 + name:Trolls in Crazyland, The (Europe) + cheat + description:Invincibility + code:92ee/f0/60 + cheat + description:One hit kills + code:a268/02/00 + cheat + description:Hit anywhere + code:9133/1c/00 + +cartridge sha256:0b5d1465b23e31f24e1caecf1490f97a60deb97ba873a36fa948adb016e9c0d2 + name:Trolls on Treasure Island (USA) (Unl) + cheat + description:Infinite time + code:ce13/86/dd + cheat + description:Only one jewel needed to clear stage + code:df77/d0/f0 + +cartridge sha256:e2b26560d326cc626736efa2addf1c66f5af77913968fcf5cde738188c4a0132 + name:Twin Cobra (USA) + cheat + description:Infinite lives + code:d26c/ce/ad + cheat + description:Infinite Bombs + code:f972/ce/ad + cheat + description:Infinite continues + code:c64f/01/00 + cheat + description:Autofire + code:f916/1b/00 + cheat + description:Keep weapon type after death + code:d276/85/24 + cheat + description:Keep super chargers after death + code:d278/85/24 + cheat + description:9 Bombs after dying + code:d270/03/0a + cheat + description:20 Bombs after dying + code:d270/03/14 + cheat + description:Start with 1 life + code:c5b2/02/00 + cheat + description:Start with 6 lives + code:c5b2/02/05 + cheat + description:Start with 9 lives + code:c5b2/02/08 + cheat + description:Start with 1 life after a continue + code:c67b/02/00 + cheat + description:Start with 6 lives after a continue + code:c67b/02/05 + cheat + description:Start with 9 lives after a continue + code:c67b/02/08 + cheat + description:Start with 9 continues + code:c59d/05/09 + cheat + description:Start with 9 Bombs + code:cd04/03/0a + cheat + description:Start with 20 Bombs + code:cd04/03/14 + +cartridge sha256:8eb6aa7818f1cac84af0f91350b167f2884dba45073c9f00510f47d0a38e4192 + name:Twin Eagle (USA) + cheat + description:Infinite lives - P1 + code:d99e/c6/a5 + cheat + description:Infinite Bombs on pick-up - P1 + code:ddfa/ce/ad + cheat + description:Infinite Bombs on pick-up - P2 + code:df52/ce/ad + cheat + description:Never lose weapons - P1 + code:eb4e/8d/f0+eb4f/a4/07 + cheat + description:Never lose weapons - P2 + code:ebac/8d/f0+ebad/a5/07 + cheat + description:1 life after a continue - P1 + code:ce0a/03/01 + cheat + description:4 lives after a continue - P1 + code:ce0a/03/04 + cheat + description:7 lives after a continue - P1 + code:ce0a/03/07 + cheat + description:Start with 7 lives - both players + code:e185/03/07 + cheat + description:Start with 4 lives - both players + code:e185/03/04 + cheat + description:Start with 1 life - both players + code:e185/03/01 + +cartridge sha256:4b9c46714fa085d61ad1177b72bdaa9428d104a171eb6335a03bf06ad9782389 + name:TwinBee (Japan) + cheat + description:Invincibility + code:0093/10 + +cartridge sha256:ef818c90f326383d13087b6e0131bf36563d76c3c1a3c13821c79368e377cf8d + name:Ufouria - The Saga (Europe) + cheat + description:Invincibility + code:806e/f0/d0+874b/f0/d0 + cheat + description:Start with all characters + code:e7df/1f/01+e7e1/00/07 + +cartridge sha256:af5ac55d6283b709bcd96889708a6e7ad3c77e3bdd377aae796fd87b4b90dc4b + name:Ultima - Exodus (USA) + cheat + description:Take no damage from most monsters + code:cc39/e5/24 + cheat + description:No limit on stat points + code:8e94/08/00 + cheat + description:Never lose tools + code:d120/01/00 + cheat + description:Never lose magic + code:da6b/91/94 + cheat + description:Never miss with the Fight command + code:d0f9/80/48 + cheat + description:Can always attack with the Fight command + code:d0dc/1e/00 + cheat + description:One hit kills + code:b92b/90/d0 + cheat + description:Rapid magic recovery + code:8739/01/00+8734/d1/b1 + cheat + description:Start with 5 of each item + code:9196/01/05 + cheat + description:Start with 10 of each item + code:9196/01/0a + cheat + description:Start with 40 of each item + code:9196/01/f0 + cheat + description:Start with 35,328 gold + code:9188/64/8a+9186/30/31 + cheat + description:Start with 512 gold + code:9188/64/02+9186/30/31 + cheat + description:Start with 200 gold + code:9188/64/c8 + cheat + description:Start with 75 stat points + code:8e83/2e/47+8fb6/32/4b+9059/32/4b + cheat + description:Start with 5F stat points + code:8e83/2e/5b+8fb6/32/5f+9059/32/5f + +cartridge sha256:bb625b8df6ddbeb991bb1cbf9b818a5352dcd4856d84640612b2df66148c442f + name:Ultima - Quest of the Avatar (USA) + cheat + description:Infinite MP + code:a032/99/b9 + cheat + description:Infinite Herbs + code:ec9f/de/bd + cheat + description:Infinite Oil + code:bc74/ce/ad + cheat + description:Infinite Torches + code:b28d/de/bd + cheat + description:Infinite Gems + code:b5ec/ce/ad + cheat + description:No random battles + code:e952/85/a5 + cheat + description:Heal costs nothing instead of 70 + code:d5c6/46/00 + cheat + description:Cure poison costs nothing + code:d563/0a/00 + cheat + description:Axe costs 1 instead of 225 + code:8f0f/e1/01 + cheat + description:Staff costs 1 instead of 20 + code:8f0b/14/01 + cheat + description:Sword costs 144 instead of 400 + code:8f12/01/00 + cheat + description:Bow costs 168 instead of 680 + code:8f04/02/00 + cheat + description:Leather costs 1 instead of 200 + code:8f21/c8/01 + cheat + description:Chain costs 88 instead of 600 + code:8f24/02/00 + cheat + description:Plate costs 196 instead of 2500 + code:8f2a/09/00 + cheat + description:Start with perfect virtues (worthy of Avatarhood) + code:9562/32/63 + cheat + description:Start with 8336 Gold Pieces + code:9546/01/20 + cheat + description:Start with 4240 Gold Pieces + code:9546/01/10 + cheat + description:Start with 144 Gold Pieces (for experts) + code:9546/01/00 + cheat + description:Start with 100 Ash instead of 8 + code:9625/08/64 + cheat + description:Start with 100 Ginseng instead of 8 + code:9626/08/64 + cheat + description:Start with 100 Garlic instead of 9 + code:9627/09/64 + cheat + description:Start with 100 Silkweb instead of 7 + code:9628/07/64 + cheat + description:Start with 100 Moss instead of 8 + code:9629/08/64 + cheat + description:Start with 100 Pearl instead of 4 + code:962a/04/64 + cheat + description:Start with 100 Fungus instead of none + code:962b/00/64 + cheat + description:Start with 100 Manroot instead of none + code:962c/00/64 + cheat + description:Mage starts with 712 HP + code:95e6/00/02 + cheat + description:Mage starts with 381 EXP + code:9616/00/01 + cheat + description:Mage starts with Strength of 32 + code:95fd/10/20 + cheat + description:Fighter starts with Strength of 48 + code:95ff/1b/30 + cheat + description:Fighter starts with 255 EXP + code:9619/cd/ff + cheat + description:Fighter starts with 812 HP + code:95ea/01/03 + cheat + description:Fighter starts with 75 MP + code:95f7/00/4b + +cartridge sha256:1e8966fd8c9baf57c514fbf4d67ddd8c1ffd184be164f99342ccdec62def8db2 + name:Ultima - Warriors of Destiny (USA) + cheat + description:Infinite consumable items such as food and torches - May not be able to discard some items + code:edd2/de/bd + cheat + description:A night at the Wayfarer Inn is free + code:a105/32/00 + cheat + description:At Healer's Herbs - Sulfurous ash is free instead of 1 GP + code:a0b1/01/00 + cheat + description:At Healer's Herbs - Ginseng is free instead of 2 GP + code:a0b4/02/00 + cheat + description:At Healer's Herbs - Garlic is free instead of 2 GP + code:a0b7/02/00 + cheat + description:At Healer's Herbs - An Tym Scroll is free instead of 100 GP + code:a0bd/64/00 + cheat + description:At Healer's Herbs - Spellbook is free instead of 150 GP + code:a0c0/96/00 + cheat + description:At Healer's Herbs - Spidersilk is free instead of 4 GP + code:a0ba/04/00 + cheat + description:From Pendra - Spidersilk is free instead of 4 GP + code:a08a/04/00 + cheat + description:From Pendra - Black Pearl is free instead of 3 GP + code:a087/03/00 + cheat + description:From Pendra - Garlic is free instead of 2 GP + code:a084/02/00 + cheat + description:From Pendra - Ginseng is free instead of 2 GP + code:a081/02/00 + cheat + description:From Pendra - Sant Talisman is free instead of 75 GP + code:a08d/4b/00 + cheat + description:At Iolo's Bows - Bow is free instead of 75 GP + code:a00d/4b/00 + cheat + description:At Iolo's Bows - Wooden shield is free instead of 25 GP + code:a00a/19/00 + cheat + description:At Iolo's Bows - Dagger is free instead of 3 GP + code:a004/03/00 + cheat + description:At Iolo's Bows - Short sword is free instead of 40 GP + code:a007/28/00 + cheat + description:At Iolo's Bows - Crossbow is free instead of 150 GP + code:a010/96/00 + cheat + description:At Iolo's Bows - Arrow is free instead of 1 GP + code:a016/01/00 + cheat + description:At Iolo's Bows - Bolt is free instead of 2 GP + code:a019/02/00 + cheat + description:At Iolo's Bows - Sell Dagger for 2,305 instead of 1 GP + code:a110/00/09 + cheat + description:At Iolo's Bows - Sell Short sword for 2,848 instead of 20 GP + code:a113/40/03 + cheat + description:At Iolo's Bows - Sell Wooden shield for 3,850 instead of 10 GP + code:a116/00/0f + cheat + description:At Iolo's Bows - Magic bow is free instead of 800 GP + code:a013/20/00+a014/03/00 + cheat + description:Start new game with 201 instead of 1,225 GP + code:aad8/04/00 + cheat + description:Start new game with 4,297 instead of 1,225 GP + code:aad8/04/10 + cheat + description:Start new game with 32,713 instead of 1,225 GP + code:aad8/04/7f + 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:8dda0b6bcb5d66fd6983f71f9257225ce053822cbb5edda5d072feeddec9358e + name:Ultimate Air Combat (USA) + cheat + description:Infinite Chaff + code:a01d/ce/ad + cheat + description:Infinite Missiles + code:a5e2/ce/ad+a60c/ce/ad + +cartridge sha256:f4de2a91acb2eb3024fb75231859a30c130c0169be0e6ad24330805c8f766e03 + name:Ultimate Stuntman, The (USA) (Unl) + cheat + description:Infinite time + code:d2ff/ce/ad + cheat + description:Infinite 'Crez' weapon until end of stage + code:dbaf/ce/ad + cheat + description:Minimum damage taken + code:a9b4/e5/e9+a9b5/ff/01 + cheat + description:Don't lose a life on Ground Pursuit, Boat and Hang Glider stages + code:8cb1/ce/2c + cheat + description:9 seconds on clock pick-up + code:a8ad/06/09 + cheat + description:Full energy on pick-up + code:a992/02/00 + cheat + description:Shield lasts longer on Human Fly stages + code:ae2e/78/ff + cheat + description:Shield lasts a shorter time on Human Fly stages + code:ae2e/78/40 + cheat + description:Don't lose a life against end-of-stage bosses and on street combat stages + code:affc/ce/ad + cheat + description:Don't lose a life on Human Fly stages + code:bdaa/ce/ad + cheat + description:Start with 1 life (first credit only) + code:ecff/02/00 + cheat + description:Start with 6 lives (first credit only) + code:ecff/02/05 + cheat + description:Start with 9 lives (first credit only) + code:ecff/02/08 + +cartridge sha256:c7ad19e926809adc47c0b44c852e19be7a95e7235ee58cb753e68d7cdee9c89c + name:Uncanny X-Men, The (USA) + cheat + description:Infinite life + code:8d8a/e5/a5 + cheat + description:Half life - Wolverine + code:a1b1/c8/64 + cheat + description:Half life - Cyclops + code:a1b7/c8/64 + cheat + description:Half life - Nightcrawler + code:a1bd/82/41 + cheat + description:Half life - Iceman + code:a1c3/be/5f + cheat + description:Half life - Colossus + code:a1c9/ff/7f + cheat + description:Half life - Storm + code:a1cf/a0/50 + +cartridge sha256:018f8a4f35d15af7891070cbfe6232791d603e92cbd95a49527e80f3825e770d + name: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 + name:Untouchables, The (USA) (Rev A) + cheat + description:Infinite energy on scenes 1 and 4 + code:8418/d6/b5 + cheat + description:Infinite energy on scene 2 + code:86c0/c6/a5 + cheat + description:Infinite time on scenes 1 and 4 + code:84b2/c6/a5 + cheat + description:More time on scene 1 + code:81ab/02/04 + cheat + description:Less time on scene 1 + code:81ab/02/01 + cheat + description:More time on scene 2 + code:802b/04/06 + cheat + description:Less time on scene 2 + code:802b/04/02 + cheat + description:More time on scene 3 + code:802f/04/06 + cheat + description:Less time on scene 3 + code:802f/04/02 + cheat + description:More time on scene 5 + code:8021/05/06 + cheat + description:Less time on scene 5 + code:8021/05/03 + cheat + description:More time on scene 7 + code:8018/01/02 + cheat + description:More ammo picked up on scene 2 + code:847e/10/20 + cheat + description:Less ammo picked up on scene 2 + code:847e/10/05 + cheat + description:More ammo picked up on scene 7 + code:801c/06/09 + cheat + description:Start on scene 2 + code:c02e/0c/00 + cheat + description:Start on scene 3 + code:c02e/0c/02 + cheat + description:Start on scene 4 + code:c02e/0c/04 + cheat + description:Start on scene 5 + code:c02e/0c/06 + cheat + description:Start on scene 7 + code:c02e/0c/0a + 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 + name:Untouchables, The (USA) + cheat + description:Infinite energy on scenes 1 and 4 + code:8418/d6/b5 + cheat + description:Infinite energy on scene 2 + code:86c0/c6/a5 + cheat + description:Infinite time on scenes 1 and 4 + code:84b2/c6/a5 + cheat + description:More time on scene 1 + code:81ab/02/04 + cheat + description:Less time on scene 1 + code:81ab/02/01 + cheat + description:More time on scene 2 + code:802b/04/06 + cheat + description:Less time on scene 2 + code:802b/04/02 + cheat + description:More time on scene 3 + code:802f/04/06 + cheat + description:Less time on scene 3 + code:802f/04/02 + cheat + description:More time on scene 5 + code:8021/05/06 + cheat + description:Less time on scene 5 + code:8021/05/03 + cheat + description:More time on scene 7 + code:8018/01/02 + cheat + description:More ammo picked up on scene 2 + code:847e/10/20 + cheat + description:Less ammo picked up on scene 2 + code:847e/10/05 + cheat + description:More ammo picked up on scene 7 + code:801c/06/09 + cheat + description:Start on scene 2 + code:c02e/0c/00 + cheat + description:Start on scene 3 + code:c02e/0c/02 + cheat + description:Start on scene 4 + code:c02e/0c/04 + cheat + description:Start on scene 5 + code:c02e/0c/06 + cheat + description:Start on scene 7 + code:c02e/0c/0a + 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 + name:Urban Champion (World) + cheat + description:Infinite time + code:e312/c6/24 + cheat + description:Powerful quick punches + code:d482/04/08 + cheat + description:Super powerful quick punch + code:d482/04/16 + cheat + description:Speed up the timer + code:e2fe/06/03 + cheat + description:Become a stronger fighter + code:d32b/01/00 + cheat + description:Become a weaker fighter + code:d32b/01/03 + cheat + description:Infinite stamina + code:00ca/99 + +cartridge sha256:433f6bcbd59a9d5916d2209ddeacd39d24810c1ed21a33366171b4991fc7e844 + name:Vice - Project Doom (USA) + cheat + description:Invincibility + code:dd78/17/00 + cheat + description:Infinite lives + code:c15d/ce/ad + cheat + description:Infinite time + code:fd7f/ce/ad + cheat + description:Infinite grenades + code:fc62/ce/ad + cheat + description:Infinite bullets + code:fc4a/ce/ad + cheat + description:Infinite power + code:fce6/8d/ad + cheat + description:Hit anywhere + code:f882/e8/00 + cheat + description:Multi-jump + code:c5ed/4a/ea + cheat + description:10 coins for an extra life + code:fc97/64/0a + cheat + description:25 coins for an extra life + code:fc97/64/19 + cheat + description:20 extra Grenades on pick-up + code:fb88/05/14 + cheat + description:25 extra Bullets on pick-up + code:fba2/0a/19 + cheat + description:Start timer for round 1 at 150 + code:8419/fa/96 + cheat + description:Start timer for round 2 at 150 + code:8432/fa/96 + cheat + description:Start with 99 grenades + code:fb7a/05/63 + +cartridge sha256:8104dc7acdaea42b027b2cc7b05dc6a1ffdba6e74b35581c2bb0250df89a28fa + name:Vindicators (USA) (Unl) + cheat + description:Infinite lives + code:8634/d6/b4 + cheat + description:Automatic fuel replenishment + code:cd38/d6/f6 + cheat + description:Never lose Stars + code:8a1e/f9/2c + cheat + description:Quicker shot re-load + code:c63f/12/02 + cheat + description:Turbo speed + code:c64b/0c/1b + cheat + description:Start with increased shot range + code:c647/08/20 + cheat + description:Start with 10 Stars + code:81e0/85/e6 + cheat + description:Start with 80 Shots + code:c63f/12/08+c641/d0/d6 + cheat + description:Start with 80 Bombs + code:c63f/12/08+c641/d0/d4 + cheat + description:Start with 1 life + code:c64f/02/00 + cheat + description:Start with 6 lives + code:c64f/02/05 + cheat + description:Start with 9 lives + code:c64f/02/08 + +cartridge sha256:2e312fc327c1e569eccf14eee5a00c41f676c1492035d99af0873681da0f034d + name:Volleyball (USA, Europe) + cheat + description:Computer doesn't get points for scoring + code:d6f0/0f + cheat + description:3 points - team 1 + code:0063/03 + +cartridge sha256:f38b9681b53008d32813880c2f28a8969a228a4b3b485ce09f7c0a4334f4abcc + name:VS. Castlevania (VS) + cheat + description:Invincibility (blinking) + code:e991/f0/d0 + cheat + description:Infinite health + code:e7fa/85/a5 + cheat + description:Infinite lives + code:c2ec/c6/a5 + +cartridge sha256:60098a93322a9e07a2b164a02e5517bc22664ca33f6323c2ae23a62941ad393b + name:VS. Super Mario Bros. (VS) + cheat + description:Invincibility + code:b1f9/89/9e+ee51/f0/d0 + cheat + description:Infinite lives + code:988b/ad + cheat + description:Go to minus world + code:9718/23+971a/5f+971b/07 + +cartridge sha256:8589b1dc55e04d23e56e864f1b001c6eecf18b7dcb7a0c4a9c4a40cbcc451601 + name:Wacky Races (USA) + cheat + description:Invincibility + code:d97b/f0/d0+d9b5/f0/d0+cd8d/f0/d0 + cheat + description:Infinite health + code:ced5/ce/cd+cdbb/ce/cd + cheat + description:Infinite health (alt) + code:ced5/ce/2c+ce7e/ce/2c+cdbb/ce/2c + cheat + description:Don't take most damage + code:ced5/ce/2c + cheat + description:Infinite lives + code:d05a/ce/8d+d0c7/ce/8d + cheat + description:Infinite lives (alt) + code:d054/ad/10+d055/5d/08 + cheat + description:Infinite Bones after obtaining one + code:d793/8d/ad + cheat + description:Go straight to level boss + code:edbc/c4/f2 + cheat + description:Start at race 1, end of stage 1 + code:edbc/c4/c8 + cheat + description:Start at race 1, end of stage 2 + code:edbc/c4/cf + cheat + description:Start at race 1, end of stage 3 + code:edbc/c4/d4 + cheat + description:Start at race 2, end of stage 1 + code:edbe/d6/d8 + cheat + description:Start at race 2, end of stage 2 + code:edbe/d6/dc + cheat + description:Start at race 2, end of stage 3 + code:edbe/d6/e0 + cheat + description:Start at race 3, end of stage 1 + code:edc0/e2/e4 + cheat + description:Start at race 3, end of stage 2 + code:edc0/e2/e8 + cheat + description:Start at race 3, end of stage 3 + code:edc0/e2/ec + cheat + description:Start at race 3, end of stage 4 + code:edc0/e2/f0 + cheat + description:Start with 1 life + code:ed48/02/00 + cheat + description:Start with 5 lives + code:ed48/02/04 + cheat + description:Start with 7 lives + code:ed48/02/06 + cheat + description:Start with 9 lives + code:ed48/02/08 + cheat + description:Start with 6 hearts + code:ed51/03/06 + cheat + description:Start with 8 hearts + code:ed51/03/08 + 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 + name:Wall Street Kid (USA) + cheat + description:Infinite money + code:fbde/91/b1 + cheat + description:Sart a new game with $16,777,215 + code:810b/07/ff+810a/a1/ff+8109/20/ff + cheat + description:Infinite money (alt) + code:03e1/ff + +cartridge sha256:50b6f1f87fb14c8ff74a54e60b85139e11adcaecb62eb24174aeb58a20b7698f + name:Wally Bear and the No! Gang (USA) (Unl) + cheat + description:Invincibility + code:a7bf/d0/10 + cheat + description:Multi-jump + code:a57a/85/24 + cheat + description:Collect items from anywhere + code:b775/5c/00+b77b/56/00 + +cartridge sha256:c12771e8155b030eff0081bfabd98e57a162d6592899f29dd16f141f0e6e08a3 + name:Wario's Woods (USA) + cheat + description:Infinite time + code:a17b/ce/ea + cheat + description:Clear round A data to complete round A and B + code:9b41/00/63+9b46/42/41 + cheat + description:Each coin gives you a credit + code:9a68/1e/01 + cheat + description:Always get blue monsters + code:b85f/b1/a9+b860/b3/f0 + cheat + description:Always get 1 line of monsters + code:b850/8d/ee + cheat + description:Wario doesn't cause ceiling to fall, no enemies fall + code:87f6/8d/a9 + cheat + description:One bomb in Birdo time only + code:a24c/ce/ea + cheat + description:Invisible Toad + code:d891/85/a5 + cheat + description:Invisible coins + code:99a5/d0/f0 + cheat + description:Coins worth 5 + code:98a5/8d/ea + cheat + description:Infinite coins fall + code:98a8/ce/ea + cheat + description:Only 1 coin falls + code:97de/ce/ae + cheat + description:No Coins fall + code:97de/ce/80 + cheat + description:Diamonds don't form in lesson mode + code:ad53/99/ff + +cartridge sha256:059409954035963f1f13029dfa25468100a8e6a90d9388c4a225f235ade97a45 + name:Wayne's World (USA) + cheat + description:Infinite lives + code:8acd/ce/ae + cheat + description:Infinite time + code:81d3/ce/ad + cheat + description:Infinite Worthiness + code:8b5a/8d/ad + cheat + description:More time in level 1 + code:b7d7/b4/ff + cheat + description:More time in Donut shop in level 1 + code:b7f5/32/ff + cheat + description:Power-up restores all Worthiness + code:8b74/02/00 + cheat + description:Power-up worth nothing + code:8b77/8d/ad + cheat + description:Getting all donuts is worth no extra lives + code:9b1d/ee/ad + cheat + description:Faster timer + code:81ca/3b/1f + cheat + description:Slower timer + code:81ca/3b/60 + cheat + description:5 special moves on pick-up + code:a802/14/05 + cheat + description:40 special moves on pick-up + code:a802/14/28 + cheat + description:Start with less Worthiness + code:807a/b0/80 + cheat + description:Start with much less Worthiness + code:807a/b0/40 + cheat + description:Start with 2 lives + code:807f/04/01 + cheat + description:Start with 8 lives + code:807f/04/07 + cheat + description:Start with 10 lives + code:807f/04/09 + +cartridge sha256:a00db4c89bfd12704c53768b62b4f09d57d28891093447d81a0678b059629e59 + name:WCW World Championship Wrestling (USA) + cheat + description:Always win - P1 + code:a715/1d/c0+a716/09/01+a717/05/ea + +cartridge sha256:ab6f1bbcda6f0c0bbe1450b5f2ab2b21a5e01ec39143a455701862965cdbd7b4 + name:Werewolf - The Last Warrior (USA) + cheat + description:Infinite time + code:e326/c6/a5 + cheat + description:Only 1 anger point needed to become Super-Werewolf + code:f60c/05/01 + cheat + description:Blue "W" won't change you back to a man + code:f629/ce/ad + cheat + description:Gain maximum energy from small hearts + code:f5ce/d4/d0 + cheat + description:Hit anywhere + code:cf66/64/00+cf6c/5e/00+cfa2/28/00+cfa8/22/00 + cheat + description:Don't lose energy from blue "W" + code:f63c/0a/00+f639/08/00 + 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:84e3a018cbaaf2311d7e9414112cb05cf3b43608de0b9f8a2f77bc4da33ce8e6 + name:Wheel of Fortune - Junior Edition (USA) + cheat + description:Always spin $1000 - All players + code:0071/aa + +cartridge sha256:a66195e11e38bee9f602abd279b7c04367528380dfa5b915dce0fa6fd272c23c + name:Where's Waldo (USA) + cheat + description:Infinite time + code:e283/01/00 + cheat + description:Guesses cost nothing + code:e75f/06/ee + +cartridge sha256:700ebc3c2dd27420bbdcccb987ba60d3f0680469101353de15a1b2bd565ac701 + name:Who Framed Roger Rabbit (USA) + cheat + description:Invincibility + code:e145/d0/60+db64/d0/60+c921/d0/60+e598/d0/60 + cheat + description:Infinite continues + code:87cb/ce/ad + cheat + description:Never lose a life except in Punch lines + code:95ef/c6/a5 + cheat + description:Never lose a life in Punch lines + code:af52/c6/a5 + cheat + description:Harder to build strength + code:ce3a/04/01 + cheat + description:Strength to full instantly + code:ce3a/04/90 + cheat + description:Start with 1 life + code:dfdd/03/01 + cheat + description:Start with 6 lives + code:dfdd/03/06 + cheat + description:Start with 9 lives + code:dfdd/03/09 + +cartridge sha256:b9a4542417439619239cdb2cefd8c7eced2407ba2954f026c0ab1ea7d4def3d3 + name:Whomp 'Em (USA) + cheat + description:Invincibility + code:815b/f0/60 + cheat + description:Infinite health + code:8176/85/a5 + cheat + description:Don't lose a life from health loss + code:818a/c6/a5 + cheat + description:Creatures can't steal extra lives + code:99ab/c6/a5 + cheat + description:Keep Buffalo Headdress for present level + code:814c/c6/a5 + cheat + description:Always have Buffalo Headdress + code:814b/08/02 + cheat + description:Start with 1 life + code:c0cc/03/00 + cheat + description:Start with 5 lives + code:c06f/00/03 + cheat + description:Start with 10 lives + code:c06f/00/08 + +cartridge sha256:9d875583dbdf80a0631ce4ffb3099064454d80568b5e9fe748a5e850f8fa0161 + name:Widget (USA) + cheat + description:Invincibility + code:eaf8/d0/f0 + cheat + description:Infinite health (not against spikes) + code:bcd0/8d/ad + cheat + description:Infinite health (only against spikes) + code:e8b9/ce/ad + cheat + description:Infinite time + code:8ab6/ce/ad+8aa7/ce/ad + cheat + description:Infinite MP + code:96a1/8d/ad + cheat + description:Infinite lives + code:ca35/ce/ad + 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 + cheat + description:Have Mouse Widget + code:0331/01 + cheat + description:Have Rock-Man Widget + code:0332/01 + cheat + description:Have Bird-Man Widget + code:0333/01 + cheat + description:Have Dolphin Widget + code:0334/01 + cheat + description:Have powered-up Gun + code:0594/03+0595/03 + +cartridge sha256:adff304553b64384f86f6c2b63571f43972b9d087f92359a1b9b93b54d523542 + name:Wild Gunman (World) (Rev A) + cheat + description:Infinite lives in Gang Mode + code:cf16/c6/24 + cheat + description:Infinite ammo in Gang Mode + code:d071/c6/24 + cheat + description:Shoot 5 enemies to finish level + code:d9fb/0a/05+dbbd/0a/05 + cheat + description:Start with double normal ammo + code:d9e0/0f/20 + cheat + description:Start with triple normal ammo + code:d9e0/0f/30 + cheat + description:Start with half normal ammo + code:d9e0/0f/08 + cheat + description:Start with 1 life + code:d9b5/03/0f+c8f6/03/01 + cheat + description:Start with 10 lives + code:d9b5/03/0a+c8f6/03/0a + cheat + description:Start with 15 lives + code:d9b5/03/0f+c8f6/03/0f + +cartridge sha256:62aec65696ecf24a487b7cdd19bad5cbd19f4229a89a7888634d468c67da378a + name:Wild Gunman (Japan, USA) + cheat + description:Infinite lives in Gang Mode + code:cf07/d0 + cheat + description:Infinite ammo in Gang Mode + code:d062/f0 + cheat + description:Shoot 5 enemies to finish level + code:d9fb/0a/05+dbbd/0a/05 + cheat + description:Start with double normal ammo + code:d9e0/0f/20 + cheat + description:Start with triple normal ammo + code:d9e0/0f/30 + cheat + description:Start with half normal ammo + code:d9e0/0f/08 + cheat + description:Start with 1 life + code:d9b5/03/0f+c8f6/03/01 + cheat + description:Start with 10 lives + code:d9b5/03/0a+c8f6/03/0a + cheat + description:Start with 15 lives + code:d9b5/03/0f+c8f6/03/0f + +cartridge sha256:adb1a1a9e853c2390a702e40573d145d08ca6c649cc789e4c8b41fcb63503bb6 + name:Willow (USA) + cheat + description:Infinite magic + code:815c/db/02 + cheat + description:Don't take any hits + code:d473/85/46 + cheat + description:Start with all items + code:f345/94/a2+9dba/a9/60 + cheat + description:Start at EXP Level 5 + code:dec5/0a/04+dec7/b5/71 + cheat + description:Start at EXP Level 10 + code:dec5/0a/09+dec7/b5/71 + cheat + description:Start at EXP Level 15 + code:dec5/0a/0e+dec7/b5/71 + +cartridge sha256:e9539f088b4463e36c2a0d324d6a184fc1ecc3aa26ca4c5675ad9dc948bba5e5 + name:Wing of Madoola, The (Japan) (Sample) + cheat + description:Invincibility + code:cec2/85/a5 + cheat + description:Infinite hits and magic + code:bf3e/95/b5 + cheat + description:Hit anywhere + code:ce10/09/00+ce15/5a/00+ce14/f5/29 + cheat + description:One hit kills + code:ce28/e5/18+ce29/88/18 + cheat + description:Start with 9999 hits + code:a9c4/00/99+a9c8/10/99 + cheat + description:Start with 9999 max hits + code:a9cc/00/99+a9d0/10/99 + cheat + description:Start with 9999 magic + code:a9d8/10/99+a9d4/00/99 + +cartridge sha256:c3136379fc4e9401dec41be356fd6963e79dd46193c61cc03b59d9935835401f + name:Wizardry - Proving Grounds of the Mad Overlord (USA) + cheat + description:Annointed Mace costs nothing instead of 30 + code:81ed/30/00 + cheat + description:Long Sword costs nothing instead of 25 + code:816d/25/00 + cheat + description:Short Sword costs nothing instead of 15 + code:81ad/15/00 + cheat + description:Small Shield costs nothing instead of 20 + code:82ed/20/00 + cheat + description:Staff costs nothing instead of 10 + code:826d/10/00 + cheat + description:Dagger costs nothing instead of 15 + code:82ad/05/00 + cheat + description:Robes costs nothing instead of 15 + code:836d/15/00 + cheat + description:S of Pain costs nothing instead of 500 + code:87ec/05/00 + cheat + description:S of Fire costs nothing instead of 500 + code:882c/05/00 + cheat + description:Body Armor costs nothing instead of 1500 + code:87ac/15/00 + cheat + description:Large Shield costs nothing instead of 40 + code:832d/40/00 + cheat + description:Leather Armor costs nothing instead of 50 + code:83ad/50/00 + cheat + description:Chain Mail costs nothing instead of 90 + code:83ed/90/00 + cheat + description:Breast Plate costs nothing instead of 200 + code:842c/02/00 + cheat + description:Helm costs nothing instead of 100 + code:84ac/01/00 + cheat + description:S of Curing costs nothing instead of 500 + code:84ec/05/00 + cheat + description:Rod of Iron costs nothing instead of 3000 + code:862c/30/00 + cheat + description:Padded Leather costs nothing instead of 1500 + code:86ac/15/00 + cheat + description:Shiny Chain costs nothing instead of 1500 + code:86ec/15/00 + cheat + description:Sturdy Plate costs nothing instead of 1500 + code:872c/15/00 + cheat + description:Iron Shield costs nothing instead of 1500 + code:876c/15/00 + cheat + description:Gloves of Copper costs nothing instead of 6000 + code:8cec/60/00 + cheat + description:S of Glass costs nothing instead of 1500 + code:8b6c/15/00 + cheat + description:Studly Staff costs nothing instead of 2500 + code:892c/25/00 + cheat + description:S of Neutralizing costs nothing instead of 300 + code:852c/03/00 + cheat + description:Plate Mail costs nothing instead of 750 + code:846d/50/00+846c/07/00 + cheat + description:Blade of Biting costs nothing instead of 15000 + code:85ac/50/00+85ab/01/00 + +cartridge sha256:d30e480e7a99b5c3d8fe8faecf0bc0a14a9b163025eca9bf787f600fa927bb89 + name:Wizards & Warriors (USA) (Rev A) + cheat + description:Invincibility + code:e57e/f0/d0 + cheat + description:Invincibility (flashes) + code:e581/30 + cheat + description:Infinite lives + code:b4ea/c6/24 + cheat + description:Infinite lives (alt) + code:b4ea/c6/a5 + cheat + description:Infinite health + code:e37d/e5/24 + cheat + description:Infinite health (alt) + code:e698/d0/a9+e699/3c/0c+e69a/a5/85 + cheat + description:Potions last longer + code:df07/4f/ef + cheat + description:Meat gives half health + code:e488/02/01 + cheat + description:Meat gives double health + code:e488/02/04 + cheat + description:Enter doors without needing a key + code:f341/30 + cheat + description:Jump higher + code:d15e/fc + cheat + description:Jump to the top of the scren + code:d166/cc + cheat + description:Start with 6 lives + code:b83c/02/05+c024/02/05 + cheat + description:Start with 9 lives + code:b83c/02/08+c024/02/08 + 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 + name:Wizards & Warriors (USA) + cheat + description:Invincibility + code:e57e/f0/d0 + cheat + description:Invincibility (flashes) + code:e581/30 + cheat + description:Infinite lives + code:b4ea/c6/24 + cheat + description:Infinite lives (alt) + code:b4ea/c6/a5 + cheat + description:Infinite health + code:e37d/e5/24 + cheat + description:Infinite health (alt) + code:e698/d0/a9+e699/3c/0c+e69a/a5/85 + cheat + description:Potions last longer + code:df07/4f/ef + cheat + description:Meat gives half health + code:e488/02/01 + cheat + description:Meat gives double health + code:e488/02/04 + cheat + description:Enter doors without needing a key + code:f341/30 + cheat + description:Jump higher + code:d15e/fc + cheat + description:Jump to the top of the scren + code:d166/cc + cheat + description:Start with 6 lives + code:b83c/02/05+c024/02/05 + cheat + description:Start with 9 lives + code:b83c/02/08+c024/02/08 + 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 + name:Wizards & Warriors III - Kuros...Visions of Power (USA) + cheat + description:Infinite keys + code:f6ad/c6/a5 + cheat + description:Infinite gold + code:f777/f0 + cheat + description:Shopkeeper sometimes forgets to charge + code:f772/8d/ad + cheat + description:Infinite lives + code:e3e4/c6/a5 + cheat + description:Infinite lives (except boss stages) + code:e3f1/c6/a5 + cheat + description:Coins worth 25 + code:84d4/32/19 + cheat + description:Coins worth 100 + code:84d4/32/64 + cheat + description:Coins worth 255 + code:84d4/32/ff + cheat + description:Bags worth 5 + code:84d2/0a/05 + cheat + description:Bags worth 50 + code:84d2/0a/32 + cheat + description:Bags worth 255 + code:84d2/0a/ff + cheat + description:Less health after death (except boss stages) + code:b203/80/40 + cheat + description:More health after death (except boss stages) + code:b203/80/b0 + cheat + description:Start with Less health + code:a744/80/40 + cheat + description:Start with More health + code:a744/80/b0 + cheat + description:Start with very little life force + code:a744/80/01 + cheat + description:Start with about half life force + code:a744/80/40 + cheat + description:Start with 2 lives + code:a729/03/01 + cheat + description:Start with 7 lives + code:a729/03/06 + cheat + description:Start with 10 lives + code:a729/03/09 + 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 + name:Wolverine (USA) + cheat + description:No enemies + code:d3df/5d + cheat + description:Infinite lives - both players + code:a108/ce/2c + cheat + description:Mega-jump + code:bba7/0d/28 + cheat + description:Claws use up no health + code:c327/01/00 + cheat + description:Super speed + code:bb2e/fe/fc+bb38/02/04 + cheat + description:Take less damage from bullets + code:b525/08/02+c408/08/02 + cheat + description:Start each new life as a berserker + code:d072/00/40 + cheat + description:Start with 1 life - P1 + code:d0ba/03/01 + cheat + description:Start with 6 lives - P1 + code:d0ba/03/06 + cheat + description:Start with 9 lives - P1 + code:d0ba/03/09 + cheat + description:Start with 1 life - P2 + code:d0e7/03/01 + cheat + description:Start with 6 lives - P2 + code:d0e7/03/06 + cheat + description:Start with 9 lives - P2 + code:d0e7/03/09 + cheat + description:Start on stage 2 - P1 + code:d0a2/00/01 + cheat + description:Start on stage 4 - P1 + code:d0a2/00/03 + cheat + description:Start on stage 6 - P1 + code:d0a2/00/05 + cheat + description:Start on stage 8 - P1 + code:d0a2/00/07 + cheat + description:Start on stage 2 - P2 + code:d0cf/00/01 + cheat + description:Start on stage 4 - P2 + code:d0cf/00/03 + cheat + description:Start on stage 6 - P2 + code:d0cf/00/05 + cheat + description:Start on stage 8 - P2 + code:d0cf/00/07 + cheat + description:Infinite health + code:00cd/1e + cheat + description:Infinite lives + code:04da/03 + +cartridge sha256:3950d679fd6bbd5b59b720ef0284cb916f916a985103ccec60de2f256bcd8786 + name: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 + name:Wrath of the Black Manta (USA) + cheat + description:Take no damage from most enemies + code:bbd2/ce/ad + cheat + description:Never die from falling off screen + code:986c/ce/ad + cheat + description:Mega-jump when stationary + code:ab35/9d/2c + cheat + description:Start with extra energy + code:8692/03/08 + cheat + description:Start with 1 life + code:8697/02/00 + cheat + description:Start with 6 lives + code:8697/02/05 + cheat + description:Start with 9 lives + code:8697/02/08 + 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 + name:Wrecking Crew (World) + cheat + description:Invincibility + code:c27f/20/60 + cheat + description:Infinite lives - P1 + code:a3cc/a5 + cheat + description:Infinite lives - P2 + code:a3da/a5 + cheat + description:Annoying guy doesn't bother you + code:d223/9d/ad+d1c3/9d/ad + cheat + description:Start with Golden Hammer + code:a1bc/85/e6 + cheat + description:Start with 1 life - both players + code:a1bf/01 + cheat + description:Start with 10 lives - both players + code:a1bf/09 + cheat + description:Start with 15 lives - both players + code:a1bf/0f + cheat + description:Start with 250 lives + code:a1bf/f8 + +cartridge sha256:a0354fb9c1c29e25b8bd2bd45735e8af2263cde66b56cc2e61eb5d9295a42de1 + name:Wurm - Journey to the Center of the Earth! (USA) + cheat + description:Infinite fuel + code:c757/8d/ad + cheat + description:Infinite shields and life + code:c6f2/85/a5 + cheat + description:Start on Act 2 - Dyna Crystal + code:d4a6/01/02 + cheat + description:Start on Act 3 - Magma Falls + code:d4a6/01/03 + cheat + description:Start on Act 4 - Ziggy + code:d4a6/01/04 + cheat + description:Start on Act 5 - Dual Duel + code:d4a6/01/05 + +cartridge sha256:e5de4656729ffa37f7f6afdccb7c207ca7b867768369cc1a2817626919bff8dc + name:WWF King of the Ring (USA) + cheat + description:Infinite health - both players + code:b63d/99/ae + cheat + description:Infinite health - P1 + code:0168/bf + cheat + description:No health - P2 + code:0194/00 + +cartridge sha256:a6f98e57ffb4544152138f109b00d1016ae957f7d842f29b41e118045fd54056 + name:WWF Wrestlemania (USA) + cheat + description:Infinite health - P1 + code:cf27/b0/a9+cf28/02/ca+cf29/e6/85 + cheat + description:One hit drains all health + code:cd96/90/f0 + cheat + description:Opponent is idle after a body slam + code:e9a5/ad + cheat + description:Countdown starts on 3 + code:e343/01/03 + cheat + description:1 minute tournament rounds + code:c922/03/01 + cheat + description:6 minute tournament rounds + code:c922/03/06 + cheat + description:9 minute tournament rounds + code:c922/03/09 + +cartridge sha256:89df74e7b275929c91a64580c5b1733bee26bcaf3a923dcca9fffdda835b2964 + name:WWF Wrestlemania Challenge (USA) + cheat + description:Pin count extended to 9 seconds + code:b483/04/0a + cheat + description:10-count reduced to 5 seconds + code:c1d7/0b/06 + cheat + description:All counts slower + code:c1fc/3c/65 + cheat + description:All counts faster + code:c1fc/3c/1f + +cartridge sha256:b0e4bcb63416c32fc247ff8afc28915ba15906a9b02aaed77a41e8109eab91fc + name:WWF Wrestlemania Steel Cage Challenge (USA) + cheat + description:P1 cannot lose (constant 1 count) + code:8bd5/ce/ae + cheat + description:Infinite energy refills (press select when energy is low) + code:dfa2/9d/bd + cheat + description:1 minute tournament rounds + code:c922/03/01 + cheat + description:6 minute tournament rounds + code:c922/03/06 + cheat + description:9 minute tournament rounds + code:c922/03/09 + +cartridge sha256:4b11689be770a7dd6ef560568ba1fd70d6c585babedd8c9088769a0d63d89cf1 + name:Xenophobe (USA) + cheat + description:Infinite health - both players + code:d747/eb/00 + cheat + description:Increase starting health - both players + code:d152/09/03 + cheat + description:More health - P1 + code:d163/ff/03+d165/5c/50 + cheat + description:No health pick-ups allowed + code:d6f6/99/ad + cheat + description:Start on level 2 + code:d148/07/06 + cheat + description:Start on level 3 + code:d148/07/05 + cheat + description:Start on level 4 + code:d148/07/04 + cheat + description:Start on level 5 + code:d148/07/03 + 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 + name:Xevious - The Avenger (USA) + cheat + description:Invincibility + code:fdc4/a5/85 + cheat + description:Infinite lives + code:f73a/a5 + cheat + description:Hit anywere + code:dd13/13/00+dd21/05/00+eb8e/bd/60 + cheat + description:Start with 1 life + code:fc21/01 + cheat + description:Start with 6 lives + code:fc21/06 + cheat + description:Start with 9 lives + code:fc21/09 + +cartridge sha256:2508e4eada73f233b2df86af2248a370b2d40ec2de590c8886a8750ddfb5b79c + name:Xexyz (USA) + cheat + description:Immune to enemy bullets + code:c774/e5/e9 + cheat + description:Immune to monsters + code:c674/e5/e9 + cheat + description:Infinite lives + code:a40e/ce/ad + cheat + description:Become a whirlwind on new life + code:a418/8d/ee + cheat + description:1 life after continue + code:a53b/03/01 + cheat + description:Start with 1 life + code:a236/03/01 + cheat + description:Start with 6 lives + code:a236/03/06 + cheat + description:Start with 9 lives + code:a236/03/09 + cheat + description:Start with and keep foot-wing + code:b711/08/00 + +cartridge sha256:1f349392d49c60c3e52a06be6ab4d914bf71ffd5b73857964ec9d604806b131b + name:Xybots (USA) (Proto) (Unl) + cheat + description:Infinite lives and second shots + code:f385/de/bd + cheat + description:Infinite Keys - both players + code:9004/de/ad + cheat + description:Infinite money - both players + code:8986/9d/bd + cheat + description:Infinite Slow Energy Drain and Zap power + code:e96b/9d/ad + cheat + description:Infinite Warning Arrows and Level Mappers + code:b6bb/9d/ad + cheat + description:Infinite Enemy Mappers and Guard Mapper + code:e950/99/b9 + cheat + description:Start with 6 lives and 6 second shots + code:e15c/12/66 + cheat + description:Start with 3 Slow Energy Drain and 4 Zap power - P1 + code:e152/02/24 + cheat + description:Start with 3 Slow Energy Drain and 4 Zap power - P2 + code:e157/12/24 + cheat + description:Start with 6 Warning Arrows and Level Mappers + code:e164/21/66 + cheat + description:Start with 6 Enemy Mappers and have Guard Mapper + code:e16c/01/16 + cheat + description:Start with 99 Keys, $99 and 2,544,300 points + code:e4ac/00/63 + cheat + description:Start with 4 extra Speed, extra Armor, extra Shot Speed, extra Shot Power and Wide Shot + code:e130/00/44 + cheat + description:Start at last level + code:e176/01/36 + cheat + description:Infinite health - P1 + code:0192/ff + cheat + description:Infinite health - P2 + code:0193/ff + cheat + description:Infinite Keys - P1 + code:0196/09 + cheat + description:Infinite Keys - P2 + code:0197/09 + cheat + description:Infinite Money - P1 + code:0194/ff + cheat + description:Infinite Money - P2 + code:0195/ff + +cartridge sha256:0624c93899a588232f9193db0d560291b15636727813a4cd6c3dab8b7f74badb + name:Yie Ar Kung-Fu (Japan) (Rev 1.4) + cheat + description:Infinite health + code:dd93/e6/b5 + cheat + description:Infinite health (alt) + code:00db/00 + cheat + description:One hit kills + code:de21/25/00 + cheat + description:Hit anywhere + code:dc49/d0/f0+dc39/d0/f0 + +cartridge sha256:dbe10104fc90c36ff7c95424cb192dfd9619fb7c1238bbae8da87e0bc9cc5a4e + name:Yie Ar Kung-Fu (Japan) (Rev 1.2) + cheat + description:Invincible against punches and kicks + code:dd32/85/a5 + cheat + description:Tao does not throw fireballs + code:e6fb/85/a5 + cheat + description:Chen does not hit you with his chain + code:e8f5/85/a5 + cheat + description:Lang does not throw shurikens + code:e668/c0/a9 + cheat + description:Bonus doesn't end when you're hit with a sword or fan + code:de99/a9/60 + cheat + description:Infinite health + code:00db/00 + +cartridge sha256:62a3551ce546fa7df5fd4970e725e36f1ca269be62b1e33f92546d6e649b8371 + name:Yo! Noid (USA) + cheat + description:Invincibility + code:baad/60 + cheat + description:Invincibility (alt) + code:b631/20/ad + cheat + description:Infinite time + code:b4a5/c6/a5 + cheat + description:Infinite lives + code:e3c6/ce/ad+e3c9/ce/ad + cheat + description:More magic from small scrolls + code:bc4e/01/05 + cheat + description:Multi-mega-jumps + code:ccb5/2e/00 + cheat + description:1 continue + code:da2f/03/01 + cheat + description:6 continues + code:da2f/03/06 + cheat + description:Start with 1 life + code:d9b6/32/30+d9b9/42/40 + cheat + description:Start with 6 lives + code:d9b6/32/35+d9b9/42/45 + cheat + description:Start with 9 lives + code:d9b6/32/39+d9b9/42/49 + cheat + description:Start on stage 2 + code:d9ec/01/02 + cheat + description:Start on stage 4 + code:d9ec/01/04 + cheat + description:Start on stage 6 + code:d9ec/01/06 + cheat + description:Start on stage 8 + code:d9ec/01/08 + cheat + description:Start on stage 10 + code:d9ec/01/0a + cheat + description:Start on stage 12 + code:d9ec/01/0c + +cartridge sha256:56a169bb3a6101057fb278f2febd58cb1dbf056e5aaeb709c51a55ce4cfac20d + name:Yoshi (USA) + cheat + description:Short wait for next characters + code:f0b1/28/14 + cheat + description:Really short wait for next characters + code:f0b1/28/02 + cheat + description:Really long wait for next characters + code:f0b1/28/ff + cheat + description:Freeze characters for a short time (press Down) + code:b7db/02/60 + cheat + description:Need only 1 Victory Egg to win + code:8160/03/01+e2d0/03/01+e3a2/03/01 + cheat + description:Need only 2 Victory Eggs to win + code:8160/03/02+e2d0/03/02+e3a2/03/02 + +cartridge sha256:fd4884c98d9412eb362c0654c8f5475e7f24266984f11e19961495c2d642d38a + name:Young Indiana Jones Chronicles, The (USA) + cheat + description:Infinite health + code:81dc/85/ea + cheat + description:Infinite lives + code:9c0b/c6/a5 + cheat + description:Start with 2 lives + code:dcce/03/01 + cheat + description:Start with 7 lives + code:dcce/03/06 + cheat + description:Start with 10 lives + code:dcce/03/09 + +cartridge sha256:c79202082042baeb3a45e747a1675c9530137f847c357c393270715efc32217e + name:Ys II - Ancient Ys Vanished - The Final Chapter (Japan) + cheat + description:Infinite HP + code:ed9a/85/a5 + cheat + description:Infinite gold + code:852b/85/a5+8532/85/a5 + cheat + description:Lots of EXP + code:dd9f/09/08+dda5/0a/08 + cheat + description:Start with all equipment + code:dd4c/01/7f + +cartridge sha256:ec1d85479d72847d3adbd76e2e79221143e6c9324d5647be2c4a11aa87123f75 + name:Ys III - Wanderers from Ys (Japan) + cheat + description:Hit anywhere + code:a84d/60/ea+a87b/60/ea+a864/60/ea+a892/60/ea + cheat + description:One hit kills + code:a707/04/00 + +cartridge sha256:91d281ee84a71483cd9b8e8021222ef509a8c0ea4be0a4fa675140a91b65c2da + name:Yume Koujou Doki Doki Panic (Japan) [b] (FDS) + cheat + description:Multi-jump + code:863d/d0/24 + 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 + name:Zanac (USA) + cheat + description:Invincibility + Hit anywhere + code:825c/b0/38+825d/31/60+821b/99/ad + cheat + description:Infinite lives + code:8f8f/c6/a9 + cheat + description:Start with Straight Crusher + code:9490/00/01 + cheat + description:Start with Field Shutter + code:9490/00/02 + cheat + description:Start with the Circular + code:9490/00/03 + cheat + description:Start with the Vibrator + code:9490/00/04 + cheat + description:Start with the Rewinder + code:9490/00/05 + cheat + description:Start with the Plasma Flash + code:9490/00/06 + cheat + description:Start with rapid fire + code:9490/00/07 + cheat + description:Start with 1 life + code:cb89/03/01 + cheat + description:Start with 6 lives + code:cb89/03/06 + cheat + description:Start with 9 lives + code:cb89/03/09 + cheat + description:Invincibility + code:0764/00 + +cartridge sha256:4cfc55e1521e58039d502f2a5ff16c233b84c0a05b1048185c75c971f3814c16 + name:Zelda II - The Adventure of Link (USA) + cheat + description:Infinite health + code:e335/e5/ea+e336/0c/ea + cheat + description:Almost infinite health + code:e330/e2 + cheat + description:Infinite magic + code:8df0/f9/2c + cheat + description:Infinite magic (alt) + code:8df5/8d/ad + cheat + description:Infinite magic and health in battle + code:d3f8/08 + cheat + description:Infinite lives + code:ca44/ce/ad + cheat + description:Infinite Keys after obtaining one + code:d9e4/ce/ad + cheat + description:Keys not necessary to open doors + code:d9e3/ea+d9e2/e2 + cheat + description:Gain over 2048 EXP when you defeat an enemy most of the time + code:d465/00/08 + cheat + description:Gain 256 EXP when you defeat an enemy most of the time + code:d45e/8d/ea + cheat + description:Gain more than 256 EXP for every EXP + code:d465/00/01 + cheat + description:Don't lose EXP points while leveling up + code:9f6b/8d/ad+9f74/8d/ad + cheat + description:All sword levels do massive damage + code:e732/f9/ed + cheat + description:Hit anywhere (press up if you get stuck at a Palace entrance) + code:e6a4/b0/50 + cheat + description:Multi-jump + code:9530/f7/f5+9535/ad/a9+9536/7d/fb+9537/05/8d+9538/10/7d+9539/02/05 + cheat + description:Mega-jump + code:953b/30/20 + cheat + description:Link can fly (hold A) + code:953b/30/00 + cheat + description:Faster text (when talking to people) + code:b6be/df/00 + cheat + description:Walk through walls in Overworld + code:871e/02/00 + cheat + description:Swap Shield spell for Fire spell + code:8e48/8d/f1+8e49/8e/97 + cheat + description:Swap Shield spell for Spell spell + code:8e48/8d/73+8e49/8e/8e + cheat + description:Swap Shield spell for Fairy spell + code:8e48/8d/23+8e49/8e/91 + cheat + description:Swap Shield spell for Life spell + code:8e48/8d/5d+8e49/8e/8e + cheat + description:Swap Shield spell for Thunder spell + code:8e48/8d/e6+8e49/8e/91 + cheat + description:Start with all spells + code:a60d/bd/de + cheat + description:Start with 1 life + code:c359/03/01 + cheat + description:Start with 6 lives + code:c359/03/06 + cheat + description:Start with 9 lives + code:c359/03/09 + 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 + name:Zen - Intergalactic Ninja (USA) + cheat + description:Invincibility + code:8849/11/00 + cheat + description:Hit anywhere + code:b281/2f/00+b297/19/00+b2ac/b0/a9 + cheat + description:One hit kills + code:b4c7/02/00 + cheat + description:Infinite health + code:b377/8d/2c + cheat + description:Infinite lives + code:9654/c6/a5+a617/c6/a5 + cheat + description:9 lives allowed in options menu + code:bc07/05/0a + cheat + description:Slower timer + code:ae7e/81/ff + cheat + description:Faster timer + code:ae7e/81/6f + cheat + description:Even faster timer + code:ae7e/81/5f + cheat + description:Zen does increased damage - isometric stages + code:8bb1/04/08 + cheat + description:Zen does mega damage - isometric stages + code:8bb1/04/14 + cheat + description:Jab attack does more damage - horizontal stages + code:ad4b/04/08 + cheat + description:Mega jab attack damage - horizontal stages + code:ad4b/04/14 + cheat + description:Fewer hits in shield + code:b40c/03/01+be2f/03/01 + cheat + description:Double hits in shield + code:b40c/03/06+be2f/03/06 + cheat + description:Triple hits in shield + code:b40c/03/09+be2f/03/09 + +cartridge sha256:d0850075065ecbd125a33accc952de5d012527be45aa14a1b8223a9adf1643ae + name:Zoda's Revenge - StarTropics II (USA) + cheat + description:Invincibility + code:a140/ed/ae + cheat + description:Infinite lives + code:e4c9/ce/ad + cheat + description:Infinite weapons + code:a536/de/bd + cheat + description:Hit anywhere + code:b40d/b9/4c+b40f/70/b4+b40e/b4/8b + cheat + description:Walk faster - battle mode + code:a83c/01/02 + cheat + description:Jump faster and further - battle mode + code:a83c/00/01 + cheat + description:Throw Tink's axe further + code:b0cb/40/60 + cheat + description:1 star gives energy + code:a651/05/01+a655/05/01 + cheat + description:Throw Tink's Axe faster (can't be combined with other Axe code) + code:b038/41/f1 + cheat + description:Tink's Axe splits into 3 little ones when thrown (can't be combined with other Axe code) + code:b038/41/43 + cheat + description:Throw Tink's splitting-Axe faster (can't be combined with other Axe code) + code:b038/f1/f3 + cheat + description:Start with 1 life (Only effective in battle mode on first life) + code:e266/03/01 + cheat + description:Start with 6 lives (Only effective in battle mode on first life) + code:e266/03/06 + cheat + description:Start with 9 lives (Only effective in battle mode on first life) + code:e266/03/09 + +cartridge sha256:a18476a3b06ec3d9767ed6b6cf528dd204440a64e7781a3b18c1250c3c18f2ec + name:Zombie Hunter (Japan) + cheat + description:Invincibility + code:dfaa/13/00 + cheat + description:One hit kills + code:dd8d/60/ea + cheat + description:Hit anywhere + code:dec1/10/00+deba/16/00+decb/b0/a9 + cheat + description:Walk on air, jump to fall down + code:e070/f3/00 + +cartridge sha256:91eae4e0e59dadd5de7cdbe71fe57e304d741ae5107928e29e0f6ff8813151a9 + name:Zombie Nation (USA) + cheat + description:Infinite health + code:eda0/a5/60 + cheat + description:Infinite continues + code:053b/05 + +cartridge sha256:061d1c3865ad62ae883bb30b9f0071e8f7aa572f15f61bfb91b3a755eeeb5eb0 + name:Zunou Senkan Galg (Japan) + cheat + description:Invincibility + code:860d/68/60+cf59/a5/60 + cheat + description:Infinite lives + code:80f8/c6/a9 + +cartridge sha256:8808783f789ca6413364a7abea240f6f7291b5906026f360ba8cfdd2791fc179 + name: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 + name:3 Ninjas Kick Back (USA) + cheat + description:Invincibility + code:82f5c6/f0+809416/d0 + cheat + description:Infinite lives + code:82ee7e/ad + 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 + name:7th Saga, The (USA) + cheat + description:Enemies aren't generated + code:c01780/6b + cheat + description:Touching an enemy doesn't cause a battle + code:c01f36/6b + cheat + description:Sell an item for maximum gold + code:c0b139/80 + cheat + description:Walk anywhere + code:c41d90/00 + cheat + description:Human fighter has 50 HP + code:c0623f/32 + cheat + description:Human fighter has 100 HP + code:c0623f/64 + cheat + description:Human fighter has 200 HP + code:c0623f/c8 + cheat + description:Tetujin has 50 HP + code:c06287/32 + cheat + description:Tetujin has 100 HP + code:c06287/64 + cheat + description:Tetujin has 200 HP + code:c06287/c8 + cheat + description:Dwarf has 50 HP + code:c06251/32 + cheat + description:Dwarf has 100 HP + code:c06251/64 + cheat + description:Dwarf has 200 HP + code:c06251/c8 + cheat + description:Human mage has 50 HP + code:c06299/32 + cheat + description:Human mage has 100 HP + code:c06299/64 + cheat + description:Human mage has 200 HP + code:c06299/c8 + cheat + description:Elf has 50 HP + code:c06263/32 + cheat + description:Elf has 100 HP + code:c06263/64 + cheat + description:Elf has 200 HP + code:c06263/c8 + cheat + description:Demon has 50 HP + code:c062ab/32 + cheat + description:Demon has 100 HP + code:c062ab/64 + cheat + description:Demon has 200 HP + code:c062ab/c8 + cheat + description:Alien has 50 HP + code:c06275/32 + cheat + description:Alien has 100 HP + code:c06275/64 + cheat + description:Alien has 200 HP + code:c06275/c8 + cheat + description:Human fighter has 20 power + code:c06243/14 + cheat + description:Tetujin has 20 power + code:c0628b/14 + cheat + description:Dwarf has 20 power + code:c06255/14 + cheat + description:Human mage has 20 power + code:c0629d/14 + cheat + description:Elf has 20 power + code:c06267/14 + cheat + description:Demon has 20 power + code:c062af/14 + cheat + description:Alien has 20 power + code:c06279/14 + cheat + description:Human fighter has 30 MP + code:c06241/1e + cheat + description:Tetujin has 30 MP + code:c06289/1e + cheat + description:Dwarf has 30 MP + code:c06253/1e + cheat + description:Human mage has 30 MP + code:c0629b/1e + cheat + description:Elf has 30 MP + code:c06265/1e + cheat + description:Demon has 30 MP + code:c062ad/1e + cheat + description:Alien has 30 MP + code:c06277/1e + cheat + description:Human fighter has 20 speed + code:c06246/14 + cheat + description:Tetujin has 20 speed + code:c0628e/14 + cheat + description:Dwarf has 20 speed + code:c06258/14 + cheat + description:Human mage has 20 speed + code:c062a0/14 + cheat + description:Elf has 20 speed + code:c0626a/14 + cheat + description:Demon has 20 speed + code:c062b2/14 + cheat + description:Alien has 20 speed + code:c0627c/14 + cheat + description:Get 999 Max HP when you use a 'V Seed' + code:c4a066/00 + cheat + description:Get 999 Max MP when you use an 'M Seed' + code:c4a0d7/00 + cheat + description:Get 999 Power when you use a 'P Seed' + code:c4a148/00 + cheat + description:Get 999 Guard when you use a 'Pr Seed' + code:c4a1b9/00 + cheat + description:Get 255 Magic when you use an 'I Seed' + code:c4a226/00 + cheat + description:Get 255 Speed when you use an 'A Seed' + code:c4a292/00 + cheat + description:Human fighter starts with Sword of Anger + code:c0624d/69 + cheat + description:Human fighter starts with Sword of Courage + code:c0624d/6c + cheat + description:Human fighter starts with Sword of Fire + code:c0624d/6f + cheat + description:Dwarf starts with Sword of Nature + code:c0625f/6a + cheat + description:Dwarf starts with Sword of Courage + code:c0625f/6c + cheat + description:Dwarf starts with Sword of Fire + code:c0625f/6f + cheat + description:Human mage starts with petrified staff + code:c062a7/8e + cheat + description:Human mage starts with Rod of Tide + code:c062a7/8f + cheat + description:Elf starts with petrified staff + code:c06271/8e + cheat + description:Elf starts with Staff of Brilliance + code:c06271/91 + cheat + description:Demon starts with Sword of Anger + code:c062b9/69 + cheat + description:Demon starts with Sword of Despair + code:c062b9/6d + cheat + description:Demon starts with Sword of Fire + code:c062b9/6f + cheat + description:Start with 297 gold + code:c0920b/2c+c0920c/01 + cheat + description:Start with 62,708 gold + code:c0920b/f4+c0920c/01 + cheat + description:Start with 2000 gold + code:c0920b/d0+c0920c/07 + +cartridge sha256:69c5805ad0494703e7d636d3d40d615d33e79bebef9d2cdb4a23b73d44c7b6f9 + name:A.S.P. - Air Strike Patrol (USA) + cheat + description:No damage from enemy fire + code:81dac1/ad+81e220/a7 + cheat + description:Infinite fuel + code:819f6e/ad + cheat + description:Infinite flares + code:81ea37/ad + cheat + description:Infinite missles for F-15 Strike Eagle + code:8194b3/ad + cheat + description:Infinite missles for A-10 Thunderbolt II + code:819638/ad + +cartridge sha256:ce164872c4f5814bce04cf0565edcdb5b7969ae95a3b5cd515cfb626b5cde7b3 + name:Aaahh!!! Real Monsters (USA) + cheat + description:Invincibility + code:009dfe/8d + cheat + description:Infinite health + code:00bddb/ad + cheat + description:Infinite Fish + code:00bcf2/ad + cheat + description:Infinite Books + code:00c9c5/bd + cheat + description:Infinite Garbage + code:80bcf0/00 + cheat + description:Infinite Scares + code:80c9ca/00 + cheat + description:Infinite lives + code:80a744/00 + cheat + description:Get nothing for each Trash Bag + code:00a5b7/00 + cheat + description:Get 20 for each Trash Bag + code:00a5b7/20 + cheat + description:Get 100 for each Trash Bag + code:00a5b7/bb + cheat + description:1-ups worth nothing + code:00a2f6/00 + cheat + description:1-ups worth 3 + code:00a2f6/03 + cheat + description:1-ups worth 5 + code:00a2f6/05 + cheat + description:Monster books are worth nothing + code:00a3c5/00 + cheat + description:Monster books are worth 2 + code:00a3c5/02 + cheat + description:Monster books are worth 10 + code:00a3c5/10 + cheat + description:Most health power-ups worth nothing + code:00a39c/00 + cheat + description:Most health power-ups worth more + code:00a39c/02 + cheat + description:Start with 1 life + code:86a93c/01 + cheat + description:Start with 10 lives + code:86a93c/09 + cheat + description:Start with 50 lives + code:86a93c/49 + cheat + description:Start with 0 special scares + code:84875e/00 + cheat + description:Start with 10 special scares + code:84875e/10 + cheat + description:Start with 20 special scares + code:84875e/20 + cheat + description:Infinite health (alt) + code:7e0b7a/0d + cheat + description:Infinite lives (alt) + code:7e13c8/09 + +cartridge sha256:bb83f982961c33b81fefc1f545e18ab572d1c43cf6c241948544f05a1a71f2ba + name: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:Cannot be tackled (hold X) - diving tackles + code:01e7da/43+01e7d9/a5+01e7db/0a+01e7dc/10 + cheat + description:Cannot be tackled (hold X) - normal tackles + code:01e3d9/44+01e3dc/23+01e3db/30+01e3d8/a5+01e3da/0a + 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 + name:ACME Animation Factory (USA) + cheat + description:Infinite time - game mode + code:7e1ba4/3c + +cartridge sha256:555ff99acb1b02e67ae7da12b776cdbfa9a56b8ddf248258158ec58a151554ef + name:Acrobat Mission (Japan) + cheat + description:Invincibility + code:02a3de/ea + cheat + description:Infinite lives + code:02a6d8/bd + 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/00 + cheat + description:Score Modifier [00-99] + code:7e02b3/00+7e02b4/00 + +cartridge sha256:41af71166f509b0e615b00e7dc3cf2dc660d1701014ecadfd1629257b18471b9 + name:Action Pachio (Japan) + cheat + description:Invincibility + code:898546/f0 + cheat + description:Infinite health + code:908390/a5 + cheat + description:Infinite time + code:87dad4/a5 + cheat + description:Infinite lives + code:8780e1/a5 + 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 + cheat + description:Enable round select + code:88dc1a/80 + +cartridge sha256:b8055844825653210d252d29a2229f9a3e7e512004e83940620173c57d8723f0 + name:ActRaiser (USA) + cheat + description:Invincibility after one hit + code:009c98/60 + cheat + description:Infinite health in action sequences + code:008a24/dd + cheat + description:Infinite MP (Magic Points) + code:009e0a/a5 + cheat + description:Infinite SP (Spell Points) + code:03ca73/af + cheat + description:Infinite time + code:02bc9a/a5 + cheat + description:Infinite time (alt) + code:02bc98/00 + cheat + description:Faster timer + code:02bc8b/10 + cheat + description:Slower timer + code:02bc8b/50 + cheat + description:Hit anywhere continually + code:008ad6/24+008ae1/24+008ae6/24+008aba/80+008ac8/80 + cheat + description:Monster lairs are always empty + code:03b99c/9e + cheat + description:Towns always able to grow + code:03854f/00 + cheat + description:Unlock professional mode + code:00803f/00 + cheat + description:Unlock action mode (press start at title screen) + code:008041/00 + cheat + description:Have Fire magic and 24 MP in professional mode + code:02ab26/85+02ab2c/8d+02ab2a/a9+02ab2b/01 + cheat + description:Have Stardust and 24 MP in professional mode + code:02ab26/85+02ab2c/8d+02ab2a/a9+02ab2b/02 + cheat + description:Have Aura magic and 24 MP in professional mode + code:02ab26/85+02ab2c/8d+02ab2a/a9+02ab2b/03 + cheat + description:Start with 1/2 health (first game only) + code:02be60/04 + 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:Level 99 + code:7e0291/63 + cheat + description:One hit kills on bosses + code:7e0bcc/00 + cheat + description:Have Aura magic + code:7e02ac/03 + cheat + description:Have Fire magic + code:7e02ac/01 + cheat + description:Have Stardust magic + code:7e02ac/02 + cheat + description:Have Sword Shot + code:7e00e4/80 + 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 + name:ActRaiser 2 (USA) + cheat + description:Infinite health from most enemies + code:809e45/ad + cheat + description:Infinite health from some ground hazards + code:839adc/ad + cheat + description:Infinite time + code:80e4ee/00 + cheat + description:Infinite MP (must have one to cast) + code:828e77/ea + cheat + description:Infinite lives + code:828c3a/00 + cheat + description:Hit anywhere + code:80997f/24+80998b/24+80999c/24+8099a3/24 + cheat + description:One hit kills + code:809aee/00 + cheat + description:Small magic power-up adds 3 instead of 1 + code:80af4f/03 + cheat + description:Small magic power-up adds 5 + code:80af4f/05 + cheat + description:Small magic power-up adds 9 + code:80af4f/09 + cheat + description:Large magic power-up adds 1 instead of 3 + code:80af59/01 + cheat + description:Large magic power-up adds 5 + code:80af59/05 + cheat + description:Large magic power-up adds 9 + code:80af59/09 + cheat + description:Small health power-ups add 1 instead of 2 + code:80af32/01 + cheat + description:Small health power-ups add 4 + code:80af32/04 + cheat + description:Small health power-ups add 15 + code:80af32/15 + cheat + description:Small health power-ups heal completely + code:80af32/14 + cheat + description:Medium health power-ups add 2 instead of 5 + code:80af54/02 + cheat + description:Medium health power-ups add 8 + code:80af54/08 + cheat + description:Medium health power-ups add 15 + code:80af54/15 + cheat + description:Medium health power-ups heal completely + code:80af54/14 + cheat + description:Large health power-ups add 2 instead of 10 + code:80af37/02 + cheat + description:Large health power-ups add 5 + code:80af37/04 + cheat + description:Large health power-ups add 15 + code:80af37/15 + cheat + description:Large health power-ups heal completely + code:80af37/14 + cheat + description:Start with 3 lives on Easy + code:81d830/03 + cheat + description:Start with 10 lives on Easy + code:81d830/10 + cheat + description:Start with 50 lives on Easy + code:81d830/50 + cheat + description:Start with 1 life on Normal + code:81d832/01 + cheat + description:Start with 5 lives on Normal + code:81d832/05 + cheat + description:Start with 10 lives on Normal + code:81d832/10 + cheat + description:Start with 50 lives on Normal + code:81d832/50 + cheat + description:Start with 1 life on Hard + code:81d834/01 + cheat + description:Start with 5 lives on Hard + code:81d834/05 + cheat + description:Start with 10 lives on Hard + code:81d834/10 + cheat + description:Start with 50 lives on Hard + code:81d834/50 + cheat + description:Start with 2 MP on Easy + code:82b126/02 + cheat + description:Start with 7 MP on Easy + code:82b126/07 + cheat + description:Start with 9 MP on Easy + code:82b126/09 + cheat + description:Start with 1 MP on Normal or Hard + code:82b11e/01 + cheat + description:Start with 5 MP on Normal or Hard + code:82b11e/05 + cheat + description:Start with 7 MP on Normal or Hard + code:82b11e/07 + cheat + description:Start with 9 MP on Normal or Hard + code:82b11e/09 + cheat + description:Start with 1/2 health + code:82b115/0a + cheat + description:Start with 3/4 health + code:82b115/0f + 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 + name:Addams Family, The (USA) + cheat + description:Invincibility + code:00c23d/d0 + cheat + description:Infinite health + code:00cf3a/ea + cheat + description:Infinite health (alt) + code:00cf3b/60 + cheat + description:Infinite health (alt 2) + code:00cf3b/a5 + cheat + description:Infinite lives + code:00cf6b/00 + cheat + description:Infinite lives (alt) + code:00cf6c/a5 + cheat + description:Double-jump + code:00bd37/00 + cheat + description:Each $ worth 5 + code:00a413/05 + cheat + description:Each $ worth 10 + code:00a413/10 + cheat + description:Each $ worth 25 + code:00a413/25 + cheat + description:Have Fezi-copter + code:00c2a4/80 + cheat + description:Start with and keep Fezi-copter (disable after defeating a boss, land before password screen) + code:00c30a/ea+009acd/84 + cheat + description:Start with 1 heart + code:008165/01+008166/01 + cheat + description:Start with 3 hearts + code:008165/03+008166/03 + cheat + description:Start with 4 hearts + code:008165/04+008166/04 + cheat + description:Start with 5 hearts + code:008165/05+008166/05 + cheat + description:Start with 1 life + code:009ab5/01 + cheat + description:Start with 3 lives + code:009ab5/03 + cheat + description:Start with 9 lives + code:009ab5/09 + cheat + description:Start with 20 lives + code:009ab5/20 + cheat + description:Start with 50 lives + code:009ab5/50 + cheat + description:Start with 99 lives + code:009ab5/99 + 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 + name:Addams Family, The - Pugsley's Scavenger Hunt (USA) + cheat + description:Infinite health + code:80a0aa/ea + cheat + description:Infinite hearts + code:80a0aa/ea + cheat + description:Infinite lives + code:809d87/00 + cheat + description:Each $ worth 5 + code:80a05e/05 + cheat + description:Each $ worth 25 + code:80a05e/25 + cheat + description:Higher jump + code:80cb7c/e9+80cb7d/05 + cheat + description:Super-jump + code:80cb7c/e9+80cb7d/07 + cheat + description:Mega-jump + code:80cb7c/e9+80cb7d/09 + cheat + description:Longer invulnerability time after being hit + code:80a0b0/7f + cheat + description:Shorter invulnerability time after being hit + code:80a0b0/08 + cheat + description:Get 0 lives for each $100 and 1-Up + code:809e4e/00 + cheat + description:Get 2 lives for each $100 and 1-Up + code:809e4e/02 + cheat + description:Start with 1 heart (don't edit hearts in options menu) + code:00f00e/00 + cheat + description:Start with 2 hearts (don't edit hearts in options menu) + code:00f00e/01 + cheat + description:Start with 5 hearts (don't edit hearts in options menu) + code:00f00e/04 + cheat + description:Start with 4 lives (don't edit lives in options menu) + code:00f009/00 + cheat + description:Start with 16 lives (don't edit lives in options menu) + code:00f009/09 + cheat + description:Start with 64 lives (don't edit lives in options menu) + code:00f009/30 + 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 + name:Addams Family Values (USA) (En,Fr,De) + cheat + description:Infinite health against enemies + code:809e0e/11 + cheat + description:Infinite health against everything + code:80b219/ea + cheat + description:Infinite Small Rocks + code:80d721/00 + cheat + description:Infinite Blue Marbles + code:80d6af/00 + cheat + description:Infinite Magic Seeds + code:80d6d5/00 + cheat + description:Infinite Swamp Slime + code:80d6fb/00 + cheat + description:Infinite cookies + code:80d1c2/bf + cheat + description:Start with full skull meter + code:8083d5/1c + cheat + description:Start with all items + code:b083a5/ff + 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:0a8cd5101f849ccd4e40d55fdc4edce914b2825b69eb76ec31cf53b59719e79e + name:Advanced Dungeons & Dragons - Eye of the Beholder (USA) + cheat + description:Infinite HP + code:06ba73/bd+7e05f9/bd + cheat + description:No waiting to hit again + code:06bf0d/bd + cheat + description:One hit kills (works for enemies also) + code:06c3cf/a9+06c3d1/ea + cheat + description:Pick a lawful, human male fighter and he will be at Level 8 + code:0cbb98/08 + cheat + description:Pick a lawful, human male fighter and he will be at level 6 + code:0cbb98/06 + cheat + description:999,999 EXP 1st class + code:7e0533/3f+7e0534/42+7e0535/0f + +cartridge sha256:8083307f3f4b7df9e5bf53d5f25877c2e548f0f677540d4ee62d60ccca3098f8 + name:Adventures of Batman & Robin, The (USA) + cheat + description:Invincibility (except after being grabbed) + code:80a133/d0 + cheat + description:Infinite health + code:80b0d5/a5 + cheat + description:Infinite health (alt) + code:80b0c2/00 + cheat + description:Get full health from hearts + code:848899/28 + cheat + description:Infinite Stars + code:80c76b/a5 + cheat + description:Infinite Spray Gun ammo + code:80c778/a5 + cheat + description:Infinite Plastic Explosives + code:80c792/a5 + cheat + description:Infinite Smoke Bombs + code:80c785/a5 + cheat + description:Infinite Missiles + code:80c76b/00 + cheat + description:Infinite Bombs + code:80c792/00 + cheat + description:Infinite lives + code:80b3b9/a5 + cheat + description:Hit anywhere + code:8793b9/a5+879406/a5+87939a/00+80a48b/00+8793e7/00+83f451/00 + cheat + description:Moon-jump + code:80c518/20 + cheat + description:Super-jump + code:80a738/f8 + cheat + description:Move slower + code:81be0e/00+81be10/ff + cheat + description:Move faster + code:81be0e/04+81be10/fb + cheat + description:Move even faster + code:81be0e/07+81be10/f8 + cheat + description:Moon-walk + code:81be0e/fe+81be10/01 + cheat + description:Moon-walk faster + code:81be0e/fb+81be10/04 + cheat + description:Moon-walk even faster + code:81be0e/f8+81be10/f7 + cheat + description:No credits + code:89b481/00 + cheat + description:Don't start with any Explosives and Smoke Bomb ammo + code:8097f5/00 + cheat + description:Don't start with any Stars and Spray Gun ammo + code:8097ee/00 + cheat + description:Start with 25 Stars and Spray Gun ammo + code:8097ee/19 + cheat + description:Start with 50 Stars and Spray Gun ammo + code:8097ee/33 + cheat + description:Start with 25 Explosives and Smoke Bomb ammo + code:8097f5/19 + cheat + description:Start with 50 Explosives and Smoke Bomb ammo + code:8097f5/33 + cheat + description:Start with 9 lives - not on easy mode + code:89b486/09 + cheat + description:Start with 6 lives - not on easy mode + code:89b486/06 + cheat + description:Start with 1 life - not on easy mode + code:89b486/00 + cheat + description:Start with 9 credits + code:89b481/09 + cheat + description:Start with 6 credits + code:89b481/06 + 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 + name:Adventures of Dr. Franken, The (USA) + cheat + description:Invincibility + code:809e90/ea + cheat + description:Health power-ups give a full health bar + code:80c949/0e+80c97a/8d + cheat + description:Infinite health (glitchy) + code:809495/ad+809498/ad + cheat + description:Infinite time + code:80da4f/ad + cheat + description:Infinite lives + code:80925b/ad + cheat + description:Infinite Power Balls + code:80957b/ea + cheat + description:Infinite Freeze + code:809595/ea + cheat + description:Infinite Fire + code:809591/ea + cheat + description:Infinite Lightning + code:809577/ea + +cartridge sha256:670d898bdcf97d7ca3aab6c2dd1641f1270fcc2a070bbd3028ab413aef2b2ecc + name:Adventures of Kid Kleets, The (USA) (En,Fr,Es) + cheat + description:Invincibility + code:81c18b/60 + cheat + description:Infinite time + code:8187cd/ad + cheat + description:Infinite health + code:81c18d/ad + cheat + description:Infinite lives + code:81bbdb/ad + cheat + description:Hit anywhere + code:83c04e/00+83c056/00 + cheat + description:Moon jump + code:81b5b1/7a+81b5b3/30+81b5ef/00 + +cartridge sha256:b70099186d3774355ac5db370240e370c73f9ce5341f6c805cf9f771374b43ae + name:Adventures of Rocky and Bullwinkle and Friends, The (USA) + cheat + description:Invincibility + code:9ca9c7/d0+9ca9cd/f0 + cheat + description:Infinite chances + code:88b9a4/ad + cheat + description:Infinite lives + code:81aaf6/ad + cheat + description:Infinite ammo + code:81aa15/ad + cheat + description:Infinite health + code:9ca312/ad + cheat + description:Infinite continues + code:8af0ee/ad + cheat + description:Don't lose ammo when you die + code:9ca35f/ad + cheat + description:Don't lose collected flags when you die + code:9ca23a/ad + cheat + description:1-Up with every flag collected + code:81a9ce/01 + +cartridge sha256:8049175767eddbc3e21ca5b94ee23fc225f834ccfab4ded30d2e981b0ef73ab6 + name:Adventures of Yogi Bear (USA) + cheat + description:Infinite health + code:80a909/ad + cheat + description:Infinite lives + code:80805c/ad + +cartridge sha256:b737de81315eef8ded7cfd5df6b37aba01d9e6e14566486db7ec83eb0c1aa85e + name:Aero Fighters (USA) + cheat + description:Invincibility + code:80a8d2/bd + cheat + description:Infinite lives - both players + code:81d35f/bd + cheat + description:Infinite Bombs for American F-18 - P1 + code:81e83f/bd + cheat + description:Infinite Bombs for Japanese FSX - P1 + code:81e43f/bd + cheat + description:Infinite Bombs for Swedish AJ-37 - P1 + code:81e531/bd + cheat + description:Infinite Bombs for British AV-8 - P1 + code:81e53f/bd + cheat + description:Infinite Bombs for American F-15 - P2 + code:81e3f2/bd + cheat + description:Infinite Bombs for Japanese F-15 - P2 + code:81e4c1/bd + cheat + description:Infinite Bombs for Swedish JAS-39 - P2 + code:81e554/bd + cheat + description:Infinite Bombs for British IDS - P2 + code:81e60e/bd + cheat + description:Don't lose power-ups when you die - both players + code:81d35c/bd + cheat + description:Hit anywhere + one hit kills + code:80a1c8/24+80a1cf/24+80a1d4/24+80a1d8/24+80a1dc/24+80a175/80+80a193/80 + cheat + description:One hit kills + code:80a193/80 + 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 + name:Aero the Acro-Bat (USA) + cheat + description:Infinite health from most enemies + code:82fb00/ea + cheat + description:Start with more health + code:83d831/6c + cheat + description:Infinite time + code:83f1aa/00 + cheat + description:Infinite lives + code:80879f/00 + cheat + description:Start with 19 lives + code:8080b4/70 + cheat + description:Infinite continues + code:848bff/ad + cheat + description:Each star platform is worth 4 + code:80e22f/04 + +cartridge sha256:fc5df5db0a96d39d3df651f63993adf0f5cb5a6b92a36211f3a05d460d92c72d + name:Aero the Acro-Bat 2 (USA) + cheat + description:Invincibility + code:809042/d0 + cheat + description:Infinite health + code:83be37/cd + cheat + description:Almost infinite health + code:83be37/ad + cheat + description:Infinite lives + code:8084a1/ad + cheat + description:Infinite Stars + code:83dc30/ad + cheat + description:Infinite Shots + code:83dc2e/00 + cheat + description:Stars worth 3 + code:83a9bc/03 + cheat + description:Stars worth 5 + code:83a9bc/05 + cheat + description:Stars worth 7 + code:83a9bc/07 + cheat + description:Double Drill icon lasts 99 seconds + code:83aada/99 + cheat + description:Double Drill icon lets you drill 4 times instead of 2 + code:83aad1/04 + cheat + description:Double Drill icon lets you drill 9 times instead of 2 + code:83aad1/09 + cheat + description:Can drill 5 times in the air until you pick-up a drill icon + code:85e880/05 + cheat + description:Can drill 9 times in the air until you pick-up a drill icon + code:85e880/09 + cheat + description:Drill as many times as you want without hitting the ground + code:8388f5/ad + cheat + description:Move faster + code:8382b3/02+8382c1/fd + cheat + description:Move even faster + code:8382b3/03+8382c1/fc + cheat + description:Jump higher + code:838730/10 + cheat + description:Super-jump when standing still + code:8384f6/f8+83866e/f8 + cheat + description:Flying icon worth 99 seconds of flight time + code:83abe2/99 + cheat + description:Start each life with max health + code:85e958/05 + +cartridge sha256:d5f0fbeed3774bbccbd769698fc4051487a0a5eb699790a8a094451595600f60 + name:Aerobiz (USA) + cheat + description:In scenario 1, Tokyo starts with $649,280,000 + code:04c180/00 + cheat + description:In scenario 1, Tokyo starts with $7,202,880,000 + code:04c180/05 + cheat + description:In scenario 1, Beijing starts with $420,160,000 + code:04c183/52 + cheat + description:In scenario 1, Beijing starts with $7,393,600,000 + code:04c184/05 + cheat + description:In scenario 1, Hong Kong starts with $449,440,000 + code:04c187/57 + cheat + description:In scenario 1, Hong Kong starts with $7,453,600,000 + code:04c188/05 + cheat + description:In scenario 1, Singapore starts with $400,640,000 + code:04c18b/4e + cheat + description:In scenario 1, Singapore starts with $7,353,600,000 + code:04c18c/05 + cheat + description:In scenario 1, Sydney starts with $297,920,000 + code:04c18f/3a + cheat + description:In scenario 1, Sydney starts with $7,153,600,000 + code:04c190/05 + cheat + description:In scenario 1, Delhi starts with $317,440,000 + code:04c193/3e + cheat + description:In scenario 1, Delhi starts with $7,193,600,000 + code:04c194/05 + cheat + description:In scenario 1, Tehran starts with $239,360,000 + code:04c197/2e + cheat + description:In scenario 1, Tehran starts with $7,033,600,000 + code:04c198/05 + cheat + description:In scenario 1, Cairo starts with $249,120,000 + code:04c19b/30 + cheat + description:In scenario 1, Cairo starts with $7,053,600,000 + code:04c19c/05 + cheat + description:In scenario 1, Nairobi starts with $200,320,000 + code:04c19f/27 + cheat + description:In scenario 1, Nairobi starts with $6,953,600,000 + code:04c1a0/05 + cheat + description:In scenario 1, Lagos starts with $229,600,000 + code:04c1a3/2c + cheat + description:In scenario 1, Lagos starts with $7,013,600,000 + code:04c1a4/05 + cheat + description:In scenario 1, Moscow starts with $289,280,000 + code:04c1a8/00 + cheat + description:In scenario 1, Moscow starts with $6,842,880,000 + code:04c1a8/05 + cheat + description:In scenario 1, London starts with $949,280,000 + code:04c1ac/00 + cheat + description:In scenario 1, London starts with $7,502,880,000 + code:04c1ac/05 + cheat + description:In scenario 1, Paris starts with $289,280,000 + code:04c1b0/00 + cheat + description:In scenario 1, Paris starts with $6,842,880,000 + code:04c1b0/05 + cheat + description:In scenario 1, Rome starts with $371,360,000 + code:04c1b3/48 + cheat + description:In scenario 1, Rome starts with $7,293,600,000 + code:04c1b4/05 + cheat + description:In scenario 1, New York starts with $189,280,000 + code:04c1b8/00 + cheat + description:In scenario 1, New York starts with $6,742,880,000 + code:04c1b8/05 + cheat + description:In scenario 1, Vancouver starts with $258,880,000 + code:04c1bb/32 + cheat + description:In scenario 1, Vancouver starts with $7,073,600,000 + code:04c1bc/05 + cheat + description:In scenario 1, Los Angeles starts with $649,280,000 + code:04c1c0/00 + cheat + description:In scenario 1, Los Angeles starts with $7,202,880,000 + code:04c1c0/05 + cheat + description:In scenario 1, Honolulu starts with $268,640,000 + code:04c1c3/34 + cheat + description:In scenario 1, Honolulu starts with $7,093,600,000 + code:04c1c4/05 + cheat + description:In scenario 1, Mexico City starts with $258,880,000 + code:04c1c7/32 + cheat + description:In scenario 1, Mexico City starts with $7,073,600,000 + code:04c1c8/05 + cheat + description:In scenario 1, Lima starts with $180,800,000 + code:04c1cb/23 + cheat + description:In scenario 1, Lima starts with $6,913,600,000 + code:04c1cc/05 + cheat + description:In scenario 1, Rio de Janeiro starts with $317,440,000 + code:04c1cf/3e + cheat + description:In scenario 1, Rio de Janeiro starts with $7,193,600,000 + code:04c1d0/05 + cheat + description:In scenario 1, Buenos Aires starts with $210,080,000 + code:04c1d3/29 + cheat + description:In scenario 1, Buenos Aires starts with $6,973,600,000 + code:04c1d4/05 + cheat + description:In scenario 2, Tokyo starts with $1,149,280,000 + code:04c1d8/00 + cheat + description:In scenario 2, Tokyo starts with $7,702,880,000 + code:04c1d8/05 + cheat + description:In scenario 2, Beijing starts with $498,240,000 + code:04c1db/61 + cheat + description:In scenario 2, Beijing starts with $7,553,600,000 + code:04c1dc/05 + cheat + description:In scenario 2, Hong Kong starts with $649,760,000 + code:04c1df/7e + cheat + description:In scenario 2, Hong Kong starts with $7,853,600,000 + code:04c1e0/05 + cheat + description:In scenario 2, Singapore starts with $552,160,000 + code:04c1e3/6b + cheat + description:In scenario 2, Singapore starts with $7,653,600,000 + code:04c1e4/05 + cheat + description:In scenario 2, Sydney starts with $581,440,000 + code:04c1e7/71 + cheat + description:In scenario 2, Sydney starts with $7,713,600,000 + code:04c1e8/05 + cheat + description:In scenario 2, Delhi starts with $517,760,000 + code:04c1eb/65 + cheat + description:In scenario 2, Delhi starts with $7,593,600,000 + code:04c1ec/05 + cheat + description:In scenario 2, Tehran starts with $297,920,000 + code:04c1ef/3a + cheat + description:In scenario 2, Tehran starts with $7,153,600,000 + code:04c1f0/05 + cheat + description:In scenario 2, Cairo starts with $390,880,000 + code:04c1f3/4c + cheat + description:In scenario 2, Cairo starts with $7,333,600,000 + code:04c1f4/05 + cheat + description:In scenario 2, Nairobi starts with $249,120,000 + code:04c1f7/30 + cheat + description:In scenario 2, Nairobi starts with $7,053,600,000 + code:04c1f8/05 + cheat + description:In scenario 2, Lagos starts with $299,040,000 + code:04c1fb/3a + cheat + description:In scenario 2, Lagos starts with $7,149,600,000 + code:04c1fc/05 + cheat + description:In scenario 2, Moscow starts with $689,280,000 + code:04c200/00 + cheat + description:In scenario 2, Moscow starts with $7,242,880,000 + code:04c200/05 + cheat + description:In scenario 2, London starts with $38,560,000 + code:04c204/00 + cheat + description:In scenario 2, London starts with $6,592,160,000 + code:04c204/05 + cheat + description:In scenario 2, Paris starts with $909,280,000 + code:04c208/00 + cheat + description:In scenario 2, Paris starts with $7,462,880,000 + code:04c208/05 + cheat + description:In scenario 2, Rome starts with $571,680,000 + code:04c20b/6f + cheat + description:In scenario 2, Rome starts with $7,693,600,000 + code:04c20c/05 + cheat + description:In scenario 2, New York starts with $829,280,000 + code:04c210/00 + cheat + description:In scenario 2, New York starts with $7,382,880,000 + code:04c210/05 + cheat + description:In scenario 2, Vancouver starts with $420,160,000 + code:04c213/52 + cheat + description:In scenario 2, Vancouver starts with $7,393,600,000 + code:04c214/05 + cheat + description:In scenario 2, Los Angeles starts with $1,109,280,000 + code:04c218/00 + cheat + description:In scenario 2, Los Angeles starts with $7,662,880,000 + code:04c218/05 + cheat + description:In scenario 2, Honolulu starts with $381,120,000 + code:04c21b/4a + cheat + description:In scenario 2, Honolulu starts with $7,313,600,000 + code:04c21c/05 + cheat + description:In scenario 2, Mexico City starts with $468,960,000 + code:04c21f/5b + cheat + description:In scenario 2, Mexico City starts with $7,493,600,000 + code:04c220/05 + cheat + description:In scenario 2, Lima starts with $258,880,000 + code:04c223/32 + cheat + description:In scenario 2, Lima starts with $7,073,600,000 + code:04c224/05 + cheat + description:In scenario 2, Rio de Janeiro starts with $630,240,000 + code:04c227/7b + cheat + description:In scenario 2, Rio de Janeiro starts with $7,813,600,000 + code:04c228/05 + cheat + description:In scenario 2, Buenos Aires starts with $361,600,000 + code:04c22b/46 + cheat + description:In scenario 2, Buenos Aires starts with $7,273,600,000 + code:04c22c/05 + cheat + description:Key Code + code:03f8ea/90 + cheat + description:Set money to less than $655,350,000 (must have Key) - P1, saved game 1 + code:70001c/00 + cheat + description:Set money to over $327,680,000 (must have Key) - P1, saved game 1 + code:70001c/05 + cheat + description:Set money to over $5,242,880,000 (must have Key) - P1, saved game 1 + code:70001c/08 + cheat + description:Set money to over $10,485,760,000 (must have Key) - P1, saved game 1 + code:70001c/10 + cheat + description:Set money to over $20,971,520,000 (must have Key) - P1, saved game 1 + code:70001c/20 + cheat + description:Set money to over $41,943,040,000 (must have Key) - P1, saved game 1 + code:70001c/40 + cheat + description:Set money to less than $655,350,000 (must have Key) - P2, saved game 1 + code:70005c/00 + cheat + description:Set money to over $327,680,000 (must have Key) - P2, saved game 1 + code:70005c/05 + cheat + description:Set money to over $5,242,880,000 (must have Key) - P2, saved game 1 + code:70005c/08 + cheat + description:Set money to over $10,485,760,000 (must have Key) - P2, saved game 1 + code:70005c/10 + cheat + description:Set money to over $20,971,520,000 (must have Key) - P2, saved game 1 + code:70005c/20 + cheat + description:Set money to over $41,943,040,000 (must have Key) - P2, saved game 1 + code:70005c/40 + cheat + description:Set money to less than $655,350,000 (must have Key) - P3, saved game 1 + code:70009c/00 + cheat + description:Set money to over $327,680,000 (must have Key) - P3, saved game 1 + code:70009c/05 + cheat + description:Set money to over $5,242,880,000 (must have Key) - P3, saved game 1 + code:70009c/08 + cheat + description:Set money to over $10,485,760,000 (must have Key) - P3, saved game 1 + code:70009c/10 + cheat + description:Set money to over $20,971,520,000 (must have Key) - P3, saved game 1 + code:70009c/20 + cheat + description:Set money to over $41,943,040,000 (must have Key) - P3, saved game 1 + code:70009c/40 + cheat + description:Set money to less than $655,350,000 (must have Key) - P4, saved game 1 + code:7000dc/00 + cheat + description:Set money to over $327,680,000 (must have Key) - P4, saved game 1 + code:7000dc/05 + cheat + description:Set money to over $5,242,880,000 (must have Key) - P4, saved game 1 + code:7000dc/08 + cheat + description:Set money to over $10,485,760,000 (must have Key) - P4, saved game 1 + code:7000dc/10 + cheat + description:Set money to over $20,971,520,000 (must have Key) - P4, saved game 1 + code:7000dc/20 + cheat + description:Set money to over $41,943,040,000 (must have Key) - P4, saved game 1 + code:7000dc/40 + cheat + description:Set money to less than $655,350,000 (must have Key) - P1, saved game 2 + code:70101c/00 + cheat + description:Set money to over $327,680,000 (must have Key) - P1, saved game 2 + code:70101c/05 + cheat + description:Set money to over $5,242,880,000 (must have Key) - P1, saved game 2 + code:70101c/08 + cheat + description:Set money to over $10,485,760,000 (must have Key) - P1, saved game 2 + code:70101c/10 + cheat + description:Set money to over $20,971,520,000 (must have Key) - P1, saved game 2 + code:70101c/20 + cheat + description:Set money to over $41,943,040,000 (must have Key) - P1, saved game 2 + code:70101c/40 + cheat + description:Set money to less than $655,350,000 (must have Key) - P2, saved game 2 + code:70105c/00 + cheat + description:Set money to over $327,680,000 (must have Key) - P2, saved game 2 + code:70105c/05 + cheat + description:Set money to over $5,242,880,000 (must have Key) - P2, saved game 2 + code:70105c/08 + cheat + description:Set money to over $10,485,760,000 (must have Key) - P2, saved game 2 + code:70105c/10 + cheat + description:Set money to over $20,971,520,000 (must have Key) - P2, saved game 2 + code:70105c/20 + cheat + description:Set money to over $41,943,040,000 (must have Key) - P2, saved game 2 + code:70105c/40 + cheat + description:Set money to less than $655,350,000 (must have Key) - P3, saved game 2 + code:70109c/00 + cheat + description:Set money to over $327,680,000 (must have Key) - P3, saved game 2 + code:70109c/05 + cheat + description:Set money to over $5,242,880,000 (must have Key) - P3, saved game 2 + code:70109c/08 + cheat + description:Set money to over $10,485,760,000 (must have Key) - P3, saved game 2 + code:70109c/10 + cheat + description:Set money to over $20,971,520,000 (must have Key) - P3, saved game 2 + code:70109c/20 + cheat + description:Set money to over $41,943,040,000 (must have Key) - P3, saved game 2 + code:70109c/40 + cheat + description:Set money to less than $655,350,000 (must have Key) - P4, saved game 2 + code:7010dc/00 + cheat + description:Set money to over $327,680,000 (must have Key) - P4, saved game 2 + code:7010dc/05 + cheat + description:Set money to over $5,242,880,000 (must have Key) - P4, saved game 2 + code:7010dc/08 + cheat + description:Set money to over $10,485,760,000 (must have Key) - P4, saved game 2 + code:7010dc/10 + cheat + description:Set money to over $20,971,520,000 (must have Key) - P4, saved game 2 + code:7010dc/20 + cheat + description:Set money to over $41,943,040,000 (must have Key) - P4, saved game 2 + code:7010dc/40 + +cartridge sha256:1f5738552c51de25ffe8aa44ff396c1ab238435296f1e8f99f8cf335483c03d5 + name:Air Cavalry (USA) + cheat + description:Infinite lives + code:00fbb2/e0 + cheat + description:Infinite 7.62mm rounds + code:009c3f/bd + cheat + description:Infinite 2.75 rockets + code:00f86c/b5+00f880/b5+009c75/bd + +cartridge sha256:aa768b8b00123717c8d49f2c6731cdbfd80ab6a54128bae7594e93f45e38a19e + name:Aladdin (USA) + cheat + description:Invincibility + code:81e8c1/d0 + cheat + description:Almost invincible + code:838031/ad + cheat + description:Infinite health + code:838031/cd + cheat + description:Infinite lives + code:81dc67/cd+81dc67/ad + cheat + description:Infinite Apples + code:81ce5c/ad+81ce5b/ea + cheat + description:Infinite continues + code:80b3ec/ad + cheat + description:Level select on main menu + code:809f7a/00+809fc7/00 + cheat + description:Emeralds worth 2 instead of 1 + code:83bc4b/1c + cheat + description:Emeralds worth 3 + code:83bc4b/19 + cheat + description:Rubies worth 1 instead of 3 + code:83bc65/ce + cheat + description:Rubies worth 2 + code:83bc65/ad + cheat + description:Bonus round played after every level + code:81cc30/00 + cheat + description:Only 10 gems needed for health increase/free life + code:83bc86/10 + cheat + description:Only 20 gems needed for health increase/free life + code:83bc86/20 + cheat + description:Only 30 gems needed for health increase/free life + code:83bc86/30 + cheat + description:Only 40 gems needed for health increase/free life + code:83bc86/40 + cheat + description:Only 50 gems needed for health increase/free life + code:83bc86/50 + cheat + description:Only 60 gems needed for health increase/free life + code:83bc86/60 + cheat + description:Only 90 gems needed for health increase/free life + code:83bc86/90 + cheat + description:Apple power-ups worth 20 instead of 10 + code:83b890/20 + cheat + description:Apple power-ups worth 50 + code:83b890/50 + cheat + description:Apple power-ups worth 90 + code:83b890/90 + cheat + description:Start with 5 Apples + code:818136/05 + cheat + description:Start with 20 Apples + code:818136/20 + cheat + description:Start with 2 health + code:81812b/02 + cheat + description:Start with 5 health + code:81812b/05 + cheat + description:Start with 7 health + code:81812b/07 + cheat + description:Start with 1 life + code:818120/01 + cheat + description:Start with 5 lives + code:818120/05 + cheat + description:Start with 20 lives + code:818120/14 + cheat + description:Start with 1 continue + code:809fb5/01 + cheat + description:Start with 5 continues + code:809fb5/05 + cheat + description:Start with 9 continues + code:809fb5/0a + 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 + name:Alien 3 (USA) + cheat + description:Invincibility + code:818154/00 + cheat + description:Infinite energy + code:818122/80 + cheat + description:Take less damage + code:818122/02 + cheat + description:Most attacks do no damage + code:818122/00 + cheat + description:Longer invulnerability after being hit + code:818291/ff + cheat + description:Slower fuel consumption for flame thrower + code:80db8c/ff + cheat + description:Faster fuel consumption for flame thrower + code:80db8c/30 + cheat + description:Infinite oil for flame thrower + code:80db7d/ea + cheat + description:Infinite flame thrower + code:81d9cc/ad + cheat + description:Infinite machine-gun + code:80d8b9/b9 + cheat + description:Infinite missiles + code:80dbd3/b9 + cheat + description:Infinite ammo for pulse rifle + code:80d8b8/ea + cheat + description:Infinite ammo for grenade launcher + code:80dbd2/ea + cheat + description:Less ammo in rifle clips (works with extra clips only, not the ones you start with) + code:80d8cb/32 + cheat + description:More ammo in rifle clips (works with extra clips only, not the ones you start with) + code:80d8cb/a0 + cheat + description:Less ammo in grenade clips (works with extra clips only, not the ones you start with) + code:80dbe2/05 + cheat + description:More ammo in grenade clips (works with extra clips only, not the ones you start with) + code:80dbe2/14 + cheat + description:Maximum energy from medi-kits + code:81810d/00 + cheat + description:Less energy from medi-kits + code:818103/03 + cheat + description:Start with more rifle clips + code:81e888/10 + cheat + description:Start with even more rifle clips + code:81e888/20 + cheat + description:Start with fewer rifle clips + code:81e888/04 + cheat + description:Start with more grenade clips + code:81e895/10 + cheat + description:Start with even more grenade clips + code:81e895/20 + cheat + description:Start with fewer grenade clips + code:81e895/04 + 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 + name:Alien vs Predator (USA) + cheat + description:Invincibility + code:00e197/60+00dcd8/80 + cheat + description:Infinite health + code:00e1b4/ad+00e180/ad + cheat + description:No damage taken from punches + code:00e180/ad + cheat + description:No damage taken from jumping attacks, tail attacks, rushes + code:00e1b4/ad + cheat + description:Infinite lives + code:00b38d/ad + cheat + description:Infinite lives (alt) + code:00b38d/00 + cheat + description:Infinite continues + code:02fecc/ea + cheat + description:One hit kills + code:00df07/80+00e238/80+019fbe/80+00e452/80 + cheat + description:Hit anywhere + code:00de94/24+00dd91/06+00dd02/06+00e3c8/06 + cheat + description:Disc power-ups give 1 disc instead of 6 (handicap) + code:00b6eb/01 + cheat + description:Disc power-ups give 3 discs + code:00b6eb/03 + cheat + description:Disc power-ups give 10 discs + code:00b6eb/0a + cheat + description:Disc power-ups give 25 discs + code:00b6eb/19 + cheat + description:Spear power-ups give 1 spear instead of 6 + code:00b6f2/01 + cheat + description:Spear power-ups give 3 spears + code:00b6f2/03 + cheat + description:Spear power-ups give 10 spears + code:00b6f2/0a + cheat + description:Spear power-ups give 25 spears + code:00b6f2/19 + cheat + description:Spear and disc power-ups last until end of level (can't pick up other power-ups) + code:00a9c0/f0 + cheat + description:Rhynth meat doesn't add to your maximum health + code:00b6d4/ad + cheat + description:Rhynth meat adds 1/2 as much to maximum health (handicap) + code:00b6c6/04 + cheat + description:Rhynth meat adds 2x as much to maximum health + code:00b6c6/10 + cheat + description:Rhynth meat adds 4x as much to maximum health + code:00b6c6/20 + cheat + description:Rhynth meat adds nothing to your current health + code:00b6dc/00 + cheat + description:Rhynth meat adds half as much to current health + code:00b6dc/04 + cheat + description:Rhynth meat adds 2x as much to current health + code:00b6dc/10 + cheat + description:Rhynth meat adds 4x as much to current health + code:00b6dc/20 + cheat + description:Ptera meat doesn't heal + code:00b709/ad + cheat + description:Blue bottles don't heal at all + code:00b70f/60 + cheat + description:Blue bottles heal 1/2 of your health instead of 1/4 + code:00b71e/ea + cheat + description:Blue bottles heal completely + code:00b728/00 + cheat + description:Light laser can be fired instantly + code:009f68/01 + cheat + description:Medium laser is fired above 3rd line instead of 2nd + code:009f6d/18 + cheat + description:Medium laser can be fired above 1st line + code:009f70/05 + cheat + description:Medium laser can be fired below 1st line - eliminates light laser + code:009f6b/0a + cheat + description:No damage is taken from using heavy laser + code:009f75/18 + cheat + description:Heavy laser can be fired above 2nd line - eliminates medium laser + code:009f72/01 + cheat + description:Start with full health bar on Standard level + code:009a79/ff+009a7b/ff + cheat + description:Start with full health bar on Novice level + code:009a7d/ff+009a7f/ff + cheat + description:Start with full health bar on Advanced level + code:009a81/ff+009a83/ff + cheat + description:Start with full health bar on Expert level + code:009a85/ff+009a87/ff + cheat + description:Start with up to 9 lives on Options screen (selecting downward from 1 goes to 6) + code:04b311/09 + cheat + description:Start with up to 30 continues on Options screen (selecting downward from 0 goes to 3) + code:04b313/1e + cheat + description:Start on level 1-2 + code:02f3fe/02 + cheat + description:Start on level 2-1 + code:02f3fe/03 + cheat + description:Start on level 3-1 + code:02f3fe/04 + cheat + description:Start on level 4-1 + code:02f3fe/05 + cheat + description:Start on level 5-1 + code:02f3fe/06 + cheat + description:Start on level 5-2 + code:02f3fe/07 + cheat + description:Start on level 5-3 + code:02f3fe/08 + cheat + description:Start on level 6-1 + code:02f3fe/09 + cheat + description:Start on level 6-2 + code:02f3fe/0a + cheat + description:Infinite health (alt) + code:7e1024/64 + +cartridge sha256:5c4e283efc338958b8dd45ebd6daf133a9eb280420a98e2e1df358ae0242c366 + name: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 + name: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 + name:American Tail, An - Fievel Goes West (USA) + cheat + description:Invincibility + code:0c840b/d0 + cheat + description:Invincibility (alt) + code:0c8408/a9 + cheat + description:Infinite health + code:0c8442/d0 + cheat + description:Infinite lives + code:00a674/ad + cheat + description:Infinite time + code:00a728/ea + cheat + description:Walk left faster + code:0c8335/fb + cheat + description:Walk right faster + code:0c82f3/04 + cheat + description:Multi-jumps + code:0c8972/00 + +cartridge sha256:626f1fe52b0df0f8ede23f0062cd842321c8dabf14aefdca12e526876ecf383a + name:Animaniacs (USA) + cheat + description:Every coin gives 999 saved slot rotations + code:82abb1/01 + cheat + description:Every second coin gives 99 continues + code:82abff/02 + cheat + description:Every slot machine roll gives 99 continues + code:82abff/05 + cheat + description:Super-jump and float + code:83901c/a9+83901d/08+83901e/01 + 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 + name:Arcade's Greatest Hits - The Atari Collection 1 (USA) + cheat + description:Asteroids - Invincibility + code:838feb/60 + cheat + description:Asteroids - Infinite lives - both players + code:838ff2/b5 + cheat + description:Battlezone - Invincibility + code:8594e4/c0+8594e5/00+8594e6/d0+859c11/60 + cheat + description:Battlezone - Infinite lives + code:8594fe/a5 + cheat + description:Centipede - Infinite lives - both players + code:8286dc/bd + cheat + description:Super Breakout - Infinite serves - both players + code:81ca90/ad + cheat + description:Tempest - Infinite lives - both players + code:86c689/bd + +cartridge sha256:aac9d6f2b8408e4bbdc83ebbba755428caf8021fefbfac7220fb4c772abd9944 + name:Arcana (USA) + cheat + description:Infinite money for weapons + code:03d575/ad + cheat + description:Infinite money for items + code:03d5c9/ad + cheat + description:Infinite money for rooms + code:03de59/ad + cheat + description:Infinite money for elixir + code:03df1c/ad + cheat + description:Level and statistics for all characters in group are increased after each battle + code:07b434/9e + cheat + description:Magic points don't decrease + code:07bf97/bd + cheat + description:Start with 60,000 gold pieces + code:018354/60+018355/ea + cheat + description:Start with 250 gold pieces + code:018354/fa+018355/00 + +cartridge sha256:41084f83e269d46b9d589f11c802a15e84fede57d604c7986053f2858f757adc + name:Archer Maclean's Super Dropzone (Europe) + cheat + description:Infinite lives + code:7e0025/04 + cheat + description:Infinite bombs + code:7e0026/04 + +cartridge sha256:0f474dafe5a26f3dea491d18073dd490d2f1f91313a7e91086565510d38d9a09 + name:Ardy Lightfoot (USA) + cheat + description:Invincibility + code:80e01a/d0+80bf19/d0 + cheat + description:Infinite lives + code:8082b5/ad + cheat + description:Get Stars from anywhere + code:85b493/80+85b494/19 + +cartridge sha256:91f8c264f50051c5c9fadd4df09fbb6ca8b5b54a5ba6652ad133ba103b77317d + name:Aretha (Japan) + cheat + description:No random battles + code:0081a6/80 + cheat + description:Walk anywhere + code:00b6b4/80+00b6a6/00 + +cartridge sha256:d31ea0a6f9b3ee78a724ad500f09e5f534cacf57166ff55198fd703ca1ed6f48 + name:Aretha II - Ariel no Fushigi na Tabi (Japan) + cheat + description:No random battles + code:0083d1/80 + cheat + description:Walk anywhere + code:00b815/80+00b807/00 + +cartridge sha256:14d3ece30898587eda20c661a4a55ec595ba6352ca1f0bfc177542aa0eef0039 + name:Arkanoid - Doh It Again (USA) + cheat + description:Infinite lives + code:8099bd/bd + cheat + description:Paddle hits ball anywhere + code:8192fa/80+8192f4/00 + cheat + description:"S" capsule gives you the longest paddle + code:818dd8/03 + cheat + description:"S" capsule gives you the laser paddle + code:818dd8/04 + cheat + description:Force field lasts until end of level + code:819306/ad + cheat + description:Keep current paddle when you get force field + code:818e87/00 + +cartridge sha256:55e57c5e012583ff0fafd1aee16b3f8269ee2b34fe10f10b93ba0dde72f2b78d + name:Art of Fighting (USA) + cheat + description:Invincibility (except projectiles) + code:c0683a/e0+c0683b/00+c0683c/00 + cheat + description:Infinite health + code:c0e5af/a9+c0e5b0/ef+c0e5b1/8d + cheat + description:Infinite time + code:c0e973/ad + cheat + description:Hit anywhere - both players + code:c06820/80 + +cartridge sha256:59f217912f4dbfb3dd0844f46128e71d6ddd522d7e246eb687000adeaa38d13d + name:Ashita no Joe (Japan) + cheat + description:Hit anywhere - P1 + code:00b66b/00 + cheat + description:Hit anywhere - P2 + code:00b3ca/00 + cheat + description:Invincibility - P1 + code:00b2c0/80 + cheat + description:Invincibility - P2 + code:00b564/80 + +cartridge sha256:d54d2703e474d7f469766d2d095ffcbbcab893e3fe58bbbcc57e24082a44bb40 + name:Asterix (Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:0083b3/d0+0083b5/c5 + cheat + description:Infinite health + code:00fa56/bd + cheat + description:Infinite lives + code:00fa41/bd + 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 + name: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 + name:Axelay (USA) + cheat + description:Invincibility + code:00bb31/d0 + cheat + description:Infinite lives + code:00c0f6/cd + cheat + description:Infinite lives (alt) + code:00c0f6/ad+00bd18/ad + cheat + description:Infinite credits + code:00a470/ad + cheat + description:Don't lose weapon when hit + code:00bf75/bd+00c2ce/bd + cheat + description:Hit anywhere + code:00e4a1/a5+029c09/a5+00e48d/00+00e495/00 + cheat + description:Start with 1 credit + code:008c8f/03 + cheat + description:Start with 2 credits + code:008c8f/04 + cheat + description:Start with 3 credits + code:008c8f/05 + cheat + description:Start with 4 credits + code:008c8f/06 + cheat + description:Start with 6 credits + code:008c8f/08 + cheat + description:Start with 7 credits + code:008c8f/09 + cheat + description:Start with 8 credits + code:008c8f/0a + cheat + description:Start with 9 credits + code:008c8f/0b + cheat + description:Start with 1 life + code:00db61/01 + cheat + description:Start with 2 lives + code:00db61/02 + cheat + description:Start with 5 lives + code:00db61/05 + cheat + description:Start with 7 lives + code:00db61/07 + cheat + description:Start with 9 lives + code:00db61/09 + cheat + description:Start with 15 lives + code:00db61/0f + cheat + description:Start with 25 lives + code:00db61/19 + cheat + description:Start with 50 lives + code:00db61/32 + cheat + description:Start with 75 lives + code:00db61/4b + cheat + description:Start with 99 lives + code:00db61/63 + cheat + description:Start on Stage 2 + code:009f37/a9+009f38/01+009f39/00 + cheat + description:Start on Stage 3 + code:009f37/a9+009f38/02+009f39/00 + cheat + description:Start on Stage 4 + code:009f37/a9+009f38/03+009f39/00 + cheat + description:Start on Stage 5 + code:009f37/a9+009f38/04+009f39/00 + cheat + description:Start on Stage 6 + code:009f37/a9+009f38/05+009f39/00 + 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 + cheat + description:Start a new game to view ending + code:009f67/0c + +cartridge sha256:9e6ebebcf14609c2a38a5f4409d0c8c859949cded70c5b6fd16fd15d9983d9d3 + name:B.O.B. (USA) + cheat + description:Infinite health (P) + code:00d162/ad + cheat + description:Infinite lives + code:0081f5/bd + cheat + description:Infinite lives (alt) + code:0081f5/2c + cheat + description:Infinite time + code:908230/ad + cheat + description:Infinite weapons + code:00eb3d/b9 + cheat + description:Infinite Remotes + code:8daf37/b9 + cheat + description:Infinite Remotes (alt) + code:8daf36/ea + cheat + description:Infinite weapons (except for Flame) + code:00eb3c/ea + cheat + description:Hit anywhere + code:00fad1/00+00fb11/00 + cheat + description:Max weapons on pick-up + code:8da24c/00 + cheat + description:Slow down timer + code:008962/a0 + cheat + description:Speed up timer + code:008962/35 + cheat + description:Start with 20 3-way + code:8dc581/14 + cheat + description:Start with 20 Flame + code:8dc587/14 + cheat + description:Start with 20 Rocket + code:8dc58d/14 + cheat + description:Start with 20 Bolt + code:8dc593/14 + cheat + description:Start with 20 Wave + code:8dc599/14 + cheat + description:Start with 3 Flash Remotes + code:8dc5b6/00 + cheat + description:Start with 3 Shield Remotes + code:8dc5b6/01 + cheat + description:Start with 3 Umbrella Remotes + code:8dc5b6/02 + cheat + description:Start with 3 Helicopter Hat Remotes + code:8dc5b6/04 + cheat + description:Start with 3 Floating Bomb Remotes + code:8dc5b6/05 + cheat + description:Start with 6 of selected remote + code:8dc5b8/06 + cheat + description:Start with 15 of selected remote + code:8dc5b8/0f + cheat + description:Start with 1 life + code:008180/00 + cheat + description:Start with 9 lives + code:008180/08 + cheat + description:Start with 6 lives + code:008180/05 + 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 + name:Ballz 3D - Fighting at Its Ballziest (USA) + cheat + description:Infinite time + code:c05b72/ad+c05b8c/ad + cheat + description:Always fight Kronk + code:c0b3d5/a9+c0b3d6/04+c0b3d7/00 + cheat + description:Always fight Boomer + code:c0b3d5/a9+c0b3d6/08+c0b3d7/00 + cheat + description:Always fight Bruiser + code:c0b3d5/a9+c0b3d6/0c+c0b3d7/00 + cheat + description:Always fight Turbo + code:c0b3d5/a9+c0b3d6/10+c0b3d7/00 + cheat + description:Always fight Tsunami + code:c0b3d5/a9+c0b3d6/14+c0b3d7/00 + cheat + description:Always fight Yoko + code:c0b3d5/a9+c0b3d6/18+c0b3d7/00 + cheat + description:Always fight Divine + code:c0b3d5/a9+c0b3d6/1c+c0b3d7/00 + cheat + description:Always fight Crusher + code:c0b3d5/a9+c0b3d6/20+c0b3d7/00 + cheat + description:Death match + code:c0f6bf/a0 + cheat + description:Start rounds with 10 seconds + code:c033bf/0a + cheat + description:Start rounds with 20 seconds + code:c033bf/14 + cheat + description:Start rounds with 30 seconds + code:c033bf/1e + cheat + description:Start rounds with 40 seconds + code:c033bf/28 + cheat + description:Start rounds with 50 seconds + code:c033bf/32 + cheat + description:Start rounds with 60 seconds + code:c033bf/3c + cheat + description:Start rounds with 70 seconds + code:c033bf/46 + cheat + description:Start with with 1/4 energy + code:c100ae/2f + cheat + description:Start with with 1/2 energy + code:c100ae/5f + cheat + description:Start with with 3/4 energy + code:c100ae/9f + +cartridge sha256:865919b25a9d241c907bcda18b380e3c704f33f4997ad44559046f0f08c4968b + name:Barbie Super Model (USA) + cheat + description:Infinite chances + code:00dc55/ad + +cartridge sha256:fe1ad128313b2b9a47f89cf0d95d4c0cc2cb35a817ac5d915ee6c4d98d47d675 + name:Barkley Shut Up and Jam! (USA) + cheat + description:Infinite time + code:7e0780/47 + +cartridge sha256:e2be173c77bd1957787be36d13334f655e14d32dad99cacb0fd5e5fc65d96fa1 + name:Bassin's Black Bass (USA) + cheat + description:Always catch a 60.32 pound fish + code:03abc8/a9 + cheat + description:Always catch a 75.68 pound fish + code:03abc8/a9+03abca/0e + cheat + description:Always catch a largemouth bass + code:03abb9/a9+03abba/00+03abbb/ea + cheat + description:Always have all lures (open the lure menu, close it, open it again to have all lures) + code:01f0c6/a9+01f0c7/01+01f0c8/9d+01f0cb/29 + +cartridge sha256:db1ac03cc8b7daaa812da239029bcf999b30b2afe1c03d51f7ae849a796617ea + name:Bass Masters Classic - Pro Edition (USA) + cheat + description:Start with $65,380 + code:7e2242/ff + cheat + description:Infinite money + code:7e2242/ff + +cartridge sha256:e36aaba64be016cabc33a2dcf88913341e2edacc722e2a1ebe04eccda2a5d6e7 + name:Batman Forever (USA) + cheat + description:Straight low punches are super strong + code:82d6dd/ff + cheat + description:Straight high punches are super strong + code:82d741/ff + cheat + description:Straight low kicks are super strong + code:82d455/ff + cheat + description:Straight high kicks are super strong + code:82d4ab/ff + cheat + description:Crouching low punches are super strong + code:82d98b/ff + cheat + description:Crouching high punches are super strong + code:82e347/ff + cheat + description:Crouching low kicks are super strong + code:82e311/ff + cheat + description:Crouching high kicks are super strong + code:82e2c5/ff + cheat + description:Straight low punches do no damage + code:82d6dd/00 + cheat + description:Straight high punches do no damage + code:82d741/00 + cheat + description:Straight low kicks do no damage + code:82d455/00 + cheat + description:Straight high kicks do no damage + code:82d4ab/00 + cheat + description:Crouching low punches do no damage + code:82d98b/00 + cheat + description:Crouching high punches do no damage + code:82e347/00 + cheat + description:Crouching low kicks do no damage + code:82e311/00 + cheat + description:Crouching high kicks do no damage + code:82e2c5/00 + cheat + description:Start with half energy after your first life + code:80dca1/20+81adfa/20 + cheat + description:Play as an Inmate + code:a9e3a5/12 + cheat + description:Play as a Clown + code:a9e3a5/14 + cheat + description:Play as Two-Face + code:a9e3a5/18 + cheat + description:Play as a Riddler Thug + code:a9e3a5/1a + cheat + description:Play as the Muscle Riddler + code:a9e3a5/1c + cheat + description:Start with 1 life + code:8098ec/00 + cheat + description:Start with 3 lives + code:8098ec/02 + cheat + description:Start with 10 lives + code:8098ec/09 + 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 + name:Batman Returns (USA) + cheat + description:Invincibility + code:80c9c7/d0+80c035/24 + cheat + description:Infinite health + code:80ca3f/a5 + cheat + description:Infinite lives (3/4 view levels) + code:80c97e/a5 + cheat + description:Infinite special moves + code:80d004/a5 + cheat + description:Protection from some hazards + code:80ca39/a5 + cheat + description:Hit anywhere + code:80eff4/00+82c2ff/00+87f577/00+87f58d/00 + cheat + description:Cape sweep uses up no health + code:80cffd/00 + cheat + description:Spear gun uses up no health + code:80d017/00 + cheat + description:Cape sweep uses up more health + code:80cffd/10 + cheat + description:Spear gun uses up more health + code:80d017/10 + cheat + description:Maximum health from hearts + code:82d7f2/00 + cheat + description:Cape sweep does more damage + code:81ac15/15 + cheat + description:Normal punch does more damage + code:81ac0d/15 + cheat + description:Normal knee does more damage + code:81ac0e/15 + cheat + description:Jump kick does more damage + code:81ac11/15+81ac10/15 + cheat + description:Cape sweep does mega-damage + code:81ac15/30 + cheat + description:Normal punch does mega-damage + code:81ac0d/30 + cheat + description:Normal knee does mega-damage + code:81ac0e/30 + cheat + description:Jump kick does mega-damage + code:81ac11/30+81ac10/30 + cheat + description:Cape sweep does less damage + code:81ac15/02 + cheat + description:Normal punch does less damage + code:81ac0d/02 + cheat + description:Normal knee does less damage + code:81ac0e/02 + cheat + description:Jump kick does less damage + code:81ac11/02+81ac10/02 + cheat + description:Enable stage select + code:8085a4/13+8085a5/86+80a7be/af+9efdb0/ad + cheat + description:Start with 9 + code:8180b5/09 + cheat + description:Start with 6 test tubes + code:80881a/06+80ac40/06 + cheat + description:Start with 9 test tubes + code:80881a/09+80ac40/09 + 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 + name:Batman - Revenge of the Joker (USA) (Proto) + cheat + description:Invincibility + code:81c03a/d0 + cheat + description:Infinite health + code:82fd17/ad + cheat + description:Infinite lives + code:8080e8/bd + cheat + description:Infinite health (alt) + code:7e0353/07+7e0355/07 + cheat + description:Infinite lives (alt) + code:7e0356/03+7e0358/03 + +cartridge sha256:983022203546e031773db0d1af7552c489187954882843f13ff123f09064c1d3 + name:Battle Blaze (USA) + cheat + description:Infinite continues + code:02b47b/ad + 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 + cheat + description:Hit anywhere - both players + code:00f4b9/42+00f4b8/80 + +cartridge sha256:32f42fda0667d9435a2de84c7ce7b067bcbab1164f8f6d837992ad6cfac4f8de + name:Battle Clash (USA) + cheat + description:Infinite health + code:83eb24/ad + cheat + description:Protection from most enemy attacks + code:83eb24/ad + cheat + description:Infinite time + code:818eb7/ad + cheat + description:Weapon charges faster + code:80cd53/05 + cheat + description:Weapon charges much faster + code:80cd53/10 + cheat + description:Once charged, weapon always stays charged + code:80c7c7/60 + cheat + description:Start in Cairo instead of New York + code:88f7f1/ee + cheat + description:Fight Garam at New York + code:81c293/a9+81c295/00+81c294/00 + cheat + description:Fight Scarab at Cairo + code:81c293/a9+81c295/00+81c294/01 + cheat + description:Fight Lorca at London + code:81c293/a9+81c295/00+81c294/02 + cheat + description:Fight Artemis at Andes + code:81c293/a9+81c295/00+81c294/03 + cheat + description:Fight Schneider at Kyoto + code:81c293/a9+81c295/00+81c294/04 + cheat + description:Fight Ivan at Oceania + code:81c293/a9+81c295/00+81c294/05 + cheat + description:Fight Valius at Babel + code:81c293/a9+81c295/00+81c294/06 + cheat + description:Fight Baron at Moonbase Luna + code:81c293/a9+81c295/00+81c294/07 + cheat + description:Fight Thanatos at last stage + code:81c293/a9+81c295/00+81c294/08 + cheat + description:Infinite health - P1 + code:7e15c0/80 + cheat + description:One hit kills + code:7e15a0/00 + +cartridge sha256:36cbc43a3ec85f235ecb6e0d5b134f069b619d3cc51e475427d3fcf8abb6ba44 + name:Battle Zeque Den (Japan) + cheat + description:Invincibility + code:7eb26a/03+81e7ab/1a + cheat + description:Invincibility (alt) + code:7eb26a/03 + cheat + description:Infinite lives + code:81e67f/af + cheat + description:Infinite Special + code:81a2dc/bd + cheat + description:One hit kills + code:818ef8/e0+818ef9/2e+818efa/b2+818efb/d0 + 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 + name:Battletoads-Double Dragon (USA) + cheat + description:Infinite lives + code:0095bb/24 + cheat + description:Enemies have less health + code:8281fa/0f + cheat + description:Abobo has less health + code:829130/2f + cheat + description:Big Blag has less health + code:8296e8/2f + cheat + description:Roper has less health + code:829fc7/03 + cheat + description:Robo-Manus has less health + code:82a376/03 + cheat + description:Start with 2 lives + code:00804e/01 + cheat + description:Start with 10 lives + code:00804e/09 + cheat + description:Start on level 2 with 11 lives + code:008071/00+00808a/a9+00808b/01 + cheat + description:Start on level 3 with 11 lives + code:008071/00+00808a/a9+00808b/02 + cheat + description:Start on level 4 with 11 lives + code:008071/00+00808a/a9+00808b/03 + cheat + description:Start on level 5 with 11 lives + code:008071/00+00808a/a9+00808b/04 + cheat + description:Start on level 6 with 11 lives + code:008071/00+00808a/a9+00808b/05 + cheat + description:Invincibility (blinking) - P1 + code:7e1112/7f + cheat + description:Infinite health - P1 + code:7e003a/2f + cheat + description:Infinite lives - P1 + code:7e0026/05 + cheat + description:Stage select enabled + code:7e00fd/10 + +cartridge sha256:b0dbd4d7e5689c32234e80b0c5362ef67c425ab72d6ddb49d1cb1133ef630ef7 + name:Battletoads in Battlemaniacs (USA) + cheat + description:Invincibility + code:82df4b/d0 + cheat + description:Invincibility in motorcycle levels + code:829f26/ad + cheat + description:Infinite health + code:81b3fb/dd+81b440/dd + cheat + description:Infinite lives + code:81ba85/bd + cheat + description:Infinite lives - both players (except level 2, doesnメt work on falling) + code:81ba85/b5 + cheat + description:Infinite continues - P1 + code:8087ca/a5 + cheat + description:Infinite continues - P2 + code:808798/a5 + cheat + description:Infinite lives when falling + code:82de81/b4 + cheat + description:Longer invincibility after getting hit + code:82df4b/80 + cheat + description:One hit kills + code:81b43b/e0+81b43c/00+81b43d/00+81b440/a9+81b441/ff+81b442/ff+81b443/9d + cheat + description:Take less damage from hits + code:81b440/bd + cheat + description:Protection against most strength level 1 hits + code:80c737/bd + cheat + description:Protection against most strength level 2 hazards + code:81bad4/b5 + cheat + description:Easy finish on motorcycle levels. The turtle will keep going on until the end of the level. + code:82da45/ad + cheat + description:Start with 2 lives + code:008101/01 + cheat + description:Start with 6 lives + code:008101/05 + cheat + description:Start with 10 lives + code:008101/09 + cheat + description:Start with 0 continues + code:00810b/00 + cheat + description:Start with 5 continues + code:00810b/05 + cheat + description:Start with 9 continues + code:00810b/09 + cheat + description:Infinite health - P1 + code:7e108e/0a + cheat + description:Infinite health - P2 + code:7e1090/0a + +cartridge sha256:0960f1de179f90e3d8488dacf09d5fe246fdb314913c370b3698dfdce58aa8ba + name:Bazooka Blitzkrieg (USA) + cheat + description:Immune to most damage + code:809773/2c + cheat + description:Fewer Missiles on pick-up + code:82c1ad/05 + cheat + description:More Missiles on pick-up + code:82c1ad/14 + cheat + description:Only 10 Missiles on pick-up (set Missiles to 10) + code:82c19b/0a+82c19f/0a + cheat + description:30 Missiles allowed + code:82c19b/1e+82c19f/1e + cheat + description:Less energy on pick-up from 'L' pods + code:82c119/02 + cheat + description:More energy on pick-up from 'L' pods + code:82c119/0a + cheat + description:A lot more energy on pick-up from 'L' pods + code:82c119/2f + cheat + description:Infinite health + code:7e0305/ff + cheat + description:Infinite Missiles + code:7e0304/14 + +cartridge sha256:d7271ca08400bbf5ae165b0aaa6e8a8a1b266f72e6e0ae10aae529732a472f7c + name:Beauty and the Beast (USA) + cheat + description:Invincibility (disable to pick up rocks, spikes still do damage) + code:83a34e/ea+83a34f/ea + cheat + description:Invincibility (but you can't pick up objects) + code:818013/d0 + cheat + description:Invincibility after one hit + code:818015/ea + cheat + description:Infinite health + code:83a3b1/ad + cheat + description:Infinite time + code:008e59/ad + cheat + description:Infinite flower time + code:008e79/ad + cheat + description:Infinite continues + code:00f445/ad + cheat + description:Hit anywhere + code:82816d/24+82817f/24+828174/24+828186/24 + cheat + description:Don't take damage from some enemies + code:83a3b1/ea + cheat + description:No loss of light when the candle runs off the screen + code:82acbf/2c + cheat + description:Death flash time is longer + code:838087/ff + +cartridge sha256:15d4fc90cb202a9391718cd40b9f0384165aef03018ed932540e8f7c18b397dd + name:Beavis and Butt-Head (USA) + cheat + description:Start with half health (1st life) + code:0081a1/06 + cheat + description:Start with half health (after 1st life) + code:008365/06 + cheat + description:Almost infinite health + code:02dfa5/ad + cheat + description:Gun power-ups worth 30 + code:82cabc/30 + cheat + description:Gun power-ups worth 5 + code:82cabc/05 + cheat + description:Infinite lives + code:00833d/ad + cheat + description:Start with 2 life + code:0081a9/01 + cheat + description:Start with 4 lives + code:0081a9/03 + cheat + description:Start with 10 lives + code:0081a9/09 + cheat + description:Invincibility after one hit + code:01fbc8/bd + cheat + description:Everyone is invincible, including enemies + code:01fbc7/00+02cd4b/00 + +cartridge sha256:4958eda26f2419f473449017c64121caee5e49c480ffa205422e7dd45cd23e31 + name: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 + name:Beethoven - The Ultimate Canine Caper! (USA) + cheat + description:Infinite health + code:81eb11/bd + cheat + description:Infinite time + code:81dd2d/bd + cheat + description:Infinite lives + code:80abba/bd + 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 + name:Best of the Best - Championship Karate (USA) + cheat + description:Almost infinite health + code:01bf12/08 + cheat + description:Infinite special moves + code:01b409/bd + cheat + description:No special moves - P2 + code:01a6e6/9c + cheat + description:Can play with any boxer (can't use special moves or get password) - P1 + code:00a1e3/02 + cheat + description:Less strength + code:00a1e4/0a + cheat + description:Less resistance + code:00a1e5/0a + cheat + description:Less reflexes + code:00a1e6/0a + cheat + description:More strength + code:00a1e4/32 + cheat + description:More resistance + code:00a1e5/32 + cheat + description:More reflexes + code:00a1e6/32 + cheat + description:Start with 1 special move + code:01a6e2/01 + cheat + description:Start with 8 special moves + code:01a6e2/08 + 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 + name: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 + name:Biker Mice from Mars (USA) + cheat + description:Infinite ammo + code:8398b6/ea + cheat + description:Infinite cash + code:82b65c/bf + cheat + description:Infinite Shield/Armor + code:8092be/bd + cheat + description:Infinite Skull effect + code:8382e0/ad + cheat + description:Infinite Star effect + code:83b855/bd + cheat + description:Infinite Stopwatch effect + code:8384ac/ad + cheat + description:Infinite Money - P1 + code:7efe30/99+7efe31/99 + cheat + description:Infinite Ammo - P1 + code:7e17c6/12 + cheat + description:Infinite Armor - P1 + code:7e179e/03 + cheat + description:Infinite Money - P2 + code:7efe32/99+7efe33/99 + cheat + description:Infinite Ammo - P1 + code:7e1816/12 + cheat + description:Infinite Armor - P1 + code:7e17ee/03 + cheat + description:Always finish 1st + code:7e0928/00 + cheat + description:Max Engine upgrade - P1 + code:7efe38/05 + cheat + description:Max Tire upgrade - P1 + code:7efe3c/05 + cheat + description:Max Armor upgrade - P1 + code:7efe40/05 + cheat + description:Max Shot upgrade - P1 + code:7efe44/05 + cheat + description:Max Engine upgrade - P2 + code:7efe3a/05 + cheat + description:Max Tire upgrade - P2 + code:7efe3e/05 + cheat + description:Max Armor upgrade - P2 + code:7efe42/05 + cheat + description:Max Shot upgrade - P2 + code:7efe46/05 + cheat + description:Have Nitro item - P1 + code:7e17ce/01 + cheat + description:Have Star item - P1 + code:7e17ce/02 + cheat + description:Have Skull item - P1 + code:7e17ce/03 + cheat + description:Have Clock item - P1 + code:7e17ce/04 + cheat + description:Have Money Bag item - P1 + code:7e17ce/05 + cheat + description:Have Nitro item - P2 + code:7e181e/01 + cheat + description:Have Star item - P2 + code:7e181e/02 + cheat + description:Have Skull item - P2 + code:7e181e/03 + cheat + description:Have Clock item - P2 + code:7e181e/04 + cheat + description:Have Money Bag item - P2 + code:7e181e/05 + +cartridge sha256:6fa6b8a8804ff6544bdedf94339a86ba64ce0b6dbf059605abb1cd6f102d3483 + name:Bill Laimbeer's Combat Basketball (USA) + cheat + description:2-point shots worth 3, 3-point shots worth 4 + code:00971b/38 + cheat + description:All shots worth 1 point + code:00971c/69+00971d/01 + cheat + description:All shots worth 3 points + code:00971c/69+00971d/03 + cheat + description:All shots worth 4 points + code:00971c/69+00971d/04 + cheat + description:All shots worth 5 points + code:00971c/69+00971d/05 + cheat + description:All shots worth 6 points + code:00971c/69+00971d/06 + cheat + description:Each half is 0:30 instead of 1:30 + code:00962c/00 + cheat + description:Each half is 2:30 + code:00962c/02 + cheat + description:Each half is 3:30 + code:00962c/03 + cheat + description:Each half is 4:30 + code:00962c/04 + cheat + description:Start with $65,296 instead of $10,000 + code:0aa275/ff + cheat + description:Start with $8,398,608 + code:0aa27a/80 + cheat + description:Start with $16,721,680 + code:0aa27a/ff + 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:0a96f0/ad+0a96f8/ad + cheat + description:Trade players for free + code:0a96f0/ad+0a96f8/ad+0a97f0/80 + cheat + description:Timer continues to count when it is normally stopped (time-out by pressing start) + code:00963c/00 + +cartridge sha256:ec2d91e238c26a5ddf7067d104b3b3e2eaee89255377e1eb6c4df8f301300e64 + name:Bill Walsh College Football (USA) + cheat + description:Cannot be tackled (hold X) + code:c005ea/73+c005ec/30+c005e9/a5+c005eb/0a+c005ed/f5 + +cartridge sha256:de1de85ad549a6aaf0431cceb47cbd07e1f6e81f9e16fd62575305e2c1f06240 + name:BioMetal (USA) + cheat + description:Invincibility (blinking) + code:038400/24 + cheat + description:Infinite lives + code:0386f1/ad + cheat + description:Infinite charge + code:0385d2/ad + cheat + description:Hit anywhere + code:00ddfe/28+00ddfd/80+00de34/a5 + cheat + description:Infinite lives (alt) + code:7e029d/0a + +cartridge sha256:3f030b6c6aa86bc4ab3d39568740d8c6b0ec3422a1964fe1b56e94de47dfa420 + name: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 + name:Bishoujo Senshi Sailor Moon (Japan) + cheat + description:One hit kills + code:c11204/24+c117b2/24+c1185b/24 + cheat + description:Invincibility + code:c14f0e/d0 + cheat + description:Infinite health + code:c11115/b9+c11a5c/a5 + cheat + description:Infinite lives + code:c15067/a5 + cheat + description:Hit anywhere + code:c11188/80 + +cartridge sha256:8860380ae0afa280619fdca8723aed1393485a22bec442880acc75249cab37f4 + name:Bishoujo Senshi Sailor Moon R (Japan) + cheat + description:Invincibility + code:c14f07/d0+c14f0b/d0 + cheat + description:Infinite health + code:c108a2/b9 + cheat + description:Infinite lives + code:c151da/a5 + cheat + description:Infinite Special + code:c14319/a5 + cheat + description:Hit anywhere + code:c1090a/80 + cheat + description:One hit kills + code:c109e7/24+c14c05/24+c11171/24 + +cartridge sha256:328c8f57e2ea371f6fd5b8a9834c56e35eb3bfe710502dd80f370739f9ccb7e1 + name:Blackthorne (USA) + cheat + description:Infinite items (enable after obtaining first item, disable before getting next item, repeat this process) + code:80a984/b5 + cheat + description:Infinite health + code:7e0fc5/18 + cheat + description:3rd slot item mod + code:7e187a/03 + cheat + description:Standard Shotgun + code:7e021c/00 + cheat + description:Unrestricted manual Shotgun without reload (more presses, more shots) + code:7e021c/01 + cheat + description:Very fast automatic Shotgun + code:7e021c/02 + cheat + description:Very fast automatic Shotgun with explosive shells + code:7e021c/03 + cheat + description:Normal automatic Shotgun + code:7e021c/04 + cheat + description:Infinite Iron Keys + code:7e1876/02 + cheat + description:Infinite Potions + code:7e1878/04 + cheat + description:Infinite Hover Bombs + code:7e187a/05 + cheat + description:Infinite Levitators + code:7e187c/06 + cheat + description:Infinite Bridge Keys + code:7e187e/07 + cheat + description:Infinite Remote Wasps + code:7e1880/08 + cheat + description:Infinite Fire Bombs + code:7e1882/0a + +cartridge sha256:0d4e0d134396bd1c7254cdc1da356eb944ca14910b6690f484a75a9c3a8106e7 + name:BlaZeon - The Bio-Cyborg Challenge (USA) + cheat + description:Invincibility + code:01830d/d0 + cheat + description:Infinite lives + code:009028/bd + cheat + description:Infinite lives (alt) + code:009028/ad+00920b/ad + cheat + description:Infinite Atomic Shields - Mars + code:00ac3f/ad + cheat + description:Infinite Hyper Bombs - Neptune + code:00ace6/ad + cheat + description:Hit anywhere + code:00b771/60+00b793/60+00b8cf/ad+00b770/38+00b792/38 + cheat + description:Start with 1 ship + code:008efd/00 + cheat + description:Start with 2 ships + code:008efd/01 + cheat + description:Start with 4 ships + code:008efd/03 + cheat + description:Start with 5 ships + code:008efd/04 + cheat + description:Start with 7 ships + code:008efd/06 + cheat + description:Start with 10 ships + code:008efd/09 + cheat + description:Start with 26 ships + code:008efd/19 + cheat + description:Start on Stage 2 + code:008e01/01 + cheat + description:Start on Stage 3 + code:008e01/02 + cheat + description:Start on Stage 4 + code:008e01/03 + cheat + description:Start on Stage 5 + code:008e01/04 + +cartridge sha256:99f40f06fa4dbeeea4fe67d2de5b4c1bf301bedac1958ba1c239dcaf39b0a998 + name:Blues Brothers, The (USA) + cheat + description:Invincibility + code:8095e8/60 + cheat + description:Infinite health (1P game) + code:80c3e5/bd + cheat + description:Infinite health (2P game) + code:80cdf8/bd + cheat + description:Infinite lives + code:80b718/bd + cheat + description:Infinite time + code:809bee/ad + cheat + description:Infinite Discs + code:80b654/bd + cheat + description:Multi-jump + code:80d667/80+80d652/80 + +cartridge sha256:d50ef11383d78544dbad4d350cfd1486fb28e459e208d1553acdecbd84a808b8 + name:Bobby's World (USA) (Proto) + cheat + description:Invincibility + code:829d30/d0 + cheat + description:Infinite health + code:829daa/bd + cheat + description:Infinite health (alt) + code:7e139b/03 + cheat + description:Infinite lives + code:80d50f/bd + cheat + description:Infinite lives (alt) + code:7e1395/09 + cheat + description:Multi-jump + code:8299ef/00 + +cartridge sha256:854d2492d1cb059749bb0904ca5f92a5eeec09167abf84f7cca4023b1819e4f0 + name:Bonkers (USA) + cheat + description:Invincibility + code:80aa09/d0 + cheat + description:Infinite health + code:80a520/b5 + cheat + description:Infinite bombs + code:80c294/a5 + cheat + description:Infinite lives + code:8086e1/a5 + cheat + description:Infinite dash + code:80b6a1/a5 + cheat + description:Hit anywhere + code:80f965/80+80f966/50 + +cartridge sha256:8f131182b286bd87f12cf4f00453336538ce690d0e1f0972ac0be98df4d48987 + name:Boogerman - A Pick and Flick Adventure (USA) + cheat + description:Infinite health + code:c0113f/a0 + cheat + description:Infinite lives + code:c01049/00 + cheat + description:Infinite Loogies + code:c174ab/00 + cheat + description:Infinite Boogers + code:c173ee/00 + cheat + description:Infinite Belches + code:c17575/00 + cheat + description:Infinite Super Belches + code:c17667/00 + cheat + description:Infinite Farts + code:c17a2c/00 + cheat + description:Infinite Super Farts + code:c17b22/00 + cheat + description:Infinite Chili Belches and Farts + code:c19db0/00 + cheat + description:Infinite Super Chili Belches and Farts + code:c19e9e/00 + cheat + description:Infinite Rocket Farts + code:c118f4/00 + cheat + description:Get chili when hit + code:c11cd1/01 + cheat + description:Get Milk when hit + code:c11ccb/01 + 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 + name:Boxing Legends of the Ring (USA) + cheat + description:Invincibility - P1 + code:8186cb/80 + cheat + description:Invincibility - P2 + code:818f81/80 + cheat + description:Infinite super punches - P1 + code:818f05/ad + cheat + description:Infinite super punches - P2 or CPU + code:81864b/ad + cheat + description:Infinite strength beads + code:81d59c/00+81d658/ad + cheat + description:Infinite time per round + code:009fcf/ad + cheat + description:Hit anywhere - P1 + code:81900a/60+819009/18 + cheat + description:Hit anywhere - P2 + code:818754/60+818753/18 + cheat + description:Blocking disabled - P1 + code:8186d1/00 + cheat + description:Blocking disabled - P2 + code:818f87/00 + cheat + description:Each round is 1 minute + code:80be03/01 + cheat + description:Each round is 2 minutes + code:80be03/02 + cheat + description:Each round is 4 minutes + code:80be03/04 + cheat + description:Each round is 5 minutes + code:80be03/05 + cheat + description:Each round is 6 minutes + code:80be03/06 + cheat + description:Both fighters start with no super punches + code:80ba38/00 + cheat + description:Both fighters start with 2 super punches + code:80ba38/02 + cheat + description:Both fighters start with 3 super punches + code:80ba38/03 + cheat + description:Create a stronger left jab + code:8bfef4/80 + cheat + description:Create a stronger left hook body + code:8bfef6/80 + cheat + description:Create a stronger left hook head + code:8bfef8/80 + cheat + description:Create a stronger left uppercut + code:8bfefa/80 + cheat + description:Create a stronger right cross body + code:8bfefc/80 + cheat + description:Create a stronger right cross head + code:8bfefe/80 + cheat + description:Create a stronger right uppercut + code:8bff00/80 + cheat + description:Start on round 5 + code:80ba1f/ee + cheat + description:Start on round 12 + code:80ba1f/ce + cheat + description:Infinite full stanima + code:7e05af/0f + +cartridge sha256:f4666355e7fea434843dc6d5119673bd6c23e69b884aac0b382ff036997e52b5 + name: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 + name:Brainies, The (Europe) + cheat + description:Timer disable cheat to get score then re-enable + code:7e091c/17 + +cartridge sha256:9885ca148d32c4df6230642bcfa153f7e51b9559415042a831db14d07b3e6c3d + name:Brainies, The (USA) + cheat + description:Infinite time + code:0089d0/ad + cheat + description:Infinite continues + code:0086df/ad + cheat + description:Start with and always have 9 Jokers + code:00a2a6/09 + cheat + description:Start on level 25 + code:0083e6/1a + cheat + description:Start on level 50 + code:0083e6/33 + cheat + description:Start on level 75 + code:0083e6/4c + cheat + description:Start on level 100 + code:0083e6/65 + +cartridge sha256:bbde8b46c7262f9d4a5b3926a00850cb00b4f7711f6421f0adf4e2b0c847a5d6 + name:Bram Stoker's Dracula (USA) + cheat + description:Infinite energy + code:0485e7/ad + cheat + description:Infinite lives + code:0487b2/ad + cheat + description:Infinite pistol ammo + code:03d398/a5 + cheat + description:Infinite shotgun ammo + code:03d28b/a5 + cheat + description:Turbo walking + code:00a2d6/ea + cheat + description:Infinite missile weapon + code:03d43e/a5 + cheat + description:One hit kills all enemies, except bosses + code:0484b4/80 + cheat + description:Freeze most ground enemies + code:00cab8/2c + cheat + description:Freeze most aerial enemies + code:00ca96/2c + cheat + description:Start at the final battle + code:03f9a5/10 + +cartridge sha256:130a74e76369b0ec4d6378a014550921433f1ae1ac1dddffb51f77c9f21a818f + name:Brandish (USA) + cheat + description:Have over 10,000,000 gold + code:307fe8/10 + cheat + description:Sell an item for max gold + code:81bd29/02+81bd28/80 + cheat + description:Luck stays maxed out + code:83e494/80 + cheat + description:Map gets filled when entering a level + code:c244dd/80+c244de/ea + +cartridge sha256:044b61613ed66eae08abd5fa5dcd13b24aab11a942e3309cdff624d198c47440 + name:Brawl Brothers (USA) + cheat + description:Invincibility and infinite special attack + code:8589ed/80+8589ee/01 + cheat + description:Infinite health + code:858b62/c5 + cheat + description:One hit kills on most enemies + code:858a97/ff+858a98/ff+858a9a/24 + cheat + description:Bosses die immediately + code:8589f3/ff+8589f4/ff+8589f6/24 + cheat + description:Hit anywhere - both players + code:85a4da/24+85a4df/24+85a4a1/24+85a500/24+85a4fb/24 + 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 + name:BreakThru! (USA) + cheat + description:Infinite time + code:7e125b/ff + +cartridge sha256:cbc496a7879ba78f32c51c3df4ba1a1a42f17d78d48a39ea9c709d1ad18cb8df + name:Breath of Fire (USA) + cheat + description:9999 EXP after every battle + code:84811f/ee + cheat + description:Infinite usable items in menu + code:94faf2/0f + cheat + description:Infinite Gold + code:87fa6c/bf+87fa73/bf+87faf7/bf + cheat + description:Create a new character at level 5 + code:819612/05 + cheat + description:Create a new character with 153 max HP + code:819614/99 + cheat + description:Create a new character with 153 HP + code:819616/99 + cheat + description:Create a new character with 20 max AP + code:819618/14 + cheat + description:Create a new character with 20 AP + code:81961a/14 + cheat + description:Create a new character with INT at 22 + code:819621/16 + cheat + description:Create a new character with Agility at 22 + code:819622/16 + cheat + description:Create a new character with Fate at 40 + code:819624/28 + cheat + description:Create a new character with strength at 50 + code:81961f/32 + cheat + description:Create a new character with Vigor at 50 + code:819620/32 + cheat + description:Ryu starts with Tri-Rang + code:819630/5f + cheat + description:Ryu starts with EmporSD + code:819630/08 + cheat + description:Ryu starts with DragonSH + code:819632/54 + cheat + description:Ryu starts with LifeAR + code:819634/1d + cheat + description:Ryu starts with DragonHT + code:819636/8a + cheat + description:Nina starts with PowerRP + code:819690/1d + cheat + description:Nina starts with MaskSH + code:819692/53+819693/21 + cheat + description:Nina starts with ClearCL + code:819694/2e + cheat + description:Nina starts with LoveHT + code:819696/78+819697/21 + cheat + description:Bo starts with HeroBW + code:819660/5b + cheat + description:Bo starts with IcyAR + code:819662/11 + cheat + description:Bo starts with CursedHT + code:819664/6b + cheat + description:Ox starts with Mallet + code:8196c0/26 + cheat + description:Ox starts with StarSH + code:8196c2/84 + cheat + description:Ox starts with WorldAR + code:8196c4/25 + cheat + description:Ox starts with CursedHT + code:8196c6/6b + cheat + description:Gobi starts with Sleeper + code:8196f0/38 + cheat + description:Gobi starts with StarSH + code:8196f2/84+8196f3/21 + cheat + description:Gobi starts with SpineCL + code:8196f4/14 + cheat + description:Gobi starts with CursedHT + code:8196f6/6b + cheat + description:Karn starts with DarkDR + code:819720/4c + cheat + description:Karn starts with StarSH + code:819722/84+819723/21 + cheat + description:Karn starts with QuartzAR + code:819724/1f + cheat + description:Karn starts with CursedHT + code:819726/6b + cheat + description:Mogu starts with MystCW + code:819750/3f + cheat + description:Mogu starts with StarSH + code:819752/84+819753/21 + cheat + description:Mogu starts with FlameAR + code:819754/0e + cheat + description:Mogu starts with CursedHT + code:819756/6b+819757/21 + cheat + description:Bleu starts with GlowCN + code:819780/2f + cheat + description:Bleu starts with MaskSH + code:819782/53 + cheat + description:Bleu starts with ClearCL + code:819784/2e + cheat + description:Bleu starts with CursedHT + code:819786/6b + 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 + name:Breath of Fire II (USA) + cheat + description:Infinite HP in battle + code:c213c7/a5 + cheat + description:Infinite AP In menu + code:c38323/bf + cheat + description:Infinite AP In battle + code:c20ac0/b9 + cheat + description:Main character is different + code:c00acc/28+c00acc/27+c00acc/10+c00acc/12+c00acc/14 + cheat + description:Start with 50 HP + code:c00ac6/32 + cheat + description:Start with 100 HP + code:c00ac6/64 + cheat + description:Start with 150 HP + code:c00ac6/96 + cheat + description:Start with 250 HP + code:c00ac6/fa + cheat + description:Start with 500 HP + code:c00ac7/01+c00ac6/f4 + cheat + description:Start with 750 HP + code:c00ac7/02+c00ac6/ee + cheat + description:Start with a lot of HP + code:c00ac7/1f + cheat + description:Start with 50 AP + code:c00aca/32 + cheat + description:Start with 100 AP + code:c00aca/64 + cheat + description:Start with 150 AP + code:c00aca/96 + cheat + description:Start with 250 AP + code:c00aca/fa + cheat + description:Start with 500 AP + code:c00acb/01+c00aca/f4 + cheat + description:Start with 750 AP + code:c00acb/02+c00aca/ee + cheat + description:Start with a lot of AP + code:c00acb/1f + cheat + description:Start with 0 strength + code:c00acd/00 + cheat + description:Start with Mega strength + code:c00acd/ff + cheat + description:Start with 0 stamina + code:c00ace/00 + cheat + description:Start with Mega stamina + code:c00ace/ff + cheat + description:Start with 0 agility + code:c00acf/00 + cheat + description:Start with Mega agility + code:c00acf/ff + cheat + description:Start with 0 wisdom + code:c00ae8/00 + cheat + description:Start with Mega wisdom + code:c00ae8/ff + cheat + description:Start with 0 luck + code:c00ae9/00 + cheat + description:Start with Mega luck + code:c00ae9/ff + cheat + description:Start with Mega EXP + code:c00aec/ff + 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 + name:BS Zelda no Densetsu - Dai-3-wa (Japan) (BS) + cheat + description:Disable the 57 minute time limit + code:cc0005/ea+cc0006/ea+cc0007/80 + +cartridge sha256:811cbc3287c0959e8eb242e817684d36de664ebebc5873a1fa9958693857c438 + name:Bubsy in - Claws Encounters of the Furred Kind (USA) + cheat + description:Infinite lives + code:8e996d/00 + cheat + description:Infinite time + code:809b29/00 + cheat + description:Numbered t-shirts worth one more + code:8281ae/38 + cheat + description:Bogus jump + code:8e8592/52 + cheat + description:Super-jump + code:8e8592/36 + cheat + description:Mega-jump + code:8e8592/2e + cheat + description:Each yarn ball worth 0 + code:828144/00 + cheat + description:Each yarn ball worth 5 + code:828144/05 + cheat + description:Each yarn ball worth 10 + code:828144/10 + cheat + description:Crate of yarn holds 0 instead of 25 + code:828856/00 + cheat + description:Crate of yarn holds 50 + code:828856/50 + cheat + description:Crate of yarn holds 75 + code:828856/75 + cheat + description:Crate of yarn holds 99 + code:828856/99 + cheat + description:Start with 1 life + code:80e022/00 + cheat + description:Start with 5 lives + code:80e022/04 + cheat + description:Start with 25 lives + code:80e022/24 + cheat + description:Start with 50 lives + code:80e022/50 + cheat + description:Start with 75 lives + code:80e022/75 + cheat + description:Start on chapter 2 + code:87800f/01 + cheat + description:Start on chapter 3 + code:87800f/02 + cheat + description:Start on chapter 4 + code:87800f/03 + cheat + description:Start on chapter 5 + code:87800f/04 + cheat + description:Start on chapter 6 + code:87800f/05 + cheat + description:Start on chapter 7 + code:87800f/06 + cheat + description:Start on chapter 8 + code:87800f/08 + cheat + description:Start on chapter 9 + code:87800f/0a + cheat + description:Start on chapter 10 + code:87800f/0c + cheat + description:Start on chapter 11 + code:87800f/0d + cheat + description:Start on chapter 12 + code:87800f/0e + cheat + description:Start on chapter 13 + code:87800f/0f + cheat + description:Start on chapter 14 + code:87800f/10 + cheat + description:Start on Chapter 15 + code:87800f/11 + cheat + description:Start on Chapter 16 + code:87800f/12 + +cartridge sha256:2357d344af77d25dda030520ce203045fd9060f83e3b9609a228dba859d9017b + name:Bubsy II (USA) + cheat + description:Invincibility + code:c0f575/8d + cheat + description:Infinite health + code:c00b70/b1 + cheat + description:Infinite lives + code:c004b3/ad + cheat + description:Infinite time in most main levels + code:c06e30/ad+c06e1f/ad + cheat + description:Infinite time in some bonus levels + code:c070a9/ad + cheat + description:Infinite Warp Holes + code:c101f8/ad + cheat + description:Infinite Diving Suits + code:c061df/ad + cheat + description:Infinite Smart Bombs + code:c13060/ad + cheat + description:Infinite ammo for Nerf Gun + code:c12d3a/ad + cheat + description:Infinite health (alt) + code:7e1188/04 + cheat + description:Infinite lives (alt) + code:7e3422/09 + +cartridge sha256:49020695a017acc3dfadea97a60e28609e583571f69c5abeb3c6b1c2db8113fa + name:Bugs Bunny - Rabbit Rampage (USA) + cheat + description:Invincibility + code:8085cf/d0 + cheat + description:Infinite energy + code:80b4a7/ad + cheat + description:Infinite lives + code:80cfe1/00 + cheat + description:Infinite lives (alt) + code:80cfe3/ad + cheat + description:Take minimal damage + code:80b4a7/ce + cheat + description:Full energy from carrots + code:80b4be/00 + cheat + description:Moon jumping Bugs + code:809929/14 + cheat + description:Super-jumping Bugs + code:809929/40+809930/f4 + cheat + description:Start and continue with 10 lives + code:808241/0a + cheat + description:Start and continue with 2 lives + code:808241/02 + +cartridge sha256:ba4f31353e0e1233b574391ad97a80901d7de212e2c55d7be2af11a9a57c8225 + name:Bulls vs Blazers and the NBA Playoffs (USA) + cheat + description:Never miss a shot + code:84828a/00 + +cartridge sha256:d6f6c30732dae8d00cd83628c3156acbdf26f99df701f779522e21de74dae5fe + name:Bust-A-Move (USA) + cheat + description:Infinite continues + code:0fb467/ad + cheat + description:Infinite time to shoot each ball + code:00ebbe/ea + cheat + description:Always get max bonus in shooting rounds + code:00bcea/ea + cheat + description:Shot guide is always on (new 1P game) + code:00b993/ee + cheat + description:Shot guide is always on (password game) + code:00b90f/ee + cheat + description:Shot guide is always on ("challenge record" mode) + code:05e8ff/ee + +cartridge sha256:9590110a990e90f525d5c8d70fc2a3da10879378003173b6761afb8bf042ee0d + name:Capcom's MVP Football (USA) + cheat + description:Cannot be tackled (hold B) + code:01c4e5/e0+01c4e4/30+01c4e1/ad+01c4e2/07+01c4e3/13 + +cartridge sha256:2a117951adcfbc4298763673a834d502c3f7a3964db1e59650f113c07bb831fb + name:Captain America and the Avengers (USA) + cheat + description:Invincibility - both players + code:81eab7/60+81c2c1/80+81c382/bd + cheat + description:Infinite lives - both players + code:81b3eb/ad + 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 + cheat + description:Hit anywhere + code:81b1f6/ad+81b1f8/0a+81b1f7/fa+81b1f9/f0 + +cartridge sha256:d9b7f9356be0780f0037093a86ef8450f15e569cbd3680073d1cd345dfadb709 + name:Captain Commando (USA) + cheat + description:Invincibility - p1 + code:c028f4/a9+c028f5/04+c028f6/9d + cheat + description:Hit anywhere (throws are disabled) + code:c0126a/80+c01458/80+c014c1/80+c01459/57 + cheat + description:One hit kills - Both players + code:c0152c/38+c0152d/e9+c0152e/80 + 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 + name: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 + name: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 + name:Carrier Aces (USA) + cheat + description:Invincibility (works for dogfights and ship fire) + code:00f60d/00+00f2f8/80 + cheat + description:Infinite fuel + code:009ae6/ad + cheat + description:Infinite rockets + code:00a85e/ea + +cartridge sha256:b9b982cd8f91c51089d49b550f11882b1ee785ebddcb7355cfc465916d61a042 + name:Casper (USA) + cheat + description:Infinite lives + code:9dd970/ad + cheat + description:Infinite health + code:9dd966/ad + cheat + description:Infinite health (alt) + code:7e1ab7/06 + cheat + description:Have all items and 5 lives after you leave the first room + code:88caa0/d0 + cheat + description:Do not need the girl in the room to transform + code:7e1a47/00 + +cartridge sha256:367725a149a471411e4f72ad77603b61fb101c9cab4521be5647e13708cc97ba + name:Castlevania - Dracula X (USA) + cheat + description:Invincibility + code:848251/d0 + cheat + description:Invincibility after one hit + code:848253/a5 + cheat + description:Infinite health + code:84850c/a5 + cheat + description:Infinite lives + code:80cc1f/a5 + cheat + description:All hearts worth 99 + code:83d974/d0+83d975/00 + cheat + description:Keep sub-weapon after dying + code:80cc2c/a5 + cheat + description:Keep sub-weapon after continue + code:80b57c/a5 + cheat + description:Item Crash doesn't use hearts + code:84cb81/a5 + cheat + description:Hit anywhere + code:83db48/00+83db29/00 + cheat + description:Small hearts worth 0 + code:83d95e/00 + cheat + description:Small hearts worth 10 + code:83d95e/10 + cheat + description:Small hearts worth 25 + code:83d95e/25 + cheat + description:No Invincibility after getting hit + code:848616/00 + cheat + description:More invincibility after getting hit + code:848616/ff + cheat + description:Super jump + code:84b23e/f9 + cheat + description:Super-Duper jump + code:84b23e/f8 + cheat + description:Mega-jump + code:86ba3e/f7 + cheat + description:Have the Axe + code:7e00a4/01 + cheat + description:Have the Cross + code:7e00a4/02 + cheat + description:Have the Holy Water + code:7e00a4/03 + cheat + description:Have the Knife + code:7e00a4/04 + cheat + description:Have the Clock + code:7e00a4/05 + cheat + description:Have the Key + code:7e00a4/06 + cheat + description:Start with half energy + code:80dd6d/20 + cheat + description:Start with 1/4 energy + code:80dd6d/12 + cheat + description:Start with 3/4 energy + code:80dd6d/30 + cheat + description:Start with 99 hearts + code:80b56d/80 + cheat + description:Start with 50 hearts + code:80b56d/50 + cheat + description:Start with 25 hearts + code:80b56d/25 + cheat + description:Start with 1 life + code:80b572/00 + cheat + description:Start with 10 lives + code:80b572/09 + cheat + description:Start with 25 lives + code:80b572/24 + cheat + description:Start with 50 lives + code:80b572/49 + cheat + description:Start with 99 lives + code:80b572/99 + cheat + description:Start with 25 hearts after you die + code:80cc28/25 + cheat + description:Start with 50 hearts after you die + code:80cc28/50 + cheat + description:Start with 99 hearts after you die + code:80cc28/99 + cheat + description:Start on level 2 + code:7e0078/01 + cheat + description:Start on level 3 + code:7e0078/02 + cheat + description:Start on level 4 + code:7e0078/03 + cheat + description:Start on level 5 + code:7e0078/04 + cheat + description:Start on level 6 + code:7e0078/05 + cheat + description:Start on level 7 + code:7e0078/06 + +cartridge sha256:f6e308d437f89059986d779d1b5b7a30999b7a819108da91bd313f25e231c3a8 + name:Chaos Seed - Feng Shui Kairouki (Japan) + cheat + description:Invincibility + code:c35a85/af + cheat + description:Infinite time + code:c49da4/ad + +cartridge sha256:aa69d4e19c2eb206fe88eba65994c830256c220e5506f59824aefa0a75dd44d5 + name:Chavez (USA) + cheat + description:Infinite time + code:7e1f93/15 + +cartridge sha256:ee0e51d922d1cf8abe3dfc6b0d84a988a6635dc96b2a96962007c41aaa542774 + name:Chessmaster, The (USA) + cheat + description:White player's timer is stopped + code:00a43e/a5 + cheat + description:Black player's timer is stopped + code:00a454/a5 + cheat + description:Timers count 2x as slow + code:00a42a/78 + cheat + description:Timers count 3x times as slow + code:00a42a/b4 + cheat + description:Timers count 2x as fast + code:00a42a/1e + cheat + description:Timers count 3x times as fast + code:00a42a/14 + +cartridge sha256:c7e7df8932bf0056aa530f3dc3c913c1171a359af4c197094c2b972946dc6051 + name:Chester Cheetah - Too Cool to Fool (USA) + cheat + description:Invincibility (blinking) (you may freeze if you get the guitar and fall in water) + code:018548/ea + cheat + description:Infinite life points + code:019512/ea + cheat + description:Infinite credits + code:008918/cd + cheat + description:Badges worth 5 + code:02847c/05 + cheat + description:Badges worth 25 + code:02847c/25 + cheat + description:Badges worth 50 + code:02847c/50 + cheat + description:Start with 2 life points + code:018454/02 + cheat + description:Start with 0 life points + code:018454/00 + +cartridge sha256:21a2aa488cb8140ca318f7d1f513103d14e758181aa336a594097d32ba0a7587 + name:Chester Cheetah - Wild Wild Quest (USA) + cheat + description:Invincibility (once you eat a bag of Cheetos) + code:00aea1/ae + cheat + description:Infinite Cheetos bags (once you collect one) + code:00b8d4/ad + cheat + description:Infinite time + code:0093db/ad + cheat + description:Infinte lives + code:0094af/ad + +cartridge sha256:9a064b67f522b75b82d0857519c0e33b4dbbe494c2ef79a44fdc913d605d0b26 + name:Choplifter III - Rescue-Survive (USA) + cheat + description:Have all weapons and infinte ammo + code:808e33/00+808e46/00 + cheat + description:Infinite secondary weapons + code:808f48/ea + cheat + description:Infinite choppers + code:808d0e/ad + cheat + description:Chopper can carry 30 hostages + code:8fab31/1e+8fad65/1e + cheat + description:Invincibility + code:7e0ceb/5a + +cartridge sha256:224572832b988f31a81c907f751f0292f5702a3acea5866ce6742387c7c6239d + name:Choujikuu Yousai Macross - Scrambled Valkyrie (Japan) + cheat + description:Infinite health + code:8088b6/ad+80885f/ad + cheat + description:Infinite absorb charge + code:819ad8/ad + cheat + description:Hit anywhere + code:808f94/00+808f7a/00+808f88/00 + cheat + description:Invincibility + code:7e0a90/ff + cheat + description:Infinite continues + code:7e02aa/09 + +cartridge sha256:06d1c2b06b716052c5596aaa0c2e5632a027fee1a9a28439e509f813c30829a9 + name:Chrono Trigger (USA) + cheat + description:Party does not lose health from attacks (nor do some enemies) + code:c1eca0/ea + cheat + description:Use "organize" to get 90 of all items + code:c2ab8e/98+c2ab9c/00+c2ab9e/5a + cheat + description:Maxed out abilities for all characters + code:c1f79b/87 + cheat + description:Attacks cause 9999 damage (including enemy attacks) + code:c1dce9/9e + cheat + description:Can open sealed chests + code:c064ad/80 + cheat + description:Can open sealed doors + code:c0644c/80 + cheat + description:All portals open + code:7f00a6/07 + cheat + description:Have all cats + code:7f0053/ff + cheat + description:Have all clones + code:7f005e/ff + cheat + description:Have all factory dolls + code:7f013c/c7 + cheat + description:Have all PoYoZo's + code:7f005d/ff + cheat + description:Start with a higher max HP + code:cc0005/ff + cheat + description:Start with a higher max MP + code:cc0009/8e + cheat + description:Start with max power + code:cc000b/90 + cheat + description:Start with max stamina + code:cc000c/90 + cheat + description:Start with max speed + code:cc000d/90 + cheat + description:Start with max magic + code:cc000e/90 + cheat + description:Start with max hit ratio + code:cc000f/90 + cheat + description:Start with max evade + code:cc0010/90 + cheat + description:Start with max magic defense + code:cc0011/90 + 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 Silver Points + code:7f0052/ff + cheat + description:Infinite Speed Boosts + code:7e009a/03 + cheat + description:Instantly enable next Speed Boost + code:7e00ba/00 + +cartridge sha256:63ab79e86ea13e2cf9bb67aec971febb68450db9865b00b5f412610653822393 + name:Chuck Rock (USA) + cheat + description:Infinite health + code:00c36d/a5 + cheat + description:Infinite lives + code:00c395/a5 + cheat + description:Hit anywhere + code:00c1a9/00+00c1fe/00 + cheat + description:Jump higher + code:00a35c/34 + cheat + description:Super-jump + code:00a35c/25 + cheat + description:Mega-jump + code:00a35c/17 + cheat + description:Invincibility + code:7e0baa/25 + +cartridge sha256:8b7525b2aa30cbea9e3deee601dd26e0100b8169c1948f19866be15cae0ac00d + name:Clay Fighter (USA) + cheat + description:Infinite health - P1 + code:da4095/ad+da738f/ad + cheat + description:Enable Blob's Bomb move (away, away + down, down, towards + down, towards, punch) + code:00b442/8d + cheat + description:Always fight Bad Mr. Frosty after 1st match + code:da2ecc/00+db5faf/00 + cheat + description:Always fight Taffy after 1st match + code:da2ecc/00+db5faf/01 + cheat + description:Always fight Tiny after 1st match + code:da2ecc/00+db5faf/02 + cheat + description:Always fight The Blob after 1st match + code:da2ecc/00+db5faf/03 + cheat + description:Always fight Blue Suede Goo after 1st match + code:da2ecc/00+db5faf/04 + cheat + description:Always fight Ickybod Clay after 1st match + code:da2ecc/00+db5faf/05 + cheat + description:Always fight Helga after 1st match + code:da2ecc/00+db5faf/06 + cheat + description:Always fight Bonker after 1st match + code:da2ecc/00+db5faf/07 + cheat + description:Always fight N. Boss after 1st match + code:da2ecc/00+db5faf/08 + cheat + description:Start with 1/6 health - 1st round + code:db1f3e/10 + cheat + description:Start with 1/3 health - 1st round + code:db1f3e/20 + cheat + description:Start with 1/2 health - 1st round + code:db1f3e/30 + cheat + description:Start with 2/3 health - 1st round + code:db1f3e/40 + cheat + description:Start with 5/6 health - 1st round + code:db1f3e/50 + cheat + description:Start with 1/6 health - 2nd and later rounds + code:da2bc1/10 + cheat + description:Start with 1/3 health - 2nd and later rounds + code:da2bc1/20 + cheat + description:Start with 1/2 health - 2nd and later rounds + code:da2bc1/30 + cheat + description:Start with 2/3 health - 2nd and later rounds + code:da2bc1/40 + cheat + description:Start with 5/6 health - 2nd and later rounds + code:da2bc1/50 + cheat + description:Bad Mr. Frosty's Brutal Punches do more damage + code:db278a/30+db278b/30+db278c/30+db278d/30+db278e/30 + cheat + description:Bad Mr. Frosty's Medium Punches do more damage + code:db278f/30+db2790/30+db2791/30+db2792/30+db2793/30 + cheat + description:Bad Mr. Frosty's Quick Punches do more damage + code:db2794/30+db2795/30+db2796/30+db2797/30+db2798/30 + cheat + description:Bad Mr. Frosty's Brutal Kicks do more damage + code:db2799/30+db279a/30+db279b/30+db279c/30+db279d/30 + cheat + description:Bad Mr. Frosty's Medium Kicks do more damage + code:db279e/30+db279f/30+db27a0/30+db27a1/30+db27a2/30 + cheat + description:Bad Mr. Frosty's Quick Kicks do more damage + code:db27a3/30+db27a4/30+db27a5/30+db27a6/30+db27a7/30 + cheat + description:Bad Mr. Frosty's Snow Ball (all punches) does more damage + code:db27a8/30 + cheat + description:Taffy's Brutal Punches do more damage + code:db27b2/30+db27b3/30+db27b4/30+db27b5/30+db27b6/30 + cheat + description:Taffy's Medium Punches do more damage + code:db27b7/30+db27b8/30+db27b9/30+db27ba/30+db27bb/30 + cheat + description:Taffy's Quick Punches do more damage + code:db27bc/30+db27bd/30+db27be/30+db27bf/30+db27c0/30 + cheat + description:Taffy's Brutal Kicks do more damage + code:db27c1/30+db27c2/30+db27c3/30+db27c4/30+db27c5/30 + cheat + description:Taffy's Medium kick does more damage + code:db27c6/30+db27c7/30+db27c8/30+db27c9/30+db27ca/30 + cheat + description:Taffy's Quick Kicks do more damage (not in crouch) + code:db27cb/30+db27cc/30+db28cd/30+db27ce/30+db27cf/30 + cheat + description:Taffy's Whack (all punches) does more damage + code:db27d5/30 + cheat + description:Taffy's Whack (all kicks) does more damage + code:db27d6/30 + cheat + description:Tiny's Brutal Punches do more damage + code:db27da/30+db27db/30+db27dc/30+db27dd/30+db27de/30 + cheat + description:Tiny's Medium Punches do more damage + code:db27df/30+db27e0/30+db27e1/30+db27e2/30+db27e3/30 + cheat + description:Tiny's Quick Punches do more damage + code:db27e4/30+db27e5/30+db27e6/30+db27e7/30+db27e8/30 + cheat + description:Tiny's Brutal Kicks do more damage + code:db27e9/30+db27ea/30+db27eb/30+db27ec/30+db27ed/30 + cheat + description:Tiny's Medium Kicks do more damage + code:db27ee/30+db27ef/30+db27f0/30+db27f1/30+db27f2/30 + cheat + description:Tiny's Quick Kicks do more damage + code:db27f3/30+db27f4/30+db27f5/30+db27f6/30+db27f7/30 + cheat + description:Tiny's Medicine Ball Does more damage + code:db27f8/30 + cheat + description:Tiny's Sucker Punch does more damage + code:db27fd/30 + cheat + description:Blob's Brutal Punches do more damage + code:db2802/30+db2803/30+db2804/30+db2805/30+db2806/30 + cheat + description:Blob's Medium Punches do more damage + code:db2807/30+db2808/30+db2809/30+db280a/30+db280b/30 + cheat + description:Blob's Quick Punches do more damage + code:db280c/30+db280d/30+db280e/30+db280f/30+db2810/30 + cheat + description:Blob's Brutal kick does more damage + code:db2811/30+db2812/30+db2813/30+db2814/30+db2815/30 + cheat + description:Blob's Medium Kicks do more damage + code:db2816/30+db2817/30+db2818/30+db2819/30+db281a/30 + cheat + description:Blob's Quick Kicks do more damage + code:db281b/30+db281c/30+db281d/30+db281e/30+db281f/30 + cheat + description:Blue Suede Goo's Brutal Punches do more damage + code:db282a/30+db282b/30+db282c/30+db282d/30+db282e/30 + cheat + description:Blue Suede Goo's Medium Punches do more damage + code:db282f/30+db2830/30+db2831/30+db2832/30+db2833/30 + cheat + description:Blue Suede Goo's Quick Punches do more damage + code:db2834/30+db2835/30+db2836/30+db2837/30+db2838/30 + cheat + description:Blue Suede Goo's Brutal Kicks do more damage + code:db2839/30+db283a/30+db283b/30+db283c/30+db283d/30 + cheat + description:Blue Suede Goo's Medium Kicks do more damage + code:db283e/30+db283f/30+db2840/30+db2841/30+db2842/30 + cheat + description:Blue Suede Goo's Quick Kicks do more damage + code:db2843/30+db2844/30+db2845/30+db2846/30+db2847/30 + cheat + description:Ickybod Clay's Brutal Punches do more damage + code:db2852/30+db2853/30+db2854/30+db2855/30+db2856/30 + cheat + description:Ickybod Clay's Medium Punches do more damage + code:db2857/30+db2858/30+db2859/30+db285a/30+db285b/30 + cheat + description:Ickybod Clay's Quick Punches do more damage + code:db285c/30+db285d/30+db285e/30+db285f/30+db2860/30 + cheat + description:Ickybod Clay's Brutal Kicks do more damage + code:db2861/30+db2862/30+db2863/30+db2864/30+db2865/30 + cheat + description:Ickybod Clay's Medium Kicks do more damage + code:db2866/30+db2867/30+db2868/30+db2869/30+db286a/30 + cheat + description:Ickybod Clay's Quick Kicks do more damage + code:db286b/30+db286c/30+db286d/30+db286e/30+db286f/30 + cheat + description:Ickybod Clay's Ecto Punch does more damage + code:db2871/30 + cheat + description:Helga's Brutal Punches do more damage + code:db287a/30+db287b/30+db287c/30+db287d/30+db287e/30 + cheat + description:Helga's Medium Punches do more damage + code:db287f/30+db2880/30+db2881/30+db2882/30+db2883/30 + cheat + description:Helga's Quick Punches do more damage + code:db2884/30+db2885/30+db2886/30+db2887/30+db2888/30 + cheat + description:Helga's Brutal Kicks do more damage + code:db2889/30+db288a/30+db288b/30+db288c/30+db288d/30 + cheat + description:Helga's Medium Kicks do more damage + code:db288e/30+db288f/30+db2890/30+db2891/30+db2892/30 + cheat + description:Helga's Quick Kicks do more damage (not far away) + code:db2983/30+db2894/30+db2895/30+db2896/30+db2897/30 + cheat + description:Helga's Viking Ram does more damage + code:db289a/30 + cheat + description:Bonker's Brutal Punches do more damage + code:db28a2/30+db28a3/30+db28a4/30+db28a5/30+db28a6/30 + cheat + description:Bonker's Medium Punches do more damage + code:db28a7/30+db28a8/30+db28a9/30+db28aa/30+db28ab/30 + cheat + description:Bonker's Quick Punches do more damage + code:db28ac/30+db28ad/30+db28ae/30+db28af/30+db28b0/30 + cheat + description:Bonker's Brutal Kicks do more damage + code:db28b1/30+db28b2/30+db28b3/30+db28b4/30+db28b5/30 + cheat + description:Bonker's Medium Kicks do more damage + code:db28b6/30+db28b7/30+db28b8/30+db28b9/30+db28ba/30 + cheat + description:Bonker's Quick Kicks do more damage + code:db28bb/30+db28bc/30+db28bd/30+db28be/30+db28bf/30 + cheat + description:Bonker's Cutting Cartwheel does more damage + code:db28c0/30 + +cartridge sha256:2d40c86bc19d85555bf2672acf515b04dbf56a6a59b29ad503e672310b0fae3b + name:Clay Fighter 2 - Judgment Clay (USA) + cheat + description:Select more speed in options + code:c14bbb/20 + cheat + description:Select more difficulty in options + code:c14b98/09 + cheat + description:Both players jump off the screen + code:c07f53/b1 + cheat + description:Infinite health and time + code:c07862/a9+c07865/8d+c07866/28+c07867/18 + cheat + description:Blob - Blob spit kills + code:cd44af/ff + cheat + description:Blob - Buzz saw kills + code:cd44f8/ff + cheat + description:Blob - Rocket-anvil attack kills + code:cd455e/ff + cheat + description:Hoppy - Spinning carrot kills + code:ce9940/ff + cheat + description:Hoppy - Spin kick towards (special move) kills + code:ce9996/ff + cheat + description:Octo - Brutal cartwheel kills (when close) + code:cd6dae/ff + cheat + description:Octo - Ground spin kills + code:cd6e73/ff + +cartridge sha256:1d19e7fbe32eb26181c95fcbb028a5d64797ab65b86568eb059c60b8acf0d702 + name:Claymates (USA) (Sample) + cheat + description:Invincibility + code:cd0225/ad + cheat + description:Infinite time + code:cd678c/ad + cheat + description:Multi-jump (tap jump button) + code:cd06cf/b5 + cheat + description:Infinite lives + code:cd66b8/ad + +cartridge sha256:e5980b990605a9c91fa89101c440b2ec9993329296ba09a9538042d724a080fb + name:Cliffhanger (USA) + cheat + description:Invincibility + code:81894e/f0 + cheat + description:Infinite health + code:81b4fb/ad + cheat + description:Infinite ammo + code:81af0b/ad + cheat + description:Infinite lives + code:81b592/ea + cheat + description:Hit anywhere + code:81b216/00 + cheat + description:One hit kills on normal enemies + code:8297a6/a9+8297a7/01 + cheat + description:Stop snow avalanche (run into it) + code:81b4d2/6b + +cartridge sha256:03f6c69aef92d36b5ea25a6023368da0e1da9fa160e8316ebd533d4f358ffacf + name:Clue (USA) + cheat + description:Always roll a 1 + code:009da1/a9+009da3/ea+009da2/00 + cheat + description:Always roll a 2 + code:009da1/a9+009da3/ea+009da2/01 + cheat + description:Always roll a 3 + code:009da1/a9+009da3/ea+009da2/02 + cheat + description:Always roll a 4 + code:009da1/a9+009da3/ea+009da2/03 + cheat + description:Always roll a 5 + code:009da1/a9+009da3/ea+009da2/04 + cheat + description:Always roll a 6 + code:009da1/a9+009da3/ea+009da2/05 + cheat + description:Allow no interrogations instead of 2 + code:0098ca/90 + cheat + description:Allow only 1 interrogation + code:0098c8/01 + cheat + description:Allow 3 interrogations + code:0098c8/03 + cheat + description:Allow 4 interrogations + code:0098c8/04 + cheat + description:Allow 5 interrogations + code:0098c8/05 + cheat + description:Infinite interrogations + code:00b5ed/b9 + +cartridge sha256:5536cea2da39f2572abe3b0fcf71f8fcd981376b470b174969772aae4a7a1845 + name:College Football USA 97 (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:b0be35a0d5e500f4fffca5f2940e0ec52c81ce99dacd773c3ca9cf92f592d943 + name:College Slam (USA) + cheat + description:Infinite Shot Clock + code:7e0db1/03+7e0db3/05 + cheat + description:Unlock Extra Teams + code:7e2444/01 + cheat + description:Display Shot% Power-up + code:7e0b30/01 + cheat + description:Slippery Court Power-up + code:7e0b32/01 + cheat + description:Infinite Turbo - P1 + code:7e078a/20 + cheat + description:Infinite Turbo - P2 + code:7e088a/20 + cheat + description:Infinite Turbo - P3 + code:7e098a/20 + cheat + description:Infinite Turbo - P4 + code:7e0a8a/20 + cheat + description:Power Push Power-up - P1 + code:7e07ee/01 + cheat + description:Power Push Power-up - P2 + code:7e08ee/01 + cheat + description:Power Push Power-up - P3 + code:7e09ee/01 + cheat + description:Power Push Power-up - P4 + code:7e0aee/01 + cheat + description:3-Point Power-up - P1 + code:7e07ee/02 + cheat + description:3-Point Power-up - P2 + code:7e08ee/02 + cheat + description:3-Point Power-up - P3 + code:7e09ee/02 + cheat + description:3-Point Power-up - P4 + code:7e0aee/02 + cheat + description:Infinite Turbo Power-up - P1 + code:7e07ee/04 + cheat + description:Infinite Turbo Power-up - P2 + code:7e08ee/04 + cheat + description:Infinite Turbo Power-up - P3 + code:7e09ee/04 + cheat + description:Infinite Turbo Power-up - P4 + code:7e0aee/04 + cheat + description:On-Fire Power-up - P1 + code:7e07ee/08 + cheat + description:On-Fire Power-up - P2 + code:7e08ee/08 + cheat + description:On-Fire Power-up - P3 + code:7e09ee/08 + cheat + description:On-Fire Power-up - P4 + code:7e0aee/08 + cheat + description:Super Dunk Power-up - P1 + code:7e07ee/10 + cheat + description:Super Dunk Power-up - P2 + code:7e08ee/10 + cheat + description:Super Dunk Power-up - P3 + code:7e09ee/10 + cheat + description:Super Dunk Power-up - P4 + code:7e0aee/10 + cheat + description:Max Power Power-up - P1 + code:7e07ee/20 + cheat + description:Max Power Power-up - P2 + code:7e08ee/20 + cheat + description:Max Power Power-up - P3 + code:7e09ee/20 + cheat + description:Max Power Power-up - P4 + code:7e0aee/20 + cheat + description:Goaltending Power-up - P1 + code:7e07ee/40 + cheat + description:Goaltending Power-up - P2 + code:7e08ee/40 + cheat + description:Goaltending Power-up - P3 + code:7e09ee/40 + cheat + description:Goaltending Power-up - P4 + code:7e0aee/40 + cheat + description:Quick Hands Power-up - P1 + code:7e07ee/80 + cheat + description:Quick Hands Power-up - P2 + code:7e08ee/80 + cheat + description:Quick Hands Power-up - P3 + code:7e09ee/80 + cheat + description:Quick Hands Power-up - P4 + code:7e0aee/80 + cheat + description:Offense Power-up - P1 + code:7e07ef/01 + cheat + description:Offense Power-up - P2 + code:7e08ef/01 + cheat + description:Offense Power-up - P3 + code:7e09ef/01 + cheat + description:Offense Power-up - P4 + code:7e0aef/01 + cheat + description:Super Speed Power-up - P1 + code:7e07ef/02 + cheat + description:Super Speed Power-up - P2 + code:7e08ef/02 + cheat + description:Super Speed Power-up - P3 + code:7e09ef/02 + cheat + description:Super Speed Power-up - P4 + code:7e0aef/02 + cheat + description:Knockdown Both Opponents Power-up - P1 + code:7e07ef/04 + cheat + description:Knockdown Both Opponents Power-up - P2 + code:7e08ef/04 + cheat + description:Knockdown Both Opponents Power-up - P3 + code:7e09ef/04 + cheat + description:Knockdown Both Opponents Power-up - P4 + code:7e0aef/04 + cheat + description:Teleport Pass Power-up - P1 + code:7e07ef/08 + cheat + description:Teleport Pass Power-up - P2 + code:7e08ef/08 + cheat + description:Teleport Pass Power-up - P3 + code:7e09ef/08 + cheat + description:Teleport Pass Power-up - P4 + code:7e0aef/08 + cheat + description:Knockdown Opposite Opponent Power-up - P1 + code:7e07ef/10 + cheat + description:Knockdown Opposite Opponent Power-up - P2 + code:7e08ef/10 + cheat + description:Knockdown Opposite Opponent Power-up - P3 + code:7e09ef/10 + cheat + description:Knockdown Opposite Opponent Power-up - P4 + code:7e0aef/10 + cheat + description:High Shots Power-up - P1 + code:7e07ef/20 + cheat + description:High Shots Power-up - P2 + code:7e08ef/20 + cheat + description:High Shots Power-up - P3 + code:7e09ef/20 + cheat + description:High Shots Power-up - P4 + code:7e0aef/20 + cheat + description:Whirlwind Power-up - P1 + code:7e07ef/80 + cheat + description:Whirlwind Power-up - P2 + code:7e08ef/80 + cheat + description:Whirlwind Power-up - P3 + code:7e09ef/80 + cheat + description:Whirlwind Power-up - P4 + code:7e0aef/80 + cheat + description:All Power-ups except Power Push, On-Fire, Knockdown Both Opponents, Knockdown Opposite Opponent and Whirlwind - P1 + code:7e07ee/f6+7e07ef/2b + cheat + description:All Power-ups except Power Push, On-Fire, Knockdown Both Opponents, Knockdown Opposite Opponent and Whirlwind - P2 + code:7e08ee/f6+7e08ef/2b + cheat + description:All Power-ups except Power Push, On-Fire, Knockdown Both Opponents, Knockdown Opposite Opponent and Whirlwind - P3 + code:7e09ee/f6+7e09ef/2b + cheat + description:All Power-ups except Power Push, On-Fire, Knockdown Both Opponents, Knockdown Opposite Opponent and Whirlwind - P4 + code:7e0aee/f6+7e0aef/2b + cheat + description:All Power-ups - P1 + code:7e07ee/ff+7e07ef/bf + cheat + description:All Power-ups - P2 + code:7e08ee/ff+7e08ef/bf + cheat + description:All Power-ups - P3 + code:7e09ee/ff+7e09ef/bf + cheat + description:All Power-ups - P4 + code:7e0aee/ff+7e0aef/bf + +cartridge sha256:c88a882ad72dfa07a9b1eb8a2183aa10057d60877a02edf90cf2cd8c78abe65e + name:Combatribes, The (USA) + cheat + description:Invincibility - both players + code:009b6c/d0 + cheat + description:Infinite health - both players + code:009a76/ea+009a77/a9+009a78/c8+009a7a/8d + cheat + description:Infinite credits + code:009be9/cd + cheat + description:Hit anywhere - P1 + code:00919e/e0+0091a2/34+00919f/00+0091a0/00+0091a1/f0 + cheat + description:One hit kills - both players + code:00c6eb/e0+00c6ec/00+00c6ed/00+00c6f7/24 + 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 + name:Congo's Caper (USA) + cheat + description:Infinite lives + code:80f2a6/00 + cheat + description:Hit anywhere + code:008b93/00 + cheat + description:Multi-jump + code:00c4d0/00 + cheat + description:Stay as Super Congo (you may change if you walk on spikes) + code:808f58/a9 + cheat + description:1 life after continue + code:809848/00 + cheat + description:6 lives after continue + code:809848/05 + cheat + description:9 lives after continue + code:809848/08 + cheat + description:1 ruby turns you into Super Congo + code:8093d9/a9+8093da/02 + cheat + description:Start as Super Congo + code:809854/82 + cheat + description:Start with 1 life + code:81c4a5/00 + cheat + description:Start with 6 lives + code:81c4a5/05 + cheat + description:Start with 9 lives + code:81c4a5/08 + +cartridge sha256:a93ea87fc835c530b5135c5294433d15eef6dbf656144b387e89ac19cf864996 + name:Contra III - The Alien Wars (USA) + cheat + description:Invincibility (top-view levels) + code:028e65/b5 + cheat + description:Invincibility (side-view levels) - P1 + code:019ae5/b5+01a641/b5 + cheat + description:Invincibility (side-view levels) - P2 + code:01a674/b5+019b87/b5 + cheat + description:Infinite continues + code:00a9c5/ad + cheat + description:Infinite lives (side-view levels) + code:019b91/dd + cheat + description:Infinite lives (top-view levels) + code:029695/dd+029698/80 + cheat + description:Infinite bombs (side-view levels) + code:01802e/dd + cheat + description:Infinite bombs (top-view levels) + code:0291be/dd + cheat + description:Enable 30 and 99 lives in option menu (99 actually gives 35,081 lives) + code:00bb37/05 + cheat + description:Keep main weapon when you die (side-view levels) + code:019ac7/bd + cheat + description:Keep main weapon when you die (top-view levels) + code:0296aa/bd + cheat + description:Multi-jump + code:01856b/ff+01856c/95+01856d/1e+018562/a5+018563/28+018564/29+018565/00+018566/80+018567/f0+018568/05+018569/a9+01856a/fa + cheat + description:Enable stage select + code:00a6ac/24 + cheat + description:Start with 5 bombs on each life (side-view levels) + code:019b97/05+00a2f1/05 + cheat + description:Start with 9 bombs on each life (side-view levels) + code:019b97/09+00a2f1/09 + cheat + description:Start with 5 bombs on each life (top-view levels) + code:028eed/05+00a6f1/05 + cheat + description:Start with 9 bombs on each life (top-view levels) + code:028eed/09+00a6f1/09 + 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 + name:Cool Spot (USA) + cheat + description:Infinite health + code:7e00d0/07 + cheat + description:Infinite lives + code:01d8ac/24 + cheat + description:Infinite lives (alt) + code:7e00d4/09 + cheat + description:Infinite time (disable after completing stage) + code:7e00ce/68 + cheat + description:100% Coolness (disable after completing stage) + code:7e00d2/64 + cheat + description:Less invincibility time + code:01b456/1f + cheat + description:More invincibility time + code:01b456/ff + cheat + description:5 seconds picked up + code:01bda1/05 + cheat + description:1 minute picked up + code:01bda1/3c + cheat + description:16% picked up from '7up' + code:01bd5c/10 + cheat + description:Be able to free fellow spot right away + code:01d488/00 + cheat + description:Start with 1 life + code:00d8b9/01 + cheat + description:Start with 6 lives + code:00d8b9/06 + cheat + description:Start with 9 lives + code:00d8b9/09 + +cartridge sha256:9674cc269d89a52d1719a487b44acf004fb777cbd58d76b19a2cd25749728215 + name:Cool World (USA) + cheat + description:Infinite lives + code:029888/ad + cheat + description:Infinite continues + code:009cd6/ad + cheat + description:A Nickel for a life costs nothing (must have 1 Nickel) + code:00b50a/00+00b50b/00 + cheat + description:Bank deposits cost nothing (must have 5 Nickels) + code:00b5a6/00+00b5a7/00 + cheat + description:Opening a bank account costs nothing (must have 10 Nickels) + code:00c887/00+00c888/00 + cheat + description:High-Low game at the Gold Rush costs nothing (must have 5 Nickels) + code:01afb3/00+01afb4/00 + cheat + description:Most Nickels worth 2 on pick-up (must have 5 Nickels) + code:0199ff/02+019a2e/02 + cheat + description:Most Nickels worth 10 on pick-up (must have 5 Nickels) + code:0199ff/0a+019a2e/0a + cheat + description:Continue with 9 lives + code:00b213/09 + cheat + description:Start with 1 life + code:009cf1/01 + cheat + description:Start with 9 lives + code:009cf1/09 + cheat + description:Start with 10 Nickels + code:00b238/e6+00b239/ee + cheat + description:Start with 1 Nickel + code:00b238/e6 + cheat + description:Invincibility (blinking) + code:7e02bf/ff + cheat + description:Infinite Nickels + code:7e00ed/63 + +cartridge sha256:b9d2483ba547b22cb1173ca0895e4fb20b33d1c4cca62526b12d75280dd8501b + name:Cosmo Gang - The Puzzle (Japan) + cheat + description:Clear level automatically + code:01db9b/00 + +cartridge sha256:73533c37fcd3eddce4804eb4c016214d1741c348c349f00d8e6838d341a50df9 + name:Cosmo Gang - The Video (Japan) + cheat + description:Infinite lives + code:7e0200/0a + cheat + description:Weapon modifier + code:7e0d0b/00 + +cartridge sha256:2602f6e598c711aedb2e3a22414b7869a8490993aef32f53127c408e549afc6d + name:Cosmo Police Galivan II - Arrow of Justice (Japan) + cheat + description:Invincibility + code:009623/a9+009624/01+009625/8d+009626/77+009627/12 + cheat + description:Infinite health + code:00ee12/ad + cheat + description:Infinite lives + code:009e67/cd + cheat + description:One hit kills + code:00eacf/9e + cheat + description:Hit anywhere + code:00ea08/24+00e9ea/80+00ea07/80 + 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:0ac2b8d84a7cd1801d8fb6cb03c07273df4b02c0445e9d69a952bd7ac92eac64 + name:Crayon Shin-chan - Arashi o Yobu Enji (Japan) + cheat + description:Invincibility + code:7e00ba/09 + cheat + description:Infinite health + code:7e0461/04 + cheat + description:Infinite lives + code:7e00b2/09 + cheat + description:Infinite time + code:7e00ac/7f+7e00ad/7f+7e00ae/7f+7e00af/7f + cheat + description:Infinite Invincibility Cards + code:7e00b6/09 + cheat + description:Infinite Guard Dog Cards + code:7e00b7/09 + cheat + description:Infinite Elephant Dance Cards + code:7e00b8/09 + cheat + description:Infinite Health Restore Cards + code:7e00b9/09 + cheat + description:Always carry an item to throw + code:7e00b4/01 + cheat + description:Enemies are always stunned (Elephant Card effect) + code:7e00c0/7f + cheat + description:Guard Dog stay indefinitely + code:7e00c8/7f+7e00c9/7f + cheat + description:Golden Card exists + code:7e00cc/02 + cheat + description:Moon-jump + code:7e00cd/01 + cheat + description:Walk through most walls + code:7e00ce/ff + cheat + description:Always make a choice - Rock, Paper, Scissors minigame + code:7e1f00/01 + cheat + description:Infinite tries - Card Matching minigame + code:7e1943/03 + cheat + description:Infinite time - Jumbled Picture minigame + code:7e1920/7f+7e1921/7f+7e1922/7f + cheat + description:Infinite tries - Card Search minigame + code:7e191a/00 + cheat + description:No blur - Playground Fountain minigame + code:7e190f/01 + cheat + description:Losing still allows you to move forward + code:7e1f07/01 + cheat + description:Instant win - TV Flags minigame + code:7e191a/00 + cheat + description:Very easy wins + code:7e1925/01 + cheat + description:Only need 1 Star to win + code:7e1935/01 + cheat + description:Enemy can't win (0 Stars) + code:7e1937/00 + cheat + description:Enemy always raise both flags + code:7e1930/01+7e1931/01 + +cartridge sha256:7c722f9941957630467c1784d0eb3f92fbfc0a2a1da3c8f5c27f593eca2a5a04 + name:Cutthroat Island (USA) + cheat + description:Stage select menu after character select screen + code:878c9d/ea + 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 + name:Cyber Spin (USA) + cheat + description:Infinite power + code:019b53/ad+019b75/ad+019b97/ad + cheat + description:Freeze CPU Racers (always first place) + code:01b418/a5+01b470/a5 + cheat + description:Drive anywhere + code:019a8a/ad+019757/ad+0198ab/64 + +cartridge sha256:ad31b94ce928ecff605e2b89082154671691509e95d38370ed381437f2c36698 + name:Cybernator (USA) + cheat + description:Infinite health + code:82a834/bd+82a85d/bd+8293eb/a5 + cheat + description:Protection against some hazards + code:82a85d/bd+82a834/bd + cheat + description:Infinite Vulcan + code:848723/ad+848720/ad + cheat + description:Never overheat + code:829372/ad + cheat + description:Infinite credits + code:80e024/ad + cheat + description:Only 2 P's needed for level 2 Vulcan + code:838462/02 + cheat + description:Only 4 P's needed for level 3 Vulcan + code:838464/04 + cheat + description:Only 3 P's needed for level 3 Laser + code:83846a/03 + cheat + description:Only 3 P's needed for level 3 Missile + code:838470/03 + cheat + description:Only 2 P's needed for level 2 Napalm + code:838474/02 + cheat + description:Only 4 P's needed for level 3 Napalm + code:838476/04 + cheat + description:Only 2 P's needed for level 2 Punch + code:83847a/02 + cheat + description:Only 3 P's needed for level 3 Punch + code:83847c/03 + cheat + description:Energy chip worth nothing + code:82e119/00 + cheat + description:Energy chip worth more + code:82e119/a0 + cheat + description:Weapons start at level 2 + code:809514/02 + cheat + description:Weapons start at level 3 + code:809514/03 + cheat + description:Start with Lasers + code:80951f/8d + cheat + description:Start with Homing Missiles + code:80951c/8d + cheat + description:Start with Napalm + code:809522/8d + cheat + description:Start with 2 credits + code:80956f/01 + cheat + description:Start with 6 credits + code:80956f/05 + cheat + description:Start with 10 credits + code:80956f/09 + cheat + description:Start on level 3.1 + code:80950e/02 + cheat + description:Start on level 3.2 + code:80950e/03 + cheat + description:Start on level 3.3 + code:80950e/04 + cheat + description:Start on level 4.1 + code:80950e/05 + cheat + description:Start on level 4.2 + code:80950e/06 + cheat + description:Start on level 5.1 + code:80950e/07 + cheat + description:Start on level 5.2 + code:80950e/08 + cheat + description:Start on level 6.1 + code:80950e/09 + cheat + description:Start on level 7.3 + code:80950e/10 + cheat + description:Start on level 7.4 + code:80950e/11 + cheat + description:View the failed ending + code:80950e/12 + cheat + description:View the successful ending + code:80950e/13 + +cartridge sha256:71e77fdbd9c865ae07e907549b02549ebe87fa8d436401c485e588c61797754a + name: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 + name:Daffy Duck - The Marvin Missions (USA) + cheat + description:Infinite health + code:80b7e2/ad + cheat + description:Infinite ammo (must have some ammo for the gun to be selectable) + code:80b17c/00 + cheat + description:Infinite lives + code:809be9/00 + cheat + description:Infinite continues + code:82cade/00 + cheat + description:Infinite Nutty attacks + code:80b33b/ad + cheat + description:Hit anywhere + code:80e5e0/00 + cheat + description:Get items from anywhere + code:80da4f/00+80d984/00+80de37/00+80e1a2/00 + cheat + description:One hit kills + code:80b58c/80 + cheat + description:Disable recoil + code:80b257/00 + cheat + description:Juice cans set health to 1/2 + code:80da62/06 + cheat + description:Juice cans set health to 3/4 + code:80da62/09 + cheat + description:Gem power-ups worth 0 + code:80e0aa/00 + cheat + description:Gem power-ups worth 5 (1 continue) + code:80e0aa/05 + cheat + description:Gems are free + code:82c0b8/00 + cheat + description:Freeze Gun ammo is free + code:82c0a9/00 + cheat + description:Freeze Gun ammo is $200 + code:82c0a9/20 + cheat + description:Electricity Gun ammo is free + code:82c0ab/00 + cheat + description:Electricity Gun ammo is $150 + code:82c0ab/15 + cheat + description:3-way Gun ammo is free + code:82c0ad/00 + cheat + description:3-way Gun ammo is $150 + code:82c0ad/15 + cheat + description:Bomb Gun ammo is free + code:82c0af/00 + cheat + description:Bomb Gun ammo is $150 + code:82c0af/15 + cheat + description:Antimatter Gun ammo is free + code:82c0b1/00 + cheat + description:Antimatter Gun ammo is $200 + code:82c0b1/20 + cheat + description:Freeze Gun ammo power-ups are worth 20 + code:80dcb7/20 + cheat + description:Electricity Gun ammo power-ups are worth 20 + code:80dd83/20 + cheat + description:Three-way Gun ammo power-ups are worth 20 + code:80de4f/20 + cheat + description:Bomb Gun ammo power-ups are worth 20 + code:80df1b/20 + cheat + description:Antimatter Gun ammo power-ups are worth 20 + code:80dfe7/20 + cheat + description:Nutty attacks are free + code:82c0b5/00 + cheat + description:Nutty attacks are $400 + code:82c0b5/40 + cheat + description:Jetpack fuel is free + code:82c0b3/00 + cheat + description:Fuel is consumed at 1/4 normal rate + code:80adbb/06 + cheat + description:Fuel is consumed at 1/2 normal rate + code:80adbb/0c + cheat + description:Fuel is consumed at 3/4 normal rate + code:80adbb/12 + cheat + description:Fuel power-ups are worth 1/2 as much + code:80d99c/06 + cheat + description:Fuel power-ups are worth 2x + code:80d99c/1a + cheat + description:Buy a life and get a ton of money + code:82c3be/80 + cheat + description:Bought Freeze Gun ammo is worth 20 + code:82c0f8/20 + cheat + description:Bought gems worth 0 + code:82c38b/00 + cheat + description:Bought gems worth 5 (1 continue) + code:82c38b/05 + cheat + description:Bought Electricity Gun ammo is worth 20 + code:82c159/20 + cheat + description:Bought Three-way Gun ammo is worth 20 + code:82c1ba/20 + cheat + description:Bought Bomb Gun ammo is worth 20 + code:82c21b/20 + cheat + description:Bought Anti matter Gun ammo is worth 20 + code:82c27c/20 + cheat + description:Bought fuel is worth 1/2 as much + code:82c2df/06 + cheat + description:Bought fuel is worth 2x as much + code:82c2df/1a + cheat + description:Extra lives cost $500 + code:82c0ba/00 + cheat + description:Extra lives cost $1,500 + code:82c0ba/01 + cheat + description:Extra life power-ups don't work + code:80dbe8/00 + cheat + description:Extra life power-ups worth 2 + code:80dbe8/02 + cheat + description:Extra life power-ups worth 5 + code:80dbe8/05 + cheat + description:Extra lives can't be bought + code:82c3e7/00 + cheat + description:2 extra lives for each one purchased + code:82c3e7/02 + cheat + description:5 extra lives for each one purchased + code:82c3e7/05 + cheat + description:Start with 1 life + code:809903/01 + cheat + description:Start with 9 lives (don't set lives in options menu) + code:809903/09 + cheat + description:Start with 25 lives (don't set lives in options menu) + code:809903/25 + cheat + description:Start with 51 lives (don't set lives in options menu) + code:809903/51 + cheat + description:Start with 1/2 health + code:809f20/06 + cheat + description:Start with 3/4 health + code:809f20/09 + cheat + description:Start with no nutty attacks + code:809a05/00 + cheat + description:Start with 3 nutty attacks + code:809a05/03 + cheat + description:Start with 5 nutty attacks + code:809a05/05 + cheat + description:Start with 7 nutty attacks + code:809a05/07 + cheat + description:Start with 0 gems + code:809a2e/00 + cheat + description:Start with 10 gems (2 continues) + code:809a2e/10 + cheat + description:Start with 25 gems (5 continues) + code:809a2e/25 + cheat + description:Start with 10 ammo for all Guns (except blaster) + code:809a16/10 + cheat + description:Start with 50 ammo for all Guns + code:809a16/50 + cheat + description:Start with 90 ammo for all Guns + code:809a16/90 + cheat + description:Start with almost no fuel + code:809a29/00 + cheat + description:Start with 2x fuel + code:809a29/1b + cheat + description:Start with 3x fuel + code:809a29/27 + cheat + description:Start with $2,500 + code:809a0c/02 + cheat + description:Start with $3,500 + code:809a0c/03 + cheat + description:Start with $9,500 + code:809a0c/09 + cheat + description:Start with $30,500 + code:809a0c/30 + cheat + description:Start on level 1-2 + code:809951/01 + cheat + description:Start on level 1-3 + code:809951/02 + cheat + description:Start on level 1-4 + code:809951/03 + cheat + description:Start on level 2-1 + code:809951/04 + cheat + description:Start on level 2-2 + code:809951/05 + cheat + description:Start on level 2-3 + code:809951/06 + cheat + description:Start on level 2-4 + code:809951/07 + cheat + description:Start on level 3-1 + code:809951/08 + cheat + description:Start on level 3-2 + code:809951/09 + cheat + description:Start on level 3-3 + code:809951/0a + cheat + description:Start on level 3-4 + code:809951/0b + cheat + description:Start on level 4-1 + code:809951/0c + cheat + description:Start on level 4-2 + code:809951/0d + cheat + description:Start on level 4-3 + code:809951/0e + cheat + description:Start on level 4-4 + code:809951/0f + cheat + description:Start on level 5-1 + code:809951/10 + cheat + description:Start on level 5-2 + code:809951/11 + cheat + description:Start on level 5-3 + code:809951/12 + cheat + description:Start on level 5-4 + code:809951/13 + 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 + name: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 + name:Darius Twin (USA) + cheat + description:Invincibility - P1 + code:01d60c/ad + cheat + description:Invincibility - P2 + code:01e3a6/ad + cheat + description:Infinite lives - P1 + code:01ee77/00 + cheat + description:Infinite lives - P2 + code:01ee97/00 + cheat + description:Hit anywhere - both players + code:00dae7/80+00db0e/ad+00dabf/00+00daf1/00 + cheat + description:Start with the strongest main weapon and 8 lives - both players + code:00aee3/ea+00aeea/8d+00aeed/8d+00aee1/a9+00aee2/08 + cheat + description:Start with 1 Green Power Cube - P1 + code:00af06/8d+00aef8/2c + cheat + description:Start with 1 Green Power Cube - P2 + code:00af09/8d+00aef8/2c + cheat + description:Start with 10 lives - both players + code:00aee2/10+00aee1/a9+00aee3/ea + cheat + description:Start with 15 lives - both players + code:00aee2/15+00aee1/a9+00aee3/ea + cheat + description:Start with 20 lives - both players + code:00aee2/20+00aee1/a9+00aee3/ea + cheat + description:Start with 25 lives - both players + code:00aee2/25+00aee1/a9+00aee3/ea + cheat + description:Start on planet B + code:00934c/01+00934b/a0+00934d/00+00934e/8c + cheat + description:Start on planet C + code:00934c/02+00934b/a0+00934d/00+00934e/8c + cheat + description:Start on planet D + code:00934c/03+00934b/a0+00934d/00+00934e/8c + cheat + description:Start on planet E + code:00934c/04+00934b/a0+00934d/00+00934e/8c + cheat + description:Start on planet F + code:00934c/05+00934b/a0+00934d/00+00934e/8c + cheat + description:Start on planet G + code:00934c/06+00934b/a0+00934d/00+00934e/8c + cheat + description:Start on planet H + code:00934c/07+00934b/a0+00934d/00+00934e/8c + cheat + description:Start on planet I + code:00934c/08+00934b/a0+00934d/00+00934e/8c + cheat + description:Start on planet J + code:00934c/09+00934b/a0+00934d/00+00934e/8c + cheat + description:Start on planet K + code:00934c/0a+00934b/a0+00934d/00+00934e/8c + cheat + description:Start on planet L + code:00934c/0b+00934b/a0+00934d/00+00934e/8c + 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 + name:Dark Law - Meaning of Death (Japan) + cheat + description:Sell an item to get maximum cash + code:c27cea/80+c27ceb/08 + cheat + description:Fewer random battles + code:c338f3/80 + cheat + description:Any code will open locked doors + code:d124a5/00 + cheat + description:One hit kills + code:c9a261/80 + cheat + description:Infinite walking range in battle + code:c955b5/00 + +cartridge sha256:e6efb6361af04963f22c772f879a466543f56b3b6a084204fef2dcb4659d82d9 + name:David Crane's Amazing Tennis (USA) + cheat + description:Faster side-to-side movement + code:00b394/fc+00b37c/04 + cheat + description:Even faster side-to-side movement + code:00b394/fa+00b37c/06 + +cartridge sha256:6ce516e3d1a7068cc9732cd3517cfd1e92179f2340c63a244625a1ff49815085 + name:Daze Before Christmas (Europe) + cheat + description:Infinite health + code:7e06f9/05 + cheat + description:Infinite lives + code:7e1e68/04 + +cartridge sha256:300c1937e4b68108302e9b0f49974d1ec6b6c45dd8da69dddc19443f9562ecf4 + name:Death and Return of Superman, The (USA) + cheat + description:Invincibility + code:808296/d0+8082a7/f0 + cheat + description:Infinite health + code:80d20c/a5+80d20d/55+80d20e/8d+80d20f/d2+80d210/0e + cheat + description:Infinite lives + code:80d326/ee + cheat + description:Infinite special attacks + code:80d2ee/ee+80d2ef/0e + +cartridge sha256:a33af57e62a46282e3755824cc5fc39870a8eab8a28aaeb1c3817ba2c8e8655e + name:Death Brade (Japan) + cheat + description:Infinite heath - P1 + code:7e0a10/50 + +cartridge sha256:752d24fab240f4dd1dfbfea5ec83438998316806ad44488bf8c84430ca5a2cd0 + name:Demolition Man (USA) + cheat + description:Infinite health + code:80b75e/15 + cheat + description:Infinite health (alt) + code:7e9f30/7f + cheat + description:Infinite lives + code:80c1a4/ad + cheat + description:Infinite Grenades + code:81c8d3/bd + cheat + description:Infinite ammo - Shotgun and Magnum + code:80c5cf/bd + cheat + description:Infinite ammo - Shotgun + code:80c5c8/01 + cheat + description:Infinite ammo - Magnum + code:859114/02 + cheat + description:Jump 2x higher + code:00b64c/20 + cheat + description:Jump 4x higher + code:00b64c/10 + cheat + description:Jump 8x higher + code:00b64c/08 + +cartridge sha256:248217975279bbf9db8e74da11a906a6dd867a3ec88441b0b031ecf900466618 + name:Demon's Blazon - Makai Mura Monshou Hen (Japan) + cheat + description:Invincibility + code:7e103c/5a + cheat + description:Infinite health + code:7e1062/15 + cheat + description:Maximum health bar + code:7e1e50/15 + cheat + description:999 ZAM + code:7e1063/e7+7e1064/03 + +cartridge sha256:18d40a807d5f88c5b6a1ad849eec7e0f189225d9a1586037c850f6680b5844de + name:Demon's Crest (USA) + cheat + description:Invincibility after one hit + code:80dccb/a5 + cheat + description:Infinite health + code:80e599/a5 + cheat + description:Hit anywhere + code:82888c/00+8288a2/00+828b00/80+828b23/80 + cheat + description:Get GP from anywhere + code:82c97e/00 + cheat + description:Large health refills full health + code:82c9ae/a5 + cheat + description:Rapid fire + code:80ef5c/a5 + cheat + description:Enemies always drop the 20 coin + code:82c77d/a5 + cheat + description:First enemy takes longer to kill + code:838a3d/09 + cheat + description:First enemy take less time to kill + code:838a3d/02 + cheat + description:More flash time + code:80e5c3/ff + cheat + description:Die after one hit + code:80de33/85 + cheat + description:Super-jump + code:80e175/08 + cheat + description:Ginseng costs nothing + code:81e6b4/00 + cheat + description:20 coin worth 999 + code:82c9dc/a5 + cheat + description:1 coin worth 999 + code:82c9dd/a5 + cheat + description:Start a new game with all items + code:8488e8/ce+8488eb/ce+8488ee/ce + 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 + name:Dennis the Menace (USA) + cheat + description:Infinite courage + code:809c34/a5+809c3b/a5 + cheat + description:Infinite time + code:87df11/a5 + cheat + description:Infinite lives + code:80a49b/a5 + +cartridge sha256:606abf536440173ae36466db360c7db6b474beb7a105c8a62bc74a54cbe1c38b + name:Desert Strike - Return to the Gulf (USA) + cheat + description:Infinite ammo + code:01e59c/dd + cheat + description:Infinite fuel + code:0187e9/00 + cheat + description:Infinite lives + code:0189bb/2c + cheat + description:2x fuel consumption + code:0187e9/04 + cheat + description:Faster gun auto-repeat speed + code:00e6ae/01 + cheat + description:Slower gun auto-repeat speed + code:00e6ae/18 + cheat + description:Missiles fly faster + code:00e6d2/04 + cheat + description:Hydras fly faster + code:00e6f0/04 + cheat + description:Guns do as much damage as missiles + code:00e6b2/64 + cheat + description:Hydras do as much damage as missiles + code:00e6d0/64 + cheat + description:Missiles do 250 points of damage + code:00e6ee/fa + cheat + description:AK47's do 1 point of damage + code:00e856/01 + cheat + description:AK47's do 1/2x damage + code:00e856/02 + cheat + description:AK47's do 2x damage + code:00e856/0a + cheat + description:APHIDs do 1 point of damage + code:00e7fc/01 + cheat + description:APHIDs do 1/2x damage + code:00e7fc/25 + cheat + description:APHIDs do 2x damage + code:00e7fc/96 + cheat + description:AAA's do 1 point of damage + code:00e70c/01 + cheat + description:AAA's do 1/2x damage + code:00e70c/0a + cheat + description:AAA's do 2x damage + code:00e70c/28 + cheat + description:Rapiers do 1 point of damage + code:00e7a2/01 + cheat + description:Rapiers do 1/2x damage + code:00e7a2/32 + cheat + description:Rapiers do 2x damage + code:00e7a2/c8 + cheat + description:VDA's do 1 point of damage + code:00e72a/01 + cheat + description:VDA's do 1/2x damage + code:00e72a/0c + cheat + description:VDA's do 2x damage + code:00e72a/32 + cheat + description:ZSU's do 1 point of damage + code:00e766/01 + cheat + description:ZSU's do 1/2x damage + code:00e766/14 + cheat + description:ZSU's do 2x damage + code:00e766/50 + cheat + description:Speedboats do 1 point of damage + code:00e81a/01 + cheat + description:Speedboats do 1/2x damage + code:00e81a/19 + cheat + description:Speedboats do 2x damage + code:00e81a/64 + cheat + description:Choppers do 1 point of damage + code:00e838/01 + cheat + description:Choppers do 1/2x damage + code:00e838/32 + cheat + description:Choppers do 2x damage + code:00e838/c8 + cheat + description:M48's do 1 point of damage + code:00e7de/01 + cheat + description:M48's do 1/2x damage + code:00e7de/32 + cheat + description:M48's do 2x damage + code:00e7de/c8 + cheat + description:Crotales do 1 point of damage + code:00e7c0/01 + cheat + description:Crotales do 1/2x damage + code:00e7c0/32 + cheat + description:Crotales do 2x damage + code:00e7c0/c8 + cheat + description:AK47's have 1 armor point + code:00d154/01 + cheat + description:AK47's have 1/2x armor points + code:00d154/05 + cheat + description:AK47's have 2x armor points + code:00d154/14 + cheat + description:APHIDs have 1 armor points + code:00c03e/01 + cheat + description:APHIDs have 1/2x armor points + code:00c03e/0c + cheat + description:APHIDs have 2x armor points + code:00c03e/32 + cheat + description:AAA's have 1 armor points + code:00bfe0/01 + cheat + description:AAA's have 1/2x armor points + code:00bfe0/19 + cheat + description:AAA's have 2x armor points + code:00bfe0/64 + cheat + description:Rapiers have 1 armor points + code:00c2f6/01 + cheat + description:Rapiers have 1/2x armor points + code:00c2f6/25 + cheat + description:Rapiers have 2x armor points + code:00c2f6/96 + cheat + description:VDA's have 1 armor points + code:00c354/01 + cheat + description:VDA's have 1/2x armor points + code:00c354/32 + cheat + description:VDA's have 2x armor points + code:00c354/c8 + cheat + description:ZSU's have 1 armor points + code:00c404/01 + cheat + description:ZSU's have 1/2x armor points + code:00c404/4b + cheat + description:ZSU's have 2x armor points + code:00c404/ff + cheat + description:Speedboats have 1 armor points + code:00c090/01 + cheat + description:Speedboats have 1/2x armor points + code:00c090/4b + cheat + description:Speedboats have 2x armor points + code:00c090/ff + cheat + description:Choppers have 1 armor points + code:00c130/01 + cheat + description:Choppers have 1/2x armor points + code:00c130/4b + cheat + description:Choppers have 2x armor points + code:00c130/ff + cheat + description:M48's have 1 armor points + code:00c24a/01 + cheat + description:M48's have 1/2x armor points + code:00c24a/64 + cheat + description:M48's have 2x armor points + code:00c24b/01 + cheat + description:Crotales have 1 armor points + code:00c1ec/01 + cheat + description:Crotales have 1/2x armor points + code:00c1ec/7d + cheat + description:Crotales have 2x armor points + code:00c1ed/01 + cheat + description:AK47 bullets fly slower + code:00e858/00 + cheat + description:APHID bullets fly slower + code:00e7fe/00 + cheat + description:AAA bullets fly slower + code:00e70e/00 + cheat + description:Rapier bullets fly slower + code:00e7a4/00 + cheat + description:VDA bullets fly slower + code:00e72c/00 + cheat + description:ZSU bullets fly slower + code:00e768/00 + cheat + description:Speedboat bullets fly slower + code:00e81c/00 + cheat + description:Chopper bullets fly slower + code:00e83a/00 + cheat + description:M48 bullets fly slower + code:00e7e0/00 + cheat + description:Armor starts at 344 + code:0196ab/01+018a28/01 + cheat + description:Armor starts at 856 + code:0196ab/03+018a28/03 + cheat + description:Armor starts at 1,112 + code:0196ab/04+018a28/04 + cheat + description:Armor starts at 2,136 + code:0196ab/08+018a28/08 + cheat + description:Armor starts at 5,208 + code:0196ab/14+018a28/14 + cheat + description:Fuel starts at 25 + code:02996c/19 + cheat + description:Fuel starts at 50 + code:02996c/32 + cheat + description:Fuel starts at 75 + code:02996c/4b + cheat + description:Fuel starts at 150 + code:02996c/96 + cheat + description:Fuel starts at 200 + code:02996c/c8 + cheat + description:Fuel starts at 868 + code:02996d/03 + cheat + description:Guns start at 154 rounds remaining + code:00e6b1/00 + cheat + description:Guns start at 666 rounds remaining + code:00e6b1/02 + cheat + description:Guns start at 2,458 rounds remaining + code:00e6b1/09 + cheat + description:Guns start at 5,018 rounds remaining + code:00e6b1/13 + cheat + description:Guns start at 9,882 rounds remaining + code:00e6b1/26 + cheat + description:Start with 10 hydras + code:00e6ce/0a + cheat + description:Start with 50 hydras + code:00e6ce/32 + cheat + description:Start with 100 hydras + code:00e6ce/64 + cheat + description:Start with 250 hydras + code:00e6ce/fa + cheat + description:Start with 1 missile + code:00e6ec/01 + cheat + description:Start with 20 missiles + code:00e6ec/14 + cheat + description:Start with 50 missiles + code:00e6ec/32 + cheat + description:Start with 100 missiles + code:00e6ec/64 + cheat + description:Start with 250 missiles + code:00e6ec/fa + cheat + description:Start with 1 life + code:029966/01 + cheat + description:Start with 5 lives + code:029966/05 + cheat + description:Start with 7 lives + code:029966/07 + cheat + description:Start with 10 lives + code:029966/0a + cheat + description:Start with 20 lives + code:029966/14 + cheat + description:Start with 50 lives + code:029966/32 + cheat + description:Start with 99 lives + code:029966/63 + cheat + description:Infinite lives (alt) + code:7e209e/09 + cheat + description:Infinite fuel (alt) + code:7e2098/64 + cheat + description:Infinite Load (carry unlimited number of passengers) + code:7e209c/01 + cheat + description:Landing with infinite load (use with Infinite Load code, only when landing, then disable) + code:7e209c/ff + cheat + description:Infinite Chaingun + code:7eb0c6/ff + cheat + description:Infinite Hydras + code:7eb0ea/ff + cheat + description:Infinite Hellfire Missiles + code:7eb10e/ff + cheat + description:Infinite Hellfire Missiles + code:7eb132/ff + cheat + description:Infinite Armor - Level 1 + code:7e5d00/ff + cheat + description:Infinite Armor - Level 2 + code:7e5da2/ff + cheat + description:Infinite Armor - Level 3 + code:7e5e44/ff + cheat + description:Infinite Armor - Level 4 + code:7e5d00/ff + cheat + description:Crotales do little or no damage in level 4 + code:00e7c0/01 + +cartridge sha256:337e643d3e63915de06429992f306e8d2b73aed6849b795f9c855c2d03c18180 + name:D-Force (USA) + cheat + description:Infinite lives + code:00a0c8/ea + cheat + description:Continue equipped with unguided missiles + code:0084a9/30+0084aa/da+0084ac/10 + cheat + description:Loss of a life does not decrease cannon power at normal difficulty (except on continues) + code:00a431/00 + cheat + description:Loss of a life does not decrease cannon power at hard difficulty (except on continues) + code:00a448/00 + cheat + description:Pink power-up increases missile power along with cannon power + code:00ea0a/0c + cheat + description:Continue with 10 lives + code:0084bd/36+0084be/a8 + cheat + description:Continue with 12 lives + code:0084bd/ab+0084be/a4 + cheat + description:Continue with 14 lives + code:0084bd/a1+0084be/f1 + cheat + description:Continue with 16 lives + code:0084bd/5f+0084be/a4 + cheat + description:Continue with cannon power at level 2 + code:0084b5/01+0084b2/0f + cheat + description:Continue with cannon power at level 3 + code:0084b5/02+0084b2/0f + cheat + description:Continue with cannon power at level 4 + code:0084b5/03+0084b2/0f + cheat + description:Continue with cannon power at level 6 + code:0084b5/05+0084b2/0f + cheat + description:Continue with cannon power at level 8 + code:0084b5/07+0084b2/0f + cheat + description:Continue with cannon power at level 10 + code:0084b5/09+0084b2/0f + cheat + description:Continue with cannon power at level 12 + code:0084b5/0b+0084b2/0f + cheat + description:Start with cannon power at level 2 + code:009086/01 + cheat + description:Start with cannon power at level 3 + code:009086/02 + cheat + description:Start with cannon power at level 4 + code:009086/03 + cheat + description:Start with cannon power at level 6 + code:009086/05 + cheat + description:Start with cannon power at level 8 + code:009086/07 + cheat + description:Start with cannon power at level 10 + code:009086/09 + cheat + description:Start with cannon power at level 12 + code:009086/0b + cheat + description:Start equipped with unguided missiles + code:00908e/0c+00908b/10 + cheat + description:Start with 10 lives + code:1680bc/36+1680bd/a8 + cheat + description:Start with 12 lives + code:1680bc/ab+1680bd/a4 + cheat + description:Start with 14 lives + code:1680bc/a1+1680bd/f1 + cheat + description:Start with 16 lives + code:1680bc/5f+1680bd/a4 + +cartridge sha256:7dbfc44d28a46e6d399628e43086aa9fd0b2abeda4c108751a5ad91c102c3aaf + name:Dino City (USA) + cheat + description:Infinite health + code:01c68f/b9 + cheat + description:No harm from most enemies + code:01c682/80 + cheat + description:No harm if swallowed by a monster + code:05e79c/ad+05eade/ad + cheat + description:Infinite plays - both players + code:0482f3/ad + cheat + description:Infinite time (disable in bonus stage) + code:058055/bd + cheat + description:Infinite credits - both players + code:048e4c/ad + cheat + description:Enable level select (pause and press select) + code:048873/0b+048250/00 + cheat + description:Hit and stomp anywhere + code:01c6fa/80+01c6fb/15 + cheat + description:Clock runs faster + code:05802b/3c + cheat + description:Clock runs slower + code:05802b/f0 + cheat + description:Clock runs much slower + code:05802b/f0+05802c/01 + cheat + description:Rex jumps higher + code:078c96/fa + cheat + description:Rex jumps much higher + code:078c96/f8 + cheat + description:Tops jumps higher + code:07b8cd/fa + cheat + description:Tops jumps much higher + code:07b8cd/f8 + cheat + description:Timmy and Jamie jump higher + code:07d4d7/fa + cheat + description:Timmy and Jamie jump much higher + code:07d4d7/f8 + cheat + description:Collect 2 eggs for extra play instead of 50 + code:04d233/02 + cheat + description:Collect 5 eggs for extra play + code:04d233/05 + cheat + description:Collect 10 eggs for extra play + code:04d233/10 + cheat + description:Collect 15 eggs for extra play + code:04d233/15 + cheat + description:Collect 25 eggs for extra play + code:04d233/25 + cheat + description:Collect 75 eggs for extra play + code:04d233/75 + cheat + description:Collect 99 eggs for extra play + code:04d233/99 + cheat + description:1 play per game instead of 3 - both players + code:04800e/01 + cheat + description:2 plays per game - both players + code:04800e/02 + cheat + description:4 plays per game - both players + code:04800e/04 + cheat + description:5 plays per game - both players + code:04800e/05 + cheat + description:7 plays per game - both players + code:04800e/07 + cheat + description:9 plays per game - both players + code:04800e/09 + cheat + description:Start with 1 credit instead of 3 - P1 + code:04abd9/01 + cheat + description:Start with 2 credits - P1 + code:04abd9/02 + cheat + description:Start with 5 credits - P1 + code:04abd9/05 + cheat + description:Start with 7 credits - P1 + code:04abd9/07 + cheat + description:Start with 9 credits - P1 + code:04abd9/09 + cheat + description:Start with No credits - P1 + code:04abd9/00 + cheat + description:Start with 1 credit instead of 3 - P2 + code:04ac14/01 + cheat + description:Start with 2 credits - P2 + code:04ac14/02 + cheat + description:Start with 5 credits - P2 + code:04ac14/05 + cheat + description:Start with 7 credits - P2 + code:04ac14/07 + cheat + description:Start with 9 credits - P2 + code:04ac14/09 + cheat + description:Start with No credits - P2 + code:04ac14/00 + cheat + description:Infinite health - P1 + code:7e16ed/03 + +cartridge sha256:10e07e9e094e77a2b71bab3bac1d79a62b7a7bfdb80111044b1f9c64645c622f + name: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 + name:Donkey Kong Country (USA) + cheat + description:Invincibility + code:bfc745/60+bfd31c/00 + cheat + description:Invincibility in Mine Cart Carnage stage + code:b6a6a1/00 + cheat + description:Kill enemies on contact + code:bfc746/82+bfd320/82+bfa79b/00+b686a2/ea + cheat + description:Can cartwheel and stomp enemies who are immune to it + code:bfa79b/00+b686a2/ea+be94c4/00 + cheat + description:Infinite lives + code:b6a861/ad + cheat + description:Infinite lives (alt) + code:b6a85f/ad+b6a861/ad + cheat + description:Get Life Balloons from anywhere + code:b6a732/80 + cheat + description:Get KONG letters from anywhere + code:bfd694/80 + cheat + description:Get Banana bunches from anywhere + code:bfd74d/80 + cheat + description:Get Midway Barrel from anywhere + code:b6f6ce/80 + cheat + description:Get most single Bananas from anywhere + code:b8bbb1/80+b8bb4f/00+b8bb56/00 + cheat + description:10 Bananas needed for extra life + code:80a362/09+80a36b/0a+80a359/09+80a362/0a + cheat + description:25 Bananas needed for extra life + code:80a362/18+80a36b/19+80a359/18+80a362/19 + cheat + description:50 Bananas needed for extra life + code:80a362/31+80a36b/32+80a359/31+80a362/32 + cheat + description:75 Bananas needed for extra life + code:80a362/4a+80a36b/4b+80a359/4a+80a362/4b + cheat + description:Easy level exit (press start and select) + code:809b50/00 + cheat + description:Easy level exit (press start and select) (alt) + code:809b50/00+809b4b/00 + cheat + description:Bad buddy code (In 2P team mode, the inactive player can press select to gain control) + code:bfb296/00 + cheat + description:Bad buddy code (In 2P team mode, the inactive player can press select to gain control) (alt) + code:bfb296/00+bfb2bd/00 + cheat + description:Both Kongs return (get both Kongs back on map screen after dying, doesn't work when you fall off the screen) + code:bf8f98/03 + 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:bf8e78/ff + cheat + description:Keep Animals between stages + code:808394/60+b883cb/65 + cheat + description:Keep Animals between stages (alt) + code:808394/03+b883cb/65 + cheat + description:Keep Animals between stages (alt) + code:808394/60+b883cb/65+808392/60+b883ce/68 + cheat + description:Multi-jump + code:bfb32b/80+bfb924/24+bfb929/80+bfb934/d0 + cheat + description:Multi-jump - Expresso (the Ostrich) + code:bfba48/ff + cheat + description:High-jump - Donkey Kong + code:bfb964/c4 + cheat + description:Super-jump - Donkey Kong + code:bfb964/d0 + cheat + description:Mega-jump - Donkey Kong + code:bfb964/e0 + cheat + description:Moon-jump - Donkey Kong + code:bfb964/ff + cheat + description:High-jump - Diddy Kong + code:bfb96c/b4 + cheat + description:Super-jump - Diddy Kong + code:bfb96c/c0 + cheat + description:Mega-jump - Diddy Kong + code:bfb96c/d0 + cheat + description:Moon-jump - Diddy Kong + code:bfb96c/ff + cheat + description:High-jump - Animals + code:bfba14/c4 + cheat + description:Super-jump - Animals + code:bfba14/d0 + cheat + description:Mega-jump - Animals + code:bfba14/e0 + cheat + description:Moon-jump - Animals + code:bfba14/ff + cheat + description:High-jump - Donkey Kong + code:bfb964/c4+bfb98b/c4 + cheat + description:Super-jump - Donkey Kong + code:bfb964/d0+bfb98b/d0 + cheat + description:Mega-Jump - Donkey Kong + code:bfb964/e0+bfb98b/e0 + cheat + description:High-jump - Diddy Kong + code:bfb96c/b4+bfb993/b4 + cheat + description:Super-jump - Diddy Kong + code:bfb96c/c0+bfb993/c0 + cheat + description:Mega-Jump - Diddy Kong + code:bfb96c/d0+bfb993/d0 + cheat + description:High-jump - all Animals + code:bfba14/c4+bfba3b/c4 + cheat + description:Super-jump - all Animals + code:bfba14/d0+bfba3b/d0 + cheat + description:Mega-jump - all Animals + code:bfba14/e0+bfba3b/e4 + cheat + description:See the ending + code:8083b4/a0+b883cb/dd + cheat + description:Start With 8 lives + code:b882b8/07+b882bb/07 + cheat + description:Start With 11 lives + code:b882b8/0a+b882bb/0a + cheat + description:Start With 16 lives + code:b882b8/0f+b882bb/0f + cheat + description:Start With 26 lives + code:b882b8/19+b882bb/19 + cheat + description:Start With 51 lives + code:b882b8/32+b882bb/32 + cheat + description:Start With 76 lives + code:b882b8/4b+b882bb/4b + cheat + description:Start With 100 lives + code:b882b8/63+b882bb/63 + cheat + description:Start with 255 lives + code:b882b8/ff + cheat + description:Return of Kong (alt) + code:7e0579/01 + +cartridge sha256:df2644d435330192a13768cc1f79c5aa3084a64217a5250c6dd4ffdbe2175be4 + name:Donkey Kong Country (USA) (Rev 1) + cheat + description:Invincibility + code:bfd345/00+bfc76c/60 + cheat + description:Invincibility in Mine Cart Carnage stage + code:b6a6a3/00 + cheat + description:Kill enemies on contact + code:bfc76d/82+bfd349/82+bfa7c2/00+b686a2/ea + cheat + description:Can cartwheel and stomp enemies who are immune to it + code:bfa7c2/00+b686a2/ea+be94c4/00 + cheat + description:Infinite lives + code:b6a863/ad + cheat + description:Get Life Balloons from anywhere + code:b6a734/80 + cheat + description:Get KONG letters from anywhere + code:bfd6bd/80 + cheat + description:Get Banana bunches from anywhere + code:bfd776/80 + cheat + description:Get Midway Barrel from anywhere + code:b6f6e2/80 + cheat + description:Get most single Bananas from anywhere + code:b8bb4c/80+b8bbb4/80+b8bb59/00 + cheat + description:Easy level exit (press start and select) + code:809b4b/00 + cheat + description:Bad buddy code (In 2P team mode, the inactive player can press select to gain control) + code:bfb2bd/00 + cheat + description:Both Kongs return (get both Kongs back on map screen after dying, doesn't work when you fall off the screen) + code:bf8fa4/03 + 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:bf8e84/ff + cheat + description:Keep Animals + code:808392/60+b883ce/68 + cheat + description:Multi-jump + code:bfb352/80+bfb94b/24+bfb950/80+bfb95b/d0 + cheat + description:Multi-jump - Expresso (the Ostrich) + code:bfba6f/ff + cheat + description:High-jump - Donkey Kong + code:bfb98b/c4 + cheat + description:Super-jump - Donkey Kong + code:bfb98b/d0 + cheat + description:Mega-jump - Donkey Kong + code:bfb98b/e0 + cheat + description:Moon-jump - Donkey Kong + code:bfb98b/ff + cheat + description:High-jump - Diddy Kong + code:bfb993/b4 + cheat + description:Super-jump - Diddy Kong + code:bfb993/c0 + cheat + description:Mega-jump - Diddy Kong + code:bfb993/d0 + cheat + description:Moon-jump - Diddy Kong + code:bfb993/ff + cheat + description:High-jump - Animals + code:bfba3b/c4 + cheat + description:Super-jump - Animals + code:bfba3b/d0 + cheat + description:Mega-jump - Animals + code:bfba3b/e4 + cheat + description:Moon-jump - Animals + code:bfba3b/ff + cheat + description:Land animals roll attack + code:bfc2d0/a2 + cheat + description:Start with 255 lives + code:b882bb/ff + cheat + description:Return of Kong (alt) + code:7e0579/01 + +cartridge sha256:628147468c3539283197f58f03b94df49758a332831857481ea9cc31645f0527 + name:Donkey Kong Country (USA) (Rev 2) + cheat + description:Invincibility + code:bfd395/00+bfc79e/60 + cheat + description:Invincibility in Mine Cart Carnage stage + code:b6a6ad/00 + cheat + description:Kill enemies on contact + code:bfc79f/82+bfd399/82+bfa7e4/00+b686a2/ea + cheat + description:Can cartwheel and stomp enemies who are immune to it + code:bfa7e4/00+b686a2/ea+be94c8/00 + cheat + description:Infinite lives + code:b6a873/ad + cheat + description:Get Life Balloons from anywhere + code:b6a744/80 + cheat + description:Get KONG letters from anywhere + code:bfd70d/80 + cheat + description:Get Banana bunches from anywhere + code:bfd7c6/80 + cheat + description:Get Midway Barrel from anywhere + code:b6f714/80 + cheat + description:Get most single Bananas from anywhere + code:b8bcdd/80+b8bc75/80+b8bc82/00 + cheat + description:Easy level exit (press start and select) + code:809b5e/00 + cheat + description:Bad buddy code (In 2P team mode, the inactive player can press select to gain control) + code:bfb2df/00 + cheat + description:Both Kongs return (get both Kongs back on map screen after dying, doesn't work when you fall off the screen) + code:bf8fa8/03 + 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:bf8e88/ff + cheat + description:Multi-jump + code:bfb374/80+bfb96d/24+bfb972/80+bfb97d/d0 + cheat + description:Multi-jump - Expresso (the Ostrich) + code:bfba91/ff + cheat + description:High-jump - Donkey Kong + code:bfb9ad/c4 + cheat + description:Super-jump - Donkey Kong + code:bfb9ad/d0 + cheat + description:Mega-jump - Donkey Kong + code:bfb9ad/e4 + cheat + description:Moon-jump - Donkey Kong + code:bfb9ad/ff + cheat + description:High-jump - Diddy Kong + code:bfb9b5/b4 + cheat + description:Super-jump - Diddy Kong + code:bfb9b5/c0 + cheat + description:Mega-jump - Diddy Kong + code:bfb9b5/d0 + cheat + description:Moon-jump - Diddy Kong + code:bfb9b5/ff + cheat + description:High-jump - Animals + code:bfba5d/c4 + cheat + description:Super-jump - Animals + code:bfba5d/d0 + cheat + description:Mega-jump - Animals + code:bfba5d/e4 + cheat + description:Moon-jump - Animals + code:bfba5d/ff + cheat + description:Land animals can roll attack + code:bfb394/c5 + cheat + description:Start with 255 lives + code:b883eb/ff + cheat + description:Return of Kong (alt) + code:7e0579/01 + +cartridge sha256:07ff03fa8c8e31d2f8277ef2a9785022edebf7f79b694c66a00c66d8e563bce5 + name:Donkey Kong Country (USA) (Competition Edition) + cheat + description:Kill enemies on contact + code:bfc783/82+bfd36f/82+bfa7d7/00+b686a2/ea + cheat + description:Can cartwheel and stomp enemies who are immune to it + code:bfa7d7/00+b686a2/ea+be94c4/00 + cheat + description:Multi-jump + code:bfb367/80+bfb961/00+bfb980/00+bfb965/80 + +cartridge sha256:b79c2bb86f6fc76e1fc61c62fc16d51c664c381e58bc2933be643bbc4d8b610c + name:Donkey Kong Country 2 - Diddy's Kong Quest (USA) (En,Fr) (Rev 1) + cheat + description:Master code - Must be entered + code:00fffc/f8+bec522/80+bbbe1b/80 + cheat + description:Invincibility + code:b8d1a0/a9+b8d1a1/10+b8d1a2/00 + cheat + description:Infinite lives + code:bec66d/ad+bec678/ad + cheat + description:Get 2 lives per 100 bananas collected + code:bec868/02+bec873/02 + cheat + description:Get 5 lives per 100 bananas collected + code:bec868/05+bec873/05 + cheat + description:Get 255 lives per 100 bananas collected + code:bec868/ff + cheat + description:When your last Kong is hit, the other returns + code:b8a1d1/ff+b8a2a0/ff + cheat + description:Easy level exit (press start and select) + code:808aac/00+808adb/00 + cheat + description:Kong family coins don't get used up + code:b49d5a/ad+b49d68/ad + cheat + description:Kremcoins don't get used up + code:b49d55/ad+b49d63/ad + cheat + description:Multi-jump + code:b89a00/00+b89b05/07+b89bd4/09+b8b1f5/00+b8ba3b/83 + cheat + description:Mega-jump for Diddy + code:ff0049/f0 + cheat + description:Super-jump - Diddy + code:ff0049/f3 + cheat + description:Jump higher - Diddy + code:ff0049/f6 + cheat + description:Jump lower - Diddy + code:ff0049/f9 + cheat + description:Jump much lower - Diddy + code:ff0049/fa + cheat + description:Mega-jump - Dixie + code:ff0133/f0 + cheat + description:Super-jump - Dixie + code:ff0133/f3 + cheat + description:Jump higher - Dixie + code:ff0133/f7 + cheat + description:Jump lower - Dixie + code:ff0133/f9 + cheat + description:Jump much lower - Dixie + code:ff0133/fa + cheat + description:Mega-jump - Rambi with Diddy riding + code:ff0109/f1 + cheat + description:Super-jump - Rambi with Diddy riding + code:ff0109/f3 + cheat + description:Rambi jumps higher with Diddy riding + code:ff0109/f7 + cheat + description:Rambi doesn't jump as high with Diddy riding + code:ff0109/fa + cheat + description:Start with more kong family coins + code:b4800e/8d + cheat + description:Start with more Kremcoins + code:b4800b/8d + cheat + description:Start with 3 lives + code:808f72/02+808fa1/02 + cheat + description:Start with 10 lives + code:808f72/09+808fa1/09 + cheat + description:Start with 25 lives + code:808f72/18+808fa1/18 + cheat + description:Start with 50 lives + code:808f72/31+808fa1/31 + cheat + description:Start with 99 lives + code:808f72/63+808fa1/63 + cheat + description:Start with 255 lives + code:808f72/ff + +cartridge sha256:35421a9af9dd011b40b91f792192af9f99c93201d8d394026bdfb42cbf2d8633 + name:Donkey Kong Country 2 - Diddy's Kong Quest (USA) (En,Fr) + cheat + description:Master code - Must be entered + code:00fffc/f8+bec517/80+bbbe0b/80 + cheat + description:Invincibility + code:b8d0b8/24 + cheat + description:Infinite lives + code:bec66d/ad+bec678/ad + cheat + description:When your last Kong is hit, the other returns + code:b8a1d1/ff+b8a2a0/ff + cheat + description:Easy level exit (press start and select) + code:808aac/00+808adb/00 + cheat + description:Kong family coins don't get used up + code:b49d5a/ad+b49d68/ad + cheat + description:Kremcoins don't get used up + code:b49d55/ad+b49d63/ad + cheat + description:Get single Bananas from almost anywhere + code:b5f7a8/80+b5f808/80+b5f7b6/00 + cheat + description:Get Banana bunches from anywhere + code:b3c33b/80 + cheat + description:Get DK and Banana Coins from anywhere + code:beb877/80 + cheat + description:Get KONG letters from anywhere + code:bebaba/80 + cheat + description:Get Krem Koins from anywhere + code:beb9e5/80 + cheat + description:Get Life balloons from anywhere + code:b3c3fa/80 + cheat + description:Get Midway Barrel from anywhere + code:b3e4c7/80 + cheat + description:Get 2 lives per 100 bananas collected + code:bec868/02+bec873/02 + cheat + description:Get 5 lives per 100 bananas collected + code:bec868/05+bec873/05 + cheat + description:Get 255 lives per 100 bananas collected + code:bec868/ff + cheat + description:Multi-jump + code:b8c515/20+b8c516/72+b8c517/c4+b8c518/60 + cheat + description:Mega-jump for Diddy + code:ff0049/f0 + cheat + description:Super-jump - Diddy + code:ff0049/f3 + cheat + description:Jump higher - Diddy + code:ff0049/f6 + cheat + description:Jump lower - Diddy + code:ff0049/f9 + cheat + description:Jump much lower - Diddy + code:ff0049/fa + cheat + description:Mega-jump - Dixie + code:ff0133/f0 + cheat + description:Super-jump - Dixie + code:ff0133/f3 + cheat + description:Jump higher - Dixie + code:ff0133/f7 + cheat + description:Jump lower - Dixie + code:ff0133/f9 + cheat + description:Jump much lower - Dixie + code:ff0133/fa + cheat + description:Mega-jump - Rambi with Diddy riding + code:ff0109/f1 + cheat + description:Super-jump - Rambi with Diddy riding + code:ff0109/f3 + cheat + description:Rambi jumps higher with Diddy riding + code:ff0109/f7 + cheat + description:Rambi doesn't jump as high with Diddy riding + code:ff0109/fa + cheat + description:Start with more kong family coins + code:b4800e/8d + cheat + description:Start with more Kremcoins + code:b4800b/8d + cheat + description:Start with 3 lives + code:808f72/02+808fa1/02 + cheat + description:Start with 10 lives + code:808f72/09+808fa1/09 + cheat + description:Start with 25 lives + code:808f72/18+808fa1/18 + cheat + description:Start with 50 lives + code:808f72/31+808fa1/31 + cheat + description:Start with 99 lives + code:808f72/63+808fa1/63 + cheat + description:Start with 255 lives + code:808f72/ff + +cartridge sha256:2277a2d8dddb01fe5cb0ae9a0fa225d42b3a11adccaeafa18e3c339b3794a32b + name:Donkey Kong Country 3 - Dixie Kong's Double Trouble! (USA) (En,Fr) + cheat + description:Invincibility + code:b882b8/93 + cheat + description:Invincibility (alt) + code:b8c64e/a9+b8c64f/09+b8c650/00+bee1ca/80 + cheat + description:Infinite lives + code:f880fa/a9 + cheat + description:Infinite bear coins + code:f490b5/09 + cheat + description:Infinite fuel - Rocket Rush level + code:f8b4e6/ad + cheat + description:Get Funky's Gyrocopter with no need for DK coins + code:f484ac/80+f484d7/80 + cheat + description:Get Single Bananas from almost anywhere + code:b7eba8/80+b7ec08/80+b7ebb6/00 + cheat + description:Get Banana Bunches from anywhere + code:bbd028/80 + cheat + description:Get Bear Coins from anywhere + code:bbd25a/80 + cheat + description:Get KONG letters from anywhere + code:bbcd17/80 + cheat + description:Get Midway Barrel from anywhere + code:bedc4a/80 + cheat + description:Get Bonus Coins from anywhere + code:bbd2fd/80 + cheat + description:Get Life Balloons from anywhere + code:bbd1d2/80 + cheat + description:Get DK Coins from anywhere + code:b6a74a/00 + cheat + description:Multi-jump + code:b8d79d/20+b8d79e/71+b8d79f/90+b8d7a0/60 + cheat + description:Exit unbeaten levels + code:808b96/24+808bad/24 + cheat + description:Normal controls in Poisonous Pipeline level + code:f8cd17/ca + cheat + description:No need to bash baddies in bonus round to get coin + code:bbd79b/24 + cheat + description:No need to get bananas in bonus round to get coin + code:fbd845/f0 + cheat + description:Skip intro screens + code:b287cb/80+b28cd6/80+b28f18/80+b28e7c/0f + +cartridge sha256:d45e26eb10c323ecd480e5f2326b223e29264c3adde67f48f0d2791128e519e8 + name:Doom (USA) + cheat + description:Infinite health + code:5c01fd/8f+5c01fe/ae+5c01ff/5a+5c0200/70+5c0201/80 + cheat + description:Start with mega health and mega armor + code:5ffac1/90+5ffac5/8d + cheat + description:Start with more ammo + code:5ffac9/fe + cheat + description:Heat vision/color blind mode + code:5c06e8/a9 + cheat + description:Select "The Shores of Hell" or "Inferno" in any skill level + code:5fa815/03 + +cartridge sha256:8d4ada4f98464d176ae7f0fb8a20032056680f3241637a0f903f23f31f41ff36 + name:Doom Troopers - Mutant Chronicles (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 + name:Doomsday Warrior (USA) + cheat + description:Infinite health and matches last forever + code:00a53a/bd + cheat + description:Always get 4 bonus points for improving abilities + code:0093d0/a9+0093d1/04+0093da/80 + cheat + description:On normal level, start with all stats at 2 bars instead of 0 + code:009258/05 + cheat + description:First 6 fights are against Sledge + code:009343/00+009344/80+009345/f5 + cheat + description:First 6 fights are against Layban + code:009343/01+009344/80+009345/f5 + cheat + description:First 6 fights are against Amon + code:009343/02+009344/80+009345/f5 + cheat + description:First 6 fights are against Daisy + code:009343/03+009344/80+009345/f5 + cheat + description:First 6 fights are against P-Lump + code:009343/04+009344/80+009345/f5 + cheat + description:First 6 fights are against Grimrock + code:009343/05+009344/80+009345/f5 + cheat + description:First 6 fights are against Nuform + code:009343/06+009344/80+009345/f5 + cheat + description:First 7 fights are against Shadow + code:009343/07+009344/80+009345/f5 + cheat + description:First 6 fights are against Ashura + code:009343/08+009344/80+009345/f5 + cheat + description:First 6 fights are against Main + code:009343/09+009344/80+009345/f5 + cheat + description:All fights are in order (you don't choose your opponent) + code:009337/00 + cheat + description:You can heal completely, not just to the top of each segment + code:00b4eb/00 + cheat + description:Don't heal at all + code:00b4f3/ea + 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 + name:Double Dragon V - The Shadow Falls (USA) + cheat + description:Always win - P1 + code:83cf93/00 + cheat + description:Can't perform special moves - P2/CPU + code:84a6b6/9e+84a682/9e+84a756/9c + cheat + description:Pick up to 9 points of any attribute instead of 5 + code:849da7/09 + cheat + description:Harder to recover from dizziness + code:80be75/ea + cheat + description:Dizziness doesn't last long + code:80be79/08 + cheat + description:Start with 50% health - both characters + code:80a389/28 + cheat + description:Start with 25% health - both characters + code:80a389/14 + 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 + name: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 + name:Dragon Ball Z - Hyper Dimension (Japan) + cheat + description:One hit kills + code:00c591/a9+00c592/01+00c593/00+00c59b/8d+00c59c/60 + +cartridge sha256:b698dd6e1db1a3fb2026dbc78c2cfbfd834f7c64fccb76139d5075c8b5233f28 + name:Dragon Quest I & II (Japan) + cheat + description:DQ I & II - Infinite MP in battle + code:0baa44/bd + cheat + description:DQ I & II - Infinite MP ouside battle + code:00cc80/b9 + cheat + description:DQ I & II - Keep gold after deposit in the vault + code:00f044/22 + cheat + description:DQ I & II - Take no damage from poison swamps + code:1b8935/ea + cheat + description:DQ I & II - Take no damage from barriers + code:1b897a/bd + cheat + description:DQ I & II - Take no damage from monster hits or magic + code:0b8fc0/60 + cheat + description:DQ I & II - Take no damage from monster fire + code:0b9880/80+0b9881/0a + cheat + description:DQ I & II - Inns don't take your money + code:00f4e6/ad + cheat + description:DQ I & II - All equipment in shops is free + code:00c78f/80 + cheat + description:DQ I - Infinite medical herbs + code:09836e/ad + cheat + description:DQ I - Key shops don't take your money + code:00ca40/ad + cheat + description:DQ I - Fairy water shops don't take your money + code:00c9f7/ad + +cartridge sha256:a3b1cae3fe55fe52c035ab122e7f850640b0935524496d45b1915ca3c8a934f4 + name:Dragon View (USA) + cheat + description:Infinite health (may crash at the end of Ortah Temple if using an emulator) + code:9e807e/af + cheat + description:Infinite Jade + code:92e329/af + cheat + description:Infinite Bombs + code:7e0e23/a2 + cheat + description:Infinite Potions + code:93d88b/af + cheat + description:Infinite magic for rings + code:9ae039/ad + cheat + description:Max level after killing a Demon + code:80ed26/3b + cheat + description:Sell a fruit to get 254 fruit + code:92e536/80+92e623/37 + 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 + name:Dragon's Lair (USA) + cheat + description:Infinite health + code:00b9a7/ea + cheat + description:Infinite time + code:00ba28/2c + cheat + description:Infinite lives + code:0084dd/ea + cheat + description:Start with 1 life + code:00b959/00 + cheat + description:Start with 6 lives + code:00b959/05 + cheat + description:Start with 9 lives + code:00b959/08 + cheat + description:Start with the Dagger + code:00b980/01 + cheat + description:Start with the Shuriken + code:00b980/02 + cheat + description:Slow timer + code:00ba51/70 + cheat + description:Faster timer + code:00ba51/25 + cheat + description:1 coin gives 10 + code:00b9b6/01 + 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 + name:Drakkhen (USA) + cheat + description:Protection from some attacks + code:10e206/bf+02ef49/bf+1bc9d9/bf + cheat + description:Magic points restored 50 points at a time while player is on screen + code:02eee4/32 + cheat + description:Magic points restored 10 points at a time while player is on screen + code:02eee4/0a + cheat + description:Magic points don't decrease except in battle + code:06de33/bf + +cartridge sha256:1a79d51a2ad7dd4848205a07ff8e5d873b155dc420de5e52158c9bab935e05c3 + name:Dream T.V. (USA) + cheat + description:Almost infinite health + code:82cf83/b1+82cfc7/b1 + cheat + description:Infinite lives + code:82aafc/00 + cheat + description:One hit kills, except skeletons + code:82dfee/b1 + cheat + description:Mega-jump (disable to land again) + code:82bd2c/b1 + cheat + description:Can't get hit - some characters are white + code:82ad30/00 + cheat + description:Start with 5 lives + code:8099b5/05 + cheat + description:Start with 1 life + code:8099b5/01 + cheat + description:Start with 8 lives + code:8099b5/08 + cheat + description:Start with 2/3 health - 1st life + code:809a05/20 + cheat + description:Start with 2/3 health - after 1st life + code:82aaf1/20 + cheat + description:Start with 1/3 health - 1st life + code:809a05/10 + cheat + description:Start with 1/3 health - after 1st life + code:82aaf1/10 + +cartridge sha256:c509e957873d6cff232bc360ae1795ea74e86bf4fa09c686f6cfc83bd8bac3d7 + name:Dual Orb II (Japan) + cheat + description:Gain 65,535 EXP from each battle + code:c41635/af+c41638/cb + cheat + description:Sell one item for maximum money + code:c02a14/00 + cheat + description:Can skip barrel puzzle + code:c220f4/72 + cheat + description:No random battles + code:c2309c/80 + cheat + description:Enemies start with 10 HP + code:c0d1a9/af+c0d1aa/39 + cheat + description:Enemies start with 100 HP + code:c0d1a9/af + +cartridge sha256:2dfc2e037679a62a960dab9682bca6d1b2737f603edd336c8b2fdf05db10cc07 + name:Dungeon Master (USA) + cheat + description:Almost no mana loss (must have enough to cast) + code:01957c/b7 + cheat + description:Food meter doesn't go down + code:05a517/b7 + cheat + description:Water meter doesn't go down + code:05a576/b7 + cheat + description:1st character has 250 maximum hit points + code:7004a6/fa + cheat + description:2nd character has 250 maximum hit points + code:7007c5/fa + cheat + description:3rd character has 250 maximum hit points + code:700ae4/fa + cheat + description:4th character has 250 maximum hit points + code:700e03/fa + cheat + description:1st character has 250 maximum stamina + code:7004aa/c4+7004ab/09 + cheat + description:2nd character has 250 maximum stamina + code:7007c9/c4+7007ca/09 + cheat + description:3rd character has 250 maximum stamina + code:700ae8/c4+700ae9/09 + cheat + description:4th character has 250 maximum stamina + code:700e07/c4+700e08/09 + cheat + description:1st character has 250 maximum mana + code:7004ae/fa + cheat + description:2nd character has 250 maximum mana + code:7007cd/fa + cheat + description:3rd character has 250 maximum mana + code:700aec/fa + cheat + description:4th character has 250 maximum mana + code:700e0b/fa + cheat + description:1st character has 99 current strength + code:7004ba/63 + cheat + description:2nd character has 99 current strength + code:7007d9/63 + cheat + description:3rd character has 99 current strength + code:700af8/63 + cheat + description:4th character has 99 current strength + code:700e17/63 + cheat + description:1st character has 99 maximum strength + code:7004b9/63 + cheat + description:2nd character has 99 maximum strength + code:7007d8/63 + cheat + description:3rd character has 99 maximum strength + code:700af7/63 + cheat + description:4th character has 99 maximum strength + code:700e16/63 + cheat + description:1st character has 99 current dexterity + code:7004bd/63 + cheat + description:2nd character has 99 current dexterity + code:7007dc/63 + cheat + description:3rd character has 99 current dexterity + code:700afb/63 + cheat + description:4th character has 99 current dexterity + code:700e1a/63 + cheat + description:1st character has 99 maximum dexterity + code:7004bc/63 + cheat + description:2nd character has 99 maximum dexterity + code:7007db/63 + cheat + description:3rd character has 99 maximum dexterity + code:700afa/63 + cheat + description:4th character has 99 maximum dexterity + code:700e19/63 + cheat + description:1st character has 99 current wisdom + code:7004c0/63 + cheat + description:2nd character has 99 current wisdom + code:7007df/63 + cheat + description:3rd character has 99 current wisdom + code:700afe/63 + cheat + description:4th character has 99 current wisdom + code:700e1d/63 + cheat + description:1st character has 99 maximum wisdom + code:7004bf/63 + cheat + description:2nd character has 99 maximum wisdom + code:7007de/63 + cheat + description:3rd character has 99 maximum wisdom + code:700afd/63 + cheat + description:4th character has 99 maximum wisdom + code:700e1c/63 + cheat + description:1st character has 99 current vitality + code:7004c3/63 + cheat + description:2nd character has 99 current vitality + code:7007e2/63 + cheat + description:3rd character has 99 current vitality + code:700b01/63 + cheat + description:4th character has 99 current vitality + code:700e20/63 + cheat + description:1st character has 99 maximum vitality + code:7004c2/63 + cheat + description:2nd character has 99 maximum vitality + code:7007e1/63 + cheat + description:3rd character has 99 maximum vitality + code:700b00/63 + cheat + description:4th character has 99 maximum vitality + code:700e1f/63 + cheat + description:1st character has 99 current anti-magic + code:7004c6/63 + cheat + description:2nd character has 99 current anti-magic + code:7007e5/63 + cheat + description:3rd character has 99 current anti-magic + code:700b04/63 + cheat + description:4th character has 99 current anti-magic + code:700e23/63 + cheat + description:1st character has 99 maximum anti-magic + code:7004c5/63 + cheat + description:2nd character has 99 maximum anti-magic + code:7007e4/63 + cheat + description:3rd character has 99 maximum anti-magic + code:700b03/63 + cheat + description:4th character has 99 maximum anti-magic + code:700e22/63 + cheat + description:1st character has 99 current anti-fire + code:7004c9/63 + cheat + description:2nd character has 99 current anti-fire + code:7007e8/63 + cheat + description:3rd character has 99 current anti-fire + code:700b07/63 + cheat + description:4th character has 99 current anti-fire + code:700e26/63 + cheat + description:1st character has 99 maximum anti-fire + code:7004c8/63 + cheat + description:2nd character has 99 maximum anti-fire + code:7007e7/63 + cheat + description:3rd character has 99 maximum anti-fire + code:700b06/63 + cheat + description:4th character has 99 maximum anti-fire + code:700e25/63 + cheat + description:1st character is a level 15 fighter + code:7004cf/7f + cheat + description:1st character is a level 15 ninja + code:7004d5/7f + cheat + description:1st character is a level 15 healer + code:7004db/7f + cheat + description:1st character is a level 15 wizard + code:7004e1/7f + cheat + description:2nd character is a level 15 fighter + code:7007ee/7f + cheat + description:2nd character is a level 15 ninja + code:7007f4/7f + cheat + description:2nd character is a level 15 healer + code:7007fa/7f + cheat + description:2nd character is a level 15 wizard + code:700800/7f + cheat + description:3rd character is a level 15 fighter + code:700b0d/7f + cheat + description:3rd character is a level 15 ninja + code:700b13/7f + cheat + description:3rd character is a level 15 healer + code:700b19/7f + cheat + description:3rd character is a level 15 wizard + code:700b1f/7f + cheat + description:4th character is a level 15 fighter + code:700e2c/7f + cheat + description:4th character is a level 15 ninja + code:700e32/7f + cheat + description:4th character is a level 15 healer + code:700e38/7f + cheat + description:4th character is a level 15 wizard + code:700e3e/7f + cheat + description:1st character has a nearly full food meter + code:7004b3/07 + cheat + description:1st character has a nearly full water meter + code:7004b5/07 + cheat + description:2nd character has a nearly full food meter + code:7007d2/07 + cheat + description:2nd character has a nearly full water meter + code:7007d4/07 + cheat + description:3rd character has a nearly full food meter + code:700af1/07 + cheat + description:3rd character has a nearly full water meter + code:700af3/07 + cheat + description:4th character has a nearly full food meter + code:700e10/07 + cheat + description:4th character has a nearly full water meter + code:700e12/07 + +cartridge sha256:8481e47381bd98c27b9782b5727a5d5f0976fbb3aa3df25c2c42aa37e0586815 + name:E.V.O. - Search for Eden (USA) + cheat + description:Invincibility + code:06858f/60 + cheat + description:Infinite EVO points + code:00d637/80 + cheat + description:Infinite EP + code:7e00d2/10+7e00d3/27 + cheat + description:Protection from most hazards + code:0685fc/a5 + cheat + description:Food replenishes hit points to full + code:1e844a/00 + cheat + description:Less damage from stronger creatures + code:068f8c/07 + cheat + description:Horn never breaks + code:06832f/a5 + cheat + description:Collect one health to max it out + code:1e8464/00 + cheat + description:One-hit kills + code:0787a4/00 + +cartridge sha256:0408e3d9f2259044344a3bfbd7a7ca3c3427f82108fbecd6e5c4c41e80cd303b + name:Earth Defense Force (USA) + cheat + description:Invincibility + code:0086ce/24 + cheat + description:Infinite shields + code:0086e7/ad + cheat + description:Infinite credits + code:058bb9/ad + cheat + description:Continually hit anywhere + code:138124/24+0086ce/24+138108/24+1380fa/24+138116/24 + cheat + description:Advancing experience levels is easier + code:00d665/20 + cheat + description:Advancing experience levels is much easier + code:00d665/0c + cheat + description:Keep current score when game is continued + code:00dfe4/ad+00dfe7/ad + cheat + description:1 credit + code:00dff6/00+00dff5/a9+00dff7/00 + cheat + description:2 credits + code:00dff6/01+00dff5/a9+00dff7/00 + cheat + description:3 credits + code:00dff6/02+00dff5/a9+00dff7/00 + cheat + description:6 credits + code:00dff6/05+00dff5/a9+00dff7/00 + cheat + description:8 credits + code:00dff6/07+00dff5/a9+00dff7/00 + cheat + description:10 credits + code:00dff6/09+00dff5/a9+00dff7/00 + cheat + description:Start with 4 shields + code:00dfeb/36+00dfec/e0 + cheat + description:Start with 5 shields + code:00dfeb/d9+00dfec/9b + cheat + description:Start at experience level 2 + code:00dfff/02 + cheat + description:Start at experience level 3 + code:00dfff/03 + cheat + description:Start at experience level 4 + code:00dfff/04 + cheat + description:Start at experience level 5 + code:00dfff/05 + cheat + description:Start at stage 2 + code:00e030/01+00e02f/a9+00e031/00 + cheat + description:Start at stage 3 + code:00e030/02+00e02f/a9+00e031/00 + cheat + description:Start at stage 4 + code:00e030/03+00e02f/a9+00e031/00 + cheat + description:Start at stage 5 + code:00e030/04+00e02f/a9+00e031/00 + cheat + description:Start at stage 6 + code:00e030/05+00e02f/a9+00e031/00 + cheat + description:Start a new game to view ending + code:008235/08 + +cartridge sha256:a8fe2226728002786d68c27ddddf0b90a894db52e4dfe268fdf72a68cae5f02e + name:EarthBound (USA) + cheat + description:Infinite health (all characters) + code:c2716c/bd + cheat + description:Get to level 99 after one battle (all characters) + code:c1d9fb/ff + cheat + description:Fast money (buy a bread with the code disabled, enable and sell it for $32,646) + code:d55fcc/ff + cheat + description:Dad never calls + code:c0527c/fe + cheat + description:Massive numbers of enemies (piracy check) + code:c0281d/80 + cheat + description:Start with a level 9 character + code:c1d8ec/09 + cheat + description:Start with a level 15 character + code:c1d8ec/0f + cheat + description:Start with a level 50 character + code:c1d8ec/32 + cheat + description:Start with a level 100 character + code:c1d8ec/63 + cheat + description:Start with a level 255 character + code:c1d8ec/ff + cheat + description:Start with a super strong character + code:c1d8f1/ff + cheat + description:Start with a lot of HP + code:c1d90a/99 + cheat + description:Start with a lot of PSI + code:c1d91b/99 + cheat + description:Infinite health + code:7e9a13/e7+7e9a14/03 + cheat + description:9999 current PP + code:7e9a1b/0f+7e9a1c/27 + +cartridge sha256:4579e437279f79eedd6b9cf648a814df2ab2c83d937a1bcec1578d28965fb9a0 + name:Earthworm Jim (USA) + cheat + description:Infinite health + code:c0681a/cd + cheat + description:Infinite Ammo + code:c06777/dd + cheat + description:Infinite lives + code:c00ecf/cd + cheat + description:Hit anywhere (Gun) + code:c0406e/80+c188e9/80+c0406f/15 + cheat + description:Die after one hit + code:c06836/30 + cheat + description:Start with 1 life + code:c066e4/30 + cheat + description:Start with 5 lives + code:c066e4/34 + cheat + description:Start with 10 lives + code:c066e4/39 + cheat + description:Start with 25 lives + code:c066e4/48 + cheat + description:Start with 50 lives + code:c066e4/61 + cheat + description:Start with 300% health + code:c06836/33 + cheat + description:Start with 500% health + code:c06836/35 + cheat + description:Start with 900% health + code:c06836/39 + 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 + name:Earthworm Jim 2 (USA) + cheat + description:Infinite health + code:c27431/a9 + cheat + description:Infinite lives + code:c0184a/a9 + cheat + description:Hit anywhere (Gun) + code:c27fa5/80+c27fa6/15 + cheat + description:Infinite time - Lorenzen's Soil level + code:c21ac1/ad + cheat + description:Get 1000 bullets on pick-up + code:c45cb8/03+c45cb7/e9 + cheat + description:Get 2000 bullets on pick-up + code:c45cb8/07+c45cb7/e0 + cheat + description:Start with 200% health + code:c2744d/32 + cheat + description:Start with 300% health + code:c2744d/33 + cheat + description:Start with 400% health + code:c2744d/34 + cheat + description:Start with 500% health + code:c2744d/35 + cheat + description:Start with 700% health + code:c2744d/37 + cheat + description:Start with 900% health + code:c2744d/39 + cheat + description:Start with 1 life and no continues + code:c27175/30 + cheat + description:Start with 5 lives + code:c27175/34 + cheat + description:Start with 7 lives + code:c27175/36 + cheat + description:Start with 9 lives + code:c27175/38 + cheat + description:Start with 2000 bullets + code:c459fa/32 + cheat + description:Start with 3000 bullets + code:c459fa/33 + cheat + description:Start with 4000 bullets + code:c459fa/34 + cheat + description:Start with 5000 bullets + code:c459fa/35 + cheat + description:Start with 7000 bullets + code:c459fa/37 + cheat + description:Start with 9000 bullets + code:c459fa/39 + cheat + description:Invincibility + code:7e653c/10 + +cartridge sha256:5d658b63d35e2e0baf48ae3bb04ea5e1553855b34bb39fc2c7ca41fbd3894d52 + name:Eek! The Cat (USA) + cheat + description:Infinite health + code:7e004e/bf + cheat + description:Infinite lives + code:7e1fe5/09 + +cartridge sha256:a6eec3329d956e1ddc4acfe3c738387622c10fc95fb9ab63dd5f45be8bec0b16 + name:Emerald Dragon (Japan) + cheat + description:Max level after one battle + code:c00fcd/80 + cheat + description:Max Parus after one battle + code:c00f88/80 + cheat + description:No random battles + code:c1a14c/18 + +cartridge sha256:f14e30ee452ec930a6d08094094b287d0c40c8108f2017c418015242987649b3 + name:Emmitt Smith Football (USA) + cheat + description:Cannot be tackled (hold B) + code:80c919/ef+80c916/55+80c915/ad+80c917/01 + +cartridge sha256:cfd666f0bbabec59613d9fe189db7d0a060a78047bc084c0c365840769047bf2 + name:Equinox (USA) + cheat + description:Invincibility against most small monsters + code:08b314/ad + cheat + description:Infinite life + code:08cd42/ea + cheat + description:Infinite magic (must have enough MP for spell to work) + code:08cdf1/af + cheat + description:More life from Apples + code:81d6c8/a9 + cheat + description:Super-jump + code:81d135/21+81d144/24 + cheat + description:Mega-jump + code:81d135/1a+81d144/24 + cheat + description:Super speed + code:81d0a7/9e+81d0ad/a0 + cheat + description:Colored doors don't need keys + code:08b68c/00+08b68d/ea + cheat + description:Walk through objects (hold L) + code:08b27c/d0+08b27a/20+08b277/29+08b276/ad+08b26c/0c + cheat + description:Slow spell lasts 2x as long + code:08ceab/05 + cheat + description:Slow spell lasts 3x as long + code:08ceab/08 + cheat + description:Freeze spell lasts 2x as long + code:08ce96/05 + cheat + description:Freeze spell lasts 3x as long + code:08ce96/08 + +cartridge sha256:1576066e0cb771a91caf79e7d4f6dc00eb0daa47f0786f1604b32537429a7f45 + name:Extra Innings (USA) + cheat + description:Game lasts 1 inning + code:0093f3/01+009416/01+009524/01 + cheat + description:Game lasts 2 innings + code:0093f3/02+009416/02+009524/02 + cheat + description:Game lasts 3 innings + code:0093f3/03+009416/03+009524/03 + cheat + description:Game lasts 4 innings + code:0093f3/04+009416/04+009524/04 + cheat + description:Game lasts 5 innings + code:0093f3/05+009416/05+009524/05 + cheat + description:Game lasts 7 innings + code:0093f3/07+009416/07+009524/07 + cheat + description:1 strike and batter's out + code:008c35/01+008f48/00 + cheat + description:2 strikes and batter's out + code:008c35/02+008f48/01 + cheat + description:Batter never strikes out + code:008c2e/ad+008f4b/ad + cheat + description:1 ball and batter walks + code:008cc7/01 + cheat + description:2 balls and batter walks + code:008cc7/02 + cheat + description:3 balls and batter walks + code:008cc7/03 + cheat + description:Batter never walks + code:008cc0/ad + cheat + description:1 out per inning + code:008f32/01+008c6b/01 + cheat + description:2 outs per inning + code:008f32/02+008c6b/02 + +cartridge sha256:1d38e3af9e3a6409e93f4705b68c42558f558c68f3e83ef2a40e46cf560b26cc + name:F-1 ROC - Race of Champions (USA) + cheat + description:No damage when hitting walls + code:00c1bc/a5 + cheat + description:No damage when hitting other cars + code:00d1d4/a5 + cheat + description:Normal tires are free + code:05faf7/00 + cheat + description:Hi-grip tires are free + code:05faf9/00 + cheat + description:Rain tires are free + code:05faf5/00 + cheat + description:2L nitro is free + code:05fb09/00 + cheat + description:3L nitro is free + code:05fb0b/00 + cheat + description:4L nitro is free + code:05fb0d/00 + cheat + description:Ford V-8 engine is free + code:05faff/00+05fb00/00 + cheat + description:Ilmoa V-8 engine is free + code:05fb01/00+05fb02/00 + cheat + description:Remart V-10 engine is free + code:05fb03/00+05fb04/00 + cheat + description:Low DF rear wing is free + code:05faed/00 + cheat + description:High DF rear wing is free + code:05faf1/00+05faf2/00 + cheat + description:Low DF front wing is free + code:05fae3/00 + cheat + description:High DF front wing is free + code:05fae7/00+05fae8/00 + cheat + description:Special-L front wing is free + code:05fae9/00+05faea/00 + cheat + description:Small diffuser is free + code:05fadb/00 + cheat + description:Large diffuser is free + code:05fadf/00 + cheat + description:Special diffuser is free + code:05fae1/00+05fae2/00 + cheat + description:Hard suspension is free + code:05fad7/00 + cheat + description:Active suspension is free + code:05fad9/00+05fada/00 + cheat + description:Carbon brakes are free + code:05fad1/00 + cheat + description:Antilock brakes are free + code:05fad3/00+05fad4/00 + cheat + description:5-speed transmission is free + code:05fac9/00 + cheat + description:6-speed transmission is free + code:05facb/00+05facc/00 + cheat + description:7-speed transmission is free + code:05facd/00+05face/00 + cheat + description:Type 2 chassis is free + code:05fac3/00+05fac4/00 + cheat + description:Type 3 chassis is free + code:05fac5/00+05fac6/00 + cheat + description:Start with no money instead of $500 + code:08d788/9c + cheat + description:Start with $5,240 + code:08d784/ea+08d785/a9+08d787/02 + cheat + description:Start with $20,600 + code:08d784/ea+08d785/a9+08d787/08 + cheat + description:Start with $163,960 + code:08d784/ea+08d785/a9+08d787/40 + cheat + description:Start with $327,800 + code:08d784/ea+08d785/a9+08d787/80 + cheat + description:Start with $652,920 + code:08d784/ea+08d785/a9+08d787/ff + +cartridge sha256:d689392884df91c2bb84b1411a96f3919b6c9cc8a583dff901a98f0d86d31c30 + name:Faceball 2000 (USA) + cheat + description:Infinite lives + code:02cc9d/b5 + cheat + description:Only need 8 tags to win in arena mode instead of 10 (start with 2 instead of 0) + code:019a65/95 + cheat + description:Allow 98 seconds in zone 1 bonus level + code:0f8461/64 + cheat + description:Allow 98 seconds in zone 2 bonus level + code:0f865d/64 + cheat + description:Allow 98 seconds in zone 3 bonus level + code:0f88b3/64 + cheat + description:Allow 98 seconds in zone 4 bonus level + code:0f8b68/64 + cheat + description:Allow 198 seconds in zone 5 bonus level + code:0f8da8/c8 + cheat + description:Allow 198 seconds in zone 6 bonus level + code:0f9069/c8 + cheat + description:Allow 198 seconds in zone 7 bonus level + code:0f9344/c8 + cheat + description:Start with 1 life instead of 3 + code:019a8a/01 + cheat + description:Start with 5 lives + code:019a8a/05 + cheat + description:Start with 7 lives + code:019a8a/07 + cheat + description:Start with 9 lives + code:019a8a/09 + cheat + description:Start with 25 lives + code:019a8a/19 + cheat + description:Start with 50 lives + code:019a8a/32 + cheat + description:Start with 75 lives + code:019a8a/4b + cheat + description:Start with 99 lives + code:019a8a/63 + cheat + description:Start with 255 lives + code:019a8a/ff + cheat + description:Start each Cyberzone level with 1 tag required + code:029279/a9+02927a/01 + cheat + description:Start each Cyberzone level with 5 tags required + code:029279/a9+02927a/05 + cheat + description:Start each Cyberzone level with 20 tags required + code:029279/a9+02927a/14 + cheat + description:Start each Cyberzone level with 30 tags required + code:029279/a9+02927a/1e + cheat + description:Start each Cyberzone level with 60 tags required + code:029279/a9+02927a/3c + cheat + description:Start each Cyberzone level with 90 tags required + code:029279/a9+02927a/5a + cheat + description:Start Cyberzone mode on zone 1 level 2 + code:02b1dd/ad+02adfa/01 + cheat + description:Start Cyberzone mode on zone 1 level 3 + code:02b1dd/ad+02adfa/02 + cheat + description:Start Cyberzone mode on zone 1 level 4 + code:02b1dd/ad+02adfa/03 + cheat + description:Start Cyberzone mode on zone 1 level 5 + code:02b1dd/ad+02adfa/04 + cheat + description:Start Cyberzone mode on zone 1 bonus level + code:02b1dd/ad+02adfa/05 + cheat + description:Start Cyberzone mode on zone 2 level 6 + code:02b1dd/ad+02adfa/06 + cheat + description:Start Cyberzone mode on zone 2 level 7 + code:02b1dd/ad+02adfa/07 + cheat + description:Start Cyberzone mode on zone 2 level 8 + code:02b1dd/ad+02adfa/08 + cheat + description:Start Cyberzone mode on zone 2 level 9 + code:02b1dd/ad+02adfa/09 + cheat + description:Start Cyberzone mode on zone 2 level 10 + code:02b1dd/ad+02adfa/0a + cheat + description:Start Cyberzone mode on zone 2 bonus level + code:02b1dd/ad+02adfa/0b + cheat + description:Start Cyberzone mode on zone 3 level 11 + code:02b1dd/ad+02adfa/0c + cheat + description:Start Cyberzone mode on zone 3 level 12 + code:02b1dd/ad+02adfa/0d + cheat + description:Start Cyberzone mode on zone 3 level 13 + code:02b1dd/ad+02adfa/0e + cheat + description:Start Cyberzone mode on zone 3 level 14 + code:02b1dd/ad+02adfa/0f + cheat + description:Start Cyberzone mode on zone 3 level 15 + code:02b1dd/ad+02adfa/10 + cheat + description:Start Cyberzone mode on zone 3 bonus level + code:02b1dd/ad+02adfa/11 + cheat + description:Start Cyberzone mode on zone 4 level 16 + code:02b1dd/ad+02adfa/12 + cheat + description:Start Cyberzone mode on zone 4 level 17 + code:02b1dd/ad+02adfa/13 + cheat + description:Start Cyberzone mode on zone 4 level 18 + code:02b1dd/ad+02adfa/14 + cheat + description:Start Cyberzone mode on zone 4 level 19 + code:02b1dd/ad+02adfa/15 + cheat + description:Start Cyberzone mode on zone 4 level 20 + code:02b1dd/ad+02adfa/16 + cheat + description:Start Cyberzone mode on zone 4 bonus level + code:02b1dd/ad+02adfa/17 + cheat + description:Start Cyberzone mode on zone 5 level 21 + code:02b1dd/ad+02adfa/18 + cheat + description:Start Cyberzone mode on zone 5 level 22 + code:02b1dd/ad+02adfa/19 + cheat + description:Start Cyberzone mode on zone 5 level 23 + code:02b1dd/ad+02adfa/1a + cheat + description:Start Cyberzone mode on zone 5 level 24 + code:02b1dd/ad+02adfa/1b + cheat + description:Start Cyberzone mode on zone 5 level 25 + code:02b1dd/ad+02adfa/1c + cheat + description:Start Cyberzone mode on zone 5 bonus level + code:02b1dd/ad+02adfa/1d + cheat + description:Start Cyberzone mode on zone 6 level 26 + code:02b1dd/ad+02adfa/1e + cheat + description:Start Cyberzone mode on zone 6 level 27 + code:02b1dd/ad+02adfa/1f + cheat + description:Start Cyberzone mode on zone 6 level 28 + code:02b1dd/ad+02adfa/20 + cheat + description:Start Cyberzone mode on zone 6 level 29 + code:02b1dd/ad+02adfa/21 + cheat + description:Start Cyberzone mode on zone 6 level 30 + code:02b1dd/ad+02adfa/22 + cheat + description:Start Cyberzone mode on zone 6 bonus level + code:02b1dd/ad+02adfa/23 + cheat + description:Start Cyberzone mode on zone 7 level 31 + code:02b1dd/ad+02adfa/24 + cheat + description:Start Cyberzone mode on zone 7 level 32 + code:02b1dd/ad+02adfa/25 + cheat + description:Start Cyberzone mode on zone 7 level 33 + code:02b1dd/ad+02adfa/26 + cheat + description:Start Cyberzone mode on zone 7 level 34 + code:02b1dd/ad+02adfa/27 + cheat + description:Start Cyberzone mode on zone 7 level 35 + code:02b1dd/ad+02adfa/28 + cheat + description:Start Cyberzone mode on zone 7 bonus level + code:02b1dd/ad+02adfa/29 + cheat + description:Start Cyberzone mode on zone 8 level 36 + code:02b1dd/ad+02adfa/2a + cheat + description:Start Cyberzone mode on zone 8 level 37 + code:02b1dd/ad+02adfa/2b + cheat + description:Start Cyberzone mode on zone 8 level 38 + code:02b1dd/ad+02adfa/2c + cheat + description:Start Cyberzone mode on zone 8 level 39 + code:02b1dd/ad+02adfa/2d + cheat + description:Start Cyberzone mode on zone 8 level 40 + code:02b1dd/ad+02adfa/2e + cheat + description:Start Cyberzone mode on zone 8 level 41 + code:02b1dd/ad+02adfa/2f + +cartridge sha256:2891f1eab285133364ecc379a5c9e1d0026d60f425f1a458d149014f386cfa50 + name:Family Dog (USA) + cheat + description:Infinite health (except against vacuum or falls) + code:81af8c/bd + cheat + description:Infinite lives + code:81c6bc/ad + cheat + description:Infinite Super Barks + code:81c6f2/ad + cheat + description:Start with 90 Super Barks + code:80811f/09 + cheat + description:Cheese Treats worth 10 Super Barks + code:81c6d3/0a + cheat + description:Start in the Hallway + code:80ce46/50 + cheat + description:Start in the Living Room + code:80ce46/64 + cheat + description:Start in the Hallway to the Kitchen + code:80ce46/6e + cheat + description:Start in the Kitchen + code:80ce46/82 + cheat + description:Start in the Hallway to the Backdoor + code:80ce46/8c + cheat + description:Start outside the Yard + code:80ce46/96 + cheat + description:Start in the Kennel Interior + code:80ce46/be + cheat + description:Start in the Kennel Exterior + code:80ce46/e0+80ce47/01 + cheat + description:Start in the Woods and Trees + code:80ce46/f4+80ce47/01 + cheat + description:View the ending + code:80ce46/1c+80ce47/02 + +cartridge sha256:c92f389d25870aada3002775838ec9f69a988120c0238af885fd08d46bd94930 + name:Fatal Fury (USA) + cheat + description:Take minimum damage - P1 + code:00c459/ad + cheat + description:Take minimum damage - P2/CPU + code:00c4d6/ad + cheat + description:Win 1 bout to win the match instead of 2 out of 3 (disable on bonus rounds) + code:00c678/01 + cheat + description:10 seconds to complete bonus rounds + code:00a737/10 + cheat + description:30 seconds to complete bonus rounds + code:00a737/30 + cheat + description:45 seconds to complete bonus rounds + code:00a737/45 + cheat + description:60 seconds to complete bonus rounds + code:00a737/60 + cheat + description:90 seconds to complete bonus rounds + code:00a737/90 + cheat + description:Always fight Richard Myer on the West Subway + code:009223/9c+0093aa/03 + cheat + description:Always fight Michael Max on the West Subway + code:009223/9c+0093aa/04 + cheat + description:Always fight Duck King on the West Subway + code:009223/9c+0093aa/05 + cheat + description:Always fight Tung Fu Rue on the West Subway + code:009223/9c+0093aa/06 + cheat + description:Always fight Hwa Jai on the West Subway + code:009223/9c+0093aa/07 + cheat + description:Always fight Raiden on the West Subway + code:009223/9c+0093aa/08 + cheat + description:Always fight Billy Kane on the West Subway + code:009223/9c+0093aa/09 + cheat + description:Always fight Geese Howard on the West Subway + code:009223/9c+0093aa/0a + cheat + description:Start with 1/4 health - both players + code:00a70b/18 + cheat + description:Start with 1/2 health - both players + code:00a70b/30 + cheat + description:Start with 3/4 health - both players + code:00a70b/48 + +cartridge sha256:a0c554d46034caef231c36dd6849828ca39703678fb7fdd15a11f292b93bcd6b + name:Fatal Fury 2 (USA) + cheat + description:Infinite health - P1 + code:c0310b/80 + cheat + description:Infinite time + code:c030f4/00 + cheat + description:Timer is 2x fast + code:c030f4/02 + cheat + description:Timer is 3x fast + code:c030f4/03 + cheat + description:Computer can't win a round, except last round, game ends after 4 rounds + code:c07c47/ad + cheat + description:P1 is Billy Kane + code:c0b779/a9+c0b77a/08+c0b77b/00 + cheat + description:P1 is Axel Hawk + code:c0b77a/09+c0b779/a9+c0b77b/00 + cheat + description:P1 is Lawrence B + code:c0b779/a9+c0b77b/00+c0b77a/0a + cheat + description:P1 is Wolfgang Krauser + code:c0b77a/0b+c0b779/a9+c0b77b/00 + cheat + description:P2 is Billy Kane + code:c0b7d9/a9+c0b7da/08+c0b7db/00 + cheat + description:P2 is Axel Hawk + code:c0b7da/09+c0b7d9/a9+c0b7db/00 + cheat + description:P2 is Lawrence B + code:c0b7da/0a+c0b7d9/a9+c0b7db/00 + cheat + description:P2 is Wolfgang Krauser + code:c0b7da/0b+c0b7d9/a9+c0b7db/00 + cheat + description:Super vertical jump - P1 + code:ca0776/10 + cheat + description:Bogus vertical jump - P1 + code:ca0776/ff + cheat + description:Start with 1/2 health + code:c030bd/30 + +cartridge sha256:410e90db3d38507ccc85ad3bca6b27a080123fd5160e82b5de4d914d4b6d6e61 + name: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 + name:Fighter's History (USA) (Rev 1) + cheat + description:Infinite health - P1 + code:7e0a56/c8 + cheat + description:Enable Clown and Karnov + code:7e09a4/01 + cheat + description:Enable sound test + code:c107fa/ea+c107f9/20+c107f8/a9 + +cartridge sha256:f71817f55febd32fd1dce617a326a77b6b062dd0d4058ecd289f64af1b7a1d05 + name:Final Fantasy - Mystic Quest (USA) (Rev 1) + cheat + description:Infinite cure potions + code:00c019/be + cheat + description:Use a cure, gain a cure + code:00c019/fe + cheat + description:Gain 198 cures after one is used + code:00c019/4e + cheat + description:Cure restores life points to maximum + code:00c029/00 + cheat + description:Infinite life points - can make enemies invincible + code:02869b/a5 + cheat + description:Infinite ninja stars + code:0290bb/a5 + cheat + description:Infinite bombs in battle + code:02904f/a5 + cheat + description:Quick level gain + code:0cd0c2/80 + 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 + name:Final Fantasy - Mystic Quest (USA) + cheat + description:Infinite life points (can make enemies invincible, disable to defeat them) + code:02869b/a5 + cheat + description:Infinite cure potions + code:00c019/be + cheat + description:Infinite ninja stars + code:0290bb/a5 + cheat + description:Infinite bombs in battle + code:02904f/a5 + cheat + description:Use a cure, gain a cure + code:00c019/fe + cheat + description:Gain 198 cures after one is used + code:00c019/4e + cheat + description:Cure restores life points to maximum + code:00c029/00 + cheat + description:Quick level gain + code:0cd0c2/80 + 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 + name:Final Fantasy II (USA) (Rev 1) + cheat + description:Almost infinite HP (can make big and sometimes normal monsters invincible, disable to defeat them) + code:03caf6/bd + cheat + description:Infinite MP during battles, doesn't work on twin attacks + code:038532/bd + cheat + description:Infinite items outside of battle except for the Whistle + code:01a6f5/ae + cheat + description:Infinite Whistles + code:01a328/ae + cheat + description:Money doesn't decrease if you run away from a battle + code:0388d5/ad+0388de/ad + cheat + description:Money doesn't decrease in shops + code:01c702/ad+01c707/ae + cheat + description:No random battles + code:7e0686/00 + cheat + description:No random battles (alt) + code:00894d/60 + cheat + description:Always fight the rarest enemy in that area + code:008af4/0c + cheat + description:Always get a treasure from each enemy defeated + code:03ecf1/80 + cheat + description:When treasures are awarded after battle, receive 5 instead of 1 + code:01d488/05 + cheat + description:When arrows are awarded after battle, receive 50 instead of 10 + code:01d47e/32 + cheat + description:When treasures are awarded after battle, receive the rarest + code:03ed35/03 + cheat + description:Sumon the Big Chocobo anywhere by using a Carrot instead of the Whistle + code:01a325/eb + cheat + description:The quantity of items don't decrease when selling them + code:01ca54/bd + cheat + description:No music while traveling or in a town + code:008b3f/60 + cheat + description:Gunslinger code + code:01a6f2/44 + cheat + description:Save anywhere + code:0099cf/a9 + cheat + description:131,070 exp points after each battle + code:13ff7b/01+13ff91/b1 + cheat + description:16,646,142 exp points after each battle + code:13ff7b/01+13ff91/b1+13ff8b/b3 + cheat + description:Get at least 150 GP after each battle + code:03ed72/69+03ed73/96+03ed74/ea + cheat + description:Get at least 255 GP after each battle + code:03ed7e/ee + cheat + description:Get at least 65,536 GP after each battle + code:03ed87/ee + cheat + description:Get 99 of items that you are given or find in a pot, treasure chest, etc. + code:009819/63 + cheat + description:Get 99 arrows when you find them in a pot or treasure chest + code:009828/63 + cheat + description:Cure2 is ultra strong + code:0f973b/c8 + cheat + description:Cure2 restores HP to all members in the party during battle + code:0f973a/40 + cheat + description:Cure2 restores all HP/MP during battle + code:0f973d/16 + cheat + description:Fire1 spell is ultra strong + code:0f984f/c8 + cheat + description:Fire1 spell hits every enemy + code:0f984e/c1 + cheat + description:Ice1 spell is ultra strong + code:0f9861/c8 + cheat + description:Ice1 spell hits every enemy + code:0f9860/c1 + cheat + description:Lit1 spell is ultra strong + code:0f9873/c8 + cheat + description:Lit1 spell hits every enemy + code:0f9872/c1 + 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 + name:Final Fantasy II (USA) + cheat + description:Skip intro + code:128020/09+128021/04 + cheat + description:Almost infinite HP (can make big and sometimes normal monsters invincible, disable to defeat them) + code:03cae6/bd + cheat + description:Infinite MP during battles, doesn't work on twin attacks + code:038532/bd + cheat + description:Infinite items outside of battle except for the Whistle + code:01a6f5/ae + cheat + description:Infinite Whistles + code:01a328/ae + cheat + description:Money doesn't decrease if you run away from a battle + code:0388d5/ad+0388de/ad + cheat + description:Money doesn't decrease in shops + code:01c702/ad+01c707/ae + cheat + description:No random battles + code:7e0686/00 + cheat + description:No random battles (alt) + code:00894d/60 + cheat + description:Always fight the rarest enemy in that area + code:008af4/0c + cheat + description:Always get a treasure from each enemy defeated + code:03ecdc/80 + cheat + description:When treasures are awarded after battle, receive 5 instead of 1 + code:01d488/05 + cheat + description:When arrows are awarded after battle, receive 50 instead of 10 + code:01d47e/32 + cheat + description:When treasures are awarded after battle, receive the rarest + code:03ed20/03 + cheat + description:Sumon the Big Chocobo anywhere by using a Carrot instead of the Whistle + code:01a325/eb + cheat + description:The quantity of items don't decrease when selling them + code:01ca54/bd + cheat + description:No music while traveling or in a town + code:008b3f/60 + cheat + description:Gunslinger code + code:01a6f2/44 + cheat + description:Save anywhere + code:0099cf/a9 + cheat + description:131,070 exp points after each battle + code:13ff7b/01+13ff91/b1 + cheat + description:16,646,142 exp points after each battle + code:13ff7b/01+13ff91/b1+13ff8b/b3 + cheat + description:Get at least 150 GP after each battle + code:03ed5d/69+03ed5e/96+03ed5f/ea + cheat + description:Get at least 255 GP after each battle + code:03ed5d/69+03ed5e/ff+03ed5f/ea + cheat + description:Get at least 65,536 GP after each battle + code:03ed72/ee + cheat + description:Get 99 of items that you are given or find in a pot, treasure chest, etc. + code:009819/63 + cheat + description:Get 99 arrows when you find them in a pot or treasure chest + code:009828/63 + cheat + description:Cure2 is ultra strong + code:0f973b/c8 + cheat + description:Cure2 restores HP to all members in the party during battle + code:0f973a/40 + cheat + description:Cure2 restores all HP/MP during battle + code:0f973d/16 + cheat + description:Fire1 spell is ultra strong + code:0f984f/c8 + cheat + description:Fire1 spell hits every enemy + code:0f984e/c1 + cheat + description:Ice1 spell is ultra strong + code:0f9861/c8 + cheat + description:Ice1 spell hits every enemy + code:0f9860/c1 + cheat + description:Lit1 spell is ultra strong + code:0f9873/c8 + cheat + description:Lit1 spell hits every enemy + code:0f9872/c1 + 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 + name:Final Fantasy III (USA) (Rev 1) + cheat + description:Party has almost max HP and MP + code:c20f93/ff + cheat + description:Activate Terra's Morph command + code:7e1dd1/0c + cheat + description:Infinite Morph time out of battle + code:7e1cf6/ff + cheat + description:Infinite Morph time in battle + code:7e3f31/ff + cheat + description:All items in shops are free (disable to sell items) + code:c3bba5/64+c3bbab/64 + cheat + description:Infinite item use + code:c39db3/ea + cheat + description:Infinite item use (alt) + code:c39dae/ea + cheat + description:Protect from all status ailments + code:d86de8/e7+d86de9/f8 + cheat + description:Learn all spells after one battle + code:c2613b/b0 + cheat + description:Earn 65,000+ exp points after each battle + code:c25de8/43 + cheat + description:Earn tons of EXP after a battle (level 99 takes two battles) + code:c25de8/42 + cheat + description:Auto cast Float, Regen, Haste, Shell, Safe and Rflect + code:d86dea/eb + cheat + description:Remove curse from Cursed Shield after only 1 battle + code:c26002/00 + cheat + description:Steal command always gets the more rare item an enemy has + code:c239df/00 + cheat + description:Mog never stumbles when he dances + code:c217a1/00 + cheat + description:Party has Sprint Shoes and Moogle Charm effect + code:c20fa5/cc + cheat + description:Party has Sprint Shoes and Moogle Charm effect (alt) + code:c20fa3/cc + cheat + description:Party has Offering effect + code:c2293d/1a+c2293e/ea + cheat + description:Party has Merit Award effect + code:c39c5a/00 + cheat + description:Party has Economizer effect + code:c35134/00+c25744/00 + cheat + description:Offering gives character instant kill attacks + code:c21625/3f + cheat + description:Enable all characters (once you are able to switch) + code:7e1ede/ff+7e1edf/ff + cheat + description:Have 94 of all items when arrange is used + code:c326ba/a9+c326bc/8a+c3272f/af+c32732/de + cheat + description:Have all Blitz's + code:7e1d28/ff + cheat + description:Have all Dance's + code:7e1d4c/ff + cheat + description:Have all Lore's + code:7e1d29/ff+7e1d2a/ff+7e1d2b/ff + cheat + description:Have all SwdTech's + code:7e1cf7/ff + cheat + description:Have all Espers + code:7e1a69/ff+7e1a6a/ff+7e1a6b/ff+7e1a6c/ff + cheat + description:Enemy 1 has 0 HP + code:7e3bfc/00+7e3bfd/00 + cheat + description:Enemy 2 has 0 HP + code:7e3bfe/00+7e3bff/00 + cheat + description:Enemy 3 has 0 HP + code:7e3c00/00+7e3c01/00 + cheat + description:Enemy 4 has 0 HP + code:7e3c02/00+7e3c03/00 + cheat + description:Enemy 5 has 0 HP + code:7e3c04/00+7e3c05/00 + cheat + description:Enemy 6 has 0 HP + code:7e3c06/00+7e3c07/00 + cheat + description:Faster up/down movement on world map + code:ee1f96/20+ee1fe3/e0 + cheat + description:Faster left/right movement on world map + code:ee1efa/20+ee1f48/e0 + cheat + description:Save anywhere + code:7e0201/80 + cheat + description:Start Terra with Man-eater equipped + code:ed7caf/06 + cheat + description:Start Terra with Excalibur equipped + code:ed7caf/18 + cheat + description:Start Terra with Illumina equipped + code:ed7caf/1a + cheat + description:Start Terra with Atma equipped + code:ed7caf/1c + cheat + description:Start Terra with Tempest equipped + code:ed7caf/2e + cheat + description:Start Terra with Blizzard equipped + code:ed7caf/0e + cheat + description:Start Terra with Enhancer equipped + code:ed7caf/13 + cheat + description:Start Terra with Mithril shield equipped + code:ed7cb0/5c + cheat + description:Start Terra with Gold shield equipped + code:ed7cb0/5d + cheat + description:Start Terra with Ice shield equipped + code:ed7cb0/61 + cheat + description:Start Terra with Fire shield equipped + code:ed7cb0/60 + cheat + description:Start Terra with Hairband equipped + code:ed7cb1/6a + cheat + description:Start Terra with Leather hat equipped + code:ed7cb1/69 + cheat + description:Start Terra with Circlet equipped + code:ed7cb1/7a + cheat + description:Start Terra with Mystery veil equipped + code:ed7cb1/79 + cheat + description:Start Terra with Red cap equipped + code:ed7cb1/78 + cheat + description:Start Terra with Silk robe equipped + code:ed7cb2/88 + cheat + description:Start Terra with Mithril vest equipped + code:ed7cb2/89 + cheat + description:Start Terra with White dress equipped + code:ed7cb2/8b + cheat + description:Start Terra with Genji armor equipped + code:ed7cb2/9a + cheat + description:Start Terra with Force armor equipped + code:ed7cb2/94 + 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:7e1d35/ff+7e1d36/ff+7e1d37/ff+7e1d3f/ff+7e1d38/ff+7e1d40/ff+7e1d39/ff+7e1d41/ff+7e1d3a/ff+7e1d49/ff+7e1d42/ff+7e1d3b/ff+7e1d4a/ff+7e1d43/ff+7e1d3c/ff+7e1d4b/ff+7e1d44/ff+7e1d3d/ff+7e1d45/ff+7e1d3e/ff+7e1d46/ff+7e1d47/ff+7e1d48/ff+7e1d2c/ff+7e1d2d/ff+7e1d2e/ff+7e1d2f/ff+7e1d30/ff+7e1d31/ff+7e1d32/ff+7e1d33/ff+7e1d34/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 + name:Final Fantasy III (USA) + cheat + description:Party has almost max HP and MP + code:c20f93/ff + cheat + description:Activate Terra's Morph command + code:7e1dd1/0c + cheat + description:Infinite Morph time out of battle + code:7e1cf6/ff + cheat + description:Infinite Morph time in battle + code:7e3f31/ff + cheat + description:All items in shops are free (disable to sell items) + code:c3bba5/64+c3bbab/64 + cheat + description:Infinite item use + code:c39db3/ea + cheat + description:Protect from all status ailments + code:d86de8/e7+d86de9/f8 + cheat + description:Learn all spells after one battle + code:c2613b/b0 + cheat + description:Earn 65,000+ exp points after each battle + code:c25de8/43 + cheat + description:Earn tons of EXP after a battle (level 99 takes two battles) + code:c25de8/42 + cheat + description:Auto Cast Float, Regen, Haste, Shell, Safe and Rflect + code:d86dea/eb + cheat + description:Vigor/Speed/Stamina/MagPwr becomes 255 + code:c28fd6/03 + cheat + description:Remove curse from Cursed Shield after only 1 battle + code:c26002/00 + cheat + description:Steal command always gets the more rare item an enemy has + code:c239df/00 + cheat + description:Mog never stumbles when he dances + code:c217a1/00 + cheat + description:Party has Sprint Shoes and Moogle Charm effect + code:7e11df/22 + cheat + description:Party has Offering effect + code:c2293d/1a+c2293e/ea + cheat + description:Party has Merit Award effect + code:c39c5a/00 + cheat + description:Party has Economizer effect + code:c35134/00+c25744/00 + cheat + description:Offering gives character instant kill attacks + code:c21625/3f + cheat + description:Enemy 1 has 0 HP + code:7e3bfc/00+7e3bfd/00 + cheat + description:Enemy 2 has 0 HP + code:7e3bfe/00+7e3bff/00 + cheat + description:Enemy 3 has 0 HP + code:7e3c00/00+7e3c01/00 + cheat + description:Enemy 4 has 0 HP + code:7e3c02/00+7e3c03/00 + cheat + description:Enemy 5 has 0 HP + code:7e3c04/00+7e3c05/00 + cheat + description:Enemy 6 has 0 HP + code:7e3c06/00+7e3c07/00 + cheat + description:Have 94 of all items when arrange is used + code:c326ba/a9+c326bc/8a+c3272f/af+c32732/de + cheat + description:Have all Blitz's + code:7e1d28/ff + cheat + description:Have all Dance's + code:7e1d4c/ff + cheat + description:Have all Lore's + code:7e1d29/ff+7e1d2a/ff+7e1d2b/ff + cheat + description:Have all SwdTech's + code:7e1cf7/ff + cheat + description:Have all Espers + code:7e1a69/ff+7e1a6a/ff+7e1a6b/ff+7e1a6c/ff + cheat + description:Faster up/down movement on world map + code:ee1f96/20+ee1fe3/e0 + cheat + description:Faster left/right movement on world map + code:ee1efa/20+ee1f48/e0 + cheat + description:Enable all characters (once you are able to switch) + code:7e1ede/ff+7e1edf/ff + cheat + description:Save anywhere + code:7e0201/80 + cheat + description:Start Terra with Man-eater equipped + code:ed7caf/06 + cheat + description:Start Terra with Excalibur equipped + code:ed7caf/18 + cheat + description:Start Terra with Illumina equipped + code:ed7caf/1a + cheat + description:Start Terra with Atma equipped + code:ed7caf/1c + cheat + description:Start Terra with Tempest equipped + code:ed7caf/2e + cheat + description:Start Terra with Blizzard equipped + code:ed7caf/0e + cheat + description:Start Terra with Enhancer equipped + code:ed7caf/13 + cheat + description:Start Terra with Mithril shield equipped + code:ed7cb0/5c + cheat + description:Start Terra with Gold shield equipped + code:ed7cb0/5d + cheat + description:Start Terra with Ice shield equipped + code:ed7cb0/61 + cheat + description:Start Terra with Fire shield equipped + code:ed7cb0/60 + cheat + description:Start Terra with Hairband equipped + code:ed7cb1/6a + cheat + description:Start Terra with Leather hat equipped + code:ed7cb1/69 + cheat + description:Start Terra with Circlet equipped + code:ed7cb1/7a + cheat + description:Start Terra with Mystery veil equipped + code:ed7cb1/79 + cheat + description:Start Terra with Red cap equipped + code:ed7cb1/78 + cheat + description:Start Terra with Silk robe equipped + code:ed7cb2/88 + cheat + description:Start Terra with Mithril vest equipped + code:ed7cb2/89 + cheat + description:Start Terra with White dress equipped + code:ed7cb2/8b + cheat + description:Start Terra with Genji armor equipped + code:ed7cb2/9a + cheat + description:Start Terra with Force armor equipped + code:ed7cb2/94 + 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:7e1d35/ff+7e1d36/ff+7e1d37/ff+7e1d3f/ff+7e1d38/ff+7e1d40/ff+7e1d39/ff+7e1d41/ff+7e1d3a/ff+7e1d49/ff+7e1d42/ff+7e1d3b/ff+7e1d4a/ff+7e1d43/ff+7e1d3c/ff+7e1d4b/ff+7e1d44/ff+7e1d3d/ff+7e1d45/ff+7e1d3e/ff+7e1d46/ff+7e1d47/ff+7e1d48/ff+7e1d2c/ff+7e1d2d/ff+7e1d2e/ff+7e1d2f/ff+7e1d30/ff+7e1d31/ff+7e1d32/ff+7e1d33/ff+7e1d34/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:c6858d5c02894a6cc71f4dd452c7f288b319d1952ca56fdb185b4bf5e26244a2 + name:Final Fantasy V (Japan) + cheat + description:Max / infinite Gil + code:7e0947/7f+7e0948/96+7e0949/98 + cheat + description:No random battles (overworld) + code:7e16a9/00 + cheat + description:No random battles (dungeons) + code:7e0b4f/00 + cheat + description:Walk faster + code:7e0afa/7f + cheat + description:Walk through walls in overworld + code:c011b0/70 + cheat + description:Save anywhere + code:7e0a53/20 + +cartridge sha256:60cca2592d0756b8c4c7a0a254fafa5ac47aa752521fd1f77dcbf4b6ee1bee90 + name:Final Fight (USA) + cheat + description:Invincibility + code:02a706/d0 + cheat + description:Infinite health + code:01c963/b5+02ab22/a5 + cheat + description:Infinite health (alt) + code:7e0d14/50 + cheat + description:Infinite lives + code:02a2e6/c5+00e5e2/02 + cheat + description:Infinite lives (alt) + code:00e5ee/af + cheat + description:Infinite time + code:01a34c/cd + cheat + description:Hit anywhere + code:01c124/ea+01c10b/24+01c125/30+01c122/b5+01c123/15 + cheat + description:Slower timer + code:01a354/02 + cheat + description:Faster timer + code:01a354/00 + cheat + description:Any food restores all health + code:02b205/00 + cheat + description:Attack speed greatly increased + code:7e0d1e/01 + cheat + description:Start with 2 credits + code:01a8bb/01 + cheat + description:Start with 6 credits + code:01a8bb/05 + cheat + description:Start with 10 credits + code:01a8bb/09 + 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 + 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 + name:Final Fight 2 (USA) + cheat + description:Invincibility + code:82837d/d0 + cheat + description:Infinite health + code:80f46a/a5+82a6b4/a5 + cheat + description:Infinite lives + code:82a5f3/a5 + cheat + description:Infinite lives (alt) + code:82a5f2/00 + cheat + description:Infinite time + code:82c945/ad + cheat + description:Infinite time (alt) + code:82c940/00 + cheat + description:One hit kills + code:80f4bf/a9+80f4c0/ff + cheat + description:Hit anywhere - both players + code:8281d3/24+8281d8/24+8281a3/24 + cheat + description:Faster timer + code:82c940/02 + cheat + description:Barbecue restores vitality 50% instead of 95% + code:82f903/40 + cheat + description:Barbecue worth nothing + code:82f903/00 + cheat + description:Soft drink restores vitality 95% + code:82f8fd/80 + cheat + description:Soft drink worth nothing + code:82f8fd/00 + cheat + description:Both players can select same character + code:80a979/ee + cheat + description:P1 and P2 can't harm each other in a 2P game + code:829c2d/00 + cheat + description:Slow motion (disable until play begins) + code:8085cb/02 + cheat + description:Hitting someone with your super move makes you invincible + code:82a6a8/01 + cheat + description:Hitting someone with your super move uses all your health + code:82a6a8/40 + cheat + description:Start with 1 life + code:82a21c/00 + cheat + description:Start with 3 lives + code:82a21c/02 + cheat + description:Start with 7 lives + code:82a21c/06 + cheat + description:Start with 10 lives + code:82a21c/09 + +cartridge sha256:f9dac709b2c2859f828103a0dd980716817e2bde3b9d7e2fdea36e9bb9bed7f2 + name:Final Fight 3 (USA) + cheat + description:Infinite time + code:c01658/ad + cheat + description:Instant super energy + code:c09d71/a9+c09d72/28+c09d73/00+c09d75/29 + cheat + description:Can always do super special + code:c067da/00+c06844/00 + cheat + description:Infinite lives + code:c086ab/ea + cheat + description:Hit anywhere - both players + code:c0c33e/e0+c0c340/07+c0c33f/00 + 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 + name:Final Fight Guy (USA) + cheat + description:Infinite health + code:01c919/b5 + cheat + description:Infinite health (alt) + code:7e0d14/50 + cheat + description:Infinite time + code:01a6e9/60 + cheat + description:Infinite time (alt) + code:7e0cbc/09 + cheat + description:Hit anywhere + code:01c0e1/24+01c0c7/24 + cheat + description:Gain 9 lives every time you die + code:02a343/00 + cheat + description:No energy lost from spin kick + code:02ab91/b5 + cheat + description:Attack speed greatly increased + code:7e0d1e/01 + cheat + description:Any food restores all health + code:029205/00 + 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 + name:FireStriker (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 + name:Firemen, The (Europe) (En,Fr,De) + cheat + description:Invincibility + code:7e08c9/01 + 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 + name:Firepower 2000 (USA) + cheat + description:Invincibility - Jeep + code:7e612a/c7 + cheat + description:Invincibility - Heli + code:7e612c/c7 + cheat + description:Infinite lives + code:8084e0/bd + cheat + description:Loss of vehicle does not reduce bullet strength + code:80853d/bd + cheat + description:Loss of vehicle does not reduce flame strength + code:8084fd/bd + cheat + description:Loss of vehicle does not reduce plasma strength + code:80850d/bd + cheat + description:Loss of vehicle does not reduce laser strength + code:80851d/bd + cheat + description:Loss of vehicle does not reduce ionic strength + code:80852d/bd + cheat + description:Bubble shield lasts for 4 seconds instead of 12 + code:80be91/01 + cheat + description:Bubble shield lasts for 8 seconds + code:80be91/02 + cheat + description:Bubble shield lasts for 16 seconds + code:80be91/04 + cheat + description:Bubble shield lasts for 32 seconds + code:80be91/08 + cheat + description:Bubble shield lasts for 64 seconds + code:80be91/10 + cheat + description:Bubble shield on jeep lasts until end of level + code:80ab94/ad + cheat + description:Bubble shield on helicopter lasts until end of level + code:80a91a/ad + cheat + description:Start with bullet strength at 3 instead of 1 + code:80857a/03 + cheat + description:Start with bullet strength at 6 + code:80857a/06 + cheat + description:Start with flame strength at 3 instead of 1 + code:808568/03 + cheat + description:Start with flame strength at 6 + code:808568/06 + cheat + description:Start with flame strength at 0 + code:808568/00 + cheat + description:Start with plasma strength at 3 instead of 1 + code:80856e/03 + cheat + description:Start with plasma strength at 6 + code:80856e/06 + cheat + description:Start with plasma strength at 0 + code:80856e/00 + cheat + description:Start with laser strength at 1 instead of 0 + code:808574/01 + cheat + description:Start with laser strength at 3 + code:808574/03 + cheat + description:Start with laser strength at 6 + code:808574/06 + cheat + description:Start with ionic strength at 1 instead of 0 + code:808580/01 + cheat + description:Start with ionic strength at 3 + code:808580/03 + cheat + description:Start with ionic strength at 6 + code:808580/06 + cheat + description:Start with 1 life instead of 4 + code:808553/01 + cheat + description:Start with 2 lives + code:808553/02 + cheat + description:Start with 3 lives + code:808553/03 + cheat + description:Start with 5 lives + code:808553/05 + cheat + description:Start with 7 lives + code:808553/07 + cheat + description:Start with 10 lives + code:808553/0a + cheat + description:Start with 15 lives + code:808553/0f + cheat + description:Start with 25 lives + code:808553/19 + cheat + description:Start with 50 lives + code:808553/32 + cheat + description:Start with 75 lives + code:808553/4b + cheat + description:Start with 100 lives + code:808553/64 + cheat + description:Start at level 2 + code:8099ee/02 + cheat + description:Start at level 3 + code:8099ee/03 + cheat + description:Start at level 4 + code:8099ee/04 + cheat + description:Start at level 5 + code:8099ee/05 + cheat + description:Start at level 6 + code:8099ee/06 + +cartridge sha256:4c1354337efa788169387458fa6bdbcf4be0c98369920af2bd876ad98d29070f + name:First Samurai (USA) + cheat + description:Infinite life and force + code:019818/a5 + cheat + description:Infinite lives + code:0188fa/24 + cheat + description:Infinite Axe, Dagger, Grendade (slot 2 item) + code:01928d/a5+0192f1/a5 + cheat + description:Infinite Warp Lanterns + code:018d0b/a5 + cheat + description:Collect items from anywhere + code:01b585/24 + cheat + description:Hit anywhere Sword/Punch/Kick + code:019351/24 + cheat + description:Hit anywhere Axe/Tri-blades + code:01b0be/24 + cheat + description:Hit anywhere Knife/Dual Knives + code:01b012/24 + cheat + description:Full weapon power for Dagger on pick-up + code:01b5e5/03 + cheat + description:Less force picked up from enemies + code:01af77/02 + cheat + description:More force picked up from enemies + code:01af77/08 + cheat + description:Lots more power picked up from enemies + code:01af77/15 + cheat + description:Less life force from food + code:01b757/03 + cheat + description:More life force from food + code:01b757/10 + cheat + description:Start with 9 lives + code:0086ce/09 + cheat + description:Start with 2 lives + code:0086ce/02 + 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 + name:Flashback - The Quest for Identity (USA) (En,Fr,De) + cheat + description:Invincibility against enemies + code:c20a33/ad + cheat + description:Infinite shield + code:7ec746/05 + cheat + description:Never lose a shield when shot (disable to kill enemies) + code:c26b13/ea + cheat + description:Don't die from most falls + code:c26b62/b7 + cheat + description:Start with 1 shield + code:ce0d24/02 + cheat + description:Start with 2 shields + code:ce0d24/03 + cheat + description:Start with 3 shields + code:ce0d24/04 + cheat + description:Start with 5 shields + code:ce0d24/06 + cheat + description:Start with 10 shields + code:ce0d24/0b + cheat + description:Start with 20 shields + code:ce0d24/15 + cheat + description:Start with 50 shields + code:ce0d24/33 + cheat + description:Start with 100 shields + code:ce0d24/65 + cheat + description:Start with 50 credits + code:ce1544/32 + cheat + description:Start with 100 credits + code:ce1544/64 + cheat + description:Start with 250 credits + code:ce1544/fa + cheat + description:Start with 512 credits + code:ce1543/02 + cheat + description:Start with 1024 credits + code:ce1543/04 + +cartridge sha256:ff09d72d6241b331dc429d1cf27c04c26546f23312a22c7a14e6a4bf41ed1069 + name:Flintstones, The (USA) (En,Fr,De,Es,It) + cheat + description:Invincibility + code:839752/d0+8396e1/d0 + cheat + description:Infinite health + code:839699/bd+83975c/a5 + cheat + description:Infinite lives + code:0083c0/dd + cheat + description:Infinite time + code:82f2f4/cd + cheat + description:Hit anywhere + code:83b7f0/26+83b7ef/80 + cheat + description:Get items from anywhere + code:8192e8/00+81912e/00+81a624/00 + cheat + description:Multi-jump + code:839d25/00 + cheat + description:Level skip enabled (Pause + X) + code:7e0622/01 + +cartridge sha256:3d5bbc06e7e9797d937c803610c40b262c14c3f0a39e8048dd6b0b052a040fc1 + name:Flintstones, The - The Treasure of Sierra Madrock (USA) + cheat + description:Invincibility + code:84ad12/00 + cheat + description:Infinite stamina + code:84b008/ad + cheat + description:Infinite time - 1P game + code:80cb52/ad + cheat + description:Infinite lives - 1P game + code:80a91f/ad + cheat + description:Hit anywhere + code:809e07/e0+809e0b/32+809e08/38+809e09/00+809e0a/f0 + cheat + description:Get items from anywhere + code:84f5ed/80+84f23e/80 + cheat + description:Multi-jump + code:84c65f/ad + +cartridge sha256:204ecb9b809408c23d5f5772026fc248c70612d9bf6952e6b952ed7a85640867 + name:Flying Hero - Bugyuru no Daibouken (Japan) + cheat + description:Invincibility + code:01a028/1a+01a029/8d+01a02a/3f+01a02b/10 + cheat + description:Hit anywhere + code:01862f/24+018628/24+018636/24+01863d/24+018668/80 + cheat + description:Hit anywhere continually + code:018628/24+018636/24+018668/80+018618/80 + cheat + description:One hit kills + code:018668/80+02f9e7/00 + +cartridge sha256:bc6b0344a434644c391ac69a53c7720c51e2d3c5c082b8d78598ae4df100c464 + name:Foreman for Real (USA) + cheat + description:Infinite stamina - P1 + code:7e11ae/64+7e1072/27+7e043a/78+7e045a/64 + +cartridge sha256:25b380f529f5a9295df7c0adcc5213d67f131f552d078a3d8f545f988047c90a + name:Frantic Flea (USA) + cheat + description:Invincibility + code:7e1e92/1e + +cartridge sha256:1ce72767795f41049a1f4d2829e837a8885eb91e1c14faf1ca62d05839ebe3c9 + name: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 + name: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 + name:Fushigi no Dungeon 2 - Fuurai no Shiren (Japan) + cheat + description:Gain any EXP for maximum + code:c23555/00 + 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:c2380d/00+c2380e/af+c2380f/11 + cheat + description:Collect any Gitan for maximum + code:c25c17/00 + cheat + description:Never lose Satiation + code:c233d2/00 + cheat + description:One Arrow gains 99 + code:c33b74/00 + cheat + description:Smith a weapon to make it +99 + code:c30664/a9+c30665/62 + cheat + description:Items from bartender get +99 Refinement + code:c302b9/a9+c302ba/63 + +cartridge sha256:bf16c3c867c58e2ab061c70de9295b6930d63f29f81cc986f5ecae03e0ad18d2 + name:F-Zero (USA) + cheat + description:Always rank 1st + code:00e9a7/a9+00e9a8/01 + cheat + description:Infinite turbos + code:00b829/02 + cheat + description:Infinite spare machines + code:008bfb/c5 + cheat + description:Start with 1 spare machine + code:0381a5/01 + cheat + description:Start with 5 spare machines + code:0381a5/05 + cheat + description:Start with 9 spare machines + code:0381a5/09 + 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 + name:Galaxy Wars (Japan) + cheat + description:Infinite lives + code:7e0630/05 + +cartridge sha256:ca3dd4620c692b2b8d3dd49b7dbdb1daa251ee0f7943050cc8a036e209cd7a07 + name:Ganpuru - Gunman's Proof (Japan) + cheat + description:Infinite health vs enemies/bullets + code:878386/ad + cheat + description:Infinite ammo for picked up guns + code:82b863/ad + cheat + description:Infinite ammo for picked up hand weapons + code:82b887/ad + cheat + description:Always have stronger attacks + code:87858a/00 + cheat + description:Always have super strong attacks + code:878586/a9+878588/3f+87858b/85 + cheat + description:Easily get max money + code:8784bb/00 + cheat + description:Easily get max score + code:878506/00 + cheat + description:Always have Starmine Bombs (if you have none, fire 3 off) + code:849374/00+88dd14/02 + cheat + description:Always get Rank S for dungeons, regardless of time taken + code:88db96/9c + +cartridge sha256:1735f790ebcfa1bed2430aecde3abaf24c88ff99aa0186736f8f36b674bc9350 + name:Garry Kitchen's Super Battletank - War in the Gulf (USA) (Rev 1) + cheat + description:Infinite health against most enemies and mines + code:00cda2/a5 + cheat + description:Infinite weapon ammo (except Smoke Screens and Machine Gun) + code:009803/2c + cheat + description:More Machine Gun ammo on stages 1-4 + code:00d8f8/ff + cheat + description:Less Machine Gun ammo on stages 1-4 + code:00d8f8/2b + cheat + description:More Cannon ammo on each mission + code:00d8dc/64 + cheat + description:Less Cannon ammo on each mission + code:00d8dc/19 + cheat + description:More Laser Shells on each mission + code:00d8e5/05 + cheat + description:No Laser Shells on each mission + code:00d8e5/00 + cheat + description:More Smoke Screens on each mission + code:00d8ef/05 + cheat + description:No Smoke Screens on each mission + code:00d8ef/00 + 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 + name:Garry Kitchen's Super Battletank - War in the Gulf (USA) + cheat + description:Infinite health against most enemies and mines + code:00cda2/a5 + cheat + description:Infinite weapon ammo (except Smoke Screens and Machine Gun) + code:009803/2c + cheat + description:More Machine Gun ammo on stages 1-4 + code:00d8f8/ff + cheat + description:Less Machine Gun ammo on stages 1-4 + code:00d8f8/2b + cheat + description:More Cannon ammo on each mission + code:00d8dc/64 + cheat + description:Less Cannon ammo on each mission + code:00d8dc/19 + cheat + description:More Laser Shells on each mission + code:00d8e5/05 + cheat + description:No Laser Shells on each mission + code:00d8e5/00 + cheat + description:More Smoke Screens on each mission + code:00d8ef/05 + cheat + description:No Smoke Screens on each mission + code:00d8ef/00 + 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:b87874a2292fe045385a2888e33009d5d2eabf55e379059aa5ef6c73b0475ff2 + name:Gekitotsu Dangan Jidousha Kessen - Battle Mobile (Japan) + cheat + description:Invincibility + code:01b55b/95+01bf94/b5+01bfb7/b5 + cheat + description:Infinite health + code:01bf94/b5+01bfb7/b5 + cheat + description:Infinite lives + code:01bfd6/ad + cheat + description:Infinite Shields + code:019f1f/b9 + +cartridge sha256:fdafaa77f01a9a692411e27b3fb6045b247e5d625679b941d317a7b105f437d2 + name:George Foreman's KO Boxing (USA) (Rev 1) + cheat + description:Infinite time + code:0085d9/a9+0085da/78 + cheat + description:Infinite super punch after obtaining it + code:00db7a/80 + cheat + description:Time goes slower + code:00810c/78 + cheat + description:Time speeds up + code:00810c/0a + cheat + description:Damage inflicted by your opponent affects him (your health may slightly decrease) + code:00dbbe/ad+00dbbf/73+00dbc7/8d+00dbc8/73 + cheat + description:Start with 1/2x health - both players + code:0080ad/20 + +cartridge sha256:b248b2122a0caf99298ebd9a4f66ad8047dbfce1e4bbac8219ba3ea9fb7488b5 + name:Ghost Chaser Densei (Japan) + cheat + description:Invincibility + code:80b1eb/d0 + cheat + description:Infinite health + code:80c752/bd + cheat + description:Infinite time + code:81c82c/ad + cheat + description:Hit anywhere + code:80ba37/e0+80ba3a/30+80ba3b/30+80ba39/02 + cheat + description:99 hits in bonus round + code:7e0516/63 + +cartridge sha256:a4ceb31b82ea532e6eb640fa2eda61625758e72251efa5f0ae9a984f4a98a8a0 + name:Ghoul Patrol (USA) + cheat + description:Invincibility + code:81a94a/60+81a9a9/60 + cheat + description:Infinite lives + code:819700/ad + cheat + description:Super powered normal arrows + code:838a6b/ff + 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 + name:Gods (USA) + cheat + description:Invincibility + code:9e83bc/ad + cheat + description:Continually hit anywhere + code:9eccd7/24+9ecce6/24+9ecd1a/24+9ecd06/80 + cheat + description:Shields last until at least end of the world (disable if you get stuck) + code:9eff3b/60 + cheat + description:Infinite lives + code:9e865b/ad + cheat + description:Items you can afford in the shops are free + code:9ebb2f/cd + cheat + description:Start with 2 lives + code:9fe8a0/01 + cheat + description:Start with 6 lives + code:9fe8a0/05 + cheat + description:Start with 10 lives + code:9fe8a0/09 + +cartridge sha256:2bb368c47189ce813ad716eef16c01cd47685cb98e2c1cb35fa6f0173c97dd7c + name:Goof Troop (USA) + cheat + description:Infinite health + code:80dd17/85 + cheat + description:Infinite lives + code:828b16/a5 + cheat + description:Hit anywhere + code:80d7e4/00+80d51e/00 + cheat + description:Get fruits and gems from anywhere + code:82a205/00+82a211/00 + cheat + description:Walk through walls + code:82856a/80+828285/80 + cheat + description:4 hearts give you a life + code:82af47/04+82af50/9e + cheat + description:2 hearts give you a life + code:82af47/02+82af50/9e + cheat + description:2 hearts from cherries + code:83c4be/02 + cheat + description:4 hearts from bananas + code:83c4bf/04 + cheat + description:1 heart from bananas + code:83c4bf/01 + cheat + description:Goofy has quicker left-right movement + code:838e1d/02+838e2d/fd + cheat + description:Max has quicker left-right movement + code:838dfd/02+838e0d/fd + cheat + description:Start with 9 lives + code:80a10a/09 + cheat + description:Start with 6 lives + code:80a10a/06 + cheat + description:Start with 1 life + code:80a10a/01 + +cartridge sha256:93da752a0c76167d0907efa832367e5d14aab8e835b864f345c386071a9af718 + name:Gradius III (USA) + cheat + description:Invincibility + code:00d80a/80 + cheat + description:Infinite Konami code use (up, up, down, down, left, right, left, right, B, A) + code:00c150/ad + cheat + description:Infinite lives + code:00bcf0/ea+00bcf1/ea + cheat + description:Infinite credits + code:00d230/ad + cheat + description:Hit anywhere + code:00eb2d/24 + cheat + description:Makes Earwig Scorpion (Stage 1 mayor) much easier to defeat + code:02939e/01 + cheat + description:Makes Bubble Brain (Stage 2 mayor) easier to defeat + code:029a66/01 + cheat + description:Weapons status gauge remains at current level after a weapon is selected + code:00d95d/ea+00d95e/ea + cheat + description:Enemies shoot at you more + code:00c01f/a9+00c020/01 + cheat + description:Enables Arcade option in options menu + code:00b41b/03 + cheat + description:Start with 1 life + code:00ba93/00 + cheat + description:Start with 2 lives + code:00ba93/01 + cheat + description:Start with 4 lives + code:00ba93/03 + cheat + description:Start with 5 lives + code:00ba93/04 + cheat + description:Start with 9 lives + code:00ba93/08 + cheat + description:Start with 16 lives + code:00ba93/0f + cheat + description:Start with 31 lives + code:00ba93/1e + cheat + description:Start with 1 credit (1P game) + code:00a0e5/01 + cheat + description:Start with 2 credits + code:00a0e5/02 + cheat + description:Start with 6 credits + code:00a0e5/06 + cheat + description:Start with 7 credits + code:00a0e5/07 + cheat + description:Start with 8 credits + code:00a0e5/08 + cheat + description:Start with 9 credits + code:00a0e5/09 + 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 + name:Great Battle II, The - Last Fighter Twin (Japan) + cheat + description:Invincibility + code:00e14f/a9+00e150/01+00e151/8d+00e152/5b+00e153/04 + cheat + description:Infinite health + code:009797/b5 + cheat + description:Infinite lives + code:00a2bd/d5 + cheat + description:One hit kills + code:00b5b8/80 + 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 + name:Great Battle III, The (Japan) + cheat + description:Invincibility + code:00b540/d0+00b545/d0 + cheat + description:Infinite health + code:00b07e/b5 + cheat + description:Infinite lives + code:00bd6b/d5 + cheat + description:One hit kills + code:00cca3/80 + 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 + name:Great Circus Mystery Starring Mickey & Minnie, The (USA) + cheat + description:Invincibility against enemies + code:c05b2e/80 + cheat + description:Invincibility against ground hazards + code:c111e7/80 + cheat + description:Infinite Vacuum + code:c1159e/a5 + cheat + description:Infinite Bullets + code:c11697/a5 + cheat + description:Collect one coin for 999 + code:c05d01/00 + +cartridge sha256:f921297c361f16ad3f1257e91829638fc795f9323172015d7237ed648c8f7515 + name:GunForce (USA) + cheat + description:Invincibility + code:019b0b/85+019b09/a9 + cheat + description:Infinite ammo + code:00f737/ad + cheat + description:Hit anywhere + code:009b34/ad+0095bd/00+0095b6/00+00959b/00+0095a1/00 + 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 + name:Hagane - The Final Conflict (USA) + cheat + description:Invincibility + code:c0419e/60 + cheat + description:Infinite health + code:7f0000/00 + cheat + description:Infinite time + code:c08611/80 + cheat + description:Infinite Bombs + code:c09214/ea + cheat + description:Infinite Daggers + code:c09156/ea + cheat + description:Infinite special attacks + code:c08bb0/ea + cheat + description:Infinite lives + code:c085d9/ea + cheat + description:Hit anywhere + code:c03f89/00+c03f82/00+c03f90/00+c03f97/00 + cheat + description:One hit kills + code:c0400d/00 + cheat + description:Jump higher + code:c05a00/fd + cheat + description:Start with 9 lives + code:c081ec/09 + cheat + description:Start with 9 special attack points + code:c081f0/09 + cheat + description:Start with maximum health points + code:c081e4/05 + cheat + description:Start on stage 2 - Fortress Of Doom + code:c081c1/a9+c081c2/01 + cheat + description:Start on stage 3 - Violated Heavens + code:c081c1/a9+c081c2/02 + cheat + description:Start on stage 4 - Cry Of The Spirits + code:c081c1/a9+c081c2/03 + cheat + description:Start on stage 5 - Into The Darkness + code:c081c1/a9+c081c2/04 + +cartridge sha256:de1cf1512e48473b03adb87b7504f394e8b330b346bac24044f833d83609799a + name:HAL's Hole in One Golf (USA) + cheat + description:No penalty if you land in water or out of bounds + code:0186a2/2c + cheat + description:Always start hole with 1-shot penalty + code:018111/01 + cheat + description:Max 7 strokes per hole + code:018ba9/07 + cheat + description:Max 5 strokes per hole + code:018ba9/05 + +cartridge sha256:6e2a02a8944c19db3da76d2646f232fbe3ed039bc7d44cc03910814fa77a7acf + name:Harley's Humongous Adventure (USA) + cheat + description:Protection against some hazards + code:05ad42/ad + cheat + description:Infinite ammo + code:05b33a/00 + cheat + description:Infinite lives + code:05adbe/ad + cheat + description:Infinite Jet Fuel on pick-up + code:05ae00/00 + cheat + description:Infinite time on Vent level + code:00bbe3/ea + cheat + description:Any fuel power-up gives maximum amount + code:05ae29/00 + cheat + description:Press X on the title screen with the house to get level select menu + code:00e5fa/02 + cheat + description:Get only 5 ammo from a weapon power-up + code:05b402/05 + cheat + description:Get 20 ammo from a weapon power-up + code:05b402/20 + cheat + description:Get 30 ammo from a weapon power-up + code:05b402/30 + cheat + description:Get 40 ammo from a weapon power-up + code:05b402/40 + cheat + description:Get 50 ammo from a weapon power-up + code:05b402/50 + cheat + description:20 seconds to collect power-ups on level 1 + code:00bbad/14 + cheat + description:60 seconds to collect power-ups on level 1 + code:00bbad/3c + cheat + description:90 seconds to collect power-ups on level 1 + code:00bbad/5a + cheat + description:60 seconds to complete the Vent level + code:00bbbc/3c + cheat + description:Start with maximum fuel on every level + code:05a91a/80 + cheat + description:Start with 4 hearts + code:05ab12/08 + cheat + description:Start with 5 hearts + code:05ab12/0a + cheat + description:Start with 10 of every weapon + code:09ded9/10 + cheat + description:Start with 25 of every weapon + code:09ded9/25 + cheat + description:Start with 50 of every weapon + code:09ded9/50 + cheat + description:Start with 99 of every weapon + code:09ded9/99 + cheat + description:Start with 2 lives + code:05ab1c/01 + cheat + description:Start with 6 lives + code:05ab1c/05 + cheat + description:Start with 11 lives + code:05ab1c/10 + cheat + description:Start with 26 lives + code:05ab1c/25 + cheat + description:Start with 51 lives + code:05ab1c/50 + cheat + description:Start with 100 lives + code:05ab1c/99 + 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 + name:Harvest Moon (USA) + cheat + description:Can access all items temporarily + code:81b34a/a5 + cheat + description:Don't lose stamina + code:81d0f0/ad + cheat + description:Go to bed to get 200 stamina + code:8283bb/a9+8283bc/c8+8283bd/ea + cheat + description:With 1 or more wood, take some to get 999 + code:83b234/80 + cheat + description:With 0 wood, take some to get 999 + code:83b230/15 + cheat + description:Fencing doesn't break when it storms + code:82a773/80 + cheat + description:Go to sleep to put a bell plant next to the stable + code:82845c/10 + cheat + description:Go to sleep to enable the egg festival prize + code:828796/09+828797/00+828798/10 + cheat + description:Town always performs Flower Festival + code:83d30f/00+83d311/d2 + +cartridge sha256:7c34908526db2a634216fab0276c42a8e4e22d59c728cd586200142a12dd2c2c + name:Home Alone (USA) + cheat + description:Infinite power + code:00d84a/ad + cheat + description:Infinite lives + code:00d864/00 + cheat + description:Infinite Baseballs, Slingshot and Rifle ammo + code:00d7ce/00 + cheat + description:Power boost on jumps + code:019d6c/e0 + cheat + description:Super power boost on jumps + code:019d6c/c0 + cheat + description:Need 1 item (instead of 24) to complete level 1 + code:00dbee/01 + cheat + description:Need 5 items to complete level 1 + code:00dbee/05 + cheat + description:Need 10 items to complete level 1 + code:00dbee/10 + cheat + description:Need 15 items to complete level 1 + code:00dbee/15 + cheat + description:Need 20 items to complete level 1 + code:00dbee/20 + cheat + description:Need 1 item (instead of 30) to complete level 2 + code:00dbef/01 + cheat + description:Need 5 items to complete level 2 + code:00dbef/05 + cheat + description:Need 10 items to complete level 2 + code:00dbef/10 + cheat + description:Need 15 items to complete level 2 + code:00dbef/15 + cheat + description:Need 20 items to complete level 2 + code:00dbef/20 + cheat + description:Need 25 items to complete level 2 + code:00dbef/25 + cheat + description:Need 1 item (instead of 35) to complete level 3 + code:00dbf0/01 + cheat + description:Need 5 items to complete level 3 + code:00dbf0/05 + cheat + description:Need 10 items to complete level 3 + code:00dbf0/10 + cheat + description:Need 15 items to complete level 3 + code:00dbf0/15 + cheat + description:Need 20 items to complete level 3 + code:00dbf0/20 + cheat + description:Need 25 items to complete level 3 + code:00dbf0/25 + cheat + description:Need 1 item (instead of 35) to complete level 4 + code:00dbf1/01 + cheat + description:Need 5 items to complete level 4 + code:00dbf1/05 + cheat + description:Need 10 items to complete level 4 + code:00dbf1/10 + cheat + description:Need 15 items to complete level 4 + code:00dbf1/15 + cheat + description:Need 20 items to complete level 4 + code:00dbf1/20 + cheat + description:Need 25 items to complete level 4 + code:00dbf1/25 + cheat + description:Extra life with 1 pizza slice instead of 8 + code:008d8b/01 + cheat + description:Extra life with 2 pizza slices + code:008d8b/02 + cheat + description:Extra life with 3 pizza slices + code:008d8b/03 + cheat + description:Extra life with 4 pizza slices + code:008d8b/04 + cheat + description:Extra life with 5 pizza slices + code:008d8b/05 + cheat + description:Extra life with 6 pizza slices + code:008d8b/06 + cheat + description:Extra life with 7 pizza slices + code:008d8b/07 + cheat + description:Start with 1 life instead of 3 + code:00db94/01 + cheat + description:Start with 2 lives + code:00db94/02 + cheat + description:Start with 5 lives + code:00db94/05 + cheat + description:Start with 9 lives + code:00db94/09 + cheat + description:Start with 25 lives + code:00db94/25 + cheat + description:Start with 50 lives + code:00db94/50 + cheat + description:Start with 99 lives + code:00db94/99 + cheat + description:Start on level 2 + code:008057/01+008059/c9+00805a/03 + cheat + description:Start on level 3 + code:008057/02+008059/c9+00805a/03 + cheat + description:Start on level 4 + code:008057/03+008059/c9+00805a/03 + +cartridge sha256:27eaccb4eea93832639565a664bf3561ed5a11ac025d377a3f33262d851c1b2b + name:Home Alone 2 - Lost in New York (USA) + cheat + description:Infinite power (some things can still kill you) + code:04d3f5/ad + cheat + description:Infinite ammo + code:009a33/ea + cheat + description:Infinite lives + code:00882a/ad + cheat + description:Dart guns have 50 shots + code:04d737/32+04d751/32 + cheat + description:Extra life from 1 pizza slice instead of 6 + code:04d796/01 + cheat + description:Extra life from 2 pizza slices + code:04d796/02 + cheat + description:Extra life from 3 pizza slices + code:04d796/03 + cheat + description:Extra life from 4 pizza slices + code:04d796/04 + cheat + description:Extra life from 5 pizza slices + code:04d796/05 + cheat + description:Start with 1 life instead of 3 + code:009e77/01 + cheat + description:Start with 5 lives + code:009e77/05 + cheat + description:Start with 9 lives + code:009e77/09 + cheat + description:Start with 25 lives + code:009e77/19 + cheat + description:Start with 50 lives + code:009e77/32 + cheat + description:Start with 99 lives + code:009e77/63 + +cartridge sha256:48a3ac52e2c9128abc2dc60e07817a51898e8a93be0d51d6f541a8635263a089 + name:Home Improvement - Power Tool Pursuit! (USA) + cheat + description:Invincibility + code:af84d6/80+af815b/80 + cheat + description:Infinite lives + code:838d54/a9 + cheat + description:Infinite Nut Bolts + code:af9ba0/a5+afa822/a5+af8012/ad + +cartridge sha256:acad4c594f156e0f30dec2532b35fcb3bab800e08263377634e2d96dfd055f3e + name:Hook (USA) + cheat + description:Infinite power (disable if you get stuck) + code:00c47d/ea + cheat + description:Infinite time + code:038ab5/cd + cheat + description:Time starts at 7 min - stage 1 + code:038793/07 + cheat + description:Time starts at 3 min - stage 1 + code:038793/03 + cheat + description:Start with 3 power leaves + code:008184/04 + cheat + description:Start with 1 leaf (shows 2, but you can only fill 1) + code:008184/02 + 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 + name: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:0f6fc06bab813b9654de97fafd4f140368714c58e79130d15046a5a955fc3083 + name:Hungry Dinosaurs (Europe) + cheat + description:Walk anywhere on the grid + code:c06489/80 + cheat + description:Move faster + code:c00a45/00+c00a4d/00 + cheat + description:Change CPU's eggs to your own by walking over them + code:c00d13/00+c00d14/d0 + +cartridge sha256:a03528344d40bf800cdbde2dd240b30442cec7aea6026fbbe312a7c36bf0f74a + name:Hunt for Red October, The (USA) + cheat + description:Infinite Bombs + code:80c9f9/ad + cheat + description:Infinite ECMs + code:80cba8/ad + cheat + description:Infinite SAMs + code:80ca94/ad + cheat + description:Infinite SSMs + code:80cb32/ad + cheat + description:Infinite Torpedoes + code:80c942/ad + cheat + description:Start with 0 Bombs instead of 40 + code:81e82e/00 + cheat + description:Start with 99 Bombs + code:81e82e/63 + cheat + description:Start with 0 Torpedoes instead of 60 + code:81e81c/00 + cheat + description:Start with 99 Torpedoes + code:81e81c/63 + cheat + description:Start with 0 Surface-to-Air Missiles (SAMs) instead of 25 + code:81e828/00 + cheat + description:Start with 50 SAMs + code:81e828/32 + cheat + description:Start with 99 SAMs + code:81e828/63 + cheat + description:Start with 0 Surface-to-Surface Missiles (SSMs) instead of 25 + code:81e822/00 + cheat + description:Start with 50 SSMs + code:81e822/32 + cheat + description:Start with 99 SSMs + code:81e822/63 + cheat + description:Start with 0 Electronic Countermeasures (ECMs) instead of 2 + code:81e816/00 + cheat + description:Start with 50 ECMs + code:81e816/32 + cheat + description:Start with 99 ECMs + code:81e816/63 + cheat + description:Start in theatre I - Caribbean + code:8099c6/02 + cheat + description:Start in theatre II - North Pacifi + code:8099c6/06 + cheat + description:Start in theatre III - Mediterranean + code:8099c6/0c + cheat + description:Start on the final mission - Return to the USSR + code:8099c6/10 + +cartridge sha256:41cc900d2461a8dc4706640e493885ddf85db04d8dffceebf7a0ed89cc983d8d + name: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 + name:HyperZone (USA) + cheat + description:Infinite power + code:01b8c4/2c + cheat + description:Restore energy more quickly + code:018ccc/03 + cheat + description:Restore energy more slowly + code:018ccc/00 + cheat + description:Start with 8 lives + code:01a824/07 + cheat + description:Start with 1 life + code:01a824/00 + +cartridge sha256:fa143784fd20721d61101920e6aae9b7f5012b8157b1ce0c7ea83ea6c875d84d + name: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 + name:Illusion of Gaia (USA) + cheat + description:Infinite HP + code:83c47b/ad + cheat + description:Less charge time for psycho dash + code:82b815/05 + cheat + description:Less charge time for dark friar + code:82b890/05 + cheat + description:Super run left/right only + code:82c5c5/05+82c57b/fb + cheat + description:Super run up/down only + code:82c532/fc+82c4ea/04 + cheat + description:Get 2x the energy from herbs + code:83889f/10 + cheat + description:Get 3x the energy from herbs + code:83889f/18 + cheat + description:Red Jewel 50 check passes + code:88cf43/00 + cheat + description:Red Jewel 30 check passes + code:88cf38/00 + cheat + description:Red Jewel 20 check passes + code:88cf27/00 + cheat + description:Red Jewel 12 check passes + code:88cf16/00 + cheat + description:Red Jewel 08 check passes + code:88cf05/00 + cheat + description:Red Jewel 05 check passes + code:88cef4/00 + cheat + description:Red Jewel 03 check passes + code:88cee3/00 + cheat + description:Start with max HP + code:808069/ff + cheat + description:Start with a lot more energy + code:808068/14 + cheat + description:Start with 20 strength points + code:808071/14 + cheat + description:Start with 50 strength points + code:808071/32 + cheat + description:Start with 80 strength points + code:808071/50 + 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 + name:Imperium (USA) + cheat + description:Invincibility + code:04aca3/80+01e7b7/00 + cheat + description:Hit anywhere + code:01e863/80+01e881/ad + cheat + description:Infinite bombs + code:00c45a/ad + cheat + description:Start with 1 life point + code:00c8db/01 + cheat + description:Start with 3 life points + code:00c8db/03 + cheat + description:Start with 5 bombs + code:009e08/05 + cheat + description:Start with 9 bombs + code:009e08/09 + +cartridge sha256:c41150c0e84055801377fb7cb273cc51ca442b269ca6287cadf514f553e34750 + name:Incantation (USA) + cheat + description:Infinite energy + code:80ee24/ad + cheat + description:Infinite lives + code:80cf44/ad + 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 + name: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 + name:Incredible Hulk, The (USA) + cheat + description:Infinite health + code:818d4a/bd+80f458/ad + cheat + description:Infinite transformation capsules on pick-up + code:8a8202/a5 + cheat + description:Health doesn't decrease when Hulked-out + code:8a804c/ad + cheat + description:Hit anywhere + code:8190e1/4c+8190e0/d0+8190dd/e0+8190de/00+8190df/00 + cheat + description:One hit kills + code:81901c/00 + cheat + description:Get items from anywhere + code:8a951e/80 + cheat + description:Get 4 shots from gun + code:8a95af/04 + cheat + description:Get 9 shots from gun + code:8a95af/09 + cheat + description:Get 20 shots from gun + code:8a95af/14 + cheat + description:Get 20 seconds from time icon + code:8a9544/20 + cheat + description:Get 40 seconds from time icon + code:8a9544/40 + cheat + description:2x energy from gamma capsules + code:8a95f8/1e + cheat + description:Gamma capsules act as mega-gamma capsules + code:8a95bd/00 + cheat + description:Super-jump (sometimes) + code:80df7b/0c+80e02f/0c + cheat + description:Mega-jump (sometimes) + code:80df7b/19+80e02f/19 + cheat + description:Mega damage from Hulk's uppercut + code:819038/0a + cheat + description:Mega damage from Hulk's head butt + code:819064/0a + cheat + description:4x damage from Hulk's uppercut + code:819038/04 + cheat + description:4x damage from Hulk's head-butt + code:819064/04 + cheat + description:Start with 1 life + code:809602/01 + cheat + description:Start with 6 lives + code:809602/06 + cheat + description:Start with 9 lives + code:809602/09 + cheat + description:Start on level 2 + code:8095d5/00 + cheat + description:Start on level 3 + code:8095d5/20 + cheat + description:Start on level 4 + code:8095d5/40 + cheat + description:Start on level 5 + code:8095d5/80 + cheat + description:Infinite and max health + code:7e0718/63 + cheat + description:Infinite lives + code:7e00c0/09 + +cartridge sha256:cf611b40f9570e8fcfdc21db623965da62561e8ca82ded59e432ba6fb0bfb562 + name:Indiana Jones' Greatest Adventures (USA) + cheat + description:Invincibility + code:80c93e/8d+80b640/d0 + cheat + description:Infinite lives + code:80abdf/ad + cheat + description:Infinite Bombs + code:80978d/ad + cheat + description:Infinite Grenades + code:80978d/ad + cheat + description:Infinite continues + code:bfc69e/ea+8a95af/14 + cheat + description:Hearts don't restore health + code:809489/ad + cheat + description:Can't collect Grenades + code:80975c/ad + cheat + description:Start with very little health + code:80af6d/01 + cheat + description:Start with about 1/2 health + code:80af6d/03 + cheat + description:Start with more health (ignore health meter) + code:81ab6d/0f + cheat + description:Start with 5 Grenades + code:80a635/05 + cheat + description:Start with 9 Grenades + code:80a635/09 + cheat + description:Start with 15 Grenades + code:80a635/0f + cheat + description:Start with 2 lives + code:bfa9ae/01 + cheat + description:Start with 5 lives + code:bfa9ae/04 + cheat + description:Start with 10 lives + code:bfa9ae/09 + cheat + description:Start with no continues + code:bfa9bb/06 + cheat + description:Infinite health + code:7e0120/06 + +cartridge sha256:5e5cac64fdcf09a52a9c0ab1ebc8bd309dcb1256faf1405284443569b5284fe5 + name: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:01f00a/c4 + cheat + description:Start with 250 health after the first battle + code:01f0a4/fa + cheat + description:Start with 100 energy after the first level up + code:01f0a8/64 + 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 + name:Inspector Gadget (USA) + cheat + description:Invincibility (keep coat in collisions) + code:c08151/ad + cheat + description:Infinite time + code:c05635/ad + cheat + description:Infinite lives + code:c06980/ad + cheat + description:Start with 3 plungers + code:c02f9c/03 + +cartridge sha256:6443fecebcdc2ff7061a40432f3ad1db6dfd354909a5f306972cf6afa122752c + name:International Superstar Soccer (USA) + cheat + description:Opponent's Goals don't count + code:7e1774/00 + cheat + description:Infinite time + code:7e1a46/55 + cheat + description:3 minute game instead of 5 (International Cup and World Series modes) + code:7e1fa2/00 + cheat + description:7 Minute game (International Cup and World Series modes) + code:7e1fa2/02 + cheat + description:No Fouls (International Cup and World Series modes) + code:7e1f96/01 + cheat + description:No Cards (International Cup and World Series modes) + code:7e1f98/01 + cheat + description:No Offside (International Cup and World Series modes) + code:7e1f90/01 + cheat + description:Always Sunny (International Cup and World Series modes) + code:7e1f92/00 + cheat + description:Always Rain (International Cup and World Series modes) + code:7e1f92/01 + cheat + description:Always Snow (International Cup and World Series modes) + code:7e1f92/02 + cheat + description:Stop Clock (Training mode) + code:7e1e38/30 + cheat + description:Stop Bonus Clock (Training mode) + code:7e1e3c/30 + cheat + description:Black Ball and Noob Saibot referee (Open Game mode) + code:7e1f9f/03 + +cartridge sha256:8304d8bc55aa9e64bdd144d384f4b185af2426e7d64888c6c23dd41366a53981 + name:Irem Skins Game, The (USA) + cheat + description:Ball goes in from anywhere + code:00c6de/80+00c687/80+00c5ba/80+00c6bb/80+00c9f7/00 + +cartridge sha256:8e0d620a307a225a757bbc9ef2a2a666792e5d533aa0279d3c0060a1b93ead82 + name:Iron Commando - Koutetsu no Senshi (Japan) + cheat + description:Invincibility - Bicycle stages + code:81fac3/6b + cheat + description:Infinite ammo + code:81c862/ad + cheat + description:One hit kills (most enemies) + code:81f81a/24+82a059/9e+82a05c/9c + +cartridge sha256:39bfe828571cdb23e7c85c23cf5b175979dcc2042c5841add58f5ae6492168a9 + name:Itchy & Scratchy Game, The (USA) + cheat + description:Infinite health + code:97fc63/ad + cheat + description:Infinite lives + code:809a90/ad + cheat + description:Infinite time + code:8dbec1/ad + cheat + description:Infinite Bones + code:80b7c0/ad + 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 + name: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 + name:J.R.R. Tolkien's The Lord of the Rings - Volume 1 (USA) + cheat + description:Invincibility - all characters + code:80c2d6/bd + cheat + description:Start with 908 HP + code:b1a2fa/09+81a2fb/09 + cheat + description:Start with 9908 HP + code:b1a2fa/99+81a2fb/99 + cheat + description:Start the game with more strength + code:81a308/8d + 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:7e02b3/ff+7e02b4/ff+7e02b5/01+7e02aa/ff+7e02ab/ff+7e02ac/ff+7e02ad/ff+7e02ae/ff+7e02af/ff+7e02b0/ff+7e02b1/ff+7e02b2/ff + cheat + description:Walk through walls + code:80e643/11 + +cartridge sha256:3ffbb6e0ccf8e9f5e4c72d9fe526a16371e562b71a91d6430e562bf358a5126b + name:Jack Nicklaus Golf (USA) + cheat + description:Ball goes in from anywhere + code:00cca9/4e+00cca8/80 + cheat + description:Infinite mulligans + code:009e1d/bd + cheat + description:Mulligan can be taken after any stroke + code:009dd1/80 + cheat + description:No mulligans allowed + code:009dca/00 + cheat + description:Each round ends after hole 1 + code:00e5ee/01+03f099/00 + cheat + description:Each round ends after hole 2 + code:00e5ee/02+03f099/01 + cheat + description:Each round ends after hole 3 + code:00e5ee/03+03f099/02 + cheat + description:Each round ends after hole 4 + code:00e5ee/04+03f099/03 + cheat + description:Each round ends after hole 5 + code:00e5ee/05+03f099/04 + cheat + description:Each round ends after hole 6 + code:00e5ee/06+03f099/05 + cheat + description:Each round ends after hole 7 + code:00e5ee/07+03f099/06 + cheat + description:Each round ends after hole 8 + code:00e5ee/08+03f099/07 + cheat + description:Each round ends after hole 9 + code:00e5ee/09+03f099/08 + cheat + description:Each round ends after hole 10 + code:00e5ee/0a+03f099/09 + cheat + description:Each round ends after hole 11 + code:00e5ee/0b+03f099/0a + cheat + description:Each round ends after hole 12 + code:00e5ee/0c+03f099/0b + cheat + description:Each round ends after hole 13 + code:00e5ee/0d+03f099/0c + cheat + description:Each round ends after hole 14 + code:00e5ee/0e+03f099/0d + cheat + description:Each round ends after hole 15 + code:00e5ee/0f+03f099/0e + cheat + description:Each round ends after hole 16 + code:00e5ee/10+03f099/0f + cheat + description:Each round ends after hole 17 + code:00e5ee/11+03f099/10 + +cartridge sha256:9cf82dd9a851cdc38bf2afc286c077ff18a0a5d3bb301eba606cc52db62f8965 + name:James Bond Jr (USA) + cheat + description:Infinite health (can still be hurt by some things) + code:06d09a/af + cheat + description:Infinite Grenades + code:06dac6/ad + cheat + description:Infinite Darts + code:06dc30/ad + cheat + description:Infinite lives on the ground + code:00f245/ad + cheat + description:Infinite lives in the air + code:028ea5/ad + cheat + description:Hearts worth 0 + code:06ea06/ad + cheat + description:Large red Grenade worth 0 instead of 5 + code:06ea2d/00 + cheat + description:Large red Grenade worth 10 + code:06ea2d/0a + cheat + description:Large red Grenade worth 20 + code:06ea2d/14 + cheat + description:Large red Grenade worth 30 + code:06ea2d/1e + cheat + description:Large red Grenade worth 40 + code:06ea2d/28 + cheat + description:Small silver Grenade worth 0 instead of 1 + code:06ebc0/ea + cheat + description:Start with 1 life on the ground instead of 5 + code:00c24d/01 + cheat + description:Start with 3 lives on the ground + code:00c24d/03 + cheat + description:Start with 7 lives on the ground + code:00c24d/07 + cheat + description:Start with 9 lives on the ground + code:00c24d/09 + cheat + description:Start with 1 life in the air instead of 5 + code:0080b3/01 + cheat + description:Start with 3 lives in the air + code:0080b3/03 + cheat + description:Start with 7 lives in the air + code:0080b3/07 + cheat + description:Start with 9 lives in the air + code:0080b3/09 + cheat + description:Start with 0 Grenades and Darts instead of 10 + code:00f236/00 + cheat + description:Start with 5 Grenades and Darts + code:00f236/05 + cheat + description:Start with 25 Grenades and Darts + code:00f236/19 + cheat + description:Start with 50 Grenades and Darts + code:00f236/32 + cheat + description:Start with 99 Grenades and Darts + code:00f236/63 + cheat + description:Start with 0 Darts instead of 10 + code:00c259/00+00f23b/af + cheat + description:Start with 5 Darts + code:00c259/05+00f23b/af + cheat + description:Start with 25 Darts + code:00c259/19+00f23b/af + cheat + description:Start with 50 Darts + code:00c259/32+00f23b/af + cheat + description:Start with 99 Darts + code:00c259/63+00f23b/af + cheat + description:Start on level 3 + code:00c2a1/a9+00c2a2/01 + cheat + description:Start on level 5 + code:00c2a1/a9+00c2a2/02 + cheat + description:Start on level 7 + code:00c2a1/a9+00c2a2/03 + cheat + description:Start on level 3, part 2 + code:00c29f/a9+00c2a0/04+00c2a1/80 + cheat + description:Start on level 3, part 3 + code:00c29f/a9+00c2a0/07+00c2a1/80 + cheat + description:Start on level 5, part 2 + code:00c29f/a9+00c2a0/05+00c2a1/80 + cheat + description:Start on level 5, part 3 + code:00c29f/a9+00c2a0/08+00c2a1/80 + cheat + description:Start on level 7, part 2 + code:00c29f/a9+00c2a0/06+00c2a1/80 + cheat + description:Start on level 7, part 3 + code:00c29f/a9+00c2a0/09+00c2a1/80 + +cartridge sha256:f5e74f09c485d58b444ef2b168d041a1d451056b5feb295901974ca73190dbdb + name:Jelly Boy (Europe) + cheat + description:Infinite lives + code:80dbb4/ad + cheat + description:Infinite time + code:81fde1/ad + cheat + description:Don't lose Music Notes when hit (can get stuck) + code:80dc87/ad + +cartridge sha256:bc09f97cb988f6e445fc92e438fff4bf97aa56cb7bbecaa234ffe93bb285d915 + name:Jelly Boy 2 (Japan) (Proto) + cheat + description:Invincibility + code:7e026b/03 + cheat + description:Infinite lives + code:7e0269/03 + +cartridge sha256:85e5f6fedc420925557092d728e1dc6b4e2042368fb78bf93c0df447f8c9c0c0 + name:Jeopardy! (USA) + cheat + description:Always get the correct answer + code:00aeb2/80+00aefb/80 + +cartridge sha256:ee7a29eb9c302ea2bb235ef990fd8344a6beb9817499941c40a8a94ad5f7c964 + name:Jetsons, The - Invasion of the Planet Pirates (USA) + cheat + description:Invincibility + code:8189de/ea + cheat + description:Infinite lives + code:808c0e/ad + cheat + description:Infinite time + code:80c402/ad + cheat + description:Maximum vacuum power + code:80919a/04 + +cartridge sha256:6a2f280ed1ef5166d95e3b0eb1a6665564f7ddcfd3feaf53344a1268b54b85c6 + name:Jikkyou Oshaberi Parodius (Japan) + cheat + description:Infinite lives + code:7e00ac/04 + +cartridge sha256:a314583b11d594b8245b5177aa64a4d3b7497d096edabbea7c1842c57aa2ad2b + name:Jim Lee's WildC.A.T.S - Covert-Action-Teams (USA) + cheat + description:Invincibility + code:8aa672/ad + cheat + description:Infinite health + code:8a82ae/bd + cheat + description:Infinite lives + code:8a9935/ea + 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 + name:Jim Power - The Lost Dimension in 3D (USA) + cheat + description:Invincibility + code:80c191/af + cheat + description:Infinite lives + code:80c205/a5 + cheat + description:Infinite time + code:81df47/a5 + cheat + description:Infinite SB + code:80e81e/a5 + 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:Hit anywhere + code:81e63e/ff+81e63f/ff+81e736/ad + cheat + description:Jump as high as you want and jump through walls (disable to come back down) + code:7e077e/10 + +cartridge sha256:3b2b8b813b58049a4a86ce1c42d2a651f19fd9bbab2407a494e20cf343d3c1a4 + name:Joe & Mac (USA) + cheat + description:Invincibility after one hit + code:00daa8/b5 + cheat + description:Infinite health + code:009ec8/d9 + cheat + description:Infinite health (alt) + code:009ec8/b9 + cheat + description:Infinite lives + code:00e089/00 + cheat + description:Infinite lives (alt) + code:00e08a/b5 + cheat + description:Infinite Keys + code:02ec8d/a5 + cheat + description:All food fully restores health + code:00f546/00 + cheat + description:Hit anywhere + code:00a1e3/80+00f070/a5+00a12e/00 + cheat + description:One hit kills + code:00a1ac/24 + cheat + description:Start with 2 lives + code:00aab9/a9+00aaba/01 + cheat + description:Start with 6 lives + code:00aab9/a9+00aaba/05 + cheat + description:Start with 10 lives + code:00aab9/a9+00aaba/09 + 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 + name:Joe & Mac 2 - Lost in the Tropics (USA) (Beta) + cheat + description:Infinite health + code:80b1de/95 + cheat + description:Infinite lives + code:80e307/b5 + cheat + description:Start with $2020 + code:80e39d/c3 + +cartridge sha256:c9889799a9ae8558f26d66ae546db930c99acb78d921b4395afbbc38da6272aa + name:Joe & Mac 2 - Lost in the Tropics (USA) + cheat + description:Infinite health + code:80b232/95 + cheat + description:Infinite lives + code:80af6a/95 + cheat + description:Hit anywhere (disable to enter stores and houses) + code:80eded/00+80ef23/00+828a8f/00 + cheat + description:Start with $2020 + code:80e41f/c3 + +cartridge sha256:5a76347672ea7d27bb334b1e30bbc73e06f92373883bed499245377327a8f0cf + name:John Madden Football (USA) + cheat + description:Always 1st down + code:00ca9b/ad + cheat + description:Infinite time-outs + code:00d32d/ea + cheat + description:Play clock is 20 seconds instead of 45 + code:00c3d8/14 + cheat + description:Play clock is 30 seconds + code:00c3d8/1e + cheat + description:Play clock is 60 seconds (CPU will run down the play clock) + code:00c3d8/3c + cheat + description:Play clock is 90 seconds (CPU will run down the play clock) + code:00c3d8/5a + cheat + description:Only have 3 plays to get a first down or TD (down counter starts at 2) + code:00cae1/02 + cheat + description:Only have 2 plays to get a first down or TD (down counter starts at 3) + code:00cae1/03 + cheat + description:Only have 1 play to get a first down or TD (down counter starts at 4) + code:00cae1/04 + cheat + description:No time-outs instead of 3 - P1 + code:008f59/00 + cheat + description:6 time-outs - P1 + code:008f59/06 + cheat + description:9 time-outs - P1 + code:008f59/09 + cheat + description:No time-outs - P2 + code:008f5a/00 + cheat + description:6 time-outs - P2 + code:008f5a/06 + cheat + description:9 time-outs - P2 + code:008f5a/09 + cheat + description:Safeties worth 1 point instead of 2 + code:00cb86/bd + cheat + description:Safeties worth 0 points + code:00cb86/bd+00cb89/bd + cheat + description:Touchdowns worth 0 points instead of 6 + code:00cd2e/00 + cheat + description:Touchdowns worth 1 point + code:00cd2e/01 + cheat + description:Touchdowns worth 2 points + code:00cd2e/02 + cheat + description:Touchdowns worth 3 points + code:00cd2e/03 + cheat + description:Touchdowns worth 4 points + code:00cd2e/04 + cheat + description:Touchdowns worth 5 points + code:00cd2e/05 + cheat + description:Touchdowns worth 7 points + code:00cd2e/07 + cheat + description:Touchdowns worth 8 points + code:00cd2e/08 + cheat + description:Touchdowns worth 9 points + code:00cd2e/09 + cheat + description:Extra points and field goals worth 0 + code:00cf3d/ea+00cf3e/ea + cheat + description:Extra point or field goal resets score to 0 + code:00cf3f/9e + cheat + description:Start with 3 points - P1 + code:008ea1/a9+008ea4/8d+008ea5/26+008eaa/f0+008ea2/03 + cheat + description:Start with 5 points - P1 + code:008ea1/a9+008ea4/8d+008ea5/26+008eaa/f0 + cheat + description:Start with 9 points - P1 + code:008ea1/a9+008ea4/8d+008ea5/26+008eaa/f0+008ea2/09 + cheat + description:Start with 12 points - P1 + code:008ea1/a9+008ea4/8d+008ea5/26+008eaa/f0+008ea2/0c + cheat + description:Start with 15 points - P1 + code:008ea1/a9+008ea4/8d+008ea5/26+008eaa/f0+008ea2/0f + cheat + description:Start with 20 points - P1 + code:008ea1/a9+008ea4/8d+008ea5/26+008eaa/f0+008ea2/14 + cheat + description:Start with 3 points - P2 + code:008ea1/a9+008ea4/8d+008ea5/2b+008eaa/f0+008ea2/03 + cheat + description:Start with 5 points - P2 + code:008ea1/a9+008ea4/8d+008ea5/2b+008eaa/f0 + cheat + description:Start with 9 points - P2 + code:008ea1/a9+008ea4/8d+008ea5/2b+008eaa/f0+008ea2/09 + cheat + description:Start with 12 points - P2 + code:008ea1/a9+008ea4/8d+008ea5/2b+008eaa/f0+008ea2/0c + cheat + description:Start with 15 points - P2 + code:008ea1/a9+008ea4/8d+008ea5/2b+008eaa/f0+008ea2/0f + cheat + description:Start with 20 points - P2 + code:008ea1/a9+008ea4/8d+008ea5/2b+008eaa/f0+008ea2/14 + +cartridge sha256:3e62872bf69ea90dd7093608268f8defa2c6016adb1011745dab3c2af45d69b7 + name:John Madden Football '93 (USA) + cheat + description:Infinite timeouts - both players + code:00e1c7/ea + cheat + description:9 timeouts - P1 + code:0be04b/09 + cheat + description:6 timeouts - P1 + code:0be04b/06 + cheat + description:1 timeout - P1 + code:0be04b/01 + cheat + description:9 timeouts - P2 + code:0be04c/09 + cheat + description:6 timeouts - P2 + code:0be04c/06 + cheat + description:1 timeout - P2 + code:0be04c/01 + +cartridge sha256:67fa7115eb6bf292c024c3a8b06ce9bd457c4d46de182a06a573afff968cc0f1 + name:Judge Dredd (USA) + cheat + description:Invincible after first hit + code:a4d1a7/ad + cheat + description:Almost infinite health + code:a4cd53/ad + cheat + description:Almost infinite ammo + code:ba94f0/ad + cheat + description:Don't flash after getting hit + code:a4cd5a/00 + cheat + description:Don't flash as long after getting hit + code:a4cd5a/32 + cheat + description:Flash longer after getting hit + code:a4cd5a/ff + cheat + description:Start with all weapons and almost infinite ammo + code:ba8de9/ff + cheat + description:Start with very little energy on your first life + code:ba8e0b/0f + cheat + description:Start with half energy on your first life + code:ba8e0b/80 + cheat + description:Start with about 3/4 energy on your first life + code:ba8e0b/c6 + cheat + description:Start with very little energy after first life + code:a4ecce/0f + cheat + description:Start with half energy after first life + code:a4ecce/80 + cheat + description:Start with about 3/4 energy after first life + code:a4ecce/c6 + cheat + description:Start with 1 life + code:ba8dd3/01 + cheat + description:Start with 5 lives + code:ba8dd3/05 + cheat + description:Start with 9 lives + code:ba8dd3/09 + 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 + name: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 + name:Jungle Book, The (USA) + cheat + description:Infinite weapons + code:808810/00 + cheat + description:Infinite lives + code:80a8ad/ad + cheat + description:Hearts from big jungle fruit restore all energy + code:80a316/00 + cheat + description:Super-jump - Mowgli + code:80abc3/fb + cheat + description:Mega-jump - Mowgli + code:80abc3/fa + cheat + description:20 seconds from hourglass + code:80a547/02 + cheat + description:30 seconds from hourglass + code:80a547/03 + cheat + description:Bonus gems worth 2 (don't collect over 100) + code:80a4c0/02 + cheat + description:Bonus gems worth 3 (don't collect over 100) + code:80a4c0/03 + cheat + description:Bonus gems worth 4 (don't collect over 100) + code:80a4c0/04 + cheat + description:Red gems worth 2 (don't collect over 100) + code:80a4d7/02 + cheat + description:Red gems worth 3 (don't collect over 100) + code:80a4d7/03 + cheat + description:Red gems worth 4 (don't collect over 100) + code:80a4d7/04 + cheat + description:The amazing rock (just for fun) + code:80807f/00 + cheat + description:Start with 9 hearts (normal game) + code:80fd16/09 + cheat + description:Start with 6 hearts (normal game) + code:80fd16/06 + cheat + description:Start with 1 heart (normal game) + code:80fd16/01 + cheat + description:Start with 10 lives (normal game) + code:80fd10/09 + cheat + description:Start with 2 lives (normal game) + code:80fd10/01 + 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 + name:Jungle Strike (USA) + cheat + description:Infinite ammo + code:80c47e/ad + cheat + description:Infinite armor + code:80cc57/ad + cheat + description:Infinite lives + code:809af8/af + cheat + description:Start with less fuel + code:81ba7c/32 + cheat + description:Start with more fuel + code:81ba7c/32 + cheat + description:Start with mega fuel + code:81ba7d/32 + cheat + description:Start with 0 hellfires + code:81ba8e/00 + cheat + description:Start with more hellfires + code:81ba8e/96 + cheat + description:Start with mega hellfires + code:81ba8f/96 + cheat + description:Start with less gun ammo + code:81ba9b/00 + cheat + description:Start with more gun ammo + code:81ba9b/16 + cheat + description:Start with mega gun ammo + code:81ba9b/32 + cheat + description:Start with less hydras + code:81ba94/19 + cheat + description:Start with more hydras + code:81ba94/ff + cheat + description:Start with mega hydras + code:81ba95/32 + +cartridge sha256:0a4e9d6fa2ac16aa51da5538d93280734de480e44c430173ed14826c84553c7d + name:Jurassic Park (USA) (Rev 1) + cheat + description:Infinite lives + code:8180cd/ad + cheat + description:Cattle Prod energy recharges to about 3/4 full when outside + code:80b2d7/18 + cheat + description:Cattle Prod energy recharges to about 1/2 full when outside + code:80b2d7/10 + cheat + description:Cattle Prod energy recharges to about 1/4 full when outside + code:80b2d7/08 + cheat + description:Infinite Cattle Prod energy when outside + code:80b27e/ad + cheat + description:Infinite 1st weapons when outside + code:80af99/ad + cheat + description:Infinite 2nd weapons when outside (except gas grenade) + code:80b053/bd + cheat + description:Cattle Prod energy recharges to 1/2 full when inside + code:80fcce/f0 + cheat + description:Infinite Cattle Prod energy when inside + code:a1bcd6/ad + cheat + description:Infinite 1st weapons when inside + code:a1af2a/ea+a1afc0/ea + cheat + description:Infinite 2nd weapons when inside (except gas grenade) + code:a1ab84/ad + cheat + description:Infinite continues with 4 lives + code:8192b8/ad + cheat + description:Continue 1st time with 5 lives + code:8192a3/04 + cheat + description:Continue with 5 lives after 1st continue + code:8192ac/04 + cheat + description:Start with 1 egg needed + code:81d7ea/01 + cheat + description:Start with 2 lives + code:81d7f0/01 + cheat + description:Start with 4 lives + code:81d7f0/03 + 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 + name:Jurassic Park (USA) + cheat + description:Infinite lives + code:8180cd/ad + cheat + description:Cattle Prod energy recharges to about 3/4 full when outside + code:80b2d7/18 + cheat + description:Cattle Prod energy recharges to about 1/2 full when outside + code:80b2d7/10 + cheat + description:Cattle Prod energy recharges to about 1/4 full when outside + code:80b2d7/08 + cheat + description:Infinite Cattle Prod energy when outside + code:80b27e/ad + cheat + description:Infinite 1st weapons when outside + code:80af99/ad + cheat + description:Infinite 2nd weapons when outside (except gas grenade) + code:80b053/bd + cheat + description:Cattle Prod energy recharges to 1/2 full when inside + code:80fcce/f0 + cheat + description:Infinite Cattle Prod energy when inside + code:a1bcd6/ad + cheat + description:Infinite 1st weapons when inside + code:a1af2a/ea+a1afc0/ea + cheat + description:Infinite 2nd weapons when inside (except gas grenade) + code:a1ab84/ad + cheat + description:Infinite continues with 4 lives + code:8192b8/ad + cheat + description:Continue 1st time with 5 lives + code:8192a3/04 + cheat + description:Continue with 5 lives after 1st continue + code:8192ac/04 + cheat + description:Start with 1 egg needed + code:81d7ea/01 + cheat + description:Start with 2 lives + code:81d7f0/01 + cheat + description:Start with 4 lives + code:81d7f0/03 + 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 + name:Jurassic Park Part 2 - The Chaos Continues (USA) (En,Fr,De,It) + cheat + description:Almost invincible + code:b4f297/b9+a08d7a/b9 + cheat + description:Invincibility after one hit until you enter a new screen + code:809a8d/bd + cheat + description:Infinite health against some larger dinosaurs + code:b4f301/80 + cheat + description:One hit kills on some dinosaurs + code:a080dc/02 + cheat + description:Regular Gun is super strong + code:938dc2/40 + cheat + description:Flash longer after getting hit + code:80e543/ff + cheat + description:Don't flash after getting hit + code:80e543/00 + cheat + description:Velociraptor takes more damage + code:aeaa70/20 + cheat + description:Start with less Machine Gun ammo + code:9ca344/0f + cheat + description:Start with more Shotgun ammo + code:9ca34b/64 + cheat + description:Start with less Tranquilizer Gun ammo + code:9ca359/10 + cheat + description:Start with more Tranquilizer Missiles + code:9ca360/64 + 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 + name: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:Hit anywhere - Normal Attacks - P1 + code:80c7e1/80+80c7e2/1e + cheat + description:Hit anywhere - Normal Attacks - P2 + code:80c85c/80+80c85d/1e + cheat + description:Hit anywhere - Projectiles - both players + code:808685/80+808686/1e + cheat + description:Win match after one round + code:7e0547/02+7e0efb/02 + +cartridge sha256:05152bcf9bf086e7bcdbfa7dd8edfe2085f1339c4d7e193e0071c49a10471ef4 + name:Ka-blooey (USA) + cheat + description:Invincibility + code:00b292/80+00c251/80 + cheat + description:Infinite lives + code:008165/ad + cheat + description:Bonus timer doesn't count down + code:00d231/ea + cheat + description:Level is completed after only one bomb goes off + code:00a9bc/9c + cheat + description:Start with 1 life instead of 5 + code:00809e/01 + cheat + description:Start with 3 lives + code:00809e/03 + cheat + description:Start with 10 lives + code:00809e/0a + cheat + description:Start with 25 lives + code:00809e/19 + cheat + description:Start with 50 lives + code:00809e/32 + cheat + description:Start with 75 lives + code:00809e/4b + cheat + description:Start with 98 lives + code:00809e/62 + cheat + description:Start on level 2 + code:00dd7c/9c+00dd78/01 + cheat + description:Start on level 3 + code:00dd7c/9c+00dd78/02 + cheat + description:Start on level 4 + code:00dd7c/9c+00dd78/03 + cheat + description:Start on level 5 + code:00dd7c/9c+00dd78/04 + cheat + description:Start on level 6 + code:00dd7c/9c+00dd78/05 + cheat + description:Start on level 7 + code:00dd7c/9c+00dd78/06 + cheat + description:Start on level 8 + code:00dd7c/9c+00dd78/07 + cheat + description:Start on level 9 + code:00dd7c/9c+00dd78/08 + cheat + description:Start on level 10 + code:00dd7c/9c+00dd78/09 + cheat + description:Start on level 11 + code:00dd7c/9c+00dd78/0a + cheat + description:Start on level 12 + code:00dd7c/9c+00dd78/0b + cheat + description:Start on level 13 + code:00dd7c/9c+00dd78/0c + cheat + description:Start on level 14 + code:00dd7c/9c+00dd78/0d + cheat + description:Start on level 15 + code:00dd7c/9c+00dd78/0e + cheat + description:Start on level 16 + code:00dd7c/9c+00dd78/0f + cheat + description:Start on level 17 + code:00dd7c/9c+00dd78/10 + cheat + description:Start on level 18 + code:00dd7c/9c+00dd78/11 + cheat + description:Start on level 19 + code:00dd7c/9c+00dd78/12 + cheat + description:Start on level 20 + code:00dd7c/9c+00dd78/13 + cheat + description:Start on level 21 + code:00dd7c/9c+00dd78/14 + cheat + description:Start on level 22 + code:00dd7c/9c+00dd78/15 + cheat + description:Start on level 23 + code:00dd7c/9c+00dd78/16 + cheat + description:Start on level 24 + code:00dd7c/9c+00dd78/17 + cheat + description:Start on level 25 + code:00dd7c/9c+00dd78/18 + cheat + description:Start on level 26 + code:00dd7c/9c+00dd78/19 + cheat + description:Start on level 27 + code:00dd7c/9c+00dd78/1a + cheat + description:Start on level 28 + code:00dd7c/9c+00dd78/1b + cheat + description:Start on level 29 + code:00dd7c/9c+00dd78/1c + cheat + description:Start on level 30 + code:00dd7c/9c+00dd78/1d + cheat + description:Start on level 31 + code:00dd7c/9c+00dd78/1e + cheat + description:Start on level 32 + code:00dd7c/9c+00dd78/1f + cheat + description:Start on level 33 + code:00dd7c/9c+00dd78/20 + cheat + description:Start on level 34 + code:00dd7c/9c+00dd78/21 + cheat + description:Start on level 35 + code:00dd7c/9c+00dd78/22 + cheat + description:Start on level 36 + code:00dd7c/9c+00dd78/23 + cheat + description:Start on level 37 + code:00dd7c/9c+00dd78/24 + cheat + description:Start on level 38 + code:00dd7c/9c+00dd78/25 + cheat + description:Start on level 39 + code:00dd7c/9c+00dd78/26 + cheat + description:Start on level 40 + code:00dd7c/9c+00dd78/27 + cheat + description:Start on level 41 + code:00dd7c/9c+00dd78/28 + cheat + description:Start on level 42 + code:00dd7c/9c+00dd78/29 + cheat + description:Start on level 43 + code:00dd7c/9c+00dd78/2a + cheat + description:Start on level 44 + code:00dd7c/9c+00dd78/2b + cheat + description:Start on level 45 + code:00dd7c/9c+00dd78/2c + cheat + description:Start on level 46 + code:00dd7c/9c+00dd78/2d + cheat + description:Start on level 47 + code:00dd7c/9c+00dd78/2e + cheat + description:Start on level 48 + code:00dd7c/9c+00dd78/2f + cheat + description:Start on level 49 + code:00dd7c/9c+00dd78/30 + cheat + description:Start on level 50 + code:00dd7c/9c+00dd78/31 + cheat + description:Start on level 51 + code:00dd7c/9c+00dd78/32 + cheat + description:Start on level 52 + code:00dd7c/9c+00dd78/33 + cheat + description:Start on level 53 + code:00dd7c/9c+00dd78/34 + cheat + description:Start on level 54 + code:00dd7c/9c+00dd78/35 + cheat + description:Start on level 55 + code:00dd7c/9c+00dd78/36 + cheat + description:Start on level 56 + code:00dd7c/9c+00dd78/37 + cheat + description:Start on level 57 + code:00dd7c/9c+00dd78/38 + cheat + description:Start on level 58 + code:00dd7c/9c+00dd78/39 + cheat + description:Start on level 59 + code:00dd7c/9c+00dd78/3a + cheat + description:Start on level 60 + code:00dd7c/9c+00dd78/3b + cheat + description:Start on level 61 + code:00dd7c/9c+00dd78/3c + cheat + description:Start on level 62 + code:00dd7c/9c+00dd78/3d + cheat + description:Start on level 63 + code:00dd7c/9c+00dd78/3e + cheat + description:Start on level 64 + code:00dd7c/9c+00dd78/3f + cheat + description:Start on level 65 + code:00dd7c/9c+00dd78/40 + cheat + description:Start on level 66 + code:00dd7c/9c+00dd78/41 + cheat + description:Start on level 67 + code:00dd7c/9c+00dd78/42 + cheat + description:Start on level 68 + code:00dd7c/9c+00dd78/43 + cheat + description:Start on level 69 + code:00dd7c/9c+00dd78/44 + cheat + description:Start on level 70 + code:00dd7c/9c+00dd78/45 + cheat + description:Start on level 71 + code:00dd7c/9c+00dd78/46 + cheat + description:Start on level 72 + code:00dd7c/9c+00dd78/47 + cheat + description:Start on level 73 + code:00dd7c/9c+00dd78/48 + cheat + description:Start on level 74 + code:00dd7c/9c+00dd78/49 + cheat + description:Start on level 75 + code:00dd7c/9c+00dd78/4a + cheat + description:Start on level 76 + code:00dd7c/9c+00dd78/4b + cheat + description:Start on level 77 + code:00dd7c/9c+00dd78/4c + cheat + description:Start on level 78 + code:00dd7c/9c+00dd78/4d + cheat + description:Start on level 79 + code:00dd7c/9c+00dd78/4e + cheat + description:Start on level 80 + code:00dd7c/9c+00dd78/4f + cheat + description:Start on level 81 + code:00dd7c/9c+00dd78/50 + cheat + description:Start on level 82 + code:00dd7c/9c+00dd78/51 + cheat + description:Start on level 83 + code:00dd7c/9c+00dd78/52 + cheat + description:Start on level 84 + code:00dd7c/9c+00dd78/53 + cheat + description:Start on level 85 + code:00dd7c/9c+00dd78/54 + cheat + description:Start on level 86 + code:00dd7c/9c+00dd78/55 + cheat + description:Start on level 87 + code:00dd7c/9c+00dd78/56 + cheat + description:Start on level 88 + code:00dd7c/9c+00dd78/57 + cheat + description:Start on level 89 + code:00dd7c/9c+00dd78/58 + cheat + description:Start on level 90 + code:00dd7c/9c+00dd78/59 + cheat + description:Start on level 91 + code:00dd7c/9c+00dd78/5a + cheat + description:Start on level 92 + code:00dd7c/9c+00dd78/5b + cheat + description:Start on level 93 + code:00dd7c/9c+00dd78/5c + cheat + description:Start on level 94 + code:00dd7c/9c+00dd78/5d + cheat + description:Start on level 95 + code:00dd7c/9c+00dd78/5e + cheat + description:Start on level 96 + code:00dd7c/9c+00dd78/5f + cheat + description:Start on level 97 + code:00dd7c/9c+00dd78/60 + cheat + description:Start on level 98 + code:00dd7c/9c+00dd78/61 + cheat + description:Start on level 99 + code:00dd7c/9c+00dd78/62 + cheat + description:Start on level 100 + code:00dd7c/9c+00dd78/63 + cheat + description:Start on level 101 + code:00dd7c/9c+00dd78/64 + cheat + description:Start on level 102 + code:00dd7c/9c+00dd78/65 + cheat + description:Start on level 103 + code:00dd7c/9c+00dd78/66 + cheat + description:Start on level 104 + code:00dd7c/9c+00dd78/67 + cheat + description:Start on level 105 + code:00dd7c/9c+00dd78/68 + cheat + description:Start on level 106 + code:00dd7c/9c+00dd78/69 + cheat + description:Start on level 107 + code:00dd7c/9c+00dd78/6a + cheat + description:Start on level 108 + code:00dd7c/9c+00dd78/6b + cheat + description:Start on level 109 + code:00dd7c/9c+00dd78/6c + cheat + description:Start on level 110 + code:00dd7c/9c+00dd78/6d + cheat + description:Start on level 111 + code:00dd7c/9c+00dd78/6e + cheat + description:Start on level 112 + code:00dd7c/9c+00dd78/6f + cheat + description:Start on level 113 + code:00dd7c/9c+00dd78/70 + cheat + description:Start on level 114 + code:00dd7c/9c+00dd78/71 + cheat + description:Start on level 115 + code:00dd7c/9c+00dd78/72 + cheat + description:Start on level 116 + code:00dd7c/9c+00dd78/73 + cheat + description:Start on level 117 + code:00dd7c/9c+00dd78/74 + cheat + description:Start on level 118 + code:00dd7c/9c+00dd78/75 + cheat + description:Start on level 119 + code:00dd7c/9c+00dd78/76 + cheat + description:Start on level 120 + code:00dd7c/9c+00dd78/77 + cheat + description:Start on level 121 + code:00dd7c/9c+00dd78/78 + cheat + description:Start on level 122 + code:00dd7c/9c+00dd78/79 + cheat + description:Start on level 123 + code:00dd7c/9c+00dd78/7a + cheat + description:Start on level 124 + code:00dd7c/9c+00dd78/7b + cheat + description:Start on level 125 + code:00dd7c/9c+00dd78/7c + cheat + description:Start on level 126 + code:00dd7c/9c+00dd78/7d + cheat + description:Start on level 127 + code:00dd7c/9c+00dd78/7e + cheat + description:Start on level 128 + code:00dd7c/9c+00dd78/7f + cheat + description:Start on level 129 + code:00dd7c/9c+00dd78/80 + cheat + description:Start on level 130 + code:00dd7c/9c+00dd78/81 + +cartridge sha256:6f2dc2486d680fe557ed6e2e7082480aad6537c6a04845bb6a6b8ef5e3d698ef + name:Kamen Rider (Japan) + cheat + description:Invincibility + code:808bb0/ad + cheat + description:Infinite health + code:808bb8/40+808bba/8f+808bbb/6a+808bbc/0c+808bbd/7e + cheat + description:Infinite lives + code:81fd14/cd + cheat + description:Infinite health (alt) + code:7e0c6a/40 + cheat + description:Infinite lives (alt) + code:7e0038/02 + +cartridge sha256:f9ec39546e18b15b8f6a738204d0227c1542cd8157e3e0ea16934e76f39e288c + name: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:7efa60/8d+7efa61/8d+7efa62/8d+7efa63/8d+7efa64/8d+7efa65/8d+7efa66/8d+7efa67/8d+7efa68/8d+7efa69/8d+7efa6a/8d+7efa6b/8d+7efa6c/8d+7efa6d/8d+7efa6e/8d+7efa6f/8d+7efa70/8d+7efa71/8d+7efa72/8d+7efa73/8d+7efa74/8d+7efa75/8d+7efa76/8d+7efa77/8d+7efa78/8d+7efa79/8d+7efa7a/8d+7efa7b/8d+7efa7c/8d+7efa7d/8d+7efa7e/8d+7efa7f/8d + +cartridge sha256:7cc3693cc5e1e834d57795f04b048fab27864a898a9507e7ca383771e2035414 + name:Kawasaki Caribbean Challenge (USA) + cheat + description:Only 1 lap required to qualify instead of 2 + code:00821b/01 + cheat + description:Races are 1 lap instead of 5 + code:00823e/01 + cheat + description:Races are 2 laps + code:00823e/02 + cheat + description:Races are 3 laps + code:00823e/03 + cheat + description:Races are 4 laps + code:00823e/04 + cheat + description:Coming in first is worth 9 points instead of 5 + code:00bdd0/09 + cheat + description:Coming in last is worth 5 points instead of 0 + code:00bdd4/05 + cheat + description:Coming in last is worth 9 points + code:00bdd4/09 + cheat + description:Always advance to the next island regardless of points + code:00b841/80 + cheat + description:Each island requires 3 points instead of 5 + code:00a9d5/03 + cheat + description:Each island requires 4 points + code:00a9d5/04 + cheat + description:Each island requires 6 points + code:00a9d5/06 + cheat + description:Each island requires 7 points + code:00a9d5/07 + cheat + description:Opponents drive erratically - player is guaranteed 1st place + code:00813f/85 + cheat + description:Start the Challenge with the 2nd motorcycle and jet ski + code:00813d/85 + +cartridge sha256:3104d6c06c8909c56f6adb2faecf1b4382f2490370798b605631da926c5306d8 + name:Ken Griffey Jr. Presents Major League Baseball (USA) + cheat + description:Can't strike out + code:8491fd/ad + cheat + description:No outs except strike outs + code:84c8d1/ad+84c8ce/ad + cheat + description:Can't walk a player + code:8491e3/a9 + cheat + description:Invisible baserunners + code:80da37/01 + cheat + description:2 outs and whole team is out + code:80a5ed/02 + cheat + description:1 ball and you walk + code:80a5ed/01 + cheat + description:2 balls and you walk + code:80a5ed/02 + cheat + description:1 strike and you're out + code:80a5f5/01 + cheat + description:2 strikes and you're out + code:80a5f5/02 + cheat + description:Computer can't score + code:80bfc7/ad + cheat + description:Computer can't score + code:849c4d/a9 + cheat + description:Computer can't score + code:80bfe8/ad + +cartridge sha256:b16661d5151d73cea5ac46d7c899531c7b2cdee2558092c23a5460c8092b80b8 + name: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:Multi-jump + code:1f8cda/00 + 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 + name:Kid Klown in Crazy Chase (USA) + cheat + description:Infinite health + code:80dd52/ad + cheat + description:Infinite continues + code:84edb7/ad + +cartridge sha256:317e25d731bbfec30bfdc5fbe4ed825cd08613a4d62d98247bae5ec85783074c + name:Kidou Butouden G Gundam (Japan) + cheat + description:Infinite health + code:7e07d4/80 + +cartridge sha256:1b50f8aa5ae75c4b01e237b29b0a1ec1f1f809bdbe76a23d9c204541ccbf403d + name: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 + name: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 + name:Kikou Keisatsu Metal Jack (Japan) + cheat + description:Invincibility + code:00bfba/f0 + cheat + description:Infinite health + code:18b7e6/a5 + cheat + description:Infinite lives + code:00c33e/a5 + 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 + name:Killer Instinct (USA) (Rev 1) + cheat + description:Invincibility - P1 + code:809f95/e0+809f99/c3+809f96/00+809f98/f0 + cheat + description:Hit anywhere - P1 + code:809f82/4c+809f83/ac+809f84/a1+809f81/0d+809f80/f0 + 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:One button finishes and humiliations + code:80b229/00 + cheat + description:Enable finishes during round + code:80b3ef/24+80b3f4/24+80b3fe/24+80b406/24+80b408/c9 + cheat + description:CPU cannot move from starting position + code:7e0e08/01 + cheat + description:CPU cannot perform special or danger moves + code:80d5cd/a9+80d5ce/00 + cheat + description:Play as Eyedol + code:7e024e/0a + +cartridge sha256:618a23636e07110e094277ec1d1e60c3620a6e9a5f386292808267593fa803ad + name:Killer Instinct (USA) + cheat + description:Master code - must be entered + code:008468/ea + cheat + description:Invincibility - P1 + code:809f8a/e0+809f8e/c3+809f8b/00+809f8d/f0 + cheat + description:Hit anywhere - P1 + code:809f77/4c+809f79/a1+809f78/a1+809f76/0d+809f75/f0 + cheat + description:One button finishes and humiliations + code:80b222/00 + cheat + description:Enable finishes during round + code:80b3e3/24+80b3e8/24+80b3f2/24+80b3fa/24+80b3fc/c9 + cheat + description:CPU cannot perform special or danger moves + code:80d624/a9+80d625/00 + cheat + description:P1 takes all damage + code:80a76b/ff + cheat + description:Always fight Jago + code:808d7a/ad+83f48c/84 + cheat + description:Always fight Combo + code:808d7a/ad+83f48c/8f + cheat + description:Always fight Thunder + code:808d7a/ad+83f48c/89 + cheat + description:Always fight Glacius + code:808d7a/ad+83f48c/81 + cheat + description:Always fight Cinder + code:808d7a/ad+83f48c/80 + cheat + description:Always fight Orchid + code:808d7a/ad+83f48c/82 + cheat + description:Always Fight Riptor + code:808d7a/ad+83f48c/94 + cheat + description:Always fight Sabrewulf + code:808d7a/ad+83f48d/a9 + cheat + description:Always fight Spinal + code:808d7a/ad+83f4ad/a9 + cheat + description:Always fight Fulgore + code:808d7a/ad+83f4b2/a9 + cheat + description:Always fight Eyedol + code:808d7a/ad+83f4b7/a9 + 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 + name:King Arthur & The Knights of Justice (USA) + cheat + description:Infinite health + code:848998/b9 + cheat + description:Infinite attack power + code:80950b/ee+80955e/ee + cheat + description:Infinite healing herbs + code:82b8c3/ad + cheat + description:Start with 99 healing herbs + code:80fb8c/62 + cheat + description:Start with 99 shield attacks + code:80fb9e/62 + +cartridge sha256:aca9eb59d6783e2cae3787c69053888fea98f5dfe4c8af8b5a6360e0afb3b5d7 + name:King Arthur's World (USA) + cheat + description:Infinite men - if you have at least one of that type + code:04c6bb/bf+04c6a7/bf + cheat + description:Infinite spells - must have at least one to use + code:0e9aa3/bf + cheat + description:Start with 4 of each type of spell + code:0df6f0/a2+0df6f1/30+0df6f2/02 + cheat + description:Start with many men + code:01fe99/a9+01fe9a/14+01fe9b/00 + cheat + description:Start on training level 2 + code:0e8062/17 + cheat + description:Start on training level 3 + code:0e8062/19 + cheat + description:Start on training level 4 + code:0e8062/16 + cheat + description:Start on training level 5 + code:0e8062/1d + cheat + description:Start on training level 6 + code:0e8062/1e + cheat + description:Start on training level 7 + code:0e8062/1f + cheat + description:Start on training level 8 + code:0e8062/20 + cheat + description:Start on training level 9 + code:0e8062/1a + cheat + description:Start on real world level 1 + code:0e8062/01 + cheat + description:Start on real world level 2 + code:0e8062/02 + cheat + description:Start on real world level 3 + code:0e8062/03 + cheat + description:Start on real world level 4 + code:0e8062/04 + cheat + description:Start on goblin underworld level 1 + code:0e8062/05 + cheat + description:Start on goblin underworld level 2 + code:0e8062/06 + cheat + description:Start on goblin underworld level 3 + code:0e8062/07 + cheat + description:Start on goblin underworld level 4 + code:0e8062/08 + cheat + description:Start on cloud world level 1 + code:0e8062/0c + cheat + description:Start on cloud world level 2 + code:0e8062/0d + cheat + description:Start on cloud world level 3 + code:0e8062/0e + cheat + description:Start on cloud world level 4 + code:0e8062/0f + cheat + description:Start on cloud world level 5 + code:0e8062/10 + cheat + description:Start on cloud world level 6 + code:0e8062/11 + cheat + description:Start on cloud world level 7 + code:0e8062/12 + +cartridge sha256:6638b5541059814d4c34574e5e277ef613aebf81c91d3def557a7642fb5840e1 + name:King of Dragons (USA) + cheat + description:Invincibility - both players + code:c0378b/f0 + cheat + description:Infinite health - both players + code:c09074/a5 + cheat + description:Infinite time + code:c043f5/00 + cheat + description:Infinite credits + code:c04275/af + cheat + description:One hit kills + code:c08b56/24+c08b58/24 + cheat + description:Hit anywhere + code:c08a63/80+c08a2f/80+c08a8f/80+c089f8/80+c089f1/80 + cheat + description:Enable 2-Player same character cheat + code:c12376/f0 + cheat + description:Start with level 6 Sword + code:c07369/8e+c07370/85 + cheat + description:Start with level 6 Shield + code:c0737f/8e+c07386/85 + 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 + name:King of the Monsters (USA) + cheat + description:Faster timer + code:11c81f/17 + cheat + description:Slower timer + code:01c817/60 + cheat + description:3 power points needed to get to next power level + code:01c963/03 + cheat + description:Start with less health - P1 + code:009fd6/80 + cheat + description:Start with less health - P2 + code:00a82e/80 + 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 + name: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 + name:Kirby Super Star (USA) + cheat + description:Infinite health + code:01fbd2/8d + cheat + description:Infinite lives + code:0387e5/ad + cheat + description:Always have invincibility + code:3035f1/0a + cheat + description:Infinite health (friend) + code:40137e/30 + +cartridge sha256:67937dd7a29a93b1aaabb6df89f0748369ff47f3f6c655a402c00d5657973140 + name:Kirby's Avalanche (USA) + cheat + description:Boulder warnings don't appear + code:88c2ba/b4 + cheat + description:CPU gets all the boulders + code:88c2d0/ce+88c2d2/07+88c2d1/52 + cheat + description:Only red blobs fall + code:888e4f/a9+888e50/00+888e51/00 + cheat + description:Only yellow blobs fall + code:888e4f/a9+888e50/01+888e51/01 + cheat + description:Only green blobs fall + code:888e4f/a9+888e50/03+888e51/03 + cheat + description:Only purple blobs fall + code:888e4f/a9+888e50/04+888e51/04 + cheat + description:Only blue blobs fall + code:888e4f/a9+888e50/05+888e51/05 + cheat + description:Only red and yellow blobs fall + code:888e4f/a9+888e50/00+888e51/01 + cheat + description:Only red and green blobs fall + code:888e4f/a9+888e50/00+888e51/03 + cheat + description:Only red and purple blobs fall + code:888e4f/a9+888e50/00+888e51/04 + cheat + description:Only red and blue blobs fall + code:888e4f/a9+888e50/00+888e51/05 + cheat + description:Only red blobs with a boulder fall + code:888e4f/a9+888e50/00+888e51/06 + cheat + description:Only yellow and red blobs fall + code:888e4f/a9+888e50/01+888e51/00 + cheat + description:Only yellow and green blobs fall + code:888e4f/a9+888e50/01+888e51/03 + cheat + description:Only yellow and purple blobs fall + code:888e4f/a9+888e50/01+888e51/04 + cheat + description:Only yellow and blue blobs fall + code:888e4f/a9+888e50/01+888e51/05 + cheat + description:Only yellow blobs with a boulder fall + code:888e4f/a9+888e50/01+888e51/06 + cheat + description:Only green and yellow blobs fall + code:888e4f/a9+888e50/03+888e51/01 + cheat + description:Only green and red blobs fall + code:888e4f/a9+888e50/03+888e51/00 + cheat + description:Only green and purple blobs fall + code:888e4f/a9+888e50/03+888e51/04 + cheat + description:Only green and blue blobs fall + code:888e4f/a9+888e50/03+888e51/05 + cheat + description:Only green blobs with a boulder fall + code:888e4f/a9+888e50/03+888e51/06 + cheat + description:Only purple and yellow blobs fall + code:888e4f/a9+888e50/04+888e51/01 + cheat + description:Only purple and green blobs fall + code:888e4f/a9+888e50/04+888e51/03 + cheat + description:Only purple and red blobs fall + code:888e4f/a9+888e50/04+888e51/00 + cheat + description:Only purple and blue blobs fall + code:888e4f/a9+888e50/04+888e51/05 + cheat + description:Only purple blobs with a boulder fall + code:888e4f/a9+888e50/04+888e51/06 + cheat + description:Only blue and yellow blobs fall + code:888e4f/a9+888e50/05+888e51/01 + cheat + description:Only blue and green blobs fall + code:888e4f/a9+888e50/05+888e51/03 + cheat + description:Only blue and purple blobs fall + code:888e4f/a9+888e50/05+888e51/04 + cheat + description:Only blue and red blobs fall + code:888e4f/a9+888e50/05+888e51/00 + cheat + description:Only blue blobs with a boulder fall + code:888e4f/a9+888e50/05+888e51/06 + cheat + description:Only a boulder and yellow blobs fall + code:888e4f/a9+888e50/06+888e51/01 + cheat + description:Only a boulder and green blobs fall + code:888e4f/a9+888e50/06+888e51/03 + cheat + description:Only a boulder and purple blobs fall + code:888e4f/a9+888e50/06+888e51/04 + cheat + description:Only a boulder and blue blobs fall + code:888e4f/a9+888e50/06+888e51/05 + cheat + description:Only a boulder and red blobs fall + code:888e4f/a9+888e50/06+888e51/00 + cheat + description:Only boulders fall + code:888e4f/a9+888e50/06+888e51/06 + cheat + description:Disable the next box + code:889030/a9+889032/ea+889035/a9+889037/ea + +cartridge sha256:0f984dc5fe8293f75e3b8fad98b0cb564706d9b1e3902b56415aa399c2d4df2b + name:Kirby's Dream Course (USA) + cheat + description:Infinite Strawberries + code:83ac12/bd + cheat + description:Don't lose a life from falling out of bounds + code:80f8d0/bd + cheat + description:Don't ever gain any Strawberries + code:83ac01/bd + cheat + description:Start with 5 lives + code:80c056/04 + cheat + description:Start with 7 lives + code:80c056/06 + cheat + description:Start with 9 lives + code:80c056/08 + cheat + description:Start with 1 Strawberry + code:80c105/01 + cheat + description:Start with 2 Strawberries + code:80c105/02 + cheat + description:Start with 3 Strawberries + code:80c105/03 + cheat + description:Infinite Tomatoes + code:83ac12/bd + +cartridge sha256:b50bf9d95485e8aeb7a6730e9f9f9c9c4ec23a85b336a4fb2e3b63034531e36f + name: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:00ba78/0a + cheat + description:Start a new game with 25 lives + code:00ba78/1a + cheat + description:Start a new game with 98 lives + code:00ba78/63 + +cartridge sha256:fb601ead645edce139b0483d3155b4e3d7ab245bf87a3a66cb88c0a617c0a526 + name:Knights of the Round (USA) + cheat + description:Invincibility + code:81d714/f0 + cheat + description:More invincibility time after successful block + code:82daac/ff + cheat + description:Infinite health + code:81dc52/b9 + cheat + description:Almost infinite health + code:81dc50/24+81ddd0/24 + cheat + description:Maximum health from most food + code:84c50e/00 + cheat + description:Infinite lives + code:82dc36/b9 + cheat + description:Infinite time + code:8084af/ad + cheat + description:One hit kills + code:81df3f/24+81e2be/24+81e0ee/24 + cheat + description:No health lost from special move + code:82d3c9/00 + cheat + description:No health lost from special move (alt) + code:82d3cb/b9 + cheat + description:Less health lost from special move + code:82d3c9/06 + cheat + description:More health lost from special move + code:82d3c9/14 + cheat + description:Super-jump - Arthur + code:82a550/0c + cheat + description:Super-jump - Lancelot + code:82a54c/0c + cheat + description:Super-jump - Percival + code:82a554/0c + cheat + description:Slower timer + code:80849f/60 + cheat + description:Faster timer + code:80849f/1e + cheat + description:Enable hidden options screen in the options menu + code:80c168/20+80c169/b2+80c16a/c9+80c9b8/60 + cheat + description:Start on stage 2 + code:81b86a/ea+81b86b/a9+81b86c/01 + cheat + description:Start on stage 3 + code:81b86a/ea+81b86b/a9+81b86c/02 + cheat + description:Start on stage 4 + code:81b86a/ea+81b86b/a9+81b86c/03 + cheat + description:Start on stage 5 + code:81b86a/ea+81b86b/a9+81b86c/04 + cheat + description:Start on stage 6 + code:81b86a/ea+81b86b/a9+81b86c/05 + 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 + name:Kouryuu no Mimi (Japan) + cheat + description:Infinite health + code:848907/a9+848908/40+848909/00+84890c/8d + cheat + description:Infinite health (alt) + code:7e09c0/40 + cheat + description:Infinite Ring power + code:7e008c/20 + +cartridge sha256:e36322697c48baae6492db91e6cbf3844a420f6e0cc8a75f3a73556026ddbbb8 + name: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 + name:Krusty's Super Fun House (USA) + cheat + description:Invincibility - Krusty + code:00d972/b3 + cheat + description:Infinite Custard Pies + code:00f06c/a6 + cheat + description:Infinite Superballs + code:00f0de/a6 + cheat + description:Infinite lives + code:008d77/ad + cheat + description:Custard Pie bonus worth 2 pies instead of 10 + code:00ee0c/02 + cheat + description:Custard Pie bonus worth 5 pies + code:00ee0c/05 + cheat + description:Custard Pie bonus same as Superball bonus (disable is game freezes) + code:00ee0e/04 + cheat + description:Superball bonus worth 2 balls instead of 5 (disable is game freezes) + code:00ee16/02 + cheat + description:Superball bonus worth 10 balls (disable is game freezes) + code:00ee16/0a + cheat + description:Superball bonus same as Custard Pie bonus (disable is game freezes) + code:00ee13/80+00ee14/f4 + cheat + description:Food bonuses restore less strength + code:00edf9/07 + cheat + description:Food bonuses restore more strength + code:00edf9/1e + cheat + description:Food bonuses restore Krusty to full strength + code:00edf9/63 + cheat + description:Food bonuses also get Custard Pie bonus + code:00ee04/04 + cheat + description:Food bonuses also get Superball bonus + code:00ee04/0e + cheat + description:Doll bonus same as Custard Pie bonus + code:00ee22/e6+00ee21/80 + cheat + description:Doll bonus same as Superball bonus + code:00ee22/f0+00ee21/80 + cheat + description:Doll bonus same as food bonus + code:00ee22/d1+00ee21/80 + cheat + description:Jump higher - Krusty + code:00e8ad/10 + cheat + description:Jump much higher - Krusty + code:00e8ad/08 + cheat + description:Start with section 1 finished + code:00867c/00+00867d/80+00867e/05 + cheat + description:Start with section 2 finished + code:00867c/01+00867d/80+00867e/05 + cheat + description:Start with section 3 finished + code:00867c/02+00867d/80+00867e/05 + cheat + description:Start with section 4 finished + code:00867c/03+00867d/80+00867e/05 + cheat + description:Start with access to all sections + code:00867c/04+00867d/80+00867e/05 + cheat + description:Start with 1 life instead of 3 + code:0088ad/01 + cheat + description:Start with 2 lives + code:0088ad/02 + cheat + description:Start with 5 lives + code:0088ad/05 + cheat + description:Start with 7 lives + code:0088ad/07 + cheat + description:Start with 9 lives + code:0088ad/09 + cheat + description:Start with 0 Custard Pies + code:00889e/00 + cheat + description:Start with 2 Custard Pies + code:00889e/02 + cheat + description:Start with 5 Custard Pies + code:00889e/05 + cheat + description:Start with 2 Superballs instead of 10 Custard Pies + code:00889e/02+0088a3/01 + cheat + description:Start with 5 Superballs + code:00889e/05+0088a3/01 + cheat + description:Start with 10 Superballs + code:0088a3/01 + +cartridge sha256:46c811f0cacffe8f20e1d63072d25d7c47e9bb3fd5124851fd05aca9884d21fb + name:Lagoon (USA) + cheat + description:HP always recovers instantly + code:019147/a9+019148/ff + cheat + description:MP always recovers instantly + code:01914f/a9+019150/ff + cheat + description:Save always available + code:02bec7/80+02bec8/13 + cheat + description:Pit death disabled + code:01c958/60 + cheat + description:Hit anywhere + code:01b628/00 + cheat + description:Get 1 gold for each creature killed + code:01947e/69+01947f/01+019480/ea + cheat + description:Get 100 gold for each creature killed + code:01947e/69+01947f/64+019480/ea + cheat + description:Get 200 gold for each creature killed + code:01947e/69+01947f/c8+019480/ea + cheat + description:Start with 0 STR + code:02d9ec/00 + cheat + description:Start with 100 STR + code:02d9ec/64 + cheat + description:Start with 255 STR + code:02d9ec/ff + cheat + description:Start with 0 DEF + code:02d9fb/00 + cheat + description:Start with 100 DEF + code:02d9fb/64 + cheat + description:Start with 255 DEF + code:02d9fb/ff + cheat + description:Start with 999 DEF + code:02d9fc/f6+02d9fb/17 + cheat + description:Start with 612 gold + code:02da02/02 + cheat + description:Start with 1,380 gold + code:02da02/05 + cheat + description:Start with 2,148 gold + code:02da02/08 + cheat + description:Start with 8,292 gold + code:02da02/20 + cheat + description:Start with 22,116 gold + code:02da02/56 + cheat + description:Start with 65,380 gold + code:02da02/ff + cheat + description:Start on level 2, MP = 8/8, HP = 17/17, EXP = 0/40 + code:02d9d9/02 + cheat + description:Start on level 3, MP = 10/10, HP = 23/23, EXP = 0/90 + code:02d9d9/03 + cheat + description:Start on level 4, MP = 12/12, HP = 28/28, EXP = 0/170 + code:02d9d9/04 + cheat + description:Start on level 5, MP = 19/19, HP =36/36, EXP = 0/280 + code:02d9d9/05 + cheat + description:Start on level 241, HP = 255, MP = 255, EXP = 22859, walk at a regular speed + code:02d9d9/f1 + cheat + description:Start on level 242, HP = 220, MP = 221, EXP = 30560, walk at a medium speed + code:02d9d9/f2 + 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 + name:Lamborghini American Challenge (USA) + cheat + description:Always finish first + code:8afe82/00+8afe84/02+8a8a4e/fe+8afe89/16+8afe86/1a+8afe8a/60+8afe83/d0+8a8a4c/20+8afe88/7e+8afe85/7b+8a8a4d/80+8afe80/c0+8afe87/99+8afe81/00 + cheat + description:Don't take damage in races + code:80bf68/b9 + cheat + description:Free turbos + code:8cd3cc/ad + cheat + description:Repair 10% of car for $100 + code:8cd626/ad + cheat + description:Repair 10% of car for free + code:8cd629/ee + cheat + description:Turbos for $1000 + code:8cd3ba/0a+8cd3bb/00 + cheat + description:Turbos for $2000 + code:8cd3ba/14+8cd3bb/00 + cheat + description:Start with 6-speed transmission + code:8a845b/06 + cheat + description:Start with $128,000 + code:8080f9/00+8080fa/05 + cheat + description:Start with $88,000 + code:8080f9/70+8080fa/03 + cheat + description:Start with $12,800 + code:8080f9/80 + 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 + name:Last Action Hero (USA) + cheat + description:Invincibility + code:80c119/8d + cheat + description:Infinite health + code:80c142/ad + cheat + description:Infinite time + code:809517/ad + cheat + description:Infinite lives + code:80a497/cd + 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:Hit anywhere continually + code:80d4d9/24+80d4ed/24 + 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 + name:Lawnmower Man, The (USA) + cheat + description:Invincible in Cyber Run level + code:8289bf/ad + cheat + description:Invincible in Cyber Tube level + code:828ac2/ad + cheat + description:Invincible in Cyber Jobe level + code:81dde0/ad + cheat + description:Invincible in Cyber Space level + code:86c8dd/ad + cheat + description:Infinite lives + code:8091f3/24 + cheat + description:After you die, your main weapon is fully powered up from then on + code:809273/04+809272/a9 + cheat + description:Super-jump + code:809c84/fa + cheat + description:Energize icon effect lasts 2x longer + code:80b77e/03 + cheat + description:Energize icon effect lasts 4x longer + code:80b77e/05 + cheat + description:Bitstream powers up instantly (don't shoot too many bitstreams at once) + code:809896/06 + cheat + description:Keep weapon power ups once gained + code:809273/00 + cheat + description:Never lose homing bullets once gained + code:809237/af + cheat + description:Never lose rear bullets once gained + code:809233/af + +cartridge sha256:c7814cee0fc95d6422cf19a3dc8c9a65b60f6f56da75f09cebea02cc5f99261b + name:Legend (USA) + cheat + description:Invincibility + code:80c387/8d+80c388/d5+80c389/13 + cheat + description:Infinite health + code:81f59d/ad + cheat + description:Infinite time + code:80e110/ad + cheat + description:Infinite lives + code:80bd50/ad + cheat + description:One hit kills + code:81a68a/24+81b566/24 + cheat + description:Hit anywhere + code:81f32f/24+81f30c/24+81f340/24+81f347/24+81f304/80+81f313/80 + 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 + name:Legend of the Mystical Ninja, The (USA) + cheat + description:Invincibility + code:00b767/24 + cheat + description:Infinite health + code:05a51f/b5 + cheat + description:Infinite lives - top-view + code:00cb8e/ea + cheat + description:Hit anywhere - top view + code:03b581/24+03b20d/24 + cheat + description:Hit anywhere - side view + code:03b16d/24+03b552/24 + cheat + description:Collect items from anywhere - top view + code:03b505/24 + cheat + description:Don't lose most weapons when hit + code:05a548/24 + cheat + description:Pick-up more coins from enemies + code:03cc12/50 + cheat + description:No coins used up when thrown + code:00f808/00 + cheat + description:Faster timer + code:0593f7/14 + cheat + description:Slower timer + code:0593f7/60 + cheat + description:Die after one hit + code:05a51b/00 + cheat + description:Start with 6 lives + code:00db3a/05 + cheat + description:Start with 9 lives + code:00db3a/08 + 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 + name:Legend of Zelda, The - A Link to the Past (USA) + cheat + description:Invincibility + code:7e031f/6a + cheat + description:Infinite rupees + code:7ef360/e7 + cheat + description:Infinite health and all heart containers + code:7ef36d/a0 + cheat + description:Almost infinite health + code:0780f7/cf + cheat + description:Infinite magic + code:7ef36e/80 + cheat + description:Almost infinite magic + code:07b0c8/cf+07b101/cf + cheat + description:Max heart containers + code:04f4f2/a0 + cheat + description:Infinite Bombs + code:098133/cf + cheat + description:Infinite Bombs (alt) + code:7ef343/63 + cheat + description:Infinite Arrows + code:7ef377/63 + cheat + description:Hit anywhere (disable before fighting Ganon, use the Boomerang instead of Sword to hit switches) + code:06f2d1/24+06ebfc/80+06ec13/24+06f3a7/24+06ec2c/80+1e83b3/24 + cheat + description:Get items from anywhere + code:06d11e/24 + cheat + description:Regular sword is very strong (100 damage instead of 2) + code:0db8fa/64 + cheat + description:Blue Boomerang has much longer reach + code:089204/bd + cheat + description:Enemies frozen by Boomerang or Hookshot stay frozen + code:06e321/bd + cheat + description:Sword can destroy solid objects in Overworld + code:1bbe39/80 + cheat + description:Objects that you can pick up and throw never break away + code:06e234/10 + cheat + description:Dash without having the Pegasus Boots + code:7ef379/ff + cheat + description:Dash without charge up + code:0790b9/27 + cheat + description:Walk on deep water + code:0787cb/64+07da3b/de+07da3a/5b + cheat + description:Use the Magic Mirror to warp between the Light and Dark Worlds freely + code:07a953/80 + cheat + description:Some shops don't take your money + code:1ef3ae/cf + cheat + description:Spin attack needs nearly no time to charge + code:079d79/08 + cheat + description:Spin attack needs no time at all to charge + code:079d79/00 + cheat + description:100% enemy drop rate (from enemies that normally drop items) + code:86f9bb/00 + cheat + description:No enemies in dungeons + code:7e0d30/05+7e0d31/05+7e0d32/05 + cheat + description:Dark rooms are fully lit + code:7e045a/03 + cheat + description:Trigger doors are open (works with most dungeon doors, some that even look closed) + code:7e068d/ff + cheat + description:Hold button L to walk over pits + code:07dc8d/00+07dc8c/f2+07dc8f/20 + cheat + description:Hold button R to walk over pits + code:07dc8d/00+07dc8c/f2+07dc8f/10 + cheat + description:Prevent Zelda from saying 'Help me... I am in the dungeon of the castle' during the beginning of the game + code:099ff3/ad + cheat + description:Have Bombos Medallion + code:7ef347/01 + cheat + description:Have Book Of Mudora + code:7ef34e/01 + cheat + description:Have Bug-Catching Net + code:7ef34d/01 + cheat + description:Have Cane Of Byrna + code:7ef351/01 + cheat + description:Have Cane Of Somaria + code:7ef350/01 + cheat + description:Have Ether Medallion + code:7ef348/01 + cheat + description:Have Fire Rod + code:7ef345/01 + cheat + description:Have Flute + code:7ef34c/02 + cheat + description:Have Flute with Duck + code:7ef34c/03 + cheat + description:Have Golden Sword (level 4) + code:7ef359/04 + cheat + description:Have Hookshot + code:7ef342/01 + cheat + description:Have Ice Rod + code:7ef346/01 + cheat + description:Have Lamp + code:7ef34a/01 + cheat + description:Have Magic Boomerang + code:7ef341/02 + cheat + description:Have Magic Cape + code:7ef352/01 + cheat + description:Have Magic Hammer + code:7ef34b/01 + cheat + description:Have Magic Mirror + code:7ef353/02 + cheat + description:Have Magic Powder + code:7ef344/02 + cheat + description:Have Mirror Shield + code:7ef35a/03 + cheat + description:Have Moon Pearl + code:7ef357/01 + cheat + description:Have Pegasus Boots + code:7ef355/02 + cheat + description:Have Quake Medallion + code:7ef349/01 + cheat + description:Have Red Mail + code:7ef35b/02 + cheat + description:Have Shovel + code:7ef34c/01 + cheat + description:Have Titan's Mitten + code:7ef354/02 + cheat + description:Have Zora's Flippers + code:7ef356/01 + cheat + description:Have 1/2 Magic curse + code:7ef37b/01 + cheat + description:Have all abilities except Lift + code:7ef379/6f + cheat + description:Have all Maps, Compasses and Big Keys + code:7ef364/ff+7ef365/ff+7ef366/ff+7ef367/ff+7ef368/ff+7ef369/ff + 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:7ef354/03 + 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 + name:Lemmings (USA) (Rev 1) + cheat + description:Infinite climbers if you start with at least 1 + code:00bf2a/a5 + cheat + description:Infinite floaters if you start with at least 1 + code:00bf11/a5 + cheat + description:Infinite bombers if you start with at least 1 + code:00bf39/a5 + cheat + description:Infinite blockers if you start with at least 1 + code:00be23/a5 + cheat + description:Infinite builders if you start with at least 1 + code:00bef1/a5 + cheat + description:Infinite bashers if you start with at least 1 + code:00bed4/a5 + cheat + description:Infinite miners if you start with at least 1 + code:00be6c/a5 + cheat + description:Infinite diggers if you start with at least 1 + code:00be9b/a5 + cheat + description:Each saved lemming counts as two + code:009687/e6+009688/6b + cheat + description:Start on Level 2; rating: Fun + code:01aca1/a9+01aca2/01+01adb4/a5 + cheat + description:Start on Level 3; rating: Fun + code:01aca1/a9+01aca2/02+01adb4/a5 + cheat + description:Start on Level 4; rating: Fun + code:01aca1/a9+01aca2/03+01adb4/a5 + cheat + description:Start on Level 5; rating: Fun + code:01aca1/a9+01aca2/04+01adb4/a5 + cheat + description:Start on Level 6; rating: Fun + code:01aca1/a9+01aca2/05+01adb4/a5 + cheat + description:Start on Level 7; rating: Fun + code:01aca1/a9+01aca2/06+01adb4/a5 + cheat + description:Start on Level 8; rating: Fun + code:01aca1/a9+01aca2/07+01adb4/a5 + cheat + description:Start on Level 9; rating: Fun + code:01aca1/a9+01aca2/08+01adb4/a5 + cheat + description:Start on Level 10; rating: Fun + code:01aca1/a9+01aca2/09+01adb4/a5 + cheat + description:Start on Level 11; rating: Fun + code:01aca1/a9+01aca2/0a+01adb4/a5 + cheat + description:Start on Level 12; rating: Fun + code:01aca1/a9+01aca2/0b+01adb4/a5 + cheat + description:Start on Level 13; rating: Fun + code:01aca1/a9+01aca2/0c+01adb4/a5 + cheat + description:Start on Level 14; rating: Fun + code:01aca1/a9+01aca2/0d+01adb4/a5 + cheat + description:Start on Level 15; rating: Fun + code:01aca1/a9+01aca2/0e+01adb4/a5 + cheat + description:Start on Level 16; rating: Fun + code:01aca1/a9+01aca2/0f+01adb4/a5 + cheat + description:Start on Level 17; rating: Fun + code:01aca1/a9+01aca2/10+01adb4/a5 + cheat + description:Start on Level 18; rating: Fun + code:01aca1/a9+01aca2/11+01adb4/a5 + cheat + description:Start on Level 19; rating: Fun + code:01aca1/a9+01aca2/12+01adb4/a5 + cheat + description:Start on Level 20; rating: Fun + code:01aca1/a9+01aca2/13+01adb4/a5 + cheat + description:Start on Level 21; rating: Fun + code:01aca1/a9+01aca2/14+01adb4/a5 + cheat + description:Start on Level 22; rating: Fun + code:01aca1/a9+01aca2/15+01adb4/a5 + cheat + description:Start on Level 23; rating: Fun + code:01aca1/a9+01aca2/16+01adb4/a5 + cheat + description:Start on Level 24; rating: Fun + code:01aca1/a9+01aca2/17+01adb4/a5 + cheat + description:Start on Level 25; rating: Fun + code:01aca1/a9+01aca2/18+01adb4/a5 + cheat + description:Start on Level 26; rating: Fun + code:01aca1/a9+01aca2/19+01adb4/a5 + cheat + description:Start on Level 27; rating: Fun + code:01aca1/a9+01aca2/1a+01adb4/a5 + cheat + description:Start on Level 28; rating: Fun + code:01aca1/a9+01aca2/1b+01adb4/a5 + cheat + description:Start on Level 29; rating: Fun + code:01aca1/a9+01aca2/1c+01adb4/a5 + cheat + description:Start on Level 30; rating: Fun + code:01aca1/a9+01aca2/1d+01adb4/a5 + cheat + description:Start on Level 1; rating: Tricky + code:01aca1/a9+01aca2/1e+01adb4/a5 + cheat + description:Start on Level 2; rating: Tricky + code:01aca1/a9+01aca2/1f+01adb4/a5 + cheat + description:Start on Level 3; rating: Tricky + code:01aca1/a9+01aca2/20+01adb4/a5 + cheat + description:Start on Level 4; rating: Tricky + code:01aca1/a9+01aca2/21+01adb4/a5 + cheat + description:Start on Level 5; rating: Tricky + code:01aca1/a9+01aca2/22+01adb4/a5 + cheat + description:Start on Level 6; rating: Tricky + code:01aca1/a9+01aca2/23+01adb4/a5 + cheat + description:Start on Level 7; rating: Tricky + code:01aca1/a9+01aca2/24+01adb4/a5 + cheat + description:Start on Level 8; rating: Tricky + code:01aca1/a9+01aca2/25+01adb4/a5 + cheat + description:Start on Level 9; rating: Tricky + code:01aca1/a9+01aca2/26+01adb4/a5 + cheat + description:Start on Level 10; rating: Tricky + code:01aca1/a9+01aca2/27+01adb4/a5 + cheat + description:Start on Level 11; rating: Tricky + code:01aca1/a9+01aca2/28+01adb4/a5 + cheat + description:Start on Level 12; rating: Tricky + code:01aca1/a9+01aca2/29+01adb4/a5 + cheat + description:Start on Level 13; rating: Tricky + code:01aca1/a9+01aca2/2a+01adb4/a5 + cheat + description:Start on Level 14; rating: Tricky + code:01aca1/a9+01aca2/2b+01adb4/a5 + cheat + description:Start on Level 15; rating: Tricky + code:01aca1/a9+01aca2/2c+01adb4/a5 + cheat + description:Start on Level 16; rating: Tricky + code:01aca1/a9+01aca2/2d+01adb4/a5 + cheat + description:Start on Level 17; rating: Tricky + code:01aca1/a9+01aca2/2e+01adb4/a5 + cheat + description:Start on Level 18; rating: Tricky + code:01aca1/a9+01aca2/2f+01adb4/a5 + cheat + description:Start on Level 19; rating: Tricky + code:01aca1/a9+01aca2/30+01adb4/a5 + cheat + description:Start on Level 20; rating: Tricky + code:01aca1/a9+01aca2/31+01adb4/a5 + cheat + description:Start on Level 21; rating: Tricky + code:01aca1/a9+01aca2/32+01adb4/a5 + cheat + description:Start on Level 22; rating: Tricky + code:01aca1/a9+01aca2/33+01adb4/a5 + cheat + description:Start on Level 23; rating: Tricky + code:01aca1/a9+01aca2/34+01adb4/a5 + cheat + description:Start on Level 24; rating: Tricky + code:01aca1/a9+01aca2/35+01adb4/a5 + cheat + description:Start on Level 25; rating: Tricky + code:01aca1/a9+01aca2/36+01adb4/a5 + cheat + description:Start on Level 26; rating: Tricky + code:01aca1/a9+01aca2/37+01adb4/a5 + cheat + description:Start on Level 27; rating: Tricky + code:01aca1/a9+01aca2/38+01adb4/a5 + cheat + description:Start on Level 28; rating: Tricky + code:01aca1/a9+01aca2/39+01adb4/a5 + cheat + description:Start on Level 29; rating: Tricky + code:01aca1/a9+01aca2/3a+01adb4/a5 + cheat + description:Start on Level 30; rating: Tricky + code:01aca1/a9+01aca2/3b+01adb4/a5 + cheat + description:Start on Level 1; rating: Taxing + code:01aca1/a9+01aca2/3c+01adb4/a5 + cheat + description:Start on Level 2; rating: Taxing + code:01aca1/a9+01aca2/3d+01adb4/a5 + cheat + description:Start on Level 3; rating: Taxing + code:01aca1/a9+01aca2/3e+01adb4/a5 + cheat + description:Start on Level 4; rating: Taxing + code:01aca1/a9+01aca2/3f+01adb4/a5 + cheat + description:Start on Level 5; rating: Taxing + code:01aca1/a9+01aca2/40+01adb4/a5 + cheat + description:Start on Level 6; rating: Taxing + code:01aca1/a9+01aca2/41+01adb4/a5 + cheat + description:Start on Level 7; rating: Taxing + code:01aca1/a9+01aca2/42+01adb4/a5 + cheat + description:Start on Level 8; rating: Taxing + code:01aca1/a9+01aca2/43+01adb4/a5 + cheat + description:Start on Level 9; rating: Taxing + code:01aca1/a9+01aca2/44+01adb4/a5 + cheat + description:Start on Level 10; rating: Taxing + code:01aca1/a9+01aca2/45+01adb4/a5 + cheat + description:Start on Level 11; rating: Taxing + code:01aca1/a9+01aca2/46+01adb4/a5 + cheat + description:Start on Level 12; rating: Taxing + code:01aca1/a9+01aca2/47+01adb4/a5 + cheat + description:Start on Level 13; rating: Taxing + code:01aca1/a9+01aca2/48+01adb4/a5 + cheat + description:Start on Level 14; rating: Taxing + code:01aca1/a9+01aca2/49+01adb4/a5 + cheat + description:Start on Level 15; rating: Taxing + code:01aca1/a9+01aca2/4a+01adb4/a5 + cheat + description:Start on Level 16; rating: Taxing + code:01aca1/a9+01aca2/4b+01adb4/a5 + cheat + description:Start on Level 17; rating: Taxing + code:01aca1/a9+01aca2/4c+01adb4/a5 + cheat + description:Start on Level 18; rating: Taxing + code:01aca1/a9+01aca2/4d+01adb4/a5 + cheat + description:Start on Level 19; rating: Taxing + code:01aca1/a9+01aca2/4e+01adb4/a5 + cheat + description:Start on Level 20; rating: Taxing + code:01aca1/a9+01aca2/4f+01adb4/a5 + cheat + description:Start on Level 21; rating: Taxing + code:01aca1/a9+01aca2/50+01adb4/a5 + cheat + description:Start on Level 22; rating: Taxing + code:01aca1/a9+01aca2/51+01adb4/a5 + cheat + description:Start on Level 23; rating: Taxing + code:01aca1/a9+01aca2/52+01adb4/a5 + cheat + description:Start on Level 24; rating: Taxing + code:01aca1/a9+01aca2/53+01adb4/a5 + cheat + description:Start on Level 25; rating: Taxing + code:01aca1/a9+01aca2/54+01adb4/a5 + cheat + description:Start on Level 26; rating: Taxing + code:01aca1/a9+01aca2/55+01adb4/a5 + cheat + description:Start on Level 27; rating: Taxing + code:01aca1/a9+01aca2/56+01adb4/a5 + cheat + description:Start on Level 28; rating: Taxing + code:01aca1/a9+01aca2/57+01adb4/a5 + cheat + description:Start on Level 29; rating: Taxing + code:01aca1/a9+01aca2/58+01adb4/a5 + cheat + description:Start on Level 30; rating: Taxing + code:01aca1/a9+01aca2/59+01adb4/a5 + cheat + description:Start on Level 1; rating: Mayhem + code:01aca1/a9+01aca2/5a+01adb4/a5 + cheat + description:Start on Level 2; rating: Mayhem + code:01aca1/a9+01aca2/5b+01adb4/a5 + cheat + description:Start on Level 3; rating: Mayhem + code:01aca1/a9+01aca2/5c+01adb4/a5 + cheat + description:Start on Level 4; rating: Mayhem + code:01aca1/a9+01aca2/5d+01adb4/a5 + cheat + description:Start on Level 5; rating: Mayhem + code:01aca1/a9+01aca2/5e+01adb4/a5 + cheat + description:Start on Level 6; rating: Mayhem + code:01aca1/a9+01aca2/5f+01adb4/a5 + cheat + description:Start on Level 7; rating: Mayhem + code:01aca1/a9+01aca2/60+01adb4/a5 + cheat + description:Start on Level 8; rating: Mayhem + code:01aca1/a9+01aca2/61+01adb4/a5 + cheat + description:Start on Level 9; rating: Mayhem + code:01aca1/a9+01aca2/62+01adb4/a5 + cheat + description:Start on Level 10; rating: Mayhem + code:01aca1/a9+01aca2/63+01adb4/a5 + cheat + description:Start on Level 11; rating: Mayhem + code:01aca1/a9+01aca2/64+01adb4/a5 + cheat + description:Start on Level 12; rating: Mayhem + code:01aca1/a9+01aca2/65+01adb4/a5 + cheat + description:Start on Level 13; rating: Mayhem + code:01aca1/a9+01aca2/66+01adb4/a5 + cheat + description:Start on Level 14; rating: Mayhem + code:01aca1/a9+01aca2/67+01adb4/a5 + cheat + description:Start on Level 15; rating: Mayhem + code:01aca1/a9+01aca2/68+01adb4/a5 + cheat + description:Start on Level 16; rating: Mayhem + code:01aca1/a9+01aca2/69+01adb4/a5 + cheat + description:Start on Level 17; rating: Mayhem + code:01aca1/a9+01aca2/6a+01adb4/a5 + cheat + description:Start on Level 18; rating: Mayhem + code:01aca1/a9+01aca2/6b+01adb4/a5 + cheat + description:Start on Level 19; rating: Mayhem + code:01aca1/a9+01aca2/6c+01adb4/a5 + cheat + description:Start on Level 20; rating: Mayhem + code:01aca1/a9+01aca2/6d+01adb4/a5 + cheat + description:Start on Level 21; rating: Mayhem + code:01aca1/a9+01aca2/6e+01adb4/a5 + cheat + description:Start on Level 22; rating: Mayhem + code:01aca1/a9+01aca2/6f+01adb4/a5 + cheat + description:Start on Level 23; rating: Mayhem + code:01aca1/a9+01aca2/70+01adb4/a5 + cheat + description:Start on Level 24; rating: Mayhem + code:01aca1/a9+01aca2/71+01adb4/a5 + cheat + description:Start on Level 25; rating: Mayhem + code:01aca1/a9+01aca2/72+01adb4/a5 + cheat + description:Start on Level 26; rating: Mayhem + code:01aca1/a9+01aca2/73+01adb4/a5 + cheat + description:Start on Level 27; rating: Mayhem + code:01aca1/a9+01aca2/74+01adb4/a5 + cheat + description:Start on Level 28; rating: Mayhem + code:01aca1/a9+01aca2/75+01adb4/a5 + cheat + description:Start on Level 29; rating: Mayhem + code:01aca1/a9+01aca2/76+01adb4/a5 + cheat + description:Start on Level 30; rating: Mayhem + code:01aca1/a9+01aca2/77+01adb4/a5 + cheat + description:Start on Level 1; rating: Sunsoft + code:01aca1/a9+01aca2/78+01adb4/a5 + cheat + description:Start on Level 2; rating: Sunsoft + code:01aca1/a9+01aca2/79+01adb4/a5 + cheat + description:Start on Level 3; rating: Sunsoft + code:01aca1/a9+01aca2/7a+01adb4/a5 + cheat + description:Start on Level 4; rating: Sunsoft + code:01aca1/a9+01aca2/7b+01adb4/a5 + cheat + description:Start on Level 5; rating: Sunsoft + code:01aca1/a9+01aca2/7c+01adb4/a5 + 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 + name:Lester the Unlikely (USA) + cheat + description:Infinite health against most enemies + code:cea6d3/ad + cheat + description:Infinite lives + code:ceac85/ad + cheat + description:Flashing lasts a long time after getting hit + code:cea6da/04 + cheat + description:Flashing lasts a really long time after getting hit + code:cea6da/0c + cheat + description:Lighter gravity effect (disable right after pressing start, donメt enable until first game play screen) + code:cea5c1/40 + cheat + description:Even lighter gravity effect + code:cea5c1/25 + cheat + description:Amazingly lighter gravity effect + code:cea5c1/15 + cheat + description:Infinite health + code:7e859b/03 + +cartridge sha256:3bc5f296c3dbee012e93a5cf25568f9288ce87b34d74085401a560350eaca03f + name:Lethal Enforcers (USA) + cheat + description:Invincibility - both players + code:84aad7/80 + cheat + description:Infinite ammo + code:82a6fb/ea + cheat + description:Infinite health - both players + code:829979/ea + cheat + description:No health loss when you hit civilians + code:8298da/ea + cheat + description:Hit anywhere - both players + code:84d0ee/80+8298ca/80+84843f/80+84d174/35 + cheat + description:1/2 health lost when you hit civilians + code:8298da/ea + cheat + description:Play with more health + code:808a76/1e+808ad2/1e + cheat + description:Keep weapon until you die + code:829917/80 + cheat + description:Magnum - more shots per round + code:81c0e6/0c + cheat + description:Normal gun - more shots per round + code:81c0e2/0c + cheat + description:Shotgun - more shots per round + code:81c0ea/0c + 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 + cheat + description:Start a new game to enter the Konami Gun System Check Mode + code:8089d5/07 + cheat + description:Start a new game to enter the Sound Check Mode + code:8089d5/10 + cheat + description:Start a new game to enter the Object Test + code:8089d5/11 + +cartridge sha256:80c22cc92d51a54de9cd9fd00db5ff58a35fff35e822169c94e445d50834fba3 + name:Lethal Weapon (USA) + cheat + description:Infinite health + code:009ff4/2c + cheat + description:Infinite ammo + code:00b80f/00 + cheat + description:Infinite time + code:00b67d/ad + cheat + description:More bullets in magazine + code:00b816/09 + cheat + description:2 magazines on pick-up + code:00a7cf/02 + cheat + description:4 magazines on pick-up + code:00a7cf/04 + cheat + description:Slower timer + code:00b695/62 + cheat + description:Faster timer + code:00b695/1f + cheat + description:Super-jump (can get stuck) + code:009508/ea + cheat + description:Start with more badges + code:0087dc/06 + cheat + description:Start with fewer badges + code:0087dc/00 + cheat + description:Start with more magazine clips + code:0087c6/09 + cheat + description:Start with fewer magazine clips + code:0087c6/01 + 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 + name:Lion King, The (USA) + cheat + description:Almost infinite health + code:c35cb0/ad + cheat + description:Infinite lives + code:c08afa/af + cheat + description:Roaring doesn't decrease your roar meter + code:c3596e/ad + cheat + description:Roar meter doesn't fill up with time + code:c0b552/ad + cheat + description:Don't lose roar power when you get hit + code:c35bed/ad + cheat + description:higher-jump + code:c31152/a9+c31153/f6+c31154/ff + cheat + description:Mega-jump + code:c31152/a9+c31153/f4+c31154/ff + cheat + description:Walk through walls + code:c481a3/80+c48136/00+c0c7d3/00 + 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 + name:Little Magic (Japan) + cheat + description:Infinite Mays / Retries + code:7e0059/09 + +cartridge sha256:7e1d6242ae2ec2c23afb876becdcf778098edd4d853234222dc16471cb51df9e + name: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 + name:Lost Vikings, The (USA) + cheat + description:Start with infinite health - all Vikings + code:7e0fe9/08 + +cartridge sha256:ab3d97c1a3a979e1680a428ec65df54cfb72997bbfe2173292248a4fa8c51ba1 + name: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 + name: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 + name:Lufia & the Fortress of Doom (USA) + cheat + description:Move around caves and world map quicker (except when leaving a vehicle) + code:019829/20 + cheat + description:Infinite HP (hit points) + code:08e987/bd + cheat + description:Infinite magic points in battle mode + code:08e9c6/bd + cheat + description:No HP lost when walking over swamp ground + code:0196b4/00 + cheat + description:More HP lost when walking over swamp ground + code:0196b4/04 + cheat + description:Cheap bombs - 1 gold each + code:0aef4d/01 + cheat + description:Cheap smokeballs - 1 gold each + code:0aeda1/01 + cheat + description:Immune to all petrifying effects (stone, poison, confused, etc.) + code:08b912/80 + cheat + description:Shopkeepers don't charge for purchases - some shops only + code:00cabf/57 + cheat + description:More agility points from speed potion + code:0aed28/10 + cheat + description:More intelligence points from mind potion + code:0aed4b/10 + cheat + description:More strength points from great potion + code:0aed6e/10 + cheat + description:Higher max level of magic points from spell potion + code:0aed05/10 + cheat + description:Higher max level of hit points from power potion + code:0aece2/10 + 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 + name:Lufia II - Rise of the Sinistrals (USA) + cheat + description:Infinite 999 MP in and out of battle + code:81f4f8/ff + cheat + description:Level 99 after one battle + code:81f99f/8f + cheat + description:Level 83 after one battle + code:81f99f/ff + cheat + description:Gain 35,000 gold after a battle + code:81fc05/ff + cheat + description:Enemies always miss + code:81fc74/ff + cheat + description:One hit kills + code:81fc38/ff + 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:7e0986/ff+7e0988/ff+7e0989/ff+7e0991/ff+7e098a/ff+7e0992/ff+7e098b/ff+7e0996/ff+7e098c/ff+7e098d/ff+7e098e/ff+7e098f/ff+7e0990/ff+7e097b/ff+7e097c/ff+7e097d/ff+7e097e/ff+7e097f/ff+7e0980/ff+7e0981/ff+7e0982/ff+7e0983/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 + name:Madden NFL '94 (USA) + cheat + description:Always 1st down + code:c0c1a0/ea + cheat + description:1 play to get a 1st down + code:c0c1bb/02 + cheat + description:2 plays to get a 1st down + code:c0c1bb/03 + cheat + description:3 plays to get a 1st down + code:c0c1bb/04 + cheat + description:5 plays to get a 1st down + code:c0c1bb/06 + cheat + description:7 plays to get a 1st down + code:c0c1bb/08 + cheat + description:Extra points worth 0 points + code:c0c7f1/00 + cheat + description:Extra points worth 3 points + code:c0c7f1/03 + cheat + description:Extra points worth 5 points + code:c0c7f1/05 + cheat + description:Extra points worth 7 points + code:c0c7f1/07 + cheat + description:Field goals worth 0 points + code:c0c7fe/00 + cheat + description:Field goals worth 2 points + code:c0c7fe/02 + cheat + description:Field goals worth 5 points + code:c0c7fe/05 + cheat + description:Field goals worth 7 points + code:c0c7fe/07 + cheat + description:Field goals worth 9 points + code:c0c7fe/09 + cheat + description:Safeties worth 0 points + code:c0c293/00 + cheat + description:Safeties worth 3 points + code:c0c293/03 + cheat + description:Safeties worth 5 points + code:c0c293/05 + cheat + description:Safeties worth 7 points + code:c0c293/07 + cheat + description:Touchdowns worth 0 points + code:c0c5c1/00 + cheat + description:Touchdowns worth 3 points + code:c0c5c1/03 + cheat + description:Touchdowns worth 5 points + code:c0c5c1/05 + cheat + description:Touchdowns worth 9 points + code:c0c5c1/09 + cheat + description:TD, FG, PAT, S worth 1 point - home team + code:c0c2d6/a9+c0c2d7/01 + cheat + description:TD, FG, PAT, S worth 3 points - home team + code:c0c2d6/a9+c0c2d7/03 + cheat + description:TD, FG, PAT, S worth 5 points - home team + code:c0c2d6/a9+c0c2d7/05 + cheat + description:TD, FG, PAT, S worth 7 points - home team + code:c0c2d6/a9+c0c2d7/07 + cheat + description:TD, FG, PAT, S worth 14 points - home team + code:c0c2d6/a9+c0c2d7/0e + cheat + description:TD, FG, PAT, S worth 21 points - home team + code:c0c2d6/a9+c0c2d7/15 + cheat + description:TD, FG, PAT, S worth 35 points - home team + code:c0c2d6/a9+c0c2d7/23 + cheat + description:TD, FG, PAT, S worth 3 points - visitor + code:c0c301/a9+c0c302/01 + cheat + description:TD, FG, PAT, S worth 5 points - visitor + code:c0c301/a9+c0c302/05 + cheat + description:TD, FG, PAT, S worth 7 points - visitor + code:c0c301/a9+c0c302/07 + cheat + description:TD, FG, PAT, S worth 14 points - visitor + code:c0c301/a9+c0c302/0e + cheat + description:TD, FG, PAT, S worth 21 points - visitor + code:c0c301/a9+c0c302/15 + cheat + description:TD, FG, PAT, S worth 35 points - visitor + code:c0c301/a9+c0c302/23 + cheat + description:Home team starts with a 3-point lead + code:c0e411/03+c0e416/0f + cheat + description:Home team starts with a 7-point lead + code:c0e411/07+c0e416/0f + cheat + description:Home team starts with a 10-point lead + code:c0e411/0a+c0e416/0f + cheat + description:Home team starts with a 14-point lead + code:c0e411/0e+c0e416/0f + cheat + description:Home team starts with a 35-point lead + code:c0e411/23+c0e416/0f + cheat + description:Visitors start with a 5-point lead + code:c0e411/05+c0e412/0f + cheat + description:Visitors start with a 7-point lead + code:c0e411/07+c0e412/0f + cheat + description:Visitors start with a 10-point lead + code:c0e411/0a+c0e412/0f + cheat + description:Visitors start with a 14-point lead + code:c0e411/0e+c0e412/0f + cheat + description:Visitors start with a 35-point lead + code:c0e411/23+c0e412/0f + +cartridge sha256:0ad77ae7af231313e1369a52d1622b88e3751aa5ec774628df7071f9e4244abc + name:Madden NFL 95 (USA) + cheat + description:Always 1st down + code:c0833a/ad + cheat + description:Infinite timeouts - both players (slightly glitchy) + code:c1714d/bd + cheat + description:Cannot be tackled (hold X) + code:c07c54/80+c07c56/30+c07c53/a5+c07c55/0a+c07c57/f5 + cheat + description:Field goals worth 0 points + code:c08a19/00 + cheat + description:Field goals worth 1 points + code:c08a19/01 + cheat + description:Field goals worth 5 points + code:c08a19/04 + cheat + description:Field goals worth 9 points + code:c08a19/09 + cheat + description:Safetys worth 0 points + code:c0841f/00 + cheat + description:Safetys worth 1 points + code:c0841f/01 + cheat + description:Safetys worth 5 points + code:c0841f/04 + cheat + description:Safetys worth 7 points + code:c0841f/07 + cheat + description:Touchdowns worth 0 points + code:c087d8/00 + cheat + description:Touchdowns worth 1 points + code:c087d8/01 + cheat + description:Touchdowns worth 5 points + code:c087d8/04 + cheat + description:Touchdowns worth 9 points + code:c087d8/09 + cheat + description:Start with 15 seconds on the play clock + code:c07678/0f + cheat + description:Start with 1 timeout - P1 + code:c00043/01 + cheat + description:Start with 1 timeout - P2 + code:c00044/01 + +cartridge sha256:3059d86cdc383985c564a7a891fe18e08f5222ead7ede9fa309159d60cde13a1 + name:Madden NFL 96 (USA) + cheat + description:Infinite time (2P mode only) + code:c002d5/ad + cheat + description:Infinite downs + code:c08ece/ad + cheat + description:Infinite timeouts + code:c15435/bd + cheat + description:Cannot be tackled (hold X) + code:c087a4/80+c087a6/30+c087a3/a5+c087a5/0a+c087a7/f5 + cheat + description:Safeties are worth 0 points + code:c08fd7/00 + cheat + description:Safeties are worth 1 point + code:c08fd7/01 + cheat + description:Safeties are worth 3 points + code:c08fd7/02 + cheat + description:Safeties are worth 5 points + code:c08fd7/05 + cheat + description:Safeties are worth 7 points + code:c08fd7/07 + cheat + description:Safeties are worth 9 points + code:c08fd7/09 + cheat + description:Field Goals are worth 0 points + code:c09693/00 + cheat + description:Field Goals are worth 1 point + code:c09693/01 + cheat + description:Field Goals are worth 2 points + code:c09693/02 + cheat + description:Field Goals are worth 5 points + code:c09693/05 + cheat + description:Field Goals are worth 7 points + code:c09693/07 + cheat + description:Field Goals are worth 9 points + code:c09693/09 + cheat + description:Start with 5 downs each possession + code:c08f7f/00 + cheat + description:Start with 3 downs each possession + code:c08f7f/03 + cheat + description:Start with 2 downs each possession + code:c08f7f/02 + cheat + description:Start with 1 down each possession + code:c08f7f/01 + +cartridge sha256:6874568d985f65dd817d4b03998e71c8cbacc8d8707411fde7bffee350605a88 + name:Madden NFL 97 (USA) + cheat + description:Cannot be tackled (hold X) + code:c08c8e/80+c08c90/30+c08c8d/a5+c08c8f/0a+c08c91/f5 + +cartridge sha256:e3c62c9fe55d2311aa6a264f41b45d6cbc7b1b069ed3aa82ee57d381c062547d + name:Madden NFL 98 (USA) + cheat + description:Cannot be tackled (hold X) + code:c08d19/80+c08d1b/30+c08d18/a5+c08d1a/0a+c08d1c/f5 + +cartridge sha256:c01fb8989d391d3e343003934937f02bd8ef9aacdad68c32c3d3f56feb72f5b0 + name:Magic Boy (USA) + cheat + description:Invincibility + code:809483/80 + cheat + description:Infinite lives + code:7e9bb6/03 + +cartridge sha256:9b6b0099f2b97ec3a18fef7a4935bfad235fdb83669dd99c3731a69506322cbe + name:Magic Knight Rayearth (Japan) + cheat + description:Infinite Gold + code:7E0D8A3F+7E0D8B42+7E0D8C0F + cheat + description:No random battles + code:c02a90/80 + cheat + description:Walk through walls + code:c02943/ad + cheat + description:Infinite items - slot 01 + code:7e0d8f/63 + cheat + description:Infinite items - slot 02 + code:7e0d91/63 + cheat + description:Infinite items - slot 03 + code:7e0d93/63 + cheat + description:Infinite items - slot 04 + code:7e0d95/63 + cheat + description:Infinite items - slot 05 + code:7e0d97/63 + cheat + description:Infinite items - slot 06 + code:7e0d99/63 + cheat + description:Infinite items - slot 07 + code:7e0d9b/63 + cheat + description:Infinite items - slot 08 + code:7e0d9d/63 + cheat + description:Infinite items - slot 09 + code:7e0d9f/63 + cheat + description:Infinite items - slot 10 + code:7e0da1/63 + cheat + description:Infinite items - slot 11 + code:7e0da3/63 + cheat + description:Infinite items - slot 12 + code:7e0da5/63 + cheat + description:Infinite items - slot 13 + code:7e0da7/63 + cheat + description:Infinite items - slot 14 + code:7e0da9/63 + cheat + description:Infinite items - slot 15 + code:7e0dab/63 + cheat + description:Infinite items - slot 16 + code:7e0dad/63 + cheat + description:Infinite items - slot 17 + code:7e0daf/63 + cheat + description:Infinite items - slot 18 + code:7e0db1/63 + cheat + description:Infinite items - slot 19 + code:7e0db3/63 + cheat + description:Infinite items - slot 20 + code:7e0db5/63 + +cartridge sha256:1d3cceaa05e054b002caeb09fd5fb9e718ec446764f4169d97bc185da76fdf4d + name:Magic Sword (USA) + cheat + description:No health loss on collision with enemies + code:019caf/ad+00b04c/ad + cheat + description:No health loss when magic is used + code:019624/ad + cheat + description:No magic counter countdown + code:00ada6/ad + cheat + description:Hit anywhere + code:03813a/ea+038137/ad+038138/08+03813b/f0+038139/16 + cheat + description:One hit kills + code:0380e9/80 + cheat + description:Slower magic counter countdown + code:00ada2/7f + cheat + description:Faster magic counter countdown + code:00ada2/ff + 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 + name: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 + name:Magical Quest Starring Mickey Mouse, The (USA) + cheat + description:Protection from most hits (lose no hearts) (disable if you get stuck) + code:03f43a/ad + cheat + description:Infinite magic - wizard's costume only + code:01eef9/ad + cheat + description:Infinite lives + code:01df93/ad + cheat + description:Small heart fill health completely + code:02d010/8d+02d015/ad + cheat + description:Each gold coin worth 10 (if too many are collected you may go back to 0) + code:02fd3d/01 + cheat + description:Longer invincibility after getting hit + code:01e207/ad + cheat + description:No invincibility after getting hit + code:01e202/a9 + cheat + description:Super-jump + code:01de0e/69+01de0f/2c + cheat + description:Mega-jump + code:01de0e/69+01de0f/20 + cheat + description:Ultra-jump + code:01de0e/69+01de0f/14 + cheat + description:Items in general store are free if you can afford them + code:02fd8b/80+02fd8c/2b + cheat + description:Start with 1 heart instead of 3 + code:00ccf8/01 + cheat + description:Start with 5 hearts + code:00ccf8/05 + cheat + description:Start with 7 hearts + code:00ccf8/07 + cheat + description:Start with 10 hearts + code:00ccf8/0a + cheat + description:Start with 1 life instead of 3 + code:01815f/00 + cheat + description:Start with 7 lives + code:01815f/06 + cheat + description:Start with 10 lives + code:01815f/09 + 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 + name:Majuu Ou (Japan) + cheat + description:Infinite health + code:7e009f/50 + cheat + description:Infinite lives + code:7e00a3/01 + +cartridge sha256:8267e2f092c86d5a29c9a826db82c7473638e28e2507cdaf5c86981f07cd0bef + name: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:80b50c/a9+80b50d/ff+80b50e/ea + cheat + description:Use computer to access any facts except pamphlets (no checks appear on computer) + code:80b60b/80+80b64d/00+80b678/00 + cheat + description:Use computer to view pamphlets on any artifact (no checks appear on computer) + code:80b5df/80 + cheat + description:Always get Yoshi after using Globulator + code:80f801/01 + cheat + description:Pick up one artifact and get all three + code:80b4ff/a9+80b500/ff+80b501/ea + 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 + name:Mario Paint (Japan, USA) + cheat + description:Invincibility in bug swatting game + code:01a51e/a9+01a523/8d+01a51f/ff + cheat + description:Infinite lives in bug swatting game + code:01a6e9/cd + cheat + description:Have all icons in bug swatting game + code:01a329/a9 + cheat + description:Star easier to get under "P" on title screen + code:8f8555/00+8f8559/00+8f855a/01 + 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 + name:Mario's Time Machine (USA) + cheat + description:Bonus timer doesn't count down in the whole game + code:818dc9/00 + cheat + description:Don't lose mushrooms in collisions + code:818727/a9+808f28/00+818729/00 + cheat + description:1 wrong answer to questions allowed + code:80d92d/01 + cheat + description:255 wrong answers allowed (ignore sad face icon) + code:80d92d/ff + +cartridge sha256:49dd77b310b476c875633335243553be59ecfb0bffae62e46f2e53ff05c20fcd + name:Marvel Super Heroes in War of the Gems (USA) + cheat + description:Infinite health + code:c00858/95 + cheat + description:Infinite Air + code:c00858/95 + cheat + description:Infinite Air (alt) + code:c271c6/f6 + cheat + description:Infinite equipment, all Gems selectable on pick-up + code:c0b87a/1c+c0b87d/80+c0b87e/1f + cheat + description:One hit kills + code:c06315/a9 + cheat + description:Always have a Gem + code:c27f28/9e + cheat + description:Always have 9 Gem power items + code:c06089/f5 + cheat + description:Always have 9 Revive items + code:c271c6/f6 + 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 + name:Mary Shelley's Frankenstein (USA) + cheat + description:Infinite health + code:809953/ad+80e3e5/b7 + cheat + description:Energy balls don't deplete health + code:85f376/00+85f377/00 + cheat + description:Cool effects + code:7e0000/00 + cheat + description:Invincibility (blinking) + code:7e200d/09 + cheat + description:Infinite health (alt) + code:7e2043/1d + +cartridge sha256:44cc113ce1e7616cc737adea9e8f140436c9f1c3fba57e8e9db48025d4ace632 + name:Mask, The (USA) + cheat + description:Invincibility + code:80a44c/24+80a456/24 + cheat + description:Invincibility after one hit + code:80a44e/bd + cheat + description:Infinite mask power + code:80b1d5/ad + cheat + description:Infinite lives + code:80856a/a5 + cheat + description:Hit anywhere + collect items from anywhere) + code:80ad7b/24+80ad8b/24+80ad8f/24+80ad5a/24+80ad5e/24 + cheat + description:Mallet doesn't use any power + code:809b10/bf + cheat + description:Walk through walls + code:80b433/ad + cheat + description:Green hearts worth 10 + code:80af8d/10 + cheat + description:Green hearts worth 30 + code:80af8d/30 + cheat + description:Green hearts worth 100 + code:80af8d/a0 + cheat + description:Green hearts worth 0 + code:80afa5/ad + cheat + description:Flash longer + code:80b1b9/ff + cheat + description:Don't flash at all + code:80b1b9/00 + cheat + description:M's worth 0 + code:80af2a/a5 + cheat + description:M's worth 10 + code:80af1f/10 + cheat + description:M's worth 30 + code:80af1f/30 + cheat + description:M's worth 100 + code:80af1f/a0 + cheat + description:Start with 100 mask energy + code:8080fb/01 + cheat + description:Start with 300 mask energy + code:8080fb/03 + cheat + description:Start with 900 mask energy + code:8080fb/09 + cheat + description:Start with 1 life + code:8080ea/a9+8080eb/00+8080ec/00 + cheat + description:Start with 5 lives + code:8080ea/a9+8080eb/05+8080ec/00 + cheat + description:Start with 9 lives + code:8080ea/a9+8080eb/09+8080ec/00 + cheat + description:Infinite life + code:7e18af/20+7e18b0/03 + cheat + description:Infinite mask power (alt) + code:7e008f/84+7e0090/03 + cheat + description:Cheat menu enabled (in options menu) + code:7e0104/01 + +cartridge sha256:a203a13870eaec92095daef1196a0c9fe8416e600504d55dd0dc724d4f5f5cb0 + name:Maui Mallard in Cold Shadow (USA) + cheat + description:Enable level skip cheat (press Select + Y + A during the game) + code:7e1f55/02 + cheat + description:Enable infinite lives cheat + code:7e1f55/04 + cheat + description:Enable water is harmless cheat + code:7e1f55/40 + cheat + description:Enable infinite health cheat (health reaches 0, but you won't die) + code:7e1f55/80 + cheat + description:Disable all cheats + code:7e1f55/00 + +cartridge sha256:2a08704748f5ef6488348c4099729feca600412d331bda3756e51efd8b94e113 + name:MechWarrior (USA) + cheat + description:Protection from most hazards + code:85b0a7/8d + cheat + description:Infinite short-range missiles + code:80da1f/ff + cheat + description:Infinite short-range homing missiles + code:80da21/ff + cheat + description:Infinite medium-range missiles + code:80da23/ff + cheat + description:Infinite medium-range homing missiles + code:80da25/ff + cheat + description:Infinite long-range missiles + code:80da27/ff + cheat + description:Infinite long-range homing missiles + code:80da29/ff + cheat + description:Infinite machine gun ammo + code:80da2b/ff + cheat + description:Never run out of any ammo + code:80a809/ea + cheat + description:Getting any money sets money to 32 million C-bills + code:80e1ba/00 + cheat + description:100 ammo for short-range missiles + code:80da1f/64 + cheat + description:100 ammo for short-range homing missiles + code:80da21/64 + cheat + description:80 ammo for medium-range missiles + code:80da23/50 + cheat + description:80 ammo for medium-range homing missiles + code:80da25/50 + cheat + description:40 ammo for long-range missiles + code:80da27/28 + cheat + description:40 ammo for long-range homing missiles + code:80da29/28 + cheat + description:200 short-range missiles + code:80da1f/c8 + cheat + description:200 short-range homing missiles + code:80da21/c8 + cheat + description:100 medium-range missiles + code:80da23/64 + cheat + description:100 medium-range homing missiles + code:80da25/64 + cheat + description:100 long-range missiles + code:80da27/64 + cheat + description:100 long-range homing missiles + code:80da29/64 + cheat + description:Mech isn't slowed down as much by most obstacles + code:84ff08/a9+84ff0a/ea + cheat + description:Start with 100,000 C-bills + code:80e2fb/64 + cheat + description:Start with 250,000 C-bills + code:80e2fb/fa + cheat + description:Start with 562,000 C-bills + code:80e2fc/02 + cheat + description:Start with 1,074,000 C-bills + code:80e2fc/04 + cheat + description:Start with 5,170,000 C-bills + code:80e2fc/14 + cheat + description:Start with 10,290,000 C-bills + code:80e2fc/28 + +cartridge sha256:7bffa1dc31604fa3d61e06ce2c59168098cc8dd7e59998e1d5f30c49bdf8d617 + name:MechWarrior 3050 (USA) + cheat + description:Almost infinite ammo + code:c05177/ad + cheat + description:Almost invincible (disable to kill some enemies) + code:c053f2/60 + cheat + description:Coolant does nothing + code:c0899a/a9+c0899d/a9 + cheat + description:Guass Rifle starts at 10 + code:d64c55/0a + cheat + description:Guass Rifle starts at 50 + code:d64c55/32 + cheat + description:Guass Rifle starts at 100 + code:d64c55/64 + cheat + description:Arrow VI Missiles start at 20 + code:d64c53/14 + cheat + description:Arrow VI Missiles start at 50 + code:d64c53/32 + cheat + description:Arrow VI Missiles start at 100 + code:d64c53/64 + cheat + description:Particle Projection Cannon start at 10 + code:d64c4f/0a + cheat + description:Particle Projection Cannon start at 50 + code:d64c4f/32 + cheat + description:Particle Projection Cannon start at 100 + code:d64c4f/64 + cheat + description:Machine Gun starts at 100 + code:d64c46/00+d64c45/64 + cheat + description:Machine Gun starts at 1,000 + code:d64c46/03+d64c45/e8 + cheat + description:Machine Gun starts at 10,000 + code:d64c46/26+d64c45/10 + cheat + description:Auto Cannon starts at 50 + code:d64c47/32 + cheat + description:Auto Cannon starts at 100 + code:d64c47/64 + cheat + description:Auto Cannon starts at 250 + code:d64c47/fa + cheat + description:Large Laser starts at 50 + code:d64c4b/32+d64c4c/00 + cheat + description:Large Laser starts at 1,000 + code:d64c4b/e8+d64c4c/03 + cheat + description:Large Laser starts at 10,000 + code:d64c4b/10+d64c4c/26 + cheat + description:"Inferno" Short-Range Missiles start at 10 + code:d64c49/0a + cheat + description:"Inferno" Short-Range Missiles start at 50 + code:d64c49/32 + cheat + description:"Inferno" Short-Range Missiles start at 250 + code:d64c49/fa + cheat + description:"Maelstrom" Long-Range Missiles start at 20 + code:d64c51/14 + cheat + description:"Maelstrom" Long-Range Missiles start at 100 + code:d64c51/64 + cheat + description:"Maelstrom" Long-Range Missiles start at 250 + code:d64c51/fa + cheat + description:"Thunder" Time-Delay Mines start at 10 + code:d64c4d/0a + cheat + description:"Thunder" Time-Delay Mines start at 100 + code:d64c4d/64 + cheat + description:"Thunder" Time-Delay Mines start at 250 + code:d64c4d/fa + +cartridge sha256:ee1a030f30f3ab06361921447b3fcf84c987dd13d76e62964e44720e0ec82c56 + name:Mega lo Mania (Europe) (En,Fr,De) + cheat + description:Infinite number of people to use + code:7ee8d9/64 + +cartridge sha256:a255fec32453739903a1954149f19bc9658f4a415600b44badf1d4e5e13a16f9 + name:Mega Man 7 (USA) + cheat + description:Invincibility after first hit (blinking) + code:c1325b/80 + cheat + description:Infinite health + code:c30596/ad + cheat + description:Infinite health (alt) + code:c30593/05 + cheat + description:Infinite E-Tanks + code:c04853/ad + cheat + description:Infinite W-Tanks + code:c04890/ad + cheat + description:Infinite S-Tanks + code:c048f1/ad + cheat + description:Infinite Beat Whistles + code:c13235/ad + cheat + description:Infinite weapon energy + code:c12fd9/1f + cheat + description:One hit kills + code:c304f4/24 + cheat + description:Hit anywhere + code:c304b0/80 + cheat + description:Multi-jump + code:c17f67/32+c17f68/20+c17f69/9a+c17f6a/11+c17f6b/60+c113a9/60+c113aa/7f+c17f60/a5+c17f61/45+c17f62/0a+c17f63/90+c17f64/03+c17f65/20+c17f66/b7 + cheat + description:Always Shoot Shots + code:c12f49/11 + cheat + description:Always shoot Freeze Cracker + code:c12f49/24 + cheat + description:Always shoot Scorch Wheel + code:c12f49/26 + cheat + description:Always shoot Danger Wrap Bombs + code:c12f49/2e + cheat + description:Always shoot Noise Crush + code:c12f49/66 + cheat + description:Always shoot Fully Charged Mega Buster Blasts + code:c12f49/7d + cheat + description:Always shoot Slash Claw + code:c12f49/9c + cheat + description:Always shoot Thunder Bolt + code:c12f49/b5 + cheat + description:Always shoot Wild Coil + code:c12f49/f3 + cheat + description:Always shoot Charged Wild Coils + code:c12f49/ff + cheat + description:White Shots/Special Weapons + code:c14fda/ff + 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 + name:Mega Man X (USA) (Rev 1) + cheat + description:Infinite weapons once obtained + code:8194e7/00 + cheat + description:Immune to drain attack + code:81c809/ad + cheat + description:One hit kills (most enemies) + code:849e71/80 + cheat + description:Hit anywhere + code:849b68/24 + cheat + description:Multi-jump + code:81857f/24+818589/fc+81858a/95 + cheat + description:Enemies always drop large energy + code:84a392/a2+84a393/02 + cheat + description:Enemies always drop large weapon energy + code:84a392/a2+84a393/04 + cheat + description:Bogus jump (may go back to normal jumps) + code:86b9c6/04 + cheat + description:Super-jump (may go back to normal jumps) + code:86b9c6/07 + cheat + description:Mega-jump (may go back to normal jumps) + code:86b9c6/09 + cheat + description:Start with less health + code:8094ff/08 + cheat + description:Start with more health + code:8094ff/20 + cheat + description:Start with 10 lives + code:8094fa/09 + cheat + description:Start with 7 lives + code:8094fa/06 + cheat + description:Start with 5 lives + code:8094fa/04 + cheat + description:Start with 1 life + code:8094fa/00 + 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 + name:Mega Man X (USA) + cheat + description:Infinite health + code:849d54/ad + cheat + description:Infinite lives + code:809b59/ad + cheat + description:Infinite weapons once obtained + code:8194ee/a5 + cheat + description:One hit kills (most enemies) + code:849e71/80 + cheat + description:Hit anywhere + code:849b68/24 + cheat + description:Weapon charges to 1st power level faster + code:819866/00 + cheat + description:Disable weapon charging + code:819847/00 + cheat + description:Multi-jump + code:818575/24+81857f/f2+818580/95 + cheat + description:Enemies always drop large energy + code:84a38d/a2+84a38e/02 + cheat + description:Enemies always drop large weapon energy + code:84a38d/a2+84a38e/04 + cheat + description:Bogus jump (may go back to normal jumps) + code:86b9c6/04 + cheat + description:Super-jump (may go back to normal jumps) + code:86b9c6/07 + cheat + description:Mega-jump (may go back to normal jumps) + code:86b9c6/09 + cheat + description:Start with all weapons and all enemies defeated (except Sigma) + code:809f05/de + cheat + description:Start with less health + code:8094ff/08 + cheat + description:Start with more health + code:8094ff/20 + cheat + description:Start with 10 lives + code:8094fa/09 + cheat + description:Start with 7 lives + code:8094fa/06 + cheat + description:Start with 5 lives + code:8094fa/04 + cheat + description:Start with 1 life + code:8094fa/00 + 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 + name:Mega Man X2 (USA) + cheat + description:Invincibility + code:089440/08 + cheat + description:Infinite health + code:08d9e9/ad + cheat + description:Infinite health (alt) + code:08d9e6/9c + cheat + description:One hit kills + code:08db05/80 + cheat + description:Hit anywhere + code:08d7bf/24+08dadf/ad+06f430/02 + cheat + description:Multi-jump + code:0898f0/24+0898fa/d8+0898fb/b9 + 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 + name:Mega Man X3 (USA) + cheat + description:Infinite health + code:04ce04/ad + cheat + description:Infinite special weapons on pick-up + code:04a593/bd+04a5c7/bd + cheat + description:Hit anywhere + code:04cbae/24+04cf40/80+04cf11/80 + cheat + description:Multi-jump + code:04852b/24+048535/0e+048536/a7 + cheat + description:Enemies always drop large energy + code:04d5f3/a2+04d5f4/02 + cheat + description:Enemies always drop large weapon energy + code:04d5f3/a2+04d5f4/04 + cheat + description:Super-jump + code:06b287/07 + cheat + description:Mega-jump + code:06b287/09 + cheat + description:Ultra mega-jump + code:06b287/0b + cheat + description:Normal weapon is much more powerful + code:04cf40/80 + cheat + description:Skip bosses at start of game and proceed to stage select + code:02e8e6/95 + cheat + description:Start with max health bar + code:04dbc0/14 + 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 + name:Mega Man Soccer (USA) + cheat + description:Choose any character to play as Dr. Willy + code:81a3c6/a9+81a3c7/14+81a3c8/00 + cheat + description:View ending (select Capcom Championship) + code:81829b/ee+81829c/e0 + cheat + description:Unlock Capcom Championship mode ending + code:82d1f0/ea+82d1f1/ea+82d1f2/ea+82d1f3/ea + cheat + description:Unlock Tournament mode ending + code:82d29c/ea+82d29d/ea+82d29e/ea+82d29f/ea + +cartridge sha256:8815a2e8b26450053d43f2450936eced005d81ee9e33faa5aea2dd8d1e3e7d65 + name:Melfand Stories (Japan) + cheat + description:Hit anywhere + code:81ac80/80+81ac81/18 + cheat + description:One hit kills + code:81b066/80 + +cartridge sha256:d4f2cb6b209db29f7aec62e5a23846681c14665fb007e94d7bcfc7b5611e938b + name: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 + name:Metal Marines (USA) + cheat + description:Building an ICBM only takes up one space + code:00c26f/80 + cheat + description:Can view entire enemy map + code:03a8f1/80 + cheat + description:Enemy has no attack phase + code:02de7b/60 + cheat + description:Instant maximum energy + code:00d17b/00 + cheat + description:Instant maximum war funds + code:00d1b1/00 + cheat + description:Enemy always has 0 energy + code:00d16f/9c + cheat + description:Enemy always has 0 war funds + code:00d1a5/9c + +cartridge sha256:057484558ebd18165f98e556b994080535e31cefdd98b5edb190516f7040fc9d + name:Metal Morph (USA) + cheat + description:Infinite ammo for all weapons (disable to change weapons) + code:81da8f/a5 + cheat + description:Infinite continues + code:81cc56/a5 + cheat + description:Infinite time on continue screen + code:81cc02/ad + cheat + description:Hit anywhere (side-scrolling mode) + code:81f946/24+81f938/24 + cheat + description:Hit anywhere (flying mode) + code:81b327/24+81b2f1/24 + cheat + description:Start with 255 continues + code:8081a4/ff + cheat + description:Invincibility + code:7e0387/03 + +cartridge sha256:0d7f875877fe856066cfb39b4ecdbbe7d48393a75770720876c94419f809bb1c + name:Metal Warriors (USA) + cheat + description:Infinite health (Mech) + code:81b010/ae + cheat + description:Infinite health (Human) + code:81c352/a5 + cheat + description:Infinite Gun ammo on pick-up + code:818da2/e4 + cheat + description:Press L to go Hyper (Mech) + code:818db5/a6 + +cartridge sha256:1b425ea5a883b7464637b74c2937fde699ffff52b53ad6940a66285e0663194a + name: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 + cheat + description:Invincibility and hit anywhere + code:c041bf/24+c041b7/24+c041c7/24+c0114f/80 + +cartridge sha256:0773eb741ce28f963f767fc7dd44678eb3d37ed4dc7fc82bb9cce7d55f1cfc64 + name:Mickey Mania - The Timeless Adventures of Mickey Mouse (USA) + cheat + description:Infinite health + code:bb9ab2/ad + cheat + description:Infinite lives + code:bb9ae9/ad + cheat + description:Infinite Marbles + code:bbc6b3/ad + cheat + description:Hit anywhere + code:bc9c93/da+bc9c95/d0+bc9c92/ad+bc9c94/06+bc9c96/16 + cheat + description:Each Marble worth 99 + code:bfb2a4/a9 + cheat + description:One hit and you're dead + code:a1c7ce/00 + cheat + description:Start with less health + code:a1c7ce/02 + cheat + description:Start with more health + code:a1c7ce/09 + cheat + description:Start with 1 life + code:a1c7e0/00 + cheat + description:Start with 7 lives + code:a1c7e3/06 + cheat + description:Start with 10 lives + code:a1c7e3/09 + cheat + description:Start on stage - the Wharf + code:a1c792/01 + cheat + description:Start on stage - Mad Doc 1 + code:a1c792/02 + cheat + description:Start on stage - Mad Doc 2 + code:a1c792/03 + cheat + description:Start on stage - Ride The Gurney + code:a1c792/04 + cheat + description:Start on stage - Mad Doc 4 + code:a1c792/05 + cheat + description:Start on stage - Elevator + code:a1c792/06 + cheat + description:Start on stage - Mad Doc Eol + code:a1c792/07 + cheat + description:Start on stage - Moose Hunt + code:a1c792/08 + cheat + description:Start on stage - Moose Chase + code:a1c792/09 + cheat + description:Start on stage - Haunted House + code:a1c792/0a + cheat + description:Start on stage - Haunted Basement + code:a1c792/0b + cheat + description:Start on stage - Haunted Halls + code:a1c792/0c + cheat + description:Start on stage - Garden + code:a1c792/0d + cheat + description:Start on stage - Tunnel + code:a1c792/0e + cheat + description:Start on stage - Steps + code:a1c792/0f + cheat + description:Start on stage - Table + code:a1c792/10 + cheat + description:Start on stage - Library + code:a1c792/11 + cheat + description:Start on stage - Kitchen + code:a1c792/12 + cheat + description:Start on stage - Dungeon + code:a1c792/13 + cheat + description:Start on stage - Tower Escape + code:a1c792/14 + cheat + description:Start on stage - Dungeon 2 + code:a1c792/15 + +cartridge sha256:453359b20f78787fcfea0dafe715238f0ff3f1d6f4d729285dc72a8004131a3b + name: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 + name:Micro Machines (USA) + cheat + description:Infinite lives + code:7e0323/09 + +cartridge sha256:889beb58d2a48a05a6230cabda14555cb030e2e986c0293bdf396e85af5c6798 + name: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 + name:Mighty Morphin Power Rangers (USA) + cheat + description:Invincibility + code:04b743/ad + cheat + description:Infinite health + code:04ba80/ad + cheat + description:Infinite lives + code:00c4c4/ea + cheat + description:Infinite bombs on pick-up + code:049d34/ad + cheat + description:Collect items from anywhere + code:04b82d/24+04b9cf/80+04b9d0/1d + cheat + description:Mega-jump + code:048fc0/fa + cheat + description:More health from capsule + code:018e2a/c0 + cheat + description:Trini moves faster before morphing + code:0485ba/02 + cheat + description:Billy moves faster before morphing + code:0485a2/02 + cheat + description:Jason moves faster before morphing + code:04859a/02 + cheat + description:Kimberley moves faster before morphing + code:0485a9/c0 + cheat + description:Zach moves faster before morphing + code:0485b2/02 + cheat + description:Trini moves faster after morphing + code:0485d2/ff + cheat + description:Billy moves faster after morphing + code:0485c9/ff + cheat + description:Jason moves faster after morphing + code:0485c1/02 + cheat + description:Kimberley moves faster after morphing + code:0485d1/c0 + cheat + description:Zach moves faster, but the wrong way + code:0485da/ff + cheat + description:Start game with full health + code:00b2d8/c0 + cheat + description:Start with 1 life + code:00b2c0/00 + cheat + description:Start with 6 lives + code:00b2c0/05 + cheat + description:Start with 9 lives + code:00b2c0/08 + cheat + description:Infinite health (Megazord) + code:7e04c0/71 + cheat + description:Infinite power (Megazord) + code:7e04c2/71 + +cartridge sha256:1b85c0690aa156a255c7f79e133e453345452698fa98abf8df744c262d0cf865 + name: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 + name:Mighty Morphin Power Rangers - The Movie (USA) + cheat + description:Invincibility + code:03b08a/8d + cheat + description:Infinite life force + code:03d58f/ad + cheat + description:Almost infinite life force + code:03d58f/b9 + cheat + description:Infinite lives + code:03d152/ad + cheat + description:Infinite continues - 1P mode + code:03f045/ad + cheat + description:Infinite continues - 2P mode + code:039367/ad + cheat + description:Large main power-up box gives max power + code:03d547/18 + cheat + description:Main collectable power doesn't go down after ranger powerup as fast + code:00be02/ea+03c228/ea + cheat + description:One hit kills + code:03d332/80 + cheat + description:No continues + code:00c1b0/00 + cheat + description:Start with mega-points + code:00c1c0/03 + cheat + description:Start with a lot of energy - first life only + code:00c1db/09 + cheat + description:Start with very little energy - first life only + code:00c1db/01 + cheat + description:Start with very little energy after first life + code:03d15c/01 + cheat + description:Start with more energy after first life + code:03d15c/09 + cheat + description:Start with 9 continues + code:00c1b0/09 + cheat + description:Start with 9 lives + code:0081f2/09 + cheat + description:Start with 5 lives + code:0081f2/05 + cheat + description:Start with 1 life + code:0081f2/01 + 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 + name:Miracle Girls (Japan) + cheat + description:Invincibility + code:c0e31b/60 + cheat + description:Infinite lives + code:c02ced/ad + +cartridge sha256:8715a641f2e4dd8b6066be7f2683d9129fff3fcccaf0a09cc8bdd2aa56460764 + name:Mohawk & Headphone Jack (USA) + cheat + description:Infinite health + code:7e0308/03 + cheat + description:Infinite lives + code:7e0306/05 + +cartridge sha256:6b0ac4d52d24536cdb7d9d0dc7d19ee30d08ac34363983290c5912ccc850fa0d + name:Monopoly (USA) (Rev 1) + cheat + description:Land, rent and some other things are free - all players + code:00b674/60 + cheat + description:Land, rent, and some other things are $50 - all players + code:00b674/e9+00b675/32+00b676/00 + cheat + description:Land, rent, and some other things are $100 - all players + code:00b674/e9+00b675/64+00b676/00 + cheat + description:Land, rent, and some other things are $200 - all players + code:00b674/e9+00b675/c8+00b676/00 + cheat + description:Land, rent, and some other things are $500 - all players + code:00b674/e9+00b675/f4+00b676/00 + cheat + description:Always throw double 6's + code:0093e5/a9+0093e6/06+0093e7/06 + cheat + description:Always throw double 5's + code:0093e5/a9+0093e6/05+0093e7/05 + cheat + description:Always throw double 4's + code:0093e5/a9+0093e6/04+0093e7/04 + cheat + description:Always throw double 3's + code:0093e5/a9+0093e6/02+0093e7/03 + cheat + description:Always throw double 2's + code:0093e5/a9+0093e6/02+0093e7/02 + cheat + description:Always throw double 1's + code:0093e5/a9+0093e6/01+0093e7/01 + 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 + name:Monopoly (USA) + cheat + description:Land, rent and some other things are free - all players + code:00b674/60 + cheat + description:Land, rent, and some other things are $50 - all players + code:00b674/e9+00b675/32+00b676/00 + cheat + description:Land, rent, and some other things are $100 - all players + code:00b674/e9+00b675/64+00b676/00 + cheat + description:Land, rent, and some other things are $200 - all players + code:00b674/e9+00b675/c8+00b676/00 + cheat + description:Land, rent, and some other things are $500 - all players + code:00b674/e9+00b675/f4+00b676/00 + cheat + description:Always throw double 6's + code:0093e5/a9+0093e6/06+0093e7/06 + cheat + description:Always throw double 5's + code:0093e5/a9+0093e6/05+0093e7/05 + cheat + description:Always throw double 4's + code:0093e5/a9+0093e6/04+0093e7/04 + cheat + description:Always throw double 3's + code:0093e5/a9+0093e6/02+0093e7/03 + cheat + description:Always throw double 2's + code:0093e5/a9+0093e6/02+0093e7/02 + cheat + description:Always throw double 1's + code:0093e5/a9+0093e6/01+0093e7/01 + 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 + name:Mortal Kombat (USA) + cheat + description:Invincibility (except against throws) + code:80a4d4/24+80a4da/24+80a4de/e0+80a4df/77+80a4e0/17+80975b/60 + cheat + description:Infinite health + code:80e647/a1+80e649/8d+80e64a/b9 + cheat + description:Infinite time + code:8095df/a5 + cheat + description:Have much more fatality time + code:809b76/7f + cheat + description:Always get Flawless Victory bonus + code:809fb2/80 + cheat + description:First strike of any kind wins round + code:8097ad/00 + cheat + description:Hit anywhere - P1 + code:809711/e0+809712/d3+809713/18+809715/32 + cheat + description:All strikes do minimal damage (all equal to 1 hit point) (2P game only, donメt choose handicap for either player) + code:809917/00 + cheat + description:P1 nearly invincible in 2P game (go to options, move P1メs handicap bar all the way to the right) + code:98b460/0b + cheat + description:One button fatalities - Liu Kang (Press Down) + code:80d10a/00 + cheat + description:One button fatalities - Johnny Cage (Press Y) + code:80ca49/08 + cheat + description:One button fatalities - Kano (Press B) + code:80d40b/08 + cheat + description:One button fatalities - Sonya (Press L or R) + code:80dac0/00 + cheat + description:One button fatalities - Sub Zero (Press Y) + code:80ccf0/08 + cheat + description:One button fatalities - Raiden (Press Y) + code:80cb01/08 + cheat + description:One button fatalities - Scorpion (Press Up, L or R) + code:80d03f/0d + cheat + description:Perform Kano's fatality from any distance + code:80d40a/24 + cheat + description:Perform Rayden's fatality from any distance + code:80cb00/24 + cheat + description:Perform Johnny Cage's fatality from any distance + code:80ca48/24 + cheat + description:Perform Scorpion's fatality from any distance + code:80d03e/24 + cheat + description:Perform Sub-Zero's fatality from any distance + code:80ccef/24 + cheat + description:All throws do more damage + code:809053/78 + cheat + description:Kano's High Punch does more damage + code:98d945/1e + cheat + description:Kano's Low Punch does more damage + code:98d94e/1e + cheat + description:Kano's High Kick does more damage + code:98d98d/48 + cheat + description:Kano's Low Kick does more damage + code:98d996/48 + cheat + description:Kano's Head Blow does more damage + code:98d960/48 + cheat + description:Kano's Knee does more damage + code:98d957/48 + cheat + description:Kano's Crouched Kick does more damage + code:98d984/3c + cheat + description:Kano's Uppercut does more damage + code:98d97b/78 + cheat + description:Kano's Roundhouse Kick does more damage + code:98d93c/60 + cheat + description:Kano's Foot Sweep does more damage + code:98d972/3c + cheat + description:Kano's Flying Punch does more damage + code:98d9a8/4b + cheat + description:Kano's Knife does more damage (only at close distance) + code:98d92a/4b + cheat + description:Johnny Cage's High Punch does more damage + code:98d8a4/1e + cheat + description:Johnny Cage's Low Punch does more damage + code:98d8ad/1e + cheat + description:Johnny Cage's High Kick does more damage + code:98d892/48 + cheat + description:Johnny Cage's Low Kick does more damage + code:98d89b/42 + cheat + description:Johnny Cage's Head Blow does more damage + code:98d8c8/3c + cheat + description:Johnny Cage's Knee does more damage + code:98d8d1/48 + cheat + description:Johnny Cage's Crouched Kick does more damage + code:98d8bf/18 + cheat + description:Johnny Cage's Uppercut does more damage + code:98d8da/78 + cheat + description:Johnny Cage's Roundhouse Kick does more damage + code:98d889/60 + cheat + description:Johnny Cage's Foot Sweep does more damage + code:98d8b6/3c + cheat + description:Johnny Cage's Flying Punch does more damage + code:98d880/4b + cheat + description:Johnny Cage's Shadow Kick does more damage + code:98d84a/5a + cheat + description:Johnny Cage's Fireball does more damage (only at close distance) + code:98d865/4b + cheat + description:Johnny Cage's Split Punch does more damage + code:98d85c/66 + cheat + description:Liu Kang's High Punch does more damage + code:98dae3/1e + cheat + description:Liu Kang's Low Punch does more damage + code:98daec/1e + cheat + description:Liu Kang's High Kick does more damage + code:98db22/48 + cheat + description:Liu Kang's Low Kick does more damage + code:98db2b/48 + cheat + description:Liu Kang's Head Blow does more damage + code:98dabf/3c + cheat + description:Liu Kang's Knee does more damage + code:98daf5/48 + cheat + description:Liu Kang's Crouched Kick does more damage + code:98db19/3c + cheat + description:Liu Kang's Uppercut does more damage + code:98db10/78 + cheat + description:Liu Kang's Roundhouse Kick does more damage + code:98dada/60 + cheat + description:Liu Kang's Foot Sweep does more damage + code:98db07/3c + cheat + description:Liu Kang's Flying Punch does more damage + code:98db3d/4b + cheat + description:Liu Kang's Special Flying Kick does more damage + code:98dab6/5a + cheat + description:Liu Kang's Fireball does more damage (only at close distance) + code:98dac8/4b + cheat + description:Sonya Blade's High Punch does more damage + code:98d717/1e + cheat + description:Sonya Blade's Low Punch does more damage + code:98d720/1e + cheat + description:Sonya Blade's High Kick does more damage + code:98d6e1/54 + cheat + description:Sonya Blade's Low Kick does more damage + code:98d6ea/51 + cheat + description:Sonya Blade's Head Blow does more damage + code:98d6f3/3c + cheat + description:Sonya Blade's Knee does more damage + code:98d6fc/48 + cheat + description:Sonya Blade's Crouched Kick does more damage + code:98d70e/3c + cheat + description:Sonya Blade's Uppercut does more damage + code:98d729/78 + cheat + description:Sonya Blade's Roundhouse Kick does more damage + code:98d6d8/66 + cheat + description:Sonya Blade's Foot Sweep does more damage + code:98d6cf/3c + cheat + description:Sonya Blade's Flying Punch does more damage + code:98d73b/4b + cheat + description:Sonya Blade's Leg Grab does more damage + code:80dd4f/78 + cheat + description:Sonya Blade's Sonic Rings does more damage (only at close distance) + code:98d6db/4b + cheat + description:Sonya Blade's Special Flying Kick does more damage + code:98d73b/4b + cheat + description:Rayden's High Punch does more damage + code:98da25/1e + cheat + description:Rayden's Low Punch does more damage + code:98da37/1e + cheat + description:Rayden's High Kick does more damage + code:98da13/45 + cheat + description:Rayden's Low Kick does more damage + code:98da1c/42 + cheat + description:Rayden's Head Blow does more damage + code:98da52/3c + cheat + description:Rayden's Knee does more damage + code:98da5b/48 + cheat + description:Rayden's Crouched Kick does more damage + code:98da49/18 + cheat + description:Rayden's Uppercut does more damage + code:98da64/78 + cheat + description:Rayden's Roundhouse Kick does more damage + code:98da0a/5a + cheat + description:Rayden's Foot Sweep does more damage + code:98da40/3c + cheat + description:Rayden's Flying Punch does more damage + code:98da01/4b + cheat + description:Rayden's Flying Thunderbolt does more damage + code:98d9dd/5a + cheat + description:Rayden's Lightning does more damage (only at close distance) + code:98d9e6/4b + cheat + description:Scorpion's, Sub-Zero's and Reptile's High Punch do more damage + code:98dbb7/1e + cheat + description:Scorpion's, Sub-Zero's and Reptile's Low Punch do more damage + code:98dbc0/1e + cheat + description:Scorpion's, Sub-Zero's and Reptile's High Kick do more damage + code:98dbf6/48 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Low Kick do more damage + code:98dbff/48 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Head Blow do more damage + code:98dbd2/3c + cheat + description:Scorpion's, Sub-Zero's and Reptile's Knee do more damage + code:98dbc9/48 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Crouched Kick do more damage + code:98dc1a/18 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Uppercut do more damage + code:98dbae/78 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Roundhouse Kick do more damage + code:98dc11/60 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Foot Sweep do more damage + code:98dc08/3c + cheat + description:Scorpion's, Sub-Zero's and Reptile's Flying Punch do more damage + code:98dbe4/4b + cheat + description:Sub-Zero's and Reptile's Deep Freeze do damage + code:98dba5/28 + cheat + description:Sub-Zero's and Reptile's Slide do more damage + code:98db78/27 + cheat + description:Scorpion's and Reptile's Harpoon do more damage + code:98db8a/18 + cheat + description:Scorpion's and Reptile's Scorpion Split do more damage + code:98dbe4/4b + cheat + description:Each round is 199 seconds (time counts down twice) + code:808b81/02 + cheat + description:Each round is 90 seconds + code:808b80/91+808b81/00 + cheat + description:Each round is 80 seconds + code:808b80/81+808b81/00 + cheat + description:Each round is 70 seconds + code:808b80/71+808b81/00 + cheat + description:Each round is 60 seconds + code:808b80/61+808b81/00 + cheat + description:Each round is 50 seconds + code:808b80/51+808b81/00 + cheat + description:Each round is 40 seconds + code:808b80/41+808b81/00 + cheat + description:Each round is 30 seconds + code:808b80/31+808b81/00 + cheat + description:Each round is 20 seconds + code:808b80/21+808b81/00 + cheat + description:Each round is 10 seconds + code:808b80/11+808b81/00 + cheat + description:Always fight in the the Courtyard + code:8084cf/00 + cheat + description:After 1st match, almost always fight at the Palace Gates + code:8084cb/a9+8084cc/01 + cheat + description:After 1st match, almost always fight in the Warrior Shrine + code:8084cb/a9+8084cc/02 + cheat + description:After 1st match, almost always fight in the Pit + code:8084cb/a9+8084cc/03 + cheat + description:After 1st match, almost always fight in the Throne Room + code:8084cb/a9+8084cc/04 + cheat + description:After 1st match, almost always fight in Goro's Lair + code:8084cb/a9+8084cc/05 + cheat + description:After 1st match, almost always fight in the bottom of the pit (screen says Goro's Lair) + code:8084cb/a9+8084cc/06 + cheat + description:Almost always fight Johnny Cage + code:9897c4/a9+9897c5/00 + cheat + description:Almost always fight Kano + code:9897c4/a9+9897c5/01 + cheat + description:Almost always fight Rayden + code:9897c4/a9+9897c5/02 + cheat + description:Almost always fight Liu Kang + code:9897c4/a9+9897c5/03 + cheat + description:Almost always fight Scorpion + code:9897c4/a9+9897c5/04 + cheat + description:Almost always fight Sub-Zero + code:9897c4/a9+9897c5/05 + cheat + description:Almost always fight Sonya Blade + code:9897c4/a9+9897c5/06 + cheat + description:Almost always fight Goro (don't use Kano's or Johnny Cage's finishing move on Goro) + code:9897c4/a9+9897c5/07 + cheat + description:Start on Match 2 + code:808168/01 + cheat + description:Start on Match 3 + code:808168/02 + cheat + description:Start on Match 4 + code:808168/03 + cheat + description:Start on Match 5 + code:808168/04 + cheat + description:Start on Match 6 + code:808168/05 + cheat + description:Start on Mirror Match + code:808168/06 + cheat + description:Start on Endurance 1 match + code:808168/07 + cheat + description:Start on Endurance 2 match + code:808168/08 + cheat + description:Start on Endurance 3 match + code:808168/09 + cheat + description:Start on match with Goro + code:808168/0a + cheat + description:Start on match with Shang Tsung + code:808168/0b + +cartridge sha256:6caa0ab221a3e690a104baa4935fc86dbc385d4272e88afb46b999bf6c6edb36 + name:Mortal Kombat - Shinken Kourin Densetsu (Japan) + cheat + description:Infinite health + code:80e866/a1+80e868/8d+80e869/f9+80e86a/04 + cheat + description:One hit kill - P1 + code:80e8a8/00+80e8aa/8d+80e8ab/fb+80e8ac/04 + +cartridge sha256:43e36a74fb73a7efc46b380599e269b1fff8f55ecf80f5cf50c34d02ceda041a + name:Mortal Kombat II (USA) + cheat + description:Invincibility - P1 + code:849d68/ad + cheat + description:Invincibility - P2/CPU + code:849d78/ad + cheat + description:Infinite health + code:83b057/a9+83b058/a1+83b059/00+83b05b/fc+83b05c/2e + cheat + description:Infinite time + code:83a133/80 + cheat + description:Infinite continues + code:83a02f/ad + cheat + description:No health - P1 + code:849d64/00 + cheat + description:No health - P2/CPU + code:849d74/00 + cheat + description:Hit anywhere - P1 + code:849c45/40+849c44/d0+849c41/e0+849c42/00 + cheat + description:Have 127x more fatality time + code:83a6d5/7f + cheat + description:CPU always does fatalities + code:80cdef/24 + cheat + description:CPU always does friendships and babalities (Smoke and Jade will also be in the Living Forest) + code:80ff47/80 + cheat + description:Disable blood + code:84fda5/24 + cheat + description:Disable throws - 2P mode + code:82da9f/8d + cheat + description:Mileena's Sai Throw does massive damage + code:80f96c/48 + cheat + description:Liu Kang's High Fireball does massive damage + code:80fd50/48 + cheat + description:Kung Lao's Hat Throw does massive damage + code:80fdde/48 + cheat + description:Cage's Shadow Kick does massive damage + code:80fc1e/48 + cheat + description:Reptile's Force Ball does massive damage + code:80f59f/48 + cheat + description:Shang Tsung's Flaming Skull attack does massive damage + code:80f847/48 + cheat + description:Kitana's Fan Throw does massive damage + code:80f95f/48 + cheat + description:Baraka's Blade Spark does massive damage + code:80fafb/48 + cheat + description:Rayden's Lightning Bolt does massive damage + code:80f728/48 + cheat + description:Enable all 2P rules/moves when fighting computer + code:84a011/80 + cheat + description:Always fight Kung Lao + code:83af82/a9+83af83/00 + cheat + description:Always fight Liu Kang + code:83af82/a9+83af83/01 + cheat + description:Always fight Cage + code:83af82/a9+83af83/02 + cheat + description:Always fight Baraka + code:83af82/a9+83af83/03 + cheat + description:Always fight Kitana + code:83af82/a9+83af83/04 + cheat + description:Always fight Mileena + code:83af82/a9+83af83/05 + cheat + description:Always fight Shang Tsung + code:83af82/a9+83af83/06 + cheat + description:Always fight Rayden + code:83af82/a9+83af83/07 + cheat + description:Always fight Sub-Zero + code:83af82/a9+83af83/08 + cheat + description:Always fight Reptile + code:83af82/a9+83af83/09 + cheat + description:Always fight Scorpion + code:83af82/a9+83af83/0a + cheat + description:Always fight Jax + code:83af82/a9+83af83/0b + cheat + description:Always fight Kintaro + code:83af82/a9+83af83/0c + cheat + description:Always fight Shao Kahn + code:83af82/a9+83af83/0d + cheat + description:Always fight Smoke + code:83af82/a9+83af83/0e + cheat + description:Always fight Noob Saibot + code:83af82/a9+83af83/0f + cheat + description:Always fight Jade + code:83af82/a9+83af83/10 + cheat + description:Start with 0 continues + code:83b2a0/01 + cheat + description:Start with 2 continues + code:83b2a0/03 + cheat + description:Start with 6 continues + code:83b2a0/07 + cheat + description:Start with 8 continues + code:83b2a0/09 + 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 + name:Mortal Kombat II (USA) (Rev 1) + cheat + description:P1 is killed by one hit + code:849d64/00 + cheat + description:P2/CPU is killed by one hit + code:849d74/00 + cheat + description:Have 127x more fatality time + code:83a6e5/7f + cheat + description:CPU always does fatalities + code:80ce01/24 + cheat + description:CPU always does friendships and babalities (Smoke and Jade will also be in the Living Forest) + code:80ff7a/80 + cheat + description:Disable blood + code:84fda9/24 + cheat + description:Disable throws - 2P mode + code:82da9f/8d + cheat + description:Enable all 2P rules/moves when fighting computer + code:84a011/80 + +cartridge sha256:417874aa57856fe93eefdb24066fa1a9ca3f23c72c09d5247ae2b3ab4b3d09d1 + name:Mortal Kombat 3 (USA) + cheat + description:Infinite health - P1 + code:83e642/ad + cheat + description:Infinite health - P2 + code:83e652/ad + cheat + description:P1 takes all damage + code:83e636/00 + cheat + description:P2 takes all damage + code:83e635/80 + cheat + description:Infinite continues + code:86d346/cd + cheat + description:Hit anywhere - P1 + code:83ff82/00+83ff83/f0+83ff84/03+83e54b/ff+83ff85/4c+83ff89/4c+83ff88/4c+83ff8a/e5+83ff87/e5+83ff80/e0+83e54a/80+83ff86/a2+83ff81/02 + cheat + description:Press A on main menu for Sound Test + code:82dcf8/02 + cheat + description:Press Up on main menu for Kool Stuff Menu + code:82dd2c/02 + cheat + description:Press Select on main menu for Kooler Stuff Menu + code:82dd60/02 + cheat + description:Press X on main menu for Scott's Menu + code:82dd94/02 + cheat + description:Always fight Kano in Master mode + code:84bf16/af+84dfef/9c+84c4f4/00 + cheat + description:Always fight Sonya in Master mode + code:84bf16/af+84dfef/9c+84c4f4/01 + cheat + description:Always fight Jax in Master mode + code:84bf16/af+84dfef/9c+84c4f4/02 + cheat + description:Always fight Nightwolf in Master mode + code:84bf16/af+84dfef/9c+84c4f4/03 + cheat + description:Always fight Sub-Zero in Master mode + code:84bf16/af+84dfef/9c+84c4f4/04 + cheat + description:Always fight Stryker in Master mode + code:84bf16/af+84dfef/9c+84c4f4/05 + cheat + description:Always fight Sindel in Master mode + code:84bf16/af+84dfef/9c+84c4f4/06 + cheat + description:Always fight Sektor in Master mode + code:84bf16/af+84dfef/9c+84c4f4/07 + cheat + description:Always fight Cyrax in Master mode + code:84bf16/af+84dfef/9c+84c4f4/08 + cheat + description:Always fight Kung Lao in Master mode + code:84bf16/af+84dfef/9c+84c4f4/09 + cheat + description:Always fight Kabal in Master mode + code:84bf16/af+84dfef/9c+84c4f4/0a + cheat + description:Always fight Sheeva in Master mode + code:84bf16/af+84dfef/9c+84c4f4/0b + cheat + description:Always fight Shang Tsung in Master mode + code:84bf16/af+84dfef/9c+84c4f4/0c + cheat + description:Always fight Liu Kang in Master mode + code:84bf16/af+84dfef/9c+84c4f4/0d + cheat + description:Always fight Smoke in Master mode + code:84bf16/af+84dfef/9c+84c4f4/0e + cheat + description:Always fight Motaro in Master mode + code:84bf16/af+84dfef/9c+84c4f4/0f + cheat + description:Always fight Shao Kahn in Master mode + code:84bf16/af+84dfef/9c+84c4f4/10 + cheat + description:Always fight Noob-Saibot in Master mode + code:84bf16/af+84dfef/9c+84c4f4/11 + 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 + name:Mr. Do! (USA) + cheat + description:Invincibility + code:02e78d/80 + cheat + description:Infinite lives + code:7e18b2/09 + cheat + description:Two enemies on screen at most + code:7e1440/00 + cheat + description:Only one Cherry needed to clear level + code:02a4d9/9c + cheat + description:Level modifier (level is always one less than entered) + code:7e189e/00+7e18a0/00+7e18b4/00 + +cartridge sha256:3472dd574b50aed2fa998f464398db4fbb00f5a300a672c3737ee9336a008a16 + name: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:44f0f159e1d56a703baa08d648a0d871c037e18198ec119c07795a3757c9e163 + name:Mr. Tuff (Europe) (En,Fr,De,Es,It) (Proto) (1994-12-05) + cheat + description:Infinite time + code:7eeb1c/39 + cheat + description:Infinite time on item pick-ups and flame-thrower fuel + code:7eeb93/27 + cheat + description:Enable auto-hit + code:7eeb79/03 + cheat + description:Easy bosses (except Octopod) + code:7ef4f8/00 + cheat + description:Jump higher + code:7e0421/00 + cheat + description:Have drill + code:7eeaf4/01 + cheat + description:Have super attack + code:7eeaf4/02 + cheat + description:Have bowling ball + code:7eeaf4/03 + cheat + description:Have fire smash + code:7eeaf4/04 + cheat + description:Have regular punch + code:7eeaf4/05 + cheat + description:Have crescent blast + code:7eeaf4/06 + cheat + description:Have mace + code:7eeaf4/07 + cheat + description:Have jet pack special + code:7eeb68/01 + cheat + description:Have missiles special + code:7eeb68/02 + cheat + description:Have flame thrower special + code:7eeb68/03 + +cartridge sha256:4f172253946ae29ddbf1e8169b48d55fe1aed8d007adafc6fa3e62685ed45de0 + name: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 + name: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/00 + +cartridge sha256:f292598ac462fdfcd32ad9b6b35ac01d4bab020391dff92bfe94780ec604289a + name:Musya - The Classic Japanese Tale of Horror (USA) + cheat + description:Invincibility (blinking) + code:7e103c/0a + 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 + cheat + description:Have strongest weapon + code:7e102c/06 + +cartridge sha256:a19337da953f63c806754b90af7ff9fbea1bf090618dae732ee3a546882b8700 + name: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 + name:NBA All-Star Challenge (USA) + cheat + description:P1 can't score in the 1-on-1, free throw or tournament stages + code:80e395/6d + cheat + description:P2 or computer can't score in the 1-on-1, free throw or tournament events + code:80e3b9/cd + cheat + description:P1 can't score in 3-point shootout + code:80e155/cd+80e13e/cd + cheat + description:P2 or computer can't score in 3-point shootout + code:80e11e/cd+80e107/cd + cheat + description:Stop shot clock (1-on-1 and 1-on-1 tournament modes) + code:80af85/cd+80af83/80 + cheat + description:12-second shot clock (1-on-1 and 1-on-1 tournament modes) + code:80afe8/01+80afe3/02 + cheat + description:48-second shot clock - after the 1st shot (1-on-1 and 1-on-1 tournament modes) + code:80afe8/04+80afe3/08 + +cartridge sha256:b257cffb3484e6be051a56268cb99ee888bd6d3e9c0e8d6d0779ff66c411f6ba + name:NBA Jam - Tournament Edition (USA) + cheat + description:Enable extended roster + code:8aa145/a9 + cheat + description:Infinite shot clock time + code:80ad5a/ad + cheat + description:Ability to set shot clock option down to 1 + code:aa85d5/01 + cheat + description:Have almost Infinite Turbo - P1 + code:81bd93/ad + cheat + description:Have almost Infinite Turbo - P2 + code:a6b587/ad + cheat + description:Turbo recharges quicker - P1 + code:81bdc2/01 + cheat + description:Turbo recharges quicker - P2 + code:a6b5b6/01 + cheat + description:Twice as much turbo - P1 + code:81bdc7/40 + cheat + description:Twice as much turbo - P2 + code:a6b5bb/40 + cheat + description:Shots worth more - P1 + code:00a6d0/38 + cheat + description:Shots worth more - P2 + code:00a8e5/38 + cheat + description:Player is On Fire after 2 baskets instead of 3 + code:9a9d1a/04 + cheat + description:No turbo (except in tournament mode) - P1 + code:91bdbe/a9 + cheat + description:No turbo (except in tournament mode) - P2 + code:a6b5b2/a9 + cheat + description:Move much faster (except in tournament mode) - all players + code:26fd27/00+26fd2c/06 + cheat + description:Move super fast (except in tournament mode) - all players + code:26fd27/00+26fd2c/09 + cheat + description:Hot spots and Power ups are on in tournament mode automatically (don't select the special features menu) + code:26fc59/06 + cheat + description:Have all secret power-ups except slippery floors on - all players + code:8afa7c/00+8afa90/80+4cf078/26 + 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:82f9c4/ff + 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:82fa6a/ff + 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:82fb10/ff + 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:82fbb6/ff + cheat + description:Have Power-up offense, Speed Up, block opponent to make both fall, Teleport Pass and High Shots - P1 + code:82f9c5/ff + cheat + description:Have Power-up offense, Speed Up, block opponent to make both fall, Teleport Pass and High Shots - P2 + code:82fa6b/ff + cheat + description:Have Power-up offense, Speed Up, block opponent to make both fall, Teleport Pass and High Shots - P3 + code:82fb11/ff + cheat + description:Have Power-up offense, Speed Up, block opponent to make both fall, Teleport Pass and High Shots - P4 + code:82fbb7/ff + cheat + description:Have all secret power-ups - all players + code:8afa7c/00+8afa90/80 + cheat + description:Have all secret power-ups on - P1 + code:82f9c4/ff+82f9c5/ff + cheat + description:Have all secret power-ups on - P2 + code:82fa6a/ff+82fa6b/ff + cheat + description:Have all secret power-ups on - P3 + code:82fb10/ff+82fb11/ff + cheat + description:Have all secret power-ups on - P4 + code:82fbb6/ff+82fbb7/ff + cheat + description:Have Power Push - P1 + code:82f9c4/01 + cheat + description:Have Powered Up 3 pointers - P1 + code:82f9c4/02 + cheat + description:Have Powered Up 3 pointers - P2 + code:82fa6a/02 + cheat + description:Have Powered Up 3 pointers - P3 + code:82fb10/02 + cheat + description:Have Powered Up 3 pointers - P4 + code:82fbb6/02 + cheat + description:Have Infinite Turbo - P1 + code:82f9c4/04 + cheat + description:Have Infinite Turbo - P2 + code:82fa6a/04 + cheat + description:Have Infinite Turbo - P3 + code:82fb10/04 + cheat + description:Have Infinite Turbo - P4 + code:82fbb6/04 + cheat + description:Always On Fire - P1 + code:82f9c4/08 + cheat + description:Always On Fire - P2 + code:82fa6a/08 + cheat + description:Always On Fire - P3 + code:82fb10/08 + cheat + description:Always On Fire - P4 + code:82fbb6/08 + cheat + description:Have Super Dunks - P1 + code:82f9c4/10 + cheat + description:Have Super Dunks - P2 + code:82fa6a/10 + cheat + description:Have Super Dunks - P3 + code:82fb10/10 + cheat + description:Have Super Dunks - P4 + code:82fbb6/10 + cheat + description:Have Max Power - P1 + code:82f9c4/20 + cheat + description:Have Max Power - P2 + code:82fa6a/20 + cheat + description:Have Max Power - P3 + code:82fb10/20 + cheat + description:Have Max Power - P4 + code:82fbb6/20 + cheat + description:Have Powered Up Goal Tending - P1 + code:82f9c4/40 + cheat + description:Have Powered Up Goal Tending - P2 + code:82fa6a/40 + cheat + description:Have Powered Up Goal Tending - P3 + code:82fb10/40 + cheat + description:Have Powered Up Goal Tending - P4 + code:82fbb6/40 + cheat + description:Have Quick Hands - P1 + code:82f9c4/80 + cheat + description:Have Quick Hands - P2 + code:82fa6a/80 + cheat + description:Have Quick Hands - P3 + code:82fb10/80 + cheat + description:Have Quick Hands - P4 + code:82fbb6/80 + cheat + description:Have Powered Up Offense - P1 + code:82f9c5/01 + cheat + description:Have Powered Up Offense - P2 + code:82fa6b/01 + cheat + description:Have Powered Up Offense - P3 + code:82fb11/01 + cheat + description:Have Powered Up Offense - P4 + code:82fbb7/01 + cheat + description:Move very quickly - P1 + code:82f9c5/02 + cheat + description:Move very quickly - P2 + code:82fa6b/02 + cheat + description:Move very quickly - P3 + code:82fb11/02 + cheat + description:Move very quickly - P4 + code:82fbb7/02 + cheat + description:Knock down both opponents by pushing one - P1 + code:82f9c5/04 + cheat + description:Knock down both opponents by pushing two - P2 + code:82fa6b/04 + cheat + description:Knock down both opponents by pushing three - P3 + code:82fb11/04 + cheat + description:Knock down both opponents by pushing four - P4 + code:82fbb7/04 + cheat + description:Knock down opposite opponent - P1 + code:82f9c5/10 + cheat + description:Knock down opposite opponent - P2 + code:82fa6b/10 + cheat + description:Knock down opposite opponent - P3 + code:82fb11/10 + cheat + description:Knock down opposite opponent - P4 + code:82fbb7/10 + cheat + description:Have High Shots - P1 + code:82f9c5/20 + cheat + description:Have High Shots - P2 + code:82fa6b/20 + cheat + description:Have High Shots - P3 + code:82fb11/20 + cheat + description:Have High Shots - P4 + code:82fbb7/20 + cheat + description:Have Power Block - P2 + code:82fa6a/01 + cheat + description:Have Power Block - P3 + code:82fb10/01 + cheat + description:Have Power Block - P4 + code:82fbb6/01 + cheat + description:Have Teleport Passes - P1 + code:82f9c5/08 + cheat + description:Have Teleport Passes - P2 + code:82fa6b/08 + cheat + description:Have Teleport Passes - P3 + code:82fb11/08 + cheat + description:Have Teleport Passes - P4 + code:82fbb7/08 + cheat + description:Start with 1 point - P1 + code:82f843/ee + cheat + description:Start with 1 point - P2 + code:82f84f/ee + +cartridge sha256:3ef9d4b537ea83c8ba9ec8be7aba37ddac22a71c73d0aec46fe8e5a8f5b34a7c + name:NBA Jam (USA) (Rev 1) + cheat + description:Always On Fire - all players + code:8afed6/08 + cheat + description:Always On Fire (alt) - all players + code:8afe51/08 + cheat + description:Have Infinite Turbo - all players + code:8afeec/08 + cheat + description:Have Infinite Turbo (alt) - all players + code:8afe67/08 + cheat + description:Have Super Dunk ability - all players + code:8afebd/0b + cheat + description:Have Super Dunk ability (alt) - all players + code:8afe38/0b + cheat + description:Have Super Interception ability - all players + code:8afe8e/0b + cheat + description:Have Super Interception ability (alt) - all players + code:8afe09/0b + cheat + description:Juice mode + code:8aff02/08 + cheat + description:Juice mode (alt) + code:8afe7d/08 + cheat + description:Visitor's baskets worth 1 + code:00a5a6/99 + cheat + description:Visitor's baskets worth 2 + code:00a5a6/e2 + cheat + description:Visitor's baskets worth 3 + code:00a5a6/e4 + cheat + description:Visitor's baskets worth 4 + code:00a5a6/e5 + cheat + description:Visitor's baskets worth 5 + code:00a5a6/e7 + cheat + description:Visitor's baskets worth 6 + code:00a5a6/e8 + cheat + description:Visitor's baskets worth 7 + code:00a5a6/ea + cheat + description:Visitor's baskets worth 8 + code:00a5a6/ec + cheat + description:Home's baskets worth 1 + code:00a78f/99 + cheat + description:Home's baskets worth 2 + code:00a78f/e2 + cheat + description:Home's baskets worth 3 + code:00a78f/e4 + cheat + description:Home's baskets worth 4 + code:00a78f/e5 + cheat + description:Home's baskets worth 5 + code:00a78f/e7 + cheat + description:Home's baskets worth 6 + code:00a78f/e8 + cheat + description:Home's baskets worth 7 + code:00a78f/ea + cheat + description:Home's baskets worth 8 + code:00a78f/ec + cheat + description:Shot success percentages displayed for non-dunk shots + code:8afea7/08 + cheat + description:Shot success percentages displayed for non-dunk shots (alt) + code:8afe22/08 + cheat + description:Need 2 baskets to be On Fire + code:9a9f03/02+9a9ec4/02 + cheat + description:Need 4 baskets to be On Fire + code:9a9f03/04 + cheat + description:Need 5 baskets to be On Fire + code:9a9f03/05 + cheat + description:Need 6 baskets to be On Fire + code:9a9f03/06 + cheat + description:Need 7 baskets to be On Fire + code:9a9f03/07 + cheat + description:Need 8 baskets to be On Fire + code:9a9f03/08 + cheat + description:Need 9 baskets to be On Fire + code:9a9f03/09 + cheat + description:Need 10 baskets to be On Fire + code:9a9f03/0a + cheat + description:Need 2 baskets to stay On Fire until an opponent goes On Fire + code:9a9f03/02 + cheat + description:Turbo bar never goes up (until next quarter) + code:a7f387/00 + cheat + description:Turbo bar never goes up (until next quarter) (alt) + code:a7f36b/00 + cheat + description:Turbo bar restores very slowly + code:a7f387/0e + cheat + description:Turbo bar restores very slowly (alt) + code:a7f36b/0e + cheat + description:Turbo bar restores much slower + code:a7f387/15 + cheat + description:Turbo bar restores much slower (alt) + code:a7f36b/15 + cheat + description:Turbo bar restores slower + code:a7f387/1d + cheat + description:Turbo bar restores slower (alt) + code:a7f36b/1d + cheat + description:Turbo bar restores faster + code:a7f387/40 + cheat + description:Turbo bar restores faster (alt) + code:a7f36b/40 + cheat + description:Turbo bar restores much faster + code:a7f387/50 + cheat + description:Turbo bar restores much faster (alt) + code:a7f36b/50 + cheat + description:Turbo bar restores extremely fast + code:a7f387/81 + cheat + description:Turbo bar restores extremely fast (alt) + code:a7f36b/81 + cheat + description:Turbo drains very slowly + code:a7f378/04 + cheat + description:Turbo drains very slowly (alt) + code:a7f35c/04 + cheat + description:Turbo drains slower + code:a7f378/08 + cheat + description:Turbo drains slower (alt) + code:a7f35c/08 + cheat + description:Turbo drains slightly slower + code:a7f378/10 + cheat + description:Turbo drains slightly slower (alt) + code:a7f35c/10 + cheat + description:Turbo drains slightly faster + code:a7f378/22 + cheat + description:Turbo drains slightly faster (alt) + code:a7f35c/22 + cheat + description:Turbo drains faster + code:a7f378/2d + cheat + description:Turbo drains faster (alt) + code:a7f35c/2d + cheat + description:Turbo drains very fast + code:a7f378/38 + cheat + description:Turbo drains very fast (alt) + code:a7f35c/38 + cheat + description:Always On Fire - P1 + code:7e0a96/01 + cheat + description:Always On Fire - P2 + code:7e0a96/03 + +cartridge sha256:0f18c496426bb97fe5e8b91ad5299f0b1c3898ac17047b745c86b167c212ab7a + name:NBA Jam (USA) + cheat + description:Always On Fire - all players + code:8afed6/08 + cheat + description:Always On Fire (alt) - all players + code:8afe51/08 + cheat + description:Have Infinite Turbo - all players + code:8afeec/08 + cheat + description:Have Infinite Turbo (alt) - all players + code:8afe67/08 + cheat + description:Have Super Dunk ability - all players + code:8afebd/0b + cheat + description:Have Super Dunk ability (alt) - all players + code:8afe38/0b + cheat + description:Have Super Interception ability - all players + code:8afe8e/0b + cheat + description:Have Super Interception ability (alt) - all players + code:8afe09/0b + cheat + description:Juice mode + code:8aff02/08 + cheat + description:Juice mode (alt) + code:8afe7d/08 + cheat + description:Visitor's baskets worth 1 + code:00a5a6/99 + cheat + description:Visitor's baskets worth 2 + code:00a5a6/e2 + cheat + description:Visitor's baskets worth 3 + code:00a5a6/e4 + cheat + description:Visitor's baskets worth 4 + code:00a5a6/e5 + cheat + description:Visitor's baskets worth 5 + code:00a5a6/e7 + cheat + description:Visitor's baskets worth 6 + code:00a5a6/e8 + cheat + description:Visitor's baskets worth 7 + code:00a5a6/ea + cheat + description:Visitor's baskets worth 8 + code:00a5a6/ec + cheat + description:Home's baskets worth 1 + code:00a78f/99 + cheat + description:Home's baskets worth 2 + code:00a78f/e2 + cheat + description:Home's baskets worth 3 + code:00a78f/e4 + cheat + description:Home's baskets worth 4 + code:00a78f/e5 + cheat + description:Home's baskets worth 5 + code:00a78f/e7 + cheat + description:Home's baskets worth 6 + code:00a78f/e8 + cheat + description:Home's baskets worth 7 + code:00a78f/ea + cheat + description:Home's baskets worth 8 + code:00a78f/ec + cheat + description:Shot success percentages displayed for non-dunk shots + code:8afea7/08 + cheat + description:Shot success percentages displayed for non-dunk shots (alt) + code:8afe22/08 + cheat + description:Need 2 baskets to be On Fire + code:9a9f03/02+9a9ec4/02 + cheat + description:Need 4 baskets to be On Fire + code:9a9f03/04 + cheat + description:Need 5 baskets to be On Fire + code:9a9f03/05 + cheat + description:Need 6 baskets to be On Fire + code:9a9f03/06 + cheat + description:Need 7 baskets to be On Fire + code:9a9f03/07 + cheat + description:Need 8 baskets to be On Fire + code:9a9f03/08 + cheat + description:Need 9 baskets to be On Fire + code:9a9f03/09 + cheat + description:Need 10 baskets to be On Fire + code:9a9f03/0a + cheat + description:Need 2 baskets to stay On Fire until an opponent goes On Fire + code:9a9f03/02 + cheat + description:Turbo bar never goes up (until next quarter) + code:a7f387/00 + cheat + description:Turbo bar never goes up (until next quarter) (alt) + code:a7f36b/00 + cheat + description:Turbo bar restores very slowly + code:a7f387/0e + cheat + description:Turbo bar restores very slowly (alt) + code:a7f36b/0e + cheat + description:Turbo bar restores much slower + code:a7f387/15 + cheat + description:Turbo bar restores much slower (alt) + code:a7f36b/15 + cheat + description:Turbo bar restores slower + code:a7f387/1d + cheat + description:Turbo bar restores slower (alt) + code:a7f36b/1d + cheat + description:Turbo bar restores faster + code:a7f387/40 + cheat + description:Turbo bar restores faster (alt) + code:a7f36b/40 + cheat + description:Turbo bar restores much faster + code:a7f387/50 + cheat + description:Turbo bar restores much faster (alt) + code:a7f36b/50 + cheat + description:Turbo bar restores extremely fast + code:a7f387/81 + cheat + description:Turbo bar restores extremely fast (alt) + code:a7f36b/81 + cheat + description:Turbo drains very slowly + code:a7f378/04 + cheat + description:Turbo drains very slowly (alt) + code:a7f35c/04 + cheat + description:Turbo drains slower + code:a7f378/08 + cheat + description:Turbo drains slower (alt) + code:a7f35c/08 + cheat + description:Turbo drains slightly slower + code:a7f378/10 + cheat + description:Turbo drains slightly slower (alt) + code:a7f35c/10 + cheat + description:Turbo drains slightly faster + code:a7f378/22 + cheat + description:Turbo drains slightly faster (alt) + code:a7f35c/22 + cheat + description:Turbo drains faster + code:a7f378/2d + cheat + description:Turbo drains faster (alt) + code:a7f35c/2d + cheat + description:Turbo drains very fast + code:a7f378/38 + cheat + description:Turbo drains very fast (alt) + code:a7f35c/38 + cheat + description:Always On Fire - P1 + code:7e0a96/01 + cheat + description:Always On Fire - P2 + code:7e0a96/03 + +cartridge sha256:6a7324734004d99206439430243b51a05fa8c25ffa314dafc7f127235d1a730f + name:NBA Showdown (USA) + cheat + description:Infinite time + code:80d823/ad + cheat + description:Infinite time-outs + code:80e156/ad + cheat + description:No personal fouls - both teams + code:82ec9b/ad + cheat + description:Infinite shot clock - computer + code:80d444/ad + cheat + description:12-sec. shot clock when ball is in-bounded - P1 + code:83f1eb/0c+83933c/0c+80e519/0c + cheat + description:12-sec. shot clock when ball is in-bounded - computer + code:83f1eb/0c+828cfc/0c+82b620/0c + cheat + description:1-min. quarters + code:86fb0b/01 + cheat + description:3 time-outs + code:83f162/03 + +cartridge sha256:8ef5d5c50ffeca1e62e88e4fe2909eaf191e28fbb5a9faf98b7b10bea72c9ed9 + name:NCAA Basketball (USA) (Rev 1) + cheat + description:Infinite time to shoot + code:019473/ad + cheat + description:Infinite timeouts - P1 + code:00d624/ad + cheat + description:Infinite timeouts - P2 + code:00d62e/ad + cheat + description:Shot timer starts at 10 sec. instead of 45 + code:019490/10 + cheat + description:Shot timer starts at 20 sec. + code:019490/20 + cheat + description:Shot timer starts at 30 sec. + code:019490/30 + cheat + description:Shot timer starts at 60 sec. + code:019490/60 + cheat + description:Shot timer starts at 90 sec. + code:019490/90 + cheat + description:3-point shots worth 0 - both players + code:00ef2e/00 + cheat + description:3-point shots worth 1 point + code:00ef2e/01 + cheat + description:3-point shots worth 2 points + code:00ef2e/02 + cheat + description:3-point shots worth 4 points + code:00ef2e/04 + cheat + description:3-point shots worth 5 points + code:00ef2e/05 + cheat + description:3-point shots worth 6 points + code:00ef2e/06 + cheat + description:3-point shots worth 7 points + code:00ef2e/07 + cheat + description:3-point shots worth 8 points + code:00ef2e/08 + cheat + description:3-point shots worth 9 points + code:00ef2e/09 + cheat + description:P1 shots worth 1 extra point (2-pt. shots worth 3, 3-pt. shots worth 4) + code:009bc9/38+009e57/38 + cheat + description:P2 shots worth 1 extra point (2-pt. shots worth 3, 3-pt. shots worth 4) + code:009e4b/38+009bbd/38 + cheat + description:P1 free throws worth 2 instead of 1 + code:009d01/38 + cheat + description:P2 free throws worth 2 + code:009cf5/38 + cheat + description:No 5-second violations + code:008c78/ad + +cartridge sha256:6a59115a9958d4a9fa167095505a2ddf222ca6291209d07618319e39a2be8b61 + name:NFL Quarterback Club (USA) + cheat + description:Cannot be tackled (hold X) + code:829c85/2f+829c84/a5+829c86/0a+829c87/10 + +cartridge sha256:f43f8ec546b8060e9d191fca860c38caf5a43eda86a304f0073647c6fad7b2c9 + name:NFL Quarterback Club 96 (USA) + cheat + description:Cannot be tackled (hold X) + code:8289ab/6e+8289aa/a5+8289ac/0a+8289ad/10 + +cartridge sha256:5132e1c0d466963e6adc09e8a608ebd90619ab94f7fc908d626bbaf6a99dfa19 + name:NHL '94 (USA) + cheat + description:Score from anywhere (hold X) + code:9e90af/75+9e90ae/0e+9e90b0/07+9e90b4/0f+9e90b1/10 + +cartridge sha256:01c0b58d5fd5d5484fea988455a55a71ed9e606538d2b3ce3f216159cc6929b0 + name:NHL 95 (USA) + cheat + description:Score from anywhere (hold X while in the opponent's half of the rink) + code:c4444c/45+c44446/c0+c4444b/a6+c44445/a5+c44447/0a+c44448/10 + +cartridge sha256:d24c0175ee4eafed88e277691c5f5dafd4e197723097e2eb68aa6b40f449fff2 + name:NHL 96 (USA) + cheat + description:Score from anywhere (hold X while in the opponent's half of the rink) + code:c643b0/b1+c643af/a5+c643b1/0a+c643b5/0a+c643b2/10 + +cartridge sha256:2a2dc2ef84efd9a773d1e8231b7e3e57f0de7e4528968670963f2f1f358eef39 + name:NHL 97 (USA) + cheat + description:Score from anywhere (hold X while in the opponent's half of the rink) + code:c64424/45+c6441e/b1+c64423/78+c6441d/a5+c6441f/0a+c64420/10 + +cartridge sha256:8113c2cedafc8fd5a56c8638ae340fb275f263ff5c5e18d04dc6c3ebc5cfffee + name:NHL 98 (USA) + cheat + description:Score from anywhere (hold X while in the opponent's half of the rink) + code:c6466d/47+c64667/b1+c6466c/c1+c64666/a5+c64668/0a+c64669/10 + +cartridge sha256:d44f487d84f5bb761955b7b70a5464b2f094e199875f595f312c88e04ac647ff + name:NHL Stanley Cup (USA) (En,Fr) + cheat + description:Visitor starts with 1 point (exhibition mode) + code:808a33/01+808a37/08+808a36/f8 + cheat + description:Home starts with 1 point (exhibition mode) + code:808a33/01+808a37/08+808a36/fa + cheat + description:Visitor starts with 3 points (exhibition mode) + code:808a33/03+808a37/08+808a36/f8 + cheat + description:Home starts with 3 points (exhibition mode) + code:808a33/03+808a37/08+808a36/fa + cheat + description:Visitor starts with 5 points (exhibition mode) + code:808a33/05+808a37/08+808a36/f8 + cheat + description:Home starts with 5 points (exhibition mode) + code:808a33/05+808a37/08+808a36/fa + cheat + description:Visitor starts with 7 points (exhibition mode) + code:808a33/07+808a37/08+808a36/f8 + cheat + description:Home starts with 7 points (exhibition mode) + code:808a33/07+808a37/08+808a36/fa + cheat + description:Visitor starts with 9 points (exhibition mode) + code:808a33/09+808a37/08+808a36/f8 + cheat + description:Home starts with 9 points (exhibition mode) + code:808a33/09+808a37/08+808a36/fa + cheat + description:Visitor scores 1 point for goals, Home scores 3 + code:81c861/69 + cheat + description:Periods are 1 min (choose 5 minutes from Options) + code:80f641/01 + cheat + description:Periods are 3 min (choose 5 minutes from Options) + code:80f641/03 + cheat + description:Periods are 7 min (choose 5 minutes from Options) + code:80f641/07 + cheat + description:Periods are 9 min (choose 5 minutes from Options) + code:80f641/09 + cheat + description:Periods are 15 min (choose 10 minutes from Options) + code:80f60a/52 + cheat + description:Periods are 30 min (choose 10 minutes from Options) + code:80f64e/03 + cheat + description:Penalty for charging is 1 minute instead of 2 + code:81d395/3c + cheat + description:Penalty for holding is 1 minute instead of 2 + code:81d39e/3c + cheat + description:Penalty for tripping is 1 minute instead of 2 + code:81d3a7/3c + cheat + description:Penalty for high sticking is 1 minute instead of 2 + code:81d3b0/3c + cheat + description:Penalty for elbowing is 1 minute instead of 2 + code:81d3b9/3c + cheat + description:Penalty for hooking is 1 minute instead of 2 + code:81d3c2/3c + cheat + description:Penalty for roughing is 1 minute instead of 2 + code:81d3cb/3c + cheat + description:Penalty for slashing is 1 minute instead of 4 + code:81d3d4/3c + cheat + description:Penalty for spearing is 1 minute instead of 2 + code:81d3dd/3c + cheat + description:Penalty for charging is 30 seconds + code:81d395/1e + cheat + description:Penalty for holding is 30 seconds + code:81d39e/1e + cheat + description:Penalty for tripping is 30 seconds + code:81d3a7/1e + cheat + description:Penalty for high sticking is 30 seconds + code:81d3b0/1e + cheat + description:Penalty for elbowing is 30 seconds + code:81d3b9/1e + cheat + description:Penalty for hooking is 30 seconds + code:81d3c2/1e + cheat + description:Penalty for roughing is 30 seconds + code:81d3cb/1e + cheat + description:Penalty for slashing is 30 seconds + code:81d3d4/1e + cheat + description:Penalty for spearing is 30 seconds + code:81d3dd/1e + cheat + description:Penalty for charging is 3 minutes + code:81d395/b4 + cheat + description:Penalty for holding is 3 minutes + code:81d39e/b4 + cheat + description:Penalty for tripping is 3 minutes + code:81d3a7/b4 + cheat + description:Penalty for high sticking is 3 minutes + code:81d3b0/b4 + cheat + description:Penalty for elbowing is 3 minutes + code:81d3b9/b4 + cheat + description:Penalty for hooking is 3 minutes + code:81d3c2/b4 + cheat + description:Penalty for roughing is 3 minutes + code:81d3cb/b4 + cheat + description:Penalty for slashing is 3 minutes + code:81d3d4/b4 + cheat + description:Penalty for spearing is 3 minutes + code:81d3dd/b4 + +cartridge sha256:55f3432a130085c112d65aa6443c41eb7a8aeec59aad2c2b4b2ac536b604b449 + name:NHLPA Hockey 93 (USA) + cheat + description:Period clock runs faster + code:8e804c/16 + cheat + description:Period clock runs slower + code:8e804c/04 + cheat + description:Period clock runs much faster + code:8e804c/40 + cheat + description:Period clock runs much slower + code:8e804c/01 + cheat + description:Period clock is frozen (no time limit) + code:8e8052/ad + cheat + description:Each period lasts 1 minute instead of 10 minutes + code:86fcb1/3c+86fcb2/00 + cheat + description:Each period lasts 2 minutes + code:86fcb1/78+86fcb2/00 + cheat + description:Each period lasts 3 minutes + code:86fcb1/b4+86fcb2/00 + cheat + description:Each period lasts 4 minutes + code:86fcb1/f0+86fcb2/00 + cheat + description:Each period lasts 15 minutes + code:86fcb1/84+86fcb2/03 + cheat + description:Each period lasts 30 minutes + code:86fcb1/08+86fcb2/07 + cheat + description:Each period lasts 40 minutes + code:86fcb1/60+86fcb2/09 + cheat + description:Each period lasts 60 minutes + code:86fcb1/10+86fcb2/0e + cheat + description:All penalties last 1 minute + code:80eb66/01+80eb65/a9 + cheat + description:All penalties last 2 minutes + code:80eb66/02+80eb65/a9 + cheat + description:All penalties last 3 minutes + code:80eb66/03+80eb65/a9 + cheat + description:All penalties last 4 minutes + code:80eb66/04+80eb65/a9 + cheat + description:All penalties last 5 minutes + code:80eb66/05+80eb65/a9 + cheat + description:All penalties last 7 minutes + code:80eb66/07+80eb65/a9 + cheat + description:All penalties last 9 minutes + code:80eb66/09+80eb65/a9 + cheat + description:CPU Always Pulls Goalie + code:7e13f5/ff + +cartridge sha256:d7ad6f67860da78fe25d9e79dd13af7ac7efaa0c8e0103898a4849ab4af9e438 + name:Nickelodeon GUTS (USA) + cheat + description:Gain lots of points in Slam Dunk / Attack levels + code:7e126d/ff + +cartridge sha256:ce9c819d6496e58901b39d9b04558a89e09ccc3aac33690b8d02bb0406682a57 + name:Nigel Mansell's World Championship Racing (USA) + cheat + description:Almost no tire wear (graphic distortion in the pits) + code:818d9d/a5+819862/a5 + cheat + description:Only 1 lap required on all tracks + code:80bf6a/f2 + cheat + description:Only 3 laps required in South Africa + code:878066/02 + cheat + description:Only 3 laps required in Mexico + code:878068/02 + cheat + description:Only 3 laps required in Brazil + code:87806a/02 + cheat + description:Only 3 laps required in Spain + code:87806c/02 + cheat + description:Only 3 laps required in San Marino + code:87806e/02 + cheat + description:Only 3 laps required in Monaco + code:878070/02 + cheat + description:Only 3 laps required in Canada + code:878072/02 + cheat + description:Only 3 laps required in France + code:878074/02 + cheat + description:Only 3 laps required in Britain + code:878076/02 + cheat + description:Only 3 laps required in Germany + code:878078/02 + cheat + description:Only 3 laps required in Hungary + code:87807a/02 + cheat + description:Only 3 laps required in Belgium + code:87807c/02 + cheat + description:Only 3 laps required in Italy + code:87807e/02 + cheat + description:Only 3 laps required in Portugal + code:878080/02 + cheat + description:Only 3 laps required in Japan + code:878082/02 + cheat + description:Only 3 laps required in Australia + code:878084/02 + cheat + description:Full season ends after South Africa + code:1fe1f9/01 + cheat + description:Full season ends after Mexico + code:1fe1f9/02 + cheat + description:Full season ends after Brazil + code:1fe1f9/03 + cheat + description:Full season ends after Spain + code:1fe1f9/04 + cheat + description:Full season ends after San Marino + code:1fe1f9/05 + cheat + description:Full season ends after Monaco + code:1fe1f9/06 + cheat + description:Full season ends after Canada + code:1fe1f9/07 + cheat + description:Full season ends after France + code:1fe1f9/08 + cheat + description:Full season ends after Britain + code:1fe1f9/09 + cheat + description:Full season ends after Germany + code:1fe1f9/0a + cheat + description:Full season ends after Hungary + code:1fe1f9/0b + cheat + description:Full season ends after Belgium + code:1fe1f9/0c + cheat + description:Full season ends after Italy + code:1fe1f9/0d + cheat + description:Full season ends after Portugal + code:1fe1f9/0e + cheat + description:Full season ends after Japan + code:1fe1f9/0f + cheat + description:Start in Mexico in the Full Season + code:1f89d5/01 + cheat + description:Start in Brazil + code:1f89d5/02 + cheat + description:Start in Spain + code:1f89d5/03 + cheat + description:Start in San Marino + code:1f89d5/04 + cheat + description:Start in Monaco + code:1f89d5/05 + cheat + description:Start in Canada + code:1f89d5/06 + cheat + description:Start in France + code:1f89d5/07 + cheat + description:Start in Britain + code:1f89d5/08 + cheat + description:Start in Germany + code:1f89d5/09 + cheat + description:Start in Hungary + code:1f89d5/0a + cheat + description:Start in Belgium + code:1f89d5/0b + cheat + description:Start in Italy + code:1f89d5/0c + cheat + description:Start in Portugal + code:1f89d5/0d + cheat + description:Start in Japan + code:1f89d5/0e + cheat + description:Start in Australia + code:1f89d5/0f + cheat + description:Start on extra course (stats are for South Africa but the course is different) + code:1f89d5/10 + +cartridge sha256:620af60cd4a6683871e9339c2db63d87538819af29b3cf967a1729b53a3bd6b3 + name:Nightmare Busters (Europe) (Proto) + cheat + description:Enable Extra Options in options menu + code:7e1f6b/02 + +cartridge sha256:fccc96af24a2463b1c53253e1c5c8ef63641355fae53c0fb410427f29743262b + name:Ninja Gaiden Trilogy (USA) + cheat + description:(NG) Invincibility + code:849f7d/80 + cheat + description:(NG) Infinite health + code:84a3e7/a5 + cheat + description:(NG) Infinite lives + code:84a616/a5 + cheat + description:(NG) Infinite time + code:84bd65/00 + cheat + description:(NG) Start with very little time + code:86afb0/96 + cheat + description:(NG) Start with lots of time + code:86afb0/ff + cheat + description:(NG) Start with very little health (after first life) + code:84a5fb/01 + cheat + description:(NG) Start with about half health (after first life) + code:84a5fb/01 + cheat + description:(NG) Start with 1 life + code:84a870/00 + cheat + description:(NG) Start with 5 lives + code:84a870/03 + cheat + description:(NG) Start with 9 lives + code:84a870/08 + cheat + description:(NGII) Invincibility + code:889220/60 + cheat + description:(NGII) Infinite health + code:889499/a5 + cheat + description:(NGII) Infinite lives + code:888f63/a5 + cheat + description:(NGII) Infinite time + code:888d16/a5 + cheat + description:(NGII) Start with very little health + code:8895e8/01 + cheat + description:(NGII) Start with about half health + code:8895e8/08 + cheat + description:(NGII) Start every life with two Shadow Ninjas + code:88995a/0f + cheat + description:(NGII) Throwing stars don't use Ninja Power (ignore counter) + code:88ad24/01 + cheat + description:(NGII) Start with 1 life + code:8896ea/00 + cheat + description:(NGIII) Invincibility + code:8ccf97/00 + cheat + description:(NGIII) Infinite health + code:8cd2c7/a5 + cheat + description:(NGIII) Infinite lives + code:8c8e51/a9 + cheat + description:(NGIII) Infinite time + code:8cd53f/a5 + cheat + description:(NGIII) Almost infinite Ninja Power + code:8cce3d/a5 + cheat + description:(NGIII) Start with 99 Ninja Power (ignore the counter) + code:8c8ea3/63 + cheat + description:(NGIII) Start with 1 life + code:8c8e96/00 + cheat + description:(NGIII) Start with 5 lives + code:8c8e96/03 + cheat + description:(NGIII) Start with 9 lives + code:8c8e96/08 + cheat + description:(NGIII) Start with very little health + code:8c8eb0/01 + cheat + description:(NGIII) Start with about half health + code:8c8eb0/08 + 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 + name:Ninjawarriors (USA) + cheat + description:Invincibility + code:029c4e/f0+02b701/f0+029c60/d0+029c65/d0+02b70d/d0 + cheat + description:Infinite health + code:029842/ad + cheat + description:Infinite time + code:00ae20/8d + cheat + description:Infinite specials once you obtain one + code:00af9a/af + cheat + description:One hit kills + code:038cbf/a9+038cc0/00+038cc1/00+02a3f0/a9+02a3f1/00+02a3f2/00 + cheat + description:Go to stage select menu (disable once the menu loads) + code:7e0000/0a + +cartridge sha256:f099937ac4c8afb38c517c5d85475224985fb8f345dacb44994a617ea05bf4e5 + name:No Escape (USA) + cheat + description:Infinite health + code:80dec6/b7 + cheat + description:Infinite time + code:8c962d/a9 + cheat + description:Infinite lives + code:80dc1b/b2 + +cartridge sha256:7f3d0ebac6ecfb99cfd1d5b13210e989df9e8b2f2319a63c42faef8ad115a964 + name:Nolan Ryan's Baseball (USA) + cheat + description:1 strike and batter is out + code:019a10/ce + cheat + description:Batter never strikes out + code:019a10/ad + cheat + description:1 ball and batter walks + code:0199f2/ce + cheat + description:Batter never walks + code:0199f2/ad + cheat + description:Each run worth 2 - P1 + code:01cda2/38 + cheat + description:Each run worth 2 - P2 + code:01cdb8/38 + cheat + description:Short game (play only odd-numbered innings) + code:018e0f/38 + cheat + description:Increasing a player's power setting does not decrease the power number excess (use to maximize stats for a player) + code:02a0bd/00 + cheat + description:Maximum power for a player is 32 instead of 25 + code:029f1f/20 + cheat + description:Maximum power for a player is 40 instead of 25 + code:029f1f/28 + cheat + description:Maximum power for a player is 48 + code:029f1f/30 + +cartridge sha256:9712829b38f23229d4e3d65da78237659c790235f425c6b12487e4d9e9a37ae9 + name:Nosferatu (USA) + cheat + description:Almost infinite health + code:8099c5/a5 + cheat + description:Infinite time + code:80dc32/a6 + cheat + description:Don't lose crystals when you get hit + code:848372/ad + cheat + description:Start with very little health + code:809fd8/01 + cheat + description:Start with less health + code:809fd8/03 + cheat + description:Start with more health + code:809fd8/09 + cheat + description:Start with a lot more health + code:809fd8/0f + cheat + description:Start with more time + code:80a2f3/a9+80a2f4/22+80a2f5/00 + cheat + description:Start on stage 1-2 + code:809fe3/06 + cheat + description:Start on stage 1-3 + code:809fe3/09 + cheat + description:Start on stage 2 + code:809fe3/0a + cheat + description:Start on stage 2-2 + code:809fe3/10 + cheat + description:Start on stage 2-3 + code:809fe3/11 + cheat + description:Start on stage 2-4 + code:809fe3/17 + cheat + description:Start on stage 3 + code:809fe3/18 + cheat + description:Start on stage 3-2 + code:809fe3/20 + cheat + description:Start on stage 3-3 + code:809fe3/24 + cheat + description:Start on stage 4 + code:809fe3/27 + cheat + description:Start on stage 4-2 + code:809fe3/2d + cheat + description:Start on stage 4-3 + code:809fe3/2e + cheat + description:Start on stage 4-4 + code:809fe3/34 + cheat + description:Start on stage 5 + code:809fe3/35 + cheat + description:Start on stage 5-2 + code:809fe3/3b + cheat + description:Start on stage 5-3 + code:809fe3/3c + cheat + description:Start on stage 5-4 + code:809fe3/45 + cheat + description:Start on stage 6 + code:809fe3/46 + cheat + description:Start on stage 6-2 + code:809fe3/4e + cheat + description:Start on the final stage + code:809fe3/54 + cheat + description:Start on the final stage with more crystals + code:809fe3/54+809fe7/8d + cheat + description:View the ending + code:809fe3/56 + +cartridge sha256:31bc862ab0a8eabf23b5124e13940cb3501e7ecdd3f15e34142248ceb4aa139a + name: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 + name:Ogre Battle - The March of the Black Queen (USA) + cheat + description:Level up after every battle (even if you run away) + code:04db14/00 + 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:02fb3d/a9+02fb42/9d+02fb43/da+02fb44/0a + cheat + description:View someone's stats from 'Edit Units' screen to give them max Luck + code:068730/a9+068731/ff+068732/ea+068733/9f + cheat + description:View someone's stats from 'Edit Units' screen to give them max Cha + code:06871c/a9+06871d/65+06871e/ea+06871f/9f + cheat + description:Every hidden thing is visible when you first enter an area + code:0583c3/a9+0583c5/a9+0583c6/ff + cheat + description:Leader's group moves 'Sky High' + code:82fd82/00 + cheat + description:Lans' group moves 'Sky High' + code:82fd36/00 + cheat + description:Judgement tarot card is stronger + code:03dd4d/ff + +cartridge sha256:e153195de7b59dd5b9854952cccca6bb93164e5fdff8292124bee6bbe5dbf16f + name:On the Ball (USA) + cheat + description:Infinite credits + code:01ccf6/ad + cheat + description:Faster timer + code:009899/02 + cheat + description:Stop timer - not lap timer (can still lose time by hitting hazards) + code:009899/00 + cheat + description:Minus blocks and bricks worth 0 (don't combine with other minus codes) + code:0098cc/ad + cheat + description:Minus 2 second block worth 0 + code:019d33/00 + cheat + description:Minus 2 second block worth minus 1 + code:019d33/10 + cheat + description:Minus 2 second block worth minus 3 + code:019d33/30 + cheat + description:Minus 2 second block worth minus 4 + code:019d33/40 + cheat + description:Minus 2 second block worth minus 5 + code:019d33/50 + cheat + description:Minus 2 second block worth minus 6 + code:019d33/60 + cheat + description:Minus 2 second block worth minus 7 + code:019d33/70 + cheat + description:Minus 2 second block worth minus 8 + code:019d33/80 + cheat + description:Minus 2 second block worth minus 9 + code:019d33/90 + cheat + description:Minus 5 second block worth 0 + code:019d46/00 + cheat + description:Minus 5 second block worth minus 1 + code:019d46/10 + cheat + description:Minus 5 second block worth minus 2 + code:019d46/20 + cheat + description:Minus 5 second block worth minus 3 + code:019d46/30 + cheat + description:Minus 5 second block worth minus 4 + code:019d46/40 + cheat + description:Minus 5 second block worth minus 6 + code:019d46/60 + cheat + description:Minus 5 second block worth minus 7 + code:019d46/70 + cheat + description:Minus 5 second block worth minus 8 + code:019d46/80 + cheat + description:Minus 5 second block worth minus 9 + code:019d46/90 + cheat + description:Minus 3 second brick worth 0 + code:019d59/00 + cheat + description:Minus 3 second brick worth minus 1 + code:019d59/10 + cheat + description:Minus 3 second brick worth minus 2 + code:019d59/20 + cheat + description:Minus 3 second brick worth minus 4 + code:019d59/40 + cheat + description:Minus 3 second brick worth minus 5 + code:019d59/50 + cheat + description:Minus 3 second brick worth minus 6 + code:019d59/60 + cheat + description:Minus 3 second brick worth minus 7 + code:019d59/70 + cheat + description:Minus 3 second brick worth minus 8 + code:019d59/80 + cheat + description:Minus 3 second brick worth minus 9 + code:019d59/90 + cheat + description:Plus bricks worth 0 (don't combine with other plus bricks codes) + code:0098b7/ad + cheat + description:Plus 3 bricks worth 0 + code:019d93/00 + cheat + description:Plus 3 bricks worth plus 1 + code:019d93/10 + cheat + description:Plus 3 bricks worth plus 2 + code:019d93/20 + cheat + description:Plus 3 bricks worth plus 4 + code:019d93/40 + cheat + description:Plus 3 bricks worth plus 5 + code:019d93/50 + cheat + description:Plus 3 bricks worth plus 6 + code:019d93/60 + cheat + description:Plus 3 bricks worth plus 7 + code:019d93/70 + cheat + description:Plus 3 bricks worth plus 8 + code:019d93/80 + cheat + description:Plus 3 bricks worth plus 9 + code:019d93/90 + cheat + description:Plus 5 bricks worth 0 + code:019da6/00 + cheat + description:Plus 5 bricks worth plus 1 + code:019da6/10 + cheat + description:Plus 5 bricks worth plus 2 + code:019da6/20 + cheat + description:Plus 5 bricks worth plus 3 + code:019da6/30 + cheat + description:Plus 5 bricks worth plus 4 + code:019da6/40 + cheat + description:Plus 5 bricks worth plus 6 + code:019da6/60 + cheat + description:Plus 5 bricks worth plus 7 + code:019da6/70 + cheat + description:Plus 5 bricks worth plus 8 + code:019da6/80 + cheat + description:Plus 5 bricks worth plus 9 + code:019da6/90 + cheat + description:Start with 2 credits + code:018083/01 + cheat + description:Start with 6 credits + code:018083/05 + cheat + description:Start with 8 credits + code:018083/07 + cheat + description:Start with 10 credits + code:018083/09 + +cartridge sha256:190742792a950a112f893cba0e083eb787cf24293f698967defff929635ba0e7 + name:Operation Logic Bomb - The Ultimate Search & Destroy (USA) + cheat + description:Infinite health + code:819070/ad + cheat + description:Take minimal damage + code:80aa8d/ee + cheat + description:Faster left-to-right movement + code:8191d5/fd+8191cd/02 + cheat + description:Faster up-and-down movement + code:819207/fd+8191e7/02 + cheat + description:Reflecting laser fire travels longer + code:8194d8/60 + cheat + description:Reflecting laser fire travels a lot longer + code:8194d8/ff + cheat + description:Start with 1 continue + code:809924/01 + cheat + description:Start with 6 continues + code:809924/06 + cheat + description:Start with 9 continues + code:809924/09 + cheat + description:Start with tracking missiles + code:809902/03+8098f0/20+809904/24 + cheat + description:Start with reflecting laser + code:809902/04+8098f0/20+809904/24 + cheat + description:Start with flame thrower + code:809902/05+8098f0/20+809904/24 + cheat + description:Start with hologram weapon + code:809914/01+809918/9c+80991b/9c + cheat + description:Start with directional mines + code:809914/02+809918/9c+80991b/9c + 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 + name:Operation Starfi5h (Europe) + cheat + description:Infinite health + code:7efb05/03 + cheat + description:Infinite lives + code:7efb03/03 + +cartridge sha256:5cbed0401734142184166917427d24f9e5f107a7adea665e2f4b4101491ad54b + name: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 + name: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 + cheat + description:Multi-jump + code:7e0c7e/00+7e0c7f/00 + +cartridge sha256:db44f8b58a31b640a47aa4390101c3c6a5f613e4e49c636d44786278033dec19 + name:Outlander (USA) + cheat + description:Infinite health while in the car + code:808e45/ad+008e45/ad + cheat + description:Almost infinite health while out of the car (except when you eat poisonous food) + code:90908d/a5 + cheat + description:Infinite handgun ammo + code:90885f/00 + cheat + description:Infinite surface-to-air missiles on pick-up + code:81b67c/ad + cheat + description:Car ammo worth nothing on pick-up + code:908a3b/00 + cheat + description:Car ammo worth more on pick-up + code:908a3c/02 + cheat + description:Water worth nothing on pick-up + code:908ae3/00 + cheat + description:Water worth more on pick-up + code:908ae4/01 + cheat + description:Hand gun ammo worth nothing on pick-up + code:908a82/00 + cheat + description:Food worth nothing on pick-up + code:908ac0/00 + cheat + description:Gas can worth nothing on pick-up + code:908a11/00 + cheat + description:Gas can worth more on pick-up + code:908a12/02 + cheat + description:Start with more car ammo + code:81b84f/05 + cheat + description:Start with less car ammo + code:81b84f/00 + cheat + description:Start with more handgun ammo + code:81b854/6c + cheat + description:Start with less handgun ammo + code:81b854/10 + cheat + description:Start with more fuel + code:81b846/02 + +cartridge sha256:582548dc86598a3557e9e3c27285c81964b006a954affe5c73948da5375ea11c + name: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 + name:Out to Lunch (USA) + cheat + description:Invincibility + code:7e0002/c8 + cheat + description:Infinite lives + code:7e0088/63 + cheat + description:Infinite time + code:7e008a/a9 + cheat + description:Score modifier + code:7e0009/63 + cheat + description:Start with Net + code:7e009e/01 + cheat + description:Start with Bag Of Flour (choose one) + code:7e009f/01 + cheat + description:Start with hot sauce attack (choose one) + code:7e009f/02 + cheat + description:Start with spoon (choose one) + code:7e009f/03 + cheat + description:Start with Cleats + code:7e00a2/01 + cheat + description:Exit is open + code:7e00be/00 + cheat + description:Hidden warp is open (whenever available) + code:7e000b/01 + +cartridge sha256:10c8abce67b49f8afbe880d2f13e0fd6d5efc162df34d5941e4a94851f23b2ff + name:Pac-Attack (USA) + cheat + description:Fairy bar is always full (normal mode) + code:7e160e/ff + +cartridge sha256:7fe4cb9c294d66589ff78e225774471ecb7db80df25f2b6199ca25671358072b + name: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 + name:Pac-Man 2 - The New Adventures (USA) + cheat + description:Infinite power pellets + code:82b7b4/ad + 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 + name:Paladin's Quest (USA) + cheat + description:Level 99 after one battle + code:018aed/80+018af9/80 + cheat + description:Infinite health + code:019e79/64 + cheat + description:Spells use up no HP + code:01b3f5/64 + cheat + description:No money needed in toolhouse and weapon shop + code:0dbaba/9c + cheat + description:No money needed in learning center + code:07edca/9c + cheat + description:Spell power increases at 2x normal rate + code:0188e9/04 + cheat + description:Spell power increases at 3x normal rate + code:0188e9/06 + cheat + description:Chezni starts with 255 max HP + code:08f691/ff + cheat + description:Chezni starts with 255 present HP + code:08f68f/ff + cheat + description:Chezni starts with 40 Power, 42 Attack + code:08f693/28 + cheat + description:Chezni starts with 60 Power, 62 Attack + code:08f693/3c + cheat + description:Chezni starts with 42 Defense, 30 Endurance + code:08f697/1e + cheat + description:Chezni starts with 72 Defense, 60 Endurance + code:08f697/3c + cheat + description:Chezni starts with 30 Speed + code:08f695/1e + cheat + description:Chezni starts with 60 Speed + code:08f695/3c + cheat + description:Chezni starts with a bow + code:08f2c5/08 + cheat + description:Chezni starts with a light sword + code:08f2c5/0d + cheat + description:Chezni starts with a mid sword + code:08f2c5/10 + cheat + description:Chezni starts with a Aybro Spear + code:08f2c5/1a + cheat + description:Chezni starts with a heavy sword + code:08f2c5/17 + cheat + description:Chezni starts with a wind sword + code:08f2c5/30 + cheat + description:Chezni starts with HST + code:08f2c5/34 + cheat + description:Chezni starts with Gomutai + code:08f2c5/51 + cheat + description:Chezni starts with a Psych Beam + code:08f2c5/72 + cheat + description:Chezni starts with a flame thrower + code:08f2c5/73 + cheat + description:Chezni starts with light armor + code:08f2c6/0b + cheat + description:Chezni starts with mid armor + code:08f2c6/0f + cheat + description:Chezni starts with heavy armor + code:08f2c6/1c + cheat + description:Chezni starts with storm armor + code:08f2c6/31 + cheat + description:Chezni starts with bib + code:08f2c6/33 + cheat + description:Chezni starts with wood boots + code:08f2c7/02 + cheat + description:Chezni starts with long boots + code:08f2c7/1b + cheat + description:Chezni starts with knife boots + code:08f2c7/24 + cheat + description:Chezni starts with mid boots + code:08f2c7/15 + cheat + description:Chezni starts with sun helm + code:08f2c3/32 + cheat + description:Chezni starts with leather helm + code:08f2c3/05 + cheat + description:Chezni starts with helmet + code:08f2c3/0c + cheat + description:Chezni starts with rage helmet + code:08f2c3/2c + cheat + description:Chezni starts with power helmet + code:08f2c3/16 + cheat + description:Chezni starts with cosmo helmet + code:08f2c3/77 + cheat + description:Chezni starts with gabni shield + code:08f2c4/35 + cheat + description:Chezni starts with leather shield + code:08f2c4/36 + cheat + description:Chezni starts with pick-axe + code:08f2c4/09 + cheat + description:Chezni starts with gauntlet + code:08f2c4/14 + cheat + description:Chezni starts with fire shield + code:08f2c4/19 + cheat + description:Chezni starts with Rft shield + code:08f2c4/75 + 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 + name:Paperboy 2 (USA) + cheat + description:Infinite papers + code:00b8ba/00 + cheat + description:Infinite time in training course + code:018438/00 + cheat + description:Infinite lives (game still ends when all subscriptions are canceled) + code:009af9/00 + cheat + description:Paper bundles worth 0 if you have less than 10 + code:018206/00 + cheat + description:Paper bundles worth 5 if you have less than 10 + code:018206/05 + cheat + description:Paper bundles worth 20 if you have less than 10 + code:018206/14 + cheat + description:Paper bundles worth 30 if you have less than 10 + code:018206/1e + cheat + description:Paper bundles worth 40 if you have less than 10 + code:018206/28 + cheat + description:Paper bundles worth 50 if you have less than 10 + code:018206/32 + cheat + description:Continue next life with 1 paper if you had less than 10 + code:00a567/01 + cheat + description:Continue next life with 5 papers if you had less than 10 + code:00a567/05 + cheat + description:Continue next life with 20 papers if you had less than 10 + code:00a567/14 + cheat + description:Continue next life with 30 papers if you had less than 10 + code:00a567/1e + cheat + description:Continue next life with 40 papers if you had less than 10 + code:00a567/28 + cheat + description:Continue next life with 50 papers if you had less than 10 + code:00a567/32 + cheat + description:Start with 79 seconds instead of 39 in Week 1 training course + code:0183c3/09 + cheat + description:Start with 59 seconds in Week 1 training course + code:0183c3/07 + cheat + description:Start with 19 seconds in Week 1 training course + code:0183c3/03 + cheat + description:Start with 25 papers instead of 10 + code:00a087/19 + cheat + description:Start with 50 papers + code:00a087/32 + cheat + description:Start with 99 papers + code:00a087/63 + cheat + description:Start with 1 life instead of 5 - Paperboy + code:009f1e/01 + cheat + description:Start with 3 lives - Paperboy + code:009f1e/03 + cheat + description:Start with 7 lives - Paperboy + code:009f1e/07 + cheat + description:Start with 9 lives - Paperboy + code:009f1e/09 + cheat + description:Start with 25 lives - Paperboy + code:009f1e/19 + cheat + description:Start with 50 lives - Paperboy + code:009f1e/32 + cheat + description:Start with 99 lives - Paperboy + code:009f1e/63 + cheat + description:Start with 1 life instead of 5 - Papergirl + code:009f70/01 + cheat + description:Start with 3 lives - Papergirl + code:009f70/03 + cheat + description:Start with 7 lives - Papergirl + code:009f70/07 + cheat + description:Start with 9 lives - Papergirl + code:009f70/09 + cheat + description:Start with 25 lives - Papergirl + code:009f70/19 + cheat + description:Start with 50 lives - Papergirl + code:009f70/32 + cheat + description:Start with 99 lives - Papergirl + code:009f70/63 + +cartridge sha256:14ad9d2fb8e6bb0f49bc9e53f3c472177653d1c24102169ade308a2fab8a8888 + name:Parodius Da! - Shinwa kara Owarai e (Japan) + cheat + description:Infinite lives + code:7e0098/03 + +cartridge sha256:c414a4084b3d03aba19496d2efdd68fcf826194d8f1308f5c98e3a7af2fcc063 + name:Peace Keepers, The (USA) + cheat + description:Invincibility + code:80de55/ad + cheat + description:Infinite health + code:80e063/8f+80e064/94+80e065/06+80e066/7e + cheat + description:One hit kills + code:83daac/64 + cheat + description:Hit anywhere + code:81ca6c/e0+81ca70/7b+81ca6d/00+81ca6e/07+81ca6f/10 + +cartridge sha256:5c0b5266a191852ca593235f07180e673cb79e3f0b0dd31f65808eef83bf6e90 + name:PGA Tour Golf (USA) + cheat + description:Ball goes in from anywhere + code:00b27f/80+00afa0/80 + cheat + description:Allow 14 clubs for full set instead of 13 + code:00ee71/0d+00d4c9/0d + cheat + description:Allow 15 clubs for full set + code:00ee71/0e+00d4c9/0e + cheat + description:Allow 16 clubs for full set + code:00ee71/0f+00d4c9/0f + cheat + description:No wind + code:00aeb0/80 + cheat + description:Constant wind of 10 mph + code:00aeb0/a9+00aeb2/00+00aeb1/0a + cheat + description:Constant wind direction to the left + code:00aec8/9c + cheat + description:Each round ends after hole 1 + code:00cb3d/01 + cheat + description:Each round ends after hole 2 + code:00cb3d/02 + cheat + description:Each round ends after hole 3 + code:00cb3d/03 + cheat + description:Each round ends after hole 4 + code:00cb3d/04 + cheat + description:Each round ends after hole 5 + code:00cb3d/05 + cheat + description:Each round ends after hole 6 + code:00cb3d/06 + cheat + description:Each round ends after hole 7 + code:00cb3d/07 + cheat + description:Each round ends after hole 8 + code:00cb3d/08 + cheat + description:Each round ends after hole 9 + code:00cb3d/09 + cheat + description:Each round ends after hole 10 + code:00cb3d/0a + cheat + description:Each round ends after hole 11 + code:00cb3d/0b + cheat + description:Each round ends after hole 12 + code:00cb3d/0c + cheat + description:Each round ends after hole 13 + code:00cb3d/0d + cheat + description:Each round ends after hole 14 + code:00cb3d/0e + cheat + description:Each round ends after hole 15 + code:00cb3d/0f + cheat + description:Each round ends after hole 16 + code:00cb3d/10 + cheat + description:Each round ends after hole 17 + code:00cb3d/11 + +cartridge sha256:0663330bc061f4b768fa1806610878ef6e6cf546f36041ae087c8e55703693b8 + name:Phalanx (USA) + cheat + description:Infinite health + code:00d761/ea + cheat + description:Infinite lives + code:00d6cb/00 + cheat + description:Infinite credits + code:0088e1/00 + cheat + description:Hit anywhere + code:00e240/ad+00e228/00+00e22d/00+00e219/00+00e21e/00 + cheat + description:Once power-up has been obtained, it is not lost until you continue (doesn't work for weapon, only power-ups) + code:00d85f/ad + cheat + description:Power capsule restores armor to full strength + code:00d6e3/50+00d6e4/83 + cheat + description:Power capsule has no effect on armor or power-up + code:00d6e2/60 + cheat + description:Start with 1 credit instead of 4 + code:1fc9bf/01+1fd109/01 + cheat + description:Start with 2 credits + code:1fc9bf/02+1fd109/02 + cheat + description:Start with 3 credits + code:1fc9bf/03+1fd109/03 + cheat + description:Start with 5 credits + code:1fc9bf/05+1fd109/05 + cheat + description:Start with 7 credits + code:1fc9bf/07+1fd109/07 + cheat + description:Start with 10 credits + code:1fc9bf/10+1fd109/10 + cheat + description:Start with 1 life + code:1fc9b3/01+1fd102/01 + cheat + description:Start with 2 lives + code:1fc9b3/02+1fd102/02 + cheat + description:Start with 3 lives + code:1fc9b3/03+1fd102/03 + cheat + description:Start with 4 lives + code:1fc9b3/04+1fd102/04 + cheat + description:Start with 6 lives + code:1fc9b3/06+1fd102/06 + cheat + description:Start with 11 lives + code:1fc9b3/11+1fd102/11 + cheat + description:Start with 26 lives + code:1fc9b3/26+1fd102/26 + cheat + description:Start with 51 lives + code:1fc9b3/51+1fd102/51 + cheat + description:Start with 100 lives + code:1fc9b3/9a+1fd102/9a + cheat + description:Start on mission 2 + code:1fd110/02+1fc9cb/02 + cheat + description:Start on mission 3 + code:1fd110/03+1fc9cb/03 + cheat + description:Start on mission 4 + code:1fd110/04+1fc9cb/04 + cheat + description:Start on mission 5 + code:1fd110/05+1fc9cb/05 + cheat + description:Start on mission 6 + code:1fd110/06+1fc9cb/06 + cheat + description:Start on mission 7 + code:1fd110/07+1fc9cb/07 + cheat + description:Start on mission 8 + code:1fd110/08+1fc9cb/08 + 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 + name:Phantom 2040 (USA) (Beta) + cheat + description:Invincibility after first hit + code:81833e/ee + cheat + description:Infinite lives + code:81c614/ad + cheat + description:Infinite weapon energy + code:81c5cb/ad + cheat + description:Access all weapons (highlight weapon and press X to equip) + code:81e798/9d + cheat + description:Invincibility + code:7e0410/dc + cheat + description:Moonjump + code:7e0294/06 + cheat + description:Have Wave Gun + code:7e0cd3/01 + cheat + description:Have Blank Space + code:7e0cd4/01 + cheat + description:Have Spread + code:7e0cd5/01 + cheat + description:Have Devestator + code:7e0cd6/01 + cheat + description:Have Homing Missile + code:7e0cd7/01 + cheat + description:Have Breaker + code:7e0cd8/01 + cheat + description:Have Boomerang + code:7e0cd9/01 + cheat + description:Have Explosive Pellets + code:7e0cda/01 + cheat + description:Have Super Explosive Pellets + code:7e0cdb/01 + cheat + description:Have Flash Pellets + code:7e0cdc/01 + cheat + description:Have Fire Retardant Pellets + code:7e0cdd/01 + cheat + description:Have Shadow Panther + code:7e0cde/01 + cheat + description:Have Invisibility + code:7e0cdf/01 + cheat + description:Have Armor + code:7e0ce0/01 + cheat + description:Have First Aid Kit + code:7e0ce1/01 + cheat + description:Have Energy Aid Kit + code:7e0ce2/01 + +cartridge sha256:b7291088f5c49e1fc55bf932076ec03f7b39f6e409ae06e884b57024c56cdc87 + name:Phantom 2040 (USA) + cheat + description:Invincibility + code:818370/ee+81836b/ee + cheat + description:Infinite lives + code:81c718/8d + cheat + description:Infinite weapon energy + code:81c6d6/ad + cheat + description:Access all weapons (highlight weapon and press X to equip) + code:81e7f4/de + cheat + description:Super jump 2X + code:819102/f6 + cheat + description:Super jump 3X + code:819102/f1 + cheat + description:Walk through walls (horizontal) + code:81cd13/18 + cheat + description:Invincibility (alt) + code:7e0410/dc + cheat + description:Moonjump + code:7e0294/06 + cheat + description:Have Wave Gun + code:7e0fd3/01 + cheat + description:Have Blank Space + code:7e0fd4/01 + cheat + description:Have Spread + code:7e0fd5/01 + cheat + description:Have Devestator + code:7e0fd6/01 + cheat + description:Have Homing Missile + code:7e0fd7/01 + cheat + description:Have Breaker + code:7e0fd8/01 + cheat + description:Have Boomerang + code:7e0fd9/01 + cheat + description:Have Explosive Pellets + code:7e0fda/01 + cheat + description:Have Super Explosive Pellets + code:7e0fdb/01 + cheat + description:Have Flash Pellets + code:7e0fdc/01 + cheat + description:Have Fire Retardant Pellets + code:7e0fdd/01 + cheat + description:Have Shadow Panther + code:7e0fde/01 + cheat + description:Have Invisibility + code:7e0fdf/01 + cheat + description:Have Armor + code:7e0fe0/01 + cheat + description:Have First Aid Kit + code:7e0fe1/01 + cheat + description:Have Energy Aid Kit + code:7e0fe2/01 + +cartridge sha256:a0b39d7fd7c39c5b0f41f3542fb8d2887530ded1c111b4ffb2a863845e704ecc + name:Pieces (USA) + cheat + description:Place pieces anywhere to auto place + code:c08261/00+c08267/00 + +cartridge sha256:03d0127f5de3237e22ad00de0c20763274da7b71142dde693240ac96d10983a3 + name:Pilotwings (USA) + cheat + description:Infinite fuel + code:00bd07/64 + cheat + description:Infinite time (disable to detach hang glider from plane) + code:01bff4/00 + cheat + description:Reduce gravity + code:80f631/20 + cheat + description:Increase gravity + code:80f631/a0 + cheat + description:Increase rocket pack thrust power 3x + code:00f615/fd + +cartridge sha256:3a52bf09850aa054dca443f7ea74d43f201dffecc40326924ecba9b0f1450e43 + name:Pinball Dreams (USA) + cheat + description:Slow motion + code:808be0/a3 + cheat + description:Ball attracts to the top + code:80a650/6e + cheat + description:Ball attracts to the side + code:80a610/6e + cheat + description:Spastic ball + code:80a6a1/9f + +cartridge sha256:0888d20ab2f834c77b0a2dc2162c43890a1640adc78c6b0bb5892ca8d5008ad3 + name:Pinball Fantasies (USA) + cheat + description:Infinite balls + code:7e00b8/03 + +cartridge sha256:d0f4a5040ecf96dc49aa0084160e291a38f2ee75319750db4d6687ab36828da9 + name:Pink Goes to Hollywood (USA) + cheat + description:Invincibility + code:83924f/60+839756/60+839667/60 + cheat + description:Invincibility (alt) + code:7e0201/ff + cheat + description:Infinite lives + code:7e01ff/03 + cheat + description:Infinite time + code:7e0203/09 + cheat + description:Have 99 tricks + code:7e0217/99 + cheat + description:Have 9 of every token + code:7e01b9/09+7e01bb/09+7e01bd/09+7e01bf/09+7e01c1/09 + +cartridge sha256:fe7b861504886b40207d777cfc0dce76778b5fd8e679a67d04c9ded98cd1e59e + name:Pinocchio (Europe) + cheat + description:Infinite health + code:7e03d8/28 + cheat + description:Infinite lives + code:7e03de/03 + +cartridge sha256:98c51c3bb577600fe79577c323333a791baa30904f37c695890e6e380b75e3c8 + name:Pinocchio (USA) + cheat + description:Infinite health + code:7e03d8/50 + cheat + description:Infinite lives + code:7e03de/05 + cheat + description:Enable level select + code:7e201c/ff + +cartridge sha256:447dfa710e69479159e9d407474fbf5f67d3a3330ab0c7627afd123ded3fdb3a + name:Pirates of Dark Water, The (USA) + cheat + description:Invincibility + code:80b89c/ad + cheat + description:Health refills about every 15 seconds + code:80b5df/21+80b5e0/07 + cheat + description:Infinite health + code:80b5db/00 + cheat + description:Infinite health (alt) + code:82df9c/8d+82df9a/a9+82df9b/58 + cheat + description:Infinite special attacks (no health loss) + code:80c570/00 + cheat + description:Infinite lives + code:80b546/ad + cheat + description:Hit anywhere + code:80c24c/24+80c3cd/24+80c22d/8d+80c254/80+80c358/80+80c217/80+80c22e/37+80c22f/07+80c218/14 + cheat + description:One hit kills + code:80c713/ea+80c714/ea+80c715/a9+80c716/7f + cheat + description:1/2 health after 1st hit (1st life only) + code:858d74/20+838ce9/20 + cheat + description:Start with less health (after 1st life) + code:809644/20 + cheat + description:Start with 6 lives (not when joining in) + code:80a8b3/05 + cheat + description:Start with 2 lives (not when joining in) + code:80a8b3/01 + +cartridge sha256:c2a1a66648a0a0bfe2f201cf4f926d138e410fbf85ecf436ccb9aac70c0df3de + name:Pit-Fighter (USA) + cheat + description:Infinite super powers after gaining one + code:01e2dd/00 + cheat + description:Executioner in match 1 has less health + code:00a58c/64 + cheat + description:Executioner in match 1 has more health + code:00a58d/01 + cheat + description:C.C. has less health in match 2 + code:00a59c/64+00a59d/00 + cheat + description:C.C. has more health in match 2 + code:00a59d/02 + cheat + description:Angel has less health in match 3 + code:00a5bc/64 + cheat + description:Angel has more health in match 3 + code:00a5bd/01 + cheat + description:All opponents have less health + code:00bd70/a2+00bd71/00+00a58c/64 + cheat + description:All opponents have more health + code:00bd70/a2+00bd71/00+00a58c/64+00a58d/02 + cheat + description:Start with more health + code:019318/ff + cheat + description:Start with less health + code:019318/32 + cheat + description:Start with a lot more health + code:01931e/02 + cheat + description:Start with 3 super powers + code:0194ee/03 + +cartridge sha256:e03d117d8b3093b0bbad5224638f85378b254b81eb304e506a732b4338802e0f + name:Pitfall - The Mayan Adventure (USA) + cheat + description:Infinite Stones of Pacal + code:81c782/00 + cheat + description:Infinite Sling Stones + code:81c57d/00 + cheat + description:Infinite Boomerangs + code:81c37d/00 + cheat + description:Walk through walls + code:808623/80 + cheat + description:Jump through ceilings + code:8089b4/80 + cheat + description:Get 2x energy from sacred hearts + code:838092/32 + cheat + description:Get 3x energy from sacred hearts + code:838092/4b + cheat + description:Sling stones do mega-damage + code:81c626/32 + cheat + description:Time keeper power-up lasts longer + code:8382a0/f0+8382a1/02 + cheat + description:20 Stones of Pacal on pick-up + code:838101/14 + cheat + description:Moon-jump + code:818a1f/00 + cheat + description:Reset game to play original Pitfall infinitely + code:809575/0e + cheat + description:Replaces main game with original Pitfall + code:83b057/0e + cheat + description:Start with 10 lives + code:818a9b/09+83af88/09 + cheat + description:Start with 7 lives + code:818a9b/06+83af88/06 + cheat + description:Start with 2 lives + code:818a9b/01+83af88/01 + 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 + name:Pocky & Rocky (USA) + cheat + description:Infinite health - Pocky + code:04ebed/a5 + cheat + description:Infinite health - Rocky + code:04effd/a5 + cheat + description:Infinite time + code:00d404/a9 + cheat + description:Infinite lives - Pocky + code:01cf32/00 + cheat + description:Infinite lives - Rocky + code:01e97e/00 + cheat + description:Enable level select (pause and press select) + code:009ae8/80 + cheat + description:Weapons don't deplete when hit - Pocky + code:04ebd8/24 + cheat + description:Weapons don't deplete when hit - Pocky + code:04efe4/24 + cheat + description:Blue ball acts as red ball - Pocky + code:04ea14/02 + cheat + description:Red ball acts as blue ball - Pocky + code:04ea0b/01 + cheat + description:Blue ball acts as red ball - Rocky + code:04ee97/02 + cheat + description:Red ball acts as blue ball - Rocky + code:04ee8e/01 + cheat + description:9 lives stolen from Rocky (must have one life remaining) + code:01c3c2/09 + cheat + description:9 lives stolen from Pocky (must have one life remaining) + code:01e4c2/09 + cheat + description:Start with 1 life - Pocky + code:008bdc/01 + cheat + description:Start with 6 lives - Pocky + code:008bdc/06 + cheat + description:Start with 9 lives - Pocky + code:008bdc/09 + cheat + description:Start with 1 life - Rocky + code:008bdd/01 + cheat + description:Start with 6 lives - Rocky + code:008bdd/06 + cheat + description:Start with 9 lives - Rocky + code:008bdd/09 + 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 + name: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 + name:Pop'n TwinBee - Rainbow Bell Adventures (Europe) + cheat + description:Infinite health + code:7e02ec/64 + +cartridge sha256:5e580f220ed16281df8ee9a5f450b553f39f8c4078d3f3048d66bda15f98e19f + name:Populous (USA) + cheat + description:Allows you to select any world from the Conquer screen with the B and X buttons + code:00e248/00 + cheat + description:Your population starts at 10 instead of 3 for battles 0-4 + code:0186a5/0a + cheat + description:Your population starts at 20 for battles 0-4 + code:0186a5/14 + cheat + description:Your population starts at 30 for battles 0-4 + code:0186a5/1e + cheat + description:His population starts at 10 instead of 3 for battles 0-4 + code:0186a6/0a + cheat + description:His population starts at 20 for battles 0-4 + code:0186a6/14 + cheat + description:His population starts at 30 for battles 0-4 + code:0186a6/1e + cheat + description:You have no Supreme Commands available for battles 0-4 + code:0186a2/00 + cheat + description:He has all Supreme Commands available for battles 0-4 + code:0186a1/3f + cheat + description:Your population starts at 10 instead of 3 for battles 5-9 + code:0186af/0a + cheat + description:Your population starts at 20 for battles 5-9 + code:0186af/14 + cheat + description:Your population starts at 30 for battles 5-9 + code:0186af/1e + cheat + description:His population starts at 10 instead of 3 for battles 5-9 + code:0186b0/0a + cheat + description:His population starts at 20 for battles 5-9 + code:0186b0/14 + cheat + description:His population starts at 30 for battles 5-9 + code:0186b0/1e + cheat + description:You have no Supreme Commands available for battles 5-9 + code:0186ac/00 + cheat + description:He has all Supreme Commands available for battles 5-9 + code:0186ab/3f + cheat + description:Your population starts at 10 instead of 2 for battles 10-14 + code:0186b9/0a + cheat + description:Your population starts at 20 for battles 10-14 + code:0186b9/14 + cheat + description:Your population starts at 30 for battles 10-14 + code:0186b9/1e + cheat + description:His population starts at 10 instead of 2 for battles 10-14 + code:0186ba/0a + cheat + description:His population starts at 20 for battles 10-14 + code:0186ba/14 + cheat + description:His population starts at 30 for battles 10-14 + code:0186ba/1e + cheat + description:You have no Supreme Commands available for battles 10-14 + code:0186b6/00 + cheat + description:He has all Supreme Commands available for battles 10-14 + code:0186b5/3f + +cartridge sha256:ee9759fdb590ba908f569c2bb8a63703d282b58b84bd1fe0a472ea47685acdc5 + name:Porky Pig's Haunted Holiday (USA) + cheat + description:Invincibility (blinking) + code:02aced/a5 + cheat + description:Don't flash after geting hit + code:02d488/00 + cheat + description:Don't flash as long after geting hit + code:02d488/12 + cheat + description:Flash longer after geting hit + code:02d488/ff + cheat + description:Cupcakes are worth 0 + code:038e14/00 + cheat + description:Cupcakes are worth 2 + code:038e14/02 + cheat + description:Cupcakes are worth 5 + code:038e14/05 + cheat + description:Cupcakes are worth 10 + code:038e14/0a + cheat + description:Cupcakes are worth 15 + code:038e14/0f + cheat + description:Start with 1 life + code:00a087/00 + cheat + description:Start with 7 lives + code:00a087/06 + cheat + description:Start with 10 lives + code:00a087/09 + cheat + description:Start with 1 heart + code:00a08a/01 + cheat + description:Start with 2 hearts + code:00a08a/02 + cheat + description:Start with 8 hearts + code:00a08a/08 + cheat + description:Start with 10 hearts + code:00a08a/0a + cheat + description:Infinite health + code:7e0eaa/04 + cheat + description:Infinite Cupcakes + code:7e0e9f/63 + cheat + description:Infinite lives + code:7e0e9e/09 + +cartridge sha256:06c8fc466805f97c9147711b2d8370d4f4d05d9fa3a916f17aa1682f73c9a63b + name:Power Instinct (USA) + cheat + description:Hit anywhere - P1 + code:c4c7da/e0+c4c7dc/00+c4c7dd/f0+c4c7de/1c + +cartridge sha256:0288ec049723cd0c7f1148cdc1aef0b6922b8a756affe373c99d5690e0dfceaa + name:Power Piggs of the Dark Age (USA) + cheat + description:Invincibility + code:809639/60+809265/80 + cheat + description:Multi-jump + code:808e87/24+82f8c8/07 + 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:982a56e543995ca2221a4a58431cdeb03ac178e2874c2d6ac00be15bddc6eb02 + name:Power Soukoban (Japan) + cheat + description:Invincibility + code:81e51c/00 + +cartridge sha256:8f387d083de1399bb79e5312c31a6f1757f2a536bfa25cecf1aea77bfd77058b + name: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/00 + 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 + name:Primal Rage (USA) + cheat + description:Infinite time + code:c04f1e/ad + cheat + description:Press down 3 times then start at the Start/Options screen for a hidden menu + code:c0d67a/05 + cheat + description:Able to select as many credits as you want in the options screen + code:c2762f/99 + cheat + description:Select different times in the options screen + code:c06800/10 + cheat + description:Start with less health + code:c0c27e/40 + 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 + name:Prince of Persia (USA) + cheat + description:Invincibility against enemies + code:0193c4/ad + cheat + description:Infinite time + code:01e9d7/80+01e9d8/0a + cheat + description:Non-fatal injuries do no damage + code:01cf83/9c + cheat + description:Non-fatal falls do no damage + code:01aa52/2e + cheat + description:Non-fatal falls do 2 points of damage instead of 1 + code:01aa6d/02 + 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:01aa4d/80 + cheat + description:Walk on air (Can walk over pits. Run to any wall to fall down or walk to the edge of any floor to climb down.) + code:01abf0/80 + cheat + description:All enemies have 1 health point + code:018b4d/ad+0180a7/01 + cheat + description:All enemies have 2 health points + code:018b4d/ad+0180a7/02 + cheat + description:All enemies have 3 health points + code:018b4d/ad+0180a7/03 + cheat + description:All enemies have 4 health points + code:018b4d/ad+0180a7/04 + cheat + description:All enemies have 5 health points + code:018b4d/ad+0180a7/05 + cheat + description:All enemies have 10 health points + code:018b4d/ad+0180a7/0a + cheat + description:Enemies defeated immediately (disable on bosses) + code:018b53/9c + cheat + description:Start with 2 health points instead of 3 + code:01ed4b/02 + cheat + description:Start with 4 health points + code:01ed4b/04 + cheat + description:Start with 5 health points + code:01ed4b/05 + cheat + description:Start with 6 health points + code:01ed4b/06 + cheat + description:Start with 7 health points + code:01ed4b/07 + cheat + description:Start with 8 health points + code:01ed4b/08 + cheat + description:Start with 9 health points + code:01ed4b/09 + cheat + description:Start with 15 health points + code:01ed4b/10 + cheat + description:Start on level 2 + code:039c3a/01 + cheat + description:Start on level 3 + code:039c3a/02 + cheat + description:Start on level 4 + code:039c3a/03 + cheat + description:Start on level 5 + code:039c3a/04 + cheat + description:Start on level 6 + code:039c3a/05 + cheat + description:Start on level 7 + code:039c3a/06 + cheat + description:Start on level 8 + code:039c3a/07 + cheat + description:Start on level 9 + code:039c3a/08 + cheat + description:Start on level 10 + code:039c3a/09 + cheat + description:Start on level 11 + code:039c3a/0a + cheat + description:Start on level 12 + code:039c3a/0b + cheat + description:Start on level 13 + code:039c3a/0c + cheat + description:Start on level 14 + code:039c3a/0d + cheat + description:Start on level 15 + code:039c3a/0e + cheat + description:Start on level 16 + code:039c3a/0f + cheat + description:Start on level 17 + code:039c3a/10 + cheat + description:Start on level 18 + code:039c3a/11 + cheat + description:Start on level 19 + code:039c3a/12 + cheat + description:Start on level 20 + code:039c3a/13 + cheat + description:Cheat menu enabled (Start+Select) + code:7e106f/02 + +cartridge sha256:04ca1a481093c4a7e12f18b33697d6e05e50e30e0f5b1655aa265abd14719bba + name:Prince of Persia 2 (USA) + cheat + description:Infinite health + code:7e0957/03 + cheat + description:Infinite time + code:7e0b98/69 + cheat + description:Hit anywhere + code:80f64a/24+80f64f/24+80f642/24+80f66b/24+80f636/24+80f63c/24+80f654/24+80f5c7/24 + cheat + description:Cheat mode enabled (level skip = Select, kills = X) + code:7e0206/01 + +cartridge sha256:65f7123ab4fc9bad24b1976da8e84976cc6977861626a05d4e2cce132ef3fd42 + name:Psycho Dream (Japan) + cheat + description:Invincibility (blinking) + code:c09232/00 + cheat + description:Infinite time + code:c03c19/00 + cheat + description:Infinite magic + code:c094fc/85 + cheat + description:Hit anywhere + code:c8070d/80+c80722/80+c80737/80+c8074c/80 + cheat + description:Best weapon on pick-up + code:c0a03b/a9 + +cartridge sha256:475c9baa1c2b76a6b3119e47d32814dc1c08e84e23250ae015bb0bccea915637 + name:Push-Over (USA) + cheat + description:Still can complete level even if time runs out + code:008695/80 + cheat + description:Tokens aren't lost when used to undo a push + code:008685/ee + cheat + description:Tokens aren't lost when used to advance when time runs out + code:00873b/ee + cheat + description:Start on level 2 + code:008782/a9+008785/8d+008783/01 + cheat + description:Start on level 3 + code:008782/a9+008785/8d+008783/02 + cheat + description:Start on level 4 + code:008782/a9+008785/8d+008783/03 + cheat + description:Start on level 5 + code:008782/a9+008785/8d+008783/04 + cheat + description:Start on level 6 + code:008782/a9+008785/8d+008783/05 + cheat + description:Start on level 7 + code:008782/a9+008785/8d+008783/06 + cheat + description:Start on level 8 + code:008782/a9+008785/8d+008783/07 + cheat + description:Start on level 9 + code:008782/a9+008785/8d+008783/08 + cheat + description:Start on level 10 + code:008782/a9+008785/8d+008783/09 + cheat + description:Start on level 11 + code:008782/a9+008785/8d+008783/0a + cheat + description:Start on level 12 + code:008782/a9+008785/8d+008783/0b + cheat + description:Start on level 13 + code:008782/a9+008785/8d+008783/0c + cheat + description:Start on level 14 + code:008782/a9+008785/8d+008783/0d + cheat + description:Start on level 15 + code:008782/a9+008785/8d+008783/0e + cheat + description:Start on level 16 + code:008782/a9+008785/8d+008783/0f + cheat + description:Start on level 17 + code:008782/a9+008785/8d+008783/10 + cheat + description:Start on level 18 + code:008782/a9+008785/8d+008783/11 + cheat + description:Start on level 19 + code:008782/a9+008785/8d+008783/12 + cheat + description:Start on level 20 + code:008782/a9+008785/8d+008783/13 + cheat + description:Start on level 21 + code:008782/a9+008785/8d+008783/14 + cheat + description:Start on level 22 + code:008782/a9+008785/8d+008783/15 + cheat + description:Start on level 23 + code:008782/a9+008785/8d+008783/16 + cheat + description:Start on level 24 + code:008782/a9+008785/8d+008783/17 + cheat + description:Start on level 25 + code:008782/a9+008785/8d+008783/18 + cheat + description:Start on level 26 + code:008782/a9+008785/8d+008783/19 + cheat + description:Start on level 27 + code:008782/a9+008785/8d+008783/1a + cheat + description:Start on level 28 + code:008782/a9+008785/8d+008783/1b + cheat + description:Start on level 29 + code:008782/a9+008785/8d+008783/1c + cheat + description:Start on level 30 + code:008782/a9+008785/8d+008783/1d + cheat + description:Start on level 31 + code:008782/a9+008785/8d+008783/1e + cheat + description:Start on level 32 + code:008782/a9+008785/8d+008783/1f + cheat + description:Start on level 33 + code:008782/a9+008785/8d+008783/20 + cheat + description:Start on level 34 + code:008782/a9+008785/8d+008783/21 + cheat + description:Start on level 35 + code:008782/a9+008785/8d+008783/22 + cheat + description:Start on level 36 + code:008782/a9+008785/8d+008783/23 + cheat + description:Start on level 37 + code:008782/a9+008785/8d+008783/24 + cheat + description:Start on level 38 + code:008782/a9+008785/8d+008783/25 + cheat + description:Start on level 39 + code:008782/a9+008785/8d+008783/26 + cheat + description:Start on level 40 + code:008782/a9+008785/8d+008783/27 + cheat + description:Start on level 41 + code:008782/a9+008785/8d+008783/28 + cheat + description:Start on level 42 + code:008782/a9+008785/8d+008783/29 + cheat + description:Start on level 43 + code:008782/a9+008785/8d+008783/2a + cheat + description:Start on level 44 + code:008782/a9+008785/8d+008783/2b + cheat + description:Start on level 45 + code:008782/a9+008785/8d+008783/2c + cheat + description:Start on level 46 + code:008782/a9+008785/8d+008783/2d + cheat + description:Start on level 47 + code:008782/a9+008785/8d+008783/2e + cheat + description:Start on level 48 + code:008782/a9+008785/8d+008783/2f + cheat + description:Start on level 49 + code:008782/a9+008785/8d+008783/30 + cheat + description:Start on level 50 + code:008782/a9+008785/8d+008783/31 + cheat + description:Start on level 51 + code:008782/a9+008785/8d+008783/32 + cheat + description:Start on level 52 + code:008782/a9+008785/8d+008783/33 + cheat + description:Start on level 53 + code:008782/a9+008785/8d+008783/34 + cheat + description:Start on level 54 + code:008782/a9+008785/8d+008783/35 + cheat + description:Start on level 55 + code:008782/a9+008785/8d+008783/36 + cheat + description:Start on level 56 + code:008782/a9+008785/8d+008783/37 + cheat + description:Start on level 57 + code:008782/a9+008785/8d+008783/38 + cheat + description:Start on level 58 + code:008782/a9+008785/8d+008783/39 + cheat + description:Start on level 59 + code:008782/a9+008785/8d+008783/3a + cheat + description:Start on level 60 + code:008782/a9+008785/8d+008783/3b + cheat + description:Start on level 61 + code:008782/a9+008785/8d+008783/3c + cheat + description:Start on level 62 + code:008782/a9+008785/8d+008783/3d + cheat + description:Start on level 63 + code:008782/a9+008785/8d+008783/3e + cheat + description:Start on level 64 + code:008782/a9+008785/8d+008783/3f + cheat + description:Start on level 65 + code:008782/a9+008785/8d+008783/40 + cheat + description:Start on level 66 + code:008782/a9+008785/8d+008783/41 + cheat + description:Start on level 67 + code:008782/a9+008785/8d+008783/42 + cheat + description:Start on level 68 + code:008782/a9+008785/8d+008783/43 + cheat + description:Start on level 69 + code:008782/a9+008785/8d+008783/44 + cheat + description:Start on level 70 + code:008782/a9+008785/8d+008783/45 + cheat + description:Start on level 71 + code:008782/a9+008785/8d+008783/46 + cheat + description:Start on level 72 + code:008782/a9+008785/8d+008783/47 + cheat + description:Start on level 73 + code:008782/a9+008785/8d+008783/48 + cheat + description:Start on level 74 + code:008782/a9+008785/8d+008783/49 + cheat + description:Start on level 75 + code:008782/a9+008785/8d+008783/4a + cheat + description:Start on level 76 + code:008782/a9+008785/8d+008783/4b + cheat + description:Start on level 77 + code:008782/a9+008785/8d+008783/4c + cheat + description:Start on level 78 + code:008782/a9+008785/8d+008783/4d + cheat + description:Start on level 79 + code:008782/a9+008785/8d+008783/4e + cheat + description:Start on level 80 + code:008782/a9+008785/8d+008783/4f + cheat + description:Start on level 81 + code:008782/a9+008785/8d+008783/50 + cheat + description:Start on level 82 + code:008782/a9+008785/8d+008783/51 + cheat + description:Start on level 83 + code:008782/a9+008785/8d+008783/52 + cheat + description:Start on level 84 + code:008782/a9+008785/8d+008783/53 + cheat + description:Start on level 85 + code:008782/a9+008785/8d+008783/54 + cheat + description:Start on level 86 + code:008782/a9+008785/8d+008783/55 + cheat + description:Start on level 87 + code:008782/a9+008785/8d+008783/56 + cheat + description:Start on level 88 + code:008782/a9+008785/8d+008783/57 + cheat + description:Start on level 89 + code:008782/a9+008785/8d+008783/58 + cheat + description:Start on level 90 + code:008782/a9+008785/8d+008783/59 + cheat + description:Start on level 91 + code:008782/a9+008785/8d+008783/5a + cheat + description:Start on level 92 + code:008782/a9+008785/8d+008783/5b + cheat + description:Start on level 93 + code:008782/a9+008785/8d+008783/5c + cheat + description:Start on level 94 + code:008782/a9+008785/8d+008783/5d + cheat + description:Start on level 95 + code:008782/a9+008785/8d+008783/5e + cheat + description:Start on level 96 + code:008782/a9+008785/8d+008783/5f + cheat + description:Start on level 97 + code:008782/a9+008785/8d+008783/60 + cheat + description:Start on level 98 + code:008782/a9+008785/8d+008783/61 + cheat + description:Start on level 99 + code:008782/a9+008785/8d+008783/62 + +cartridge sha256:ba135ad37fef9932c2f840cf6cf82d559c232dfe0f85ba068a34755f3ad5f778 + name:Putty Squad (Europe) + cheat + description:Infinite health + code:7e0026/4e + cheat + description:Infinite lives + code:7e0035/99 + cheat + description:99 Stars + code:7e004f/99 + cheat + description:All Putties saved + code:7e0024/00 + +cartridge sha256:89d57bf308033ef17f770a80080cbeed2d112244635d5b5f860f2016398cd2f6 + name:Q-bert 3 (USA) + cheat + description:Invincibility + code:00b9a3/00 + cheat + description:Infinite lives + code:00a776/ad + cheat + description:Step on any cube to clear level + code:009057/00 + cheat + description:Start with 1 life instead of 5 + code:00808c/01 + cheat + description:Start with 3 lives + code:00808c/03 + cheat + description:Start with 7 lives + code:00808c/07 + cheat + description:Start with 9 lives + code:00808c/09 + cheat + description:Start with 25 lives + code:00808c/19 + cheat + description:Start with 100 lives + code:00808c/64 + cheat + description:Start on level 1-2 + code:00806e/01 + cheat + description:Start on level 1-3 + code:00806e/02 + cheat + description:Start on level 1-4 + code:00806e/03 + cheat + description:Start on level 2-1 + code:00806e/04 + cheat + description:Start on level 2-2 + code:00806e/05 + cheat + description:Start on level 2-3 + code:00806e/06 + cheat + description:Start on level 2-4 + code:00806e/07 + cheat + description:Start on level 3-1 + code:00806e/08 + cheat + description:Start on level 3-2 + code:00806e/09 + cheat + description:Start on level 3-3 + code:00806e/0a + cheat + description:Start on level 3-4 + code:00806e/0b + cheat + description:Start on level 4-1 + code:00806e/0c + cheat + description:Start on level 4-2 + code:00806e/0d + cheat + description:Start on level 4-3 + code:00806e/0e + cheat + description:Start on level 4-4 + code:00806e/0f + cheat + description:Start on level 5-1 + code:00806e/10 + cheat + description:Start on level 5-2 + code:00806e/11 + cheat + description:Start on level 5-3 + code:00806e/12 + cheat + description:Start on level 5-4 + code:00806e/13 + cheat + description:Start on level 6-1 + code:00806e/14 + cheat + description:Start on level 6-2 + code:00806e/15 + cheat + description:Start on level 6-3 + code:00806e/16 + cheat + description:Start on level 6-4 + code:00806e/17 + cheat + description:Start on level 7-1 + code:00806e/18 + cheat + description:Start on level 7-2 + code:00806e/19 + cheat + description:Start on level 7-3 + code:00806e/1a + cheat + description:Start on level 7-4 + code:00806e/1b + cheat + description:Start on level 8-1 + code:00806e/1c + cheat + description:Start on level 8-2 + code:00806e/1d + cheat + description:Start on level 8-3 + code:00806e/1e + cheat + description:Start on level 8-4 + code:00806e/1f + cheat + description:Start on level 9-1 + code:00806e/20 + cheat + description:Start on level 9-2 + code:00806e/21 + cheat + description:Start on level 9-3 + code:00806e/22 + cheat + description:Start on level 9-4 + code:00806e/23 + cheat + description:Start on level 10-1 + code:00806e/24 + cheat + description:Start on level 10-2 + code:00806e/25 + cheat + description:Start on level 10-3 + code:00806e/26 + cheat + description:Start on level 10-4 + code:00806e/27 + cheat + description:Start on level 11-1 + code:00806e/28 + cheat + description:Start on level 11-2 + code:00806e/29 + cheat + description:Start on level 11-3 + code:00806e/2a + cheat + description:Start on level 11-4 + code:00806e/2b + cheat + description:Start on level 12-1 + code:00806e/2c + cheat + description:Start on level 12-2 + code:00806e/2d + cheat + description:Start on level 12-3 + code:00806e/2e + cheat + description:Start on level 12-4 + code:00806e/2f + cheat + description:Start on level 13-1 + code:00806e/30 + cheat + description:Start on level 13-2 + code:00806e/31 + cheat + description:Start on level 13-3 + code:00806e/32 + cheat + description:Start on level 13-4 + code:00806e/33 + cheat + description:Start on level 14-1 + code:00806e/34 + cheat + description:Start on level 14-2 + code:00806e/35 + cheat + description:Start on level 14-3 + code:00806e/36 + cheat + description:Start on level 14-4 + code:00806e/37 + cheat + description:Start on level 15-1 + code:00806e/38 + cheat + description:Start on level 15-2 + code:00806e/39 + cheat + description:Start on level 15-3 + code:00806e/3a + cheat + description:Start on level 15-4 + code:00806e/3b + cheat + description:Start on level 16-1 + code:00806e/3c + cheat + description:Start on level 16-2 + code:00806e/3d + cheat + description:Start on level 16-3 + code:00806e/3e + cheat + description:Start on level 16-4 + code:00806e/3f + cheat + description:Start on level 17-1 + code:00806e/40 + cheat + description:Start on level 17-2 + code:00806e/41 + cheat + description:Start on level 17-3 + code:00806e/42 + cheat + description:Start on level 17-4 + code:00806e/43 + cheat + description:Start on level 18-1 + code:00806e/44 + cheat + description:Start on level 18-2 + code:00806e/45 + cheat + description:Start on level 18-3 + code:00806e/46 + cheat + description:Start on level 18-4 + code:00806e/47 + cheat + description:Start on level 19-1 + code:00806e/48 + cheat + description:Start on level 19-2 + code:00806e/49 + cheat + description:Start on level 19-3 + code:00806e/4a + cheat + description:Start on level 19-4 + code:00806e/4b + cheat + description:Start on level 20-1 + code:00806e/4c + cheat + description:Start on level 20-2 + code:00806e/4d + cheat + description:Start on level 20-3 + code:00806e/4e + cheat + description:Start on level 20-4 + code:00806e/4f + cheat + description:Start on level x1 + code:00806e/50 + cheat + description:Start on level x2 + code:00806e/51 + cheat + description:Start on level x3 + code:00806e/52 + cheat + description:Start on level x4 + code:00806e/53 + cheat + description:Start on level x5 + code:00806e/54 + cheat + description:Start on level x6 + code:00806e/55 + cheat + description:Start on level x7 + code:00806e/56 + cheat + description:Start on level x8 + code:00806e/57 + cheat + description:Start on level x9 + code:00806e/58 + cheat + description:Start on level x10 + code:00806e/59 + cheat + description:Start on level x11 + code:00806e/5a + cheat + description:Start on level x12 + code:00806e/5b + cheat + description:Start on level x13 + code:00806e/5c + cheat + description:Start on level x14 + code:00806e/5d + cheat + description:Start on level x15 + code:00806e/5e + cheat + description:Start on level x16 + code:00806e/5f + cheat + description:Start on level x17 + code:00806e/60 + cheat + description:Start on level x18 + code:00806e/61 + cheat + description:Start on level x19 + code:00806e/62 + cheat + description:Start on level x20 + code:00806e/63 + +cartridge sha256:4d6c7d6d2693d8d43bafaff7582f9a94885362dadd9ee4012bbbdce1ba10c30e + name:R-Type III (USA) + cheat + description:Invincibility + code:b083d8/00 + cheat + description:Infinite lives + code:81829c/ad + cheat + description:Start at speed level 3 + code:b0821d/0c + cheat + description:Start at speed level 4 + code:b0821d/10 + cheat + description:Start at speed level 5 + code:b0821d/14 + +cartridge sha256:edf990e502c646a2fe83fcd1d359ca0ed5003ace06cb4c3de5a51a0c56d6ec54 + name:Radical Psycho Machine Racing (USA) + cheat + description:Sturdy tires are free + code:019dba/00 + cheat + description:4-liter high output engine is free + code:019d66/00 + cheat + description:Sell sturdy tires for $4,910 instead of $10 + code:019dc7/49 + cheat + description:Sell 4-liter high output engine for $9,925 instead of $25 + code:019d73/99 + cheat + description:Start new game with $9,910 instead of $4,910 + code:01a896/99 + cheat + description:Start new game with $49,104,910 + code:01a89d/8d + cheat + description:Start new game with $99,109,910 + code:01a896/99+01a89d/8d + +cartridge sha256:dd0feb78e2d5d81f59241baf3bca5e2edaebbe98f0ac860a4eb6d448718f1ca5 + name:Race Drivin' (USA) + cheat + description:Infinite time + code:00818f/cd + cheat + description:Slow timer + code:008188/b4 + cheat + description:Fast timer + code:008188/2d + cheat + description:Freeze lap timer + code:0081af/d9 + cheat + description:Slow lap timer + code:0081b3/65 + +cartridge sha256:1869c0faf93bf21b7ff965f1925fad4b2924a64b1e48f4837221eebdf741226c + name:Radical Rex (USA) + cheat + description:Infinite health + code:819a28/b5 + cheat + description:Infinite roar + code:81bda4/ad+00a85f/ad + cheat + description:Infinite lives + code:84db61/ad + cheat + description:Don't loose breath level when you die + code:8098d1/ad+8098c5/ad + +cartridge sha256:5fd7666e509f9d3cf1fd6b209dc22f2f3848f74eae7b83239d1090e031fc6df2 + name:Raiden Trad (USA) + cheat + description:Invincibility - both players + code:0af515/00 + cheat + description:Infinite bombs - P1 + code:00fabf/f0+00fac0/05+00fac1/ea+00fac3/de + cheat + description:Infinite bombs - P2 + code:00fabf/d0+00fac0/05+00fac1/ea+00fac3/de + cheat + description:Infinite bombs - both players + code:00fac2/ea + cheat + description:Infinite lives - P1 + code:009c00/ea + cheat + description:Infinite lives - P2 + code:009d7a/ea + cheat + description:Hit anywhere + code:0af2b8/22+0af2b7/80+0af2e8/a5 + cheat + description:Replacement planes carry 0 bombs - P1 + code:009c34/af+009c35/8d + cheat + description:Replacement planes carry 6 bombs - P1 + code:009c34/56+009c35/89 + cheat + description:Replacement planes carry 9 bombs - P1 + code:009c34/b1+009c35/8d + cheat + description:Replacement planes carry 0 bombs - P2 + code:009dad/af+009dae/8d + cheat + description:Replacement planes carry 6 bombs - P2 + code:009dad/56+009dae/89 + cheat + description:Replacement planes carry 9 bombs - P2 + code:009dad/b1+009dae/8d + cheat + description:Start with 1 life - both players + code:00940e/98 + cheat + description:Start with 7 lives - both players + code:00940d/b9+00940e/84 + cheat + description:Start with 9 lives - both players + code:00940d/b1+00940e/8d + cheat + description:Start with 0 bombs - P1 + code:00941f/af+009420/8d + cheat + description:Start with 6 bombs - P1 + code:00941f/56+009420/89 + cheat + description:Start with 9 bombs - P1 + code:00941f/b1+009420/8d + cheat + description:Start with 0 bombs - P2 + code:00943c/af+00943d/8d + cheat + description:Start with 6 bombs - P2 + code:00943c/56+00943d/89 + cheat + description:Start with 9 bombs - P2 + code:00943c/b1+00943d/8d + cheat + description:Start with 3 credits + code:009616/02 + cheat + description:Start with 4 credits + code:009616/03 + cheat + description:Start with 6 credits + code:009616/05 + cheat + description:Start with 8 credits + code:009616/07 + cheat + description:Start with 10 credits + code:009616/09 + cheat + description:Start with 1 credit + code:009616/00 + +cartridge sha256:e19f7d8d5c3e4cefeff5889380d8780495e01f0553d13be4182a15a5d4b615bb + name:Rampart (USA) + cheat + description:Infinite continues + code:00bc21/ad + cheat + description:Infinite cannons + code:008c9a/ea + cheat + description:Start on battlefield 2 + code:00c2cc/a9+00c2ce/00+00c2cd/01 + cheat + description:Start on battlefield 3 + code:00c2cc/a9+00c2ce/00+00c2cd/02 + cheat + description:Start on battlefield 4 + code:00c2cc/a9+00c2ce/00+00c2cd/03 + cheat + description:Start on battlefield 5 + code:00c2cc/a9+00c2ce/00+00c2cd/04 + cheat + description:Start on battlefield 6 + code:00c2cc/a9+00c2ce/00+00c2cd/05 + cheat + description:Start on battlefield 7 + code:00c2cc/a9+00c2ce/00+00c2cd/06 + +cartridge sha256:32d32ef56af83887cdc2c04b3da4be1cd82a473988deaa2e7dd50d38ef79c3a1 + name:Ranma 1-2 - Hard Battle (USA) + cheat + description:Invincibility - P1 + code:c0237c/80 + cheat + description:Invincibility - P2 + code:c023df/80 + cheat + description:Hit anywhere - P1 + code:c023df/80+c023e0/12 + cheat + description:Hit anywhere - P2 + code:c0237c/80+c0237d/12 + cheat + description:Ranma moves faster + code:019523/03+019518/fc + cheat + description:Ranma jumps faster + code:01953c/fb+01953e/04 + cheat + description:Ranma's diagonal jumps are higher + code:01953e/f6 + cheat + description:Ranma's diagonal kicks are harder + code:019332/18 + cheat + description:Ranma's dragon blast kills with 1 hit + code:019468/60 + cheat + description:Genma moves faster + code:01be10/03+01bc04/fc + cheat + description:Genma's paternal anger (running at enemy) is faster + code:01bea0/f2 + cheat + description:Genma's verbal punishment is stronger + code:01bd5a/28 + cheat + description:Genma's verbal punishment kills with 1 hit + code:01bd5a/60 + cheat + description:Ryoga moves faster + code:01b26e/fc+01927a/03 + cheat + description:Ryoga jumps faster + code:01b292/fc+01b29e/03 + cheat + description:Ryoga's bandana throw kills with 1 hit + code:7f0cb1/60 + cheat + description:Shampoo moves faster + code:01ac5e/fc+01ac6a/03 + cheat + description:Shampoo's dragon sky kick is faster + code:01ad1e/f5 + cheat + description:Shampoo's super fury charge goes farther + code:01acfa/f5 + cheat + description:Shampoo's fury charge 1 hit kill + code:01ab9b/60 + cheat + description:Shampoo's kick is faster + code:01aa7c/26 + cheat + description:Akane moves faster + code:01b828/fc+01b834/03 + cheat + description:Akane jumps faster + code:01b84c/fb+01b25e/04 + cheat + description:Akane's 2-step whip kick is faster + code:01b8f4/f8 + cheat + description:Akane's 2-step whip kick is stronger + code:01b692/26 + cheat + description:Akane's 2-step whip kick kills with 1 hit + code:01b692/60 + cheat + description:Akane's dust devil uppercut is faster + code:01b8c6/ef+01b8c9/ff + cheat + description:Gosunkugi moves faster + code:01a678/fa+01a684/04 + cheat + description:Gosunkugi jumps faster + code:01a69c/fb+01a6a8/04 + cheat + description:Gosunkugi's straw man throw does more damage + code:7f0cb1/24 + cheat + description:Gosunkugi's straw man throw kills with 1 hit + code:7f0cb1/60 + cheat + description:Ukkyo moves faster + code:019ab8/fa+019ac4/04 + cheat + description:Ukkyo jumps faster + code:019adc/fb+019ae8/04 + cheat + description:Mousse's flying egg bombs are faster + code:01a174/f9 + cheat + description:Mousse's eagle claw strike - 1 hit kill + code:019f66/60 + cheat + description:Mousse's claw strike is quicker + code:01a16a/08 + cheat + description:Every move kills every opponent with 1 hit + code:c00e39/00 + cheat + description:No knock back when opponent is cornered + code:01809d/00 + +cartridge sha256:097cbe9720903bc14599158b80e0cc314ef2fe8a585d6d0a8962eb1626031492 + name:Realm (USA) + cheat + description:Infinite ammo + code:80ff23/a5 + cheat + description:Hit anywhere (if a platform is missing go back and come back) + code:80ad95/46+80ae99/64+80ad94/d0+80ade7/bd+80ade8/1c + cheat + description:Invincibility + code:7e007d/4f + cheat + description:Invincibility after first hit + code:80dcb3/a5+80dd00/a5 + cheat + description:Almost invincible + enable stage skip (press Start + Select to skip) (enable code before title screen) + code:98868c/f0 + 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:89fc95/ad + cheat + description:Infinite health (alt) + code:7e132b/06 + cheat + description:Infinite lives + code:87ed80/ad + cheat + description:Infinite lives (alt) + code:7e1334/03 + cheat + description:Infinite ammo (alt) + code:7e00f5/09 + +cartridge sha256:549f2e5b17f685cad25ba71ce7bc6e004e7bfd09e6be12a827af9a9a26556fff + name:Redline F-1 Racer (USA) + cheat + description:Always in 1st place + code:00b6f4/a5 + cheat + description:Infinite special fuel + code:00cbc5/ea + cheat + description:Instant 255 mph speed (best to get into 6th gear before activating this code, then you can go 357 mph) + code:00a47d/a9+00a47f/ff + cheat + description:No speed loss when you get off accelerator button + code:00b6a5/a5 + cheat + description:No speed loss on grass + code:009905/a5 + +cartridge sha256:71e7083cfcf32b738f60f5eeffd4f9d1fd9250afbde0c56e22a4b97abac377a1 + name: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 + name:Ren & Stimpy Show, The - Time Warp (USA) + cheat + description:Infinite health + code:82f000/bd + cheat + description:Infinite lives + code:82996b/ea + cheat + description:Don't have to charge special attack + code:829cfa/a9+829cfc/80+829cfe/00+829cff/8d + cheat + description:Flash longer after you die + code:83e5e6/ff + cheat + description:Don't flash after you die + code:83e5e6/ff + cheat + description:Health never goes back up + code:82f3c8/bd + cheat + description:1 kitty gritty gives 99 + code:82f419/a9+82f41a/63+82f41c/ea+82f41d/ea + cheat + description:Start with 1 lives + code:83e5c3/00 + cheat + description:Start with 5 lives + code:83e5c3/04 + cheat + description:Start with 10 lives + code:83e5c3/09 + cheat + description:Have 99 kitty gritty + code:7e0583/63 + +cartridge sha256:ba54d715abf100b94fee801351986fa818e4309730cefbacf9b4fad36e284c1c + name:Ren & Stimpy Show, The - Veediots! (USA) + cheat + description:Infinite health + code:01a107/ad + cheat + description:Infinite lives + code:01a17a/ad + cheat + description:Infinite time + code:01a41f/ad + cheat + description:Powdered Toast Shield lasts 85x longer + code:02f2b0/ff + cheat + description:"Socks" power-up lasts 200x longer + code:02f41f/ff + cheat + description:Stimpy's mouth won't close + code:01a574/ad + cheat + description:Money is worth 10x more + code:019ea3/fa+01cc93/fa + +cartridge sha256:82a9ee11b5640409c67772363f1148517b26127cef13aa2a8ffc2480b487d81f + name: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:b61addb0abd36ebd29e5c2988ae642b174bfec18a899cfe40866000dc934f658 + name:Return of Double Dragon (Japan) + cheat + description:Invincibility (blinking) + code:7e1f92/01 + +cartridge sha256:5fb072c3c2e9d8e7f84bea9c4bf2253e6868eb2b1f13e35a7d75fdf05896d873 + name:Revolution X (USA) + cheat + description:Infinite CDs - both players + code:80c040/a9 + cheat + description:Infinite health - P1 + code:7e022b/ff + cheat + description:Infinite CDs - P1 + code:7e0088/ff + +cartridge sha256:f44482e2cccd9fcfd5875d84ff700f6e783f3bd8abd1ac4d939074cd6ad3fe65 + name:Rex Ronan - Experimental Surgeon (USA) (En,Es) + cheat + description:Infinite health + code:7e03c4/ff + +cartridge sha256:38be8013bbe07b2020ba30031fb0a2c77bad8a3eb61fac8217adfe82d6c402af + name:Rise of the Robots (USA) + cheat + description:Infinite time + code:c0cdae/00 + cheat + description:Hit anywhere - both players + code:c0ac6c/00+c0ac72/00+c0ac93/00 + cheat + description:One hit kills - both players + code:c0e52d/a9 + cheat + description:No jumping allowed + code:c0cbd8/a9+c0cbd9/00 + cheat + description:Win one round to advance + code:c035bf/01 + cheat + description:Every hit does more damage + code:c0e52e/20+c0af3b/ea+c0e52f/00 + +cartridge sha256:3f59cc687d22cd1b23cc33ae6e4518234c9da813c01f79f4c43716e12d32a12d + name:Rival Turf! (USA) + cheat + description:Invincibility + code:1e9413/ad + cheat + description:Infinite health + code:028870/a5 + cheat + description:Infinite lives + code:0289a3/a5 + cheat + description:Infinite continues + code:00a1e5/ad + cheat + description:Full health from all food + code:018bc2/00 + cheat + description:No score lost when special attack is used + code:0283df/00 + cheat + description:Hit anywhere (might make some enemies invisible) + code:1f9287/80+1f9288/15 + cheat + description:Start with more health + code:f80b0e/00+028a2a/ff+008deb/ff+018bbf/ff + cheat + description:Start with less health + code:00a522/1f+028a2a/1f+008deb/1f+018bbf/1f + cheat + description:Start with 1 life + code:009c3b/00 + cheat + description:Start with 8 lives + code:009c3b/07 + cheat + description:Start with 9 continues + code:009c45/09 + cheat + description:Start with 1 continue + code:009c45/01 + 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 + name:Road Riot 4WD (USA) + cheat + description:Races are 1 lap instead of 3 + code:00951c/00 + cheat + description:Races are 2 laps instead of 3 + code:00951c/01 + cheat + description:Races are 4 laps instead of 3 + code:00951c/03 + cheat + description:Races are 5 laps instead of 3 + code:00951c/04 + cheat + description:Races are 6 laps instead of 3 + code:00951c/05 + cheat + description:Races are 7 laps instead of 3 + code:00951c/06 + cheat + description:Beginner track has an extra lap + code:009523/ea + +cartridge sha256:2e8203e421f97cf165f03a5d4f69dadf0bcca18c42c6a1dfe79c8705c522cc54 + name:Road Runner's Death Valley Rally (USA) + cheat + description:Protection against most hazards + code:80c7aa/ad+86ade3/ad + cheat + description:Infinite lives + code:8098d2/00 + cheat + description:Infinite time + code:809c9a/00 + cheat + description:Stay invincible longer after getting hit (Road Runner blinks) + code:80b2a8/ff + cheat + description:Stay invincible for less time after getting hit (Road Runner blinks) + code:80b2a8/40 + cheat + description:Stay invincible after getting hit until you fall and die (Road Runner blinks) + code:80a67f/ad + cheat + description:Stay invincible after getting hit until you fall and die (Road Runner does not blink) + code:80a67d/80 + cheat + description:Eating birdseed restores turbo speed meter to maximum + code:80db89/30 + cheat + description:Eating birdseed does nothing + code:80db89/00 + cheat + description:Using turbo speed does not use up bird seed + code:80af82/00 + cheat + description:Hearts worth nothing + code:80de5d/ad + cheat + description:1-up worth nothing + code:80e0e0/00 + cheat + description:1-up worth 2 + code:80e0e0/02 + cheat + description:1-up worth 3 + code:80e0e0/03 + cheat + description:1-up worth 4 + code:80e0e0/04 + cheat + description:1-up worth 5 + code:80e0e0/05 + cheat + description:Bogus jump + code:80b0ec/30 + cheat + description:Better jump + code:80b0ec/10 + cheat + description:Super-jump + code:80b0ec/0a + cheat + description:Mega-jump + code:80b0ec/05 + cheat + description:Start with more birdseed on the turbo speed meter + code:809c08/30 + cheat + description:Start with less birdseed on the turbo speed meter + code:809c08/10 + cheat + description:Start timer at 3:00 instead of 5:00 + code:80974a/03 + cheat + description:Start timer at 7:00 + code:80974a/07 + cheat + description:Start timer at 9:00 + code:80974a/09 + cheat + description:Start with 2 lives + code:809ba4/01 + cheat + description:Start with 4 lives + code:809ba4/03 + cheat + description:Start with 6 lives + code:809ba4/05 + cheat + description:Start with 8 lives + code:809ba4/07 + cheat + description:Start with 10 lives + code:809ba4/09 + cheat + description:Start with 21 lives + code:809ba4/20 + cheat + description:Start with 51 lives + code:809ba4/50 + cheat + description:Start with 76 lives + code:809ba4/75 + cheat + description:Start with 100 lives + code:809ba4/99 + cheat + description:Start on level 1, sub-level 2 + code:809b97/1e+809b96/e1+809b94/01 + cheat + description:Start on level 1, sub-level 3 + code:809b97/1e+809b96/e1+809b94/02 + cheat + description:Start on level 1, sub-level 4 + code:809b97/1e+809b96/e1+809b94/03 + cheat + description:Start on level 2, sub-level 1 + code:809b97/1e+809b96/e1+809b94/04 + cheat + description:Start on level 2, sub-level 2 + code:809b97/1e+809b96/e1+809b94/05 + cheat + description:Start on level 2, sub-level 3 + code:809b97/1e+809b96/e1+809b94/06 + cheat + description:Start on level 2, sub-level 4 + code:809b97/1e+809b96/e1+809b94/07 + cheat + description:Start on level 3, sub-level 1 + code:809b97/1e+809b96/e1+809b94/08 + cheat + description:Start on level 3, sub-level 2 + code:809b97/1e+809b96/e1+809b94/09 + cheat + description:Start on level 3, sub-level 3 + code:809b97/1e+809b96/e1+809b94/0a + cheat + description:Start on level 3, sub-level 4 + code:809b97/1e+809b96/e1+809b94/0b + cheat + description:Start on level 4, sub-level 1 + code:809b97/1e+809b96/e1+809b94/0c + cheat + description:Start on level 4, sub-level 2 + code:809b97/1e+809b96/e1+809b94/0d + cheat + description:Start on level 4, sub-level 3 + code:809b97/1e+809b96/e1+809b94/0e + cheat + description:Start on level 4, sub-level 4 + code:809b97/1e+809b96/e1+809b94/0f + cheat + description:Start on level 5, sub-level 1 + code:809b97/1e+809b96/e1+809b94/10 + cheat + description:Start on level 5, sub-level 2 + code:809b97/1e+809b96/e1+809b94/11 + cheat + description:Start on level 5, sub-level 3 + code:809b97/1e+809b96/e1+809b94/12 + cheat + description:Start on level 5, sub-level 4 + code:809b97/1e+809b96/e1+809b94/13 + +cartridge sha256:a2115e7576dec06e0de613efb89de861815a78ef72e78a3784be09fb7541928f + name:RoboCop versus The Terminator (USA) + cheat + description:Infinite lives + code:019df1/00 + cheat + description:Super-jump + code:80ee38/00 + cheat + description:Rockets do more damage + code:8182ea/0f + cheat + description:Normal pistol does more damage + code:81804a/0f + cheat + description:Plasma Rifle does massive damage + code:818185/30 + cheat + description:Only 10 Terminators to kill on the 3-D Stage + code:80842a/10 + cheat + description:Only 30 Terminators to kill on the 3-D Stage + code:80842a/30 + cheat + description:Start with 1 life + code:8092e1/01 + cheat + description:Start with 9 lives + code:8092e1/09 + cheat + description:Start with 15 lives (ignore counter) + code:8092e1/0f + 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 + name:RoboCop 3 (USA) + cheat + description:Infinite lives + code:0082f4/2c + cheat + description:Slower timer + code:008651/70 + cheat + description:Faster timer + code:008651/1f + cheat + description:Infinite ammo (except flame thrower) + code:00ab3f/00 + cheat + description:Ammo pick-ups worth more + code:00fca2/01+00fca4/02 + cheat + description:Ammo pick-ups worth less + code:00fca1/30+00fca4/00+00fca3/30 + cheat + description:Faster Robocop - except on stages 3 and 5 + code:00a238/02+00a253/fe + cheat + description:Start with 1 life + code:0080dc/00 + cheat + description:Start with 6 lives + code:0080dc/05 + cheat + description:Start on stage 2 + code:00ea3b/01 + cheat + description:Start on stage 3 + code:00ea3b/02 + cheat + description:Start on stage 4 + code:00ea3b/03 + cheat + description:Start on stage 5 + code:00ea3b/04 + 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 + name:Robotrek (USA) + cheat + description:Infinite battle bonus time + code:84c7c0/ea + cheat + description:Infinite robot points + code:8babf0/80 + cheat + description:Infinite vanish time + code:8bef27/ad + cheat + description:Everything is free + code:88eea2/ad + cheat + description:Get 9900 gold when you look into the robot book + code:8c9050/99 + cheat + description:More energy for robot energy + code:8bf582/90 + cheat + description:Mean robot + code:85f596/a9+85f597/99+85f598/00+85f599/ea + cheat + description:One-hit kills + code:8bf2dc/a9 + cheat + description:Start at level 3 + code:88ef20/a9+88ef21/03 + cheat + description:Start at level 10 + code:88ef20/a9+88ef21/0a + cheat + description:Start at level 20 + code:88ef20/a9+88ef21/14 + cheat + description:Start at level 50 + code:88ef20/a9+88ef21/32 + 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 + name:Rock n' Roll Racing (USA) + cheat + description:Infinite forward weapons + code:80941e/ad + cheat + description:Infinite power charges + code:809917/ad + cheat + description:No damage from hitting other cars + code:80fe72/ea + cheat + description:No damage from most mines + code:80df88/00 + cheat + description:No points needed to advance to any level + code:81ae9a/9c + cheat + description:Buy items for free if you have enough money + code:81b6a6/ad+81b69b/ad + cheat + description:More damage from mines + code:80df88/06 + cheat + description:Red Cross packages worth nothing + code:80e085/00 + cheat + description:Red Cross packages can blow up + code:80e085/10 + cheat + description:Start with $50,000 + code:81ae10/05 + cheat + description:Start with $100,000 + code:81ae10/10 + cheat + description:Start with $500,000 + code:81ae10/50 + cheat + description:Start with $990,000 + code:81ae10/99 + cheat + description:Start with $5,020,000 + code:81ae11/05 + +cartridge sha256:b072fd9b08042e3262446fdf418a41848251072a32bd7f8335cc03543c4ae6c8 + name:Rocketeer, The (USA) + cheat + description:Protection against guns (only partly against grenades) (only in hangar) + code:00b1b7/a5 + cheat + description:Protection against Armored Flying Tank + code:00b4a1/a5 + cheat + description:Protection against enemy rocketmen on the Zeppelin + code:00c749/a5 + cheat + description:Invincibility in the skies + code:008224/a5 + cheat + description:Infinite Super Shots on pick-up + code:008f6e/a5 + cheat + description:Infinite chances + code:008d47/bd + cheat + description:Automatically win first race at Bigelow + code:0086df/00 + cheat + description:Automatically win second race at Bigelow + code:0086e0/00 + cheat + description:Automatically win third race at Bigelow + code:0086e1/00 + cheat + description:First race at Bigelow is 1 lap instead of 10 + code:0086df/01 + cheat + description:First race at Bigelow is 5 laps + code:0086df/05 + cheat + description:First race at Bigelow is 15 laps + code:0086df/0f + cheat + description:First race at Bigelow is 25 laps + code:0086df/19 + cheat + description:First race at Bigelow is 50 laps + code:0086df/32 + cheat + description:First race at Bigelow is 99 laps + code:0086df/63 + cheat + description:Second race at Bigelow is 1 lap + code:0086e0/01 + cheat + description:Second race at Bigelow is 5 laps + code:0086e0/05 + cheat + description:Second race at Bigelow is 10 laps + code:0086e0/0a + cheat + description:Second race at Bigelow is 25 laps + code:0086e0/19 + cheat + description:Second race at Bigelow is 50 laps + code:0086e0/32 + cheat + description:Second race at Bigelow is 99 laps + code:0086e0/63 + cheat + description:Third race at Bigelow is 1 lap instead of 10 + code:0086e1/01 + cheat + description:Third race at Bigelow is 5 laps + code:0086e1/05 + cheat + description:Third race at Bigelow is 25 laps + code:0086e1/19 + cheat + description:Third race at Bigelow is 50 laps + code:0086e1/32 + cheat + description:Third race at Bigelow is 99 laps + code:0086e1/63 + cheat + description:Cliff starts with 2/3 normal energy in hangar + code:008708/4a + cheat + description:Cliff starts with 1/3 normal energy in hangar + code:008708/25 + cheat + description:Enemies start with 2/3 normal energy in hangar + code:00870f/4a + cheat + description:Enemies start with 1/3 normal energy in hangar + code:00870f/25 + cheat + description:Super Shots worth nothing on pick-up instead of 3 + code:00849e/00 + cheat + description:Super Shots worth 6 on pick-up (cannot gain over 29) + code:00849e/06 + cheat + description:Super Shots worth 9 on pick-up (cannot gain over 29) + code:00849e/09 + cheat + description:Super Shots worth 12 on pick-up (cannot gain over 29) + code:00849e/0c + cheat + description:Easily defeat enemy rocketmen on the Zeppelin + code:00c4b4/64 + cheat + description:Start with 1 chance instead of 3 + code:0085af/01 + cheat + description:Start with 2 chances + code:0085af/02 + cheat + description:Start with 4 chances + code:0085af/04 + cheat + description:Start with 5 chances + code:0085af/05 + cheat + description:Start with 6 chances + code:0085af/06 + cheat + description:Start with 7 chances + code:0085af/07 + cheat + description:Start with 8 chances + code:0085af/08 + cheat + description:Start with 9 chances + code:0085af/09 + +cartridge sha256:4fc2832e7aa01d105ca67977b38840ec1188869b5e74d20e58613c1cd127d78f + name:Rockman & Forte (Japan) + cheat + description:Invincibility against enemies + code:c345b7/6b + cheat + description:Invincibility against fire + code:c13411/6b + cheat + description:Invincibility against pits + code:c12cb8/60 + cheat + description:Invincibility against spikes + code:c133e9/6b + cheat + description:One hit kills + code:c34585/24 + cheat + description:Multi-jump - Megaman + code:c11c95/60+c11c96/7f+c17f60/20+c17f61/fd+c17f62/3a+c17f63/20+c17f64/e9+c17f65/31+c17f66/60 + cheat + description:Multi-jump - Bass + code:c12662/fd + 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:306049/ff+30604a/ff+30604b/ff+30604c/1f+306040/fe+306041/ff+306042/ff+306043/ff+306044/ff+306045/ff+306046/ff+306047/ff+306048/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 + name:Rocky Rodent (USA) + cheat + description:Infinite lives + code:80cc03/ea + cheat + description:Keep hairdo after you die + code:81afe0/ad + cheat + description:Start with red hairdo + code:80c9bc/02 + cheat + description:Start with purple hairdo + code:80c9bc/04 + cheat + description:Start with corkscrew hairdo + code:80c9bc/06 + cheat + description:Start with green ponytail hairdo + code:80c9bc/08 + cheat + description:Start with birdnest hairdo + code:80c9bc/0a + cheat + description:Invincibility + code:7e0054/72 + +cartridge sha256:f7e3c3012af2dbad350646b6ef3470f0b4c42e4a2873109f7aa6c81d7157c887 + name:Roger Clemens' MVP Baseball (USA) (Rev 1) + cheat + description:Batter never walks + code:00d207/ad + cheat + description:Batter never strikes out + code:00d232/ad + cheat + description:1 ball per walk + code:00d20e/01 + cheat + description:2 balls per walk + code:00d20e/02 + cheat + description:3 balls per walk + code:00d20e/03 + cheat + description:5 balls per walk + code:00d20e/05 + cheat + description:6 balls per walk + code:00d20e/06 + cheat + description:7 balls per walk + code:00d20e/07 + cheat + description:1 strike per out + code:00d239/01 + cheat + description:2 strikes per out + code:00d239/02 + cheat + description:4 strikes per out + code:00d239/04 + cheat + description:5 strikes per out + code:00d239/05 + cheat + description:Each run counts as 2 + code:018974/38+018955/38 + cheat + description:1 out per inning per team + code:00951c/01 + cheat + description:2 outs per inning per team + code:00951c/02 + +cartridge sha256:815bfcf4fd6eb23a20c2e50dde023c210b273ffb6cd86a93909d803c3643ce46 + name:Romance of the Three Kingdoms II (USA) + cheat + description:Scenario 1 - Start with 30,000 gold pieces + code:01ff3a/30+01ff3b/75 + cheat + description:Scenario 1 - Start with 30,000 rice + code:01ff3e/30+01ff3d/75 + cheat + description:Scenario 1 - Start with 30,000 population + code:01ff3e/30+01ff3f/75 + cheat + description:Scenario 2 - Start with 30,000 gold pieces + code:028339/30+02830a/75 + cheat + description:Scenario 2 - Start with 30,000 rice + code:02833b/30+02830c/75 + cheat + description:Scenario 2 - Start with 30,000 population + code:02833d/30+02830e/75 + cheat + description:Scenario 3 - Start with 30,000 gold pieces + code:02873c/30+02873d/75 + cheat + description:Scenario 3 - Start with 30,000 rice + code:02873e/30+02873f/75 + cheat + description:Scenario 3 - Start with 30,000 population + code:028740/30+028741/75 + cheat + description:Scenario 4 - Start with 30,000 gold pieces + code:028b3d/30+028b3e/75 + cheat + description:Scenario 4 - Start with 30,000 rice + code:028b3f/30+028b40/75 + cheat + description:Scenario 4 - Start with 30,000 population + code:028b41/30+028b42/75 + cheat + description:Scenario 5 - Start with 30,000 gold pieces + code:02909c/30+02909d/75 + cheat + description:Scenario 5 - Start with 30,000 rice + code:02909e/30+02909f/75 + cheat + description:Scenario 5 - Start with 30,000 population + code:0290a0/30+0290a1/75 + cheat + description:Scenario 6 - Start with 30,000 gold pieces + code:02925e/30+02925f/75 + cheat + description:Scenario 6 - Start with 30,000 rice + code:029260/30+029261/75 + cheat + description:Scenario 6 - Start with 30,000 population + code:029262/30+029263/75 + +cartridge sha256:4158e3e8890a52f0b12dc9ad5a29276058a247ff41e9f1d22897ebde1eb11269 + name:Run Saber (USA) + cheat + description:Almost invincible - P1 (disable if you fall into a pit) + code:809a53/ad + cheat + description:Almost invincible - P2 (disable if you fall into a pit) + code:809a6b/ad + cheat + description:Almost invincible - both players (disable if you fall into a pit) + code:809a4b/6b + cheat + description:Infinite lives - P1 + code:80d566/00 + cheat + description:Infinite lives - P2 + code:80d586/00 + cheat + description:Infinite Super Bombs - P1 + code:9ffb27/00 + cheat + description:Infinite Super Bombs - P2 + code:9ffb10/00 + cheat + description:Infinite continues + code:9ff43c/ad + cheat + description:Level select and 9 lives selectable on the option menu + code:0ceac9/01 + cheat + description:Hit anywhere - male character + code:86fc7f/80+86fc80/15 + cheat + description:Bomb power-ups give no Super Bombs + code:85fc6a/00 + cheat + description:Bomb power-ups give 2 Super Bombs + code:85fc6a/02 + cheat + description:Start with no Super Bombs + code:0cd958/00 + cheat + description:Start with 1 Super Bomb + code:0cd958/01 + cheat + description:Start with 5 Super Bombs + code:0cd958/05 + cheat + description:Start with 9 Super Bombs + code:0cd958/09 + cheat + description:Start with 1 health + code:0cd972/01 + cheat + description:Start with 4 health + code:0cd972/04+0ce959/04 + cheat + description:Start with 5 health + code:0cd972/05+0ce959/05 + cheat + description:Start with 8 health + code:0cd972/08+0ce959/08 + cheat + description:Start with no continues + code:0cbbe2/01 + cheat + description:Start with 1 continue + code:0cbbe2/02 + cheat + description:Start with 5 continues + code:0cbbe2/06 + cheat + description:Start with 9 continues + code:0cbbe2/0a + +cartridge sha256:00e78318926e5cae79bce0535fddd3dccaa732f5c70e43acefc2769a9899eaed + name:Rushing Beat Shura (Japan) + cheat + description:Invincibility + code:80ddc0/ad + cheat + description:One hit kills + code:83dab0/64 + cheat + description:Choose Dick to play as Super Dick + code:7e060a/16+7e060b/04 + +cartridge sha256:0aa16d6b588ba05ab00936201e68a694746fc5e1b2e4f2dbf7cda09265a81379 + name: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 + name:Samurai Shodown (USA) + cheat + description:Hit anywhere - both players + code:c042e4/00 + cheat + description:Max POW meter after one hit + code:c0f26e/01 + cheat + description:Start with 1/2 health + code:c15829/40 + cheat + description:Start with 1/4 health + code:c15829/20 + cheat + description:Start with 33 seconds + code:c078eb/21 + 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 + name: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 + name:Saturday Night Slam Masters (USA) + cheat + description:Able to pick the same characters + code:c03b54/60+c03b39/60 + cheat + description:Stingray becomes Biff + code:80a666/00 + cheat + description:Stingray becomes Gunloc + code:80a666/01 + cheat + description:Stingray becomes Oni + code:80a666/02 + cheat + description:Stingray becomes Titan + code:80a666/03 + cheat + description:Stingray becomes Haggar + code:80a666/05 + cheat + description:Stingray becomes Grater + code:80a666/06 + cheat + description:Stingray becomes Rasta + code:80a666/07 + cheat + description:Stingray becomes Jumbo + code:80a666/08 + cheat + description:Stingray becomes Scorpion + code:80a666/09 + cheat + description:Biff becomes Gunloc + code:80a662/01 + cheat + description:Biff becomes Oni + code:80a662/02 + cheat + description:Biff becomes Titan + code:80a662/03 + cheat + description:Biff becomes Stingray + code:80a662/04 + cheat + description:Biff becomes Haggar + code:80a662/05 + cheat + description:Biff becomes Grater + code:80a662/06 + cheat + description:Biff becomes Rasta + code:80a662/07 + cheat + description:Biff becomes Jumbo + code:80a662/08 + cheat + description:Biff becomes Scorpion + code:80a662/09 + cheat + description:14-second count outside ring + code:c10991/0e + cheat + description:10-second count outside ring + code:c10991/0a + cheat + description:9-second count for pin + code:c10980/09 + cheat + description:6-second count for pin + code:c10980/06 + cheat + description:1-second count for pin + code:c10980/01 + cheat + description:Faster timer + code:c06215/1e + cheat + description:Slower timer + code:c06215/60 + cheat + description:Stingray has faster jalepeno comet + code:c1dd0e/06+c1dd15/f9 + cheat + description:Quicker 'pattycake slap' for Grater + code:80bdec/4a+80bdf6/03 + cheat + description:Quicker 'sonic fist' for Gunloc + code:80bde7/4a+80bdf1/03 + cheat + description:Quicker 'sonic fist' for Biff + code:80bde6/4a+80bdf1/03 + cheat + description:Quicker 'jungle fever' for Rasta + code:80bded/4a+80bdf7/02 + cheat + description:Infinite health - P1 + code:7e0879/ff + cheat + description:Infinite health - P3 + code:7e0c79/ff + cheat + description:Infinite health - P4 + code:7e0e79/ff + cheat + description:No health - P1 + code:7e0879/00 + cheat + description:No health - P2 + code:7e0a79/00 + cheat + description:No health - P3 + code:7e0c79/00 + cheat + description:No health - P4 + code:7e0e79/00 + cheat + description:Infinite time + code:7e1a70/01 + cheat + description:Infinite time (alt) + code:7e1a70/59+7e1a71/02 + cheat + description:Infinite ringout time - all players + code:7e1a60/00 + cheat + description:P1 wrestler modifier - Jumbo + code:7e1b86/00 + cheat + description:P1 wrestler modifier - Biff + code:7e1b86/01 + cheat + description:P1 wrestler modifier - Gunloc + code:7e1b86/02 + cheat + description:P1 wrestler modifier - Oni + code:7e1b86/03 + cheat + description:P1 wrestler modifier - Titan + code:7e1b86/04 + cheat + description:P1 wrestler modifier - Stingray + code:7e1b86/05 + cheat + description:P1 wrestler modifier - Haggar + code:7e1b86/06 + cheat + description:P1 wrestler modifier - Grater + code:7e1b86/07 + cheat + description:P1 wrestler modifier - Rasta + code:7e1b86/08 + cheat + description:P1 wrestler modifier - Scorpion + code:7e1b86/09 + cheat + description:P2 wrestler modifier - Jumbo + code:7e1b87/00 + cheat + description:P2 wrestler modifier - Biff + code:7e1b87/01 + cheat + description:P2 wrestler modifier - Gunloc + code:7e1b87/02 + cheat + description:P2 wrestler modifier - Oni + code:7e1b87/03 + cheat + description:P2 wrestler modifier - Titan + code:7e1b87/04 + cheat + description:P2 wrestler modifier - Stingray + code:7e1b87/05 + cheat + description:P2 wrestler modifier - Haggar + code:7e1b87/06 + cheat + description:P2 wrestler modifier - Grater + code:7e1b87/07 + cheat + description:P2 wrestler modifier - Rasta + code:7e1b87/08 + cheat + description:P2 wrestler modifier - Scorpion + code:7e1b87/09 + cheat + description:P3 wrestler modifier - Jumbo + code:7e1b88/00 + cheat + description:P3 wrestler modifier - Biff + code:7e1b88/01 + cheat + description:P3 wrestler modifier - Gunloc + code:7e1b88/02 + cheat + description:P3 wrestler modifier - Oni + code:7e1b88/03 + cheat + description:P3 wrestler modifier - Titan + code:7e1b88/04 + cheat + description:P3 wrestler modifier - Stingray + code:7e1b88/05 + cheat + description:P3 wrestler modifier - Haggar + code:7e1b88/06 + cheat + description:P3 wrestler modifier - Grater + code:7e1b88/07 + cheat + description:P3 wrestler modifier - Rasta + code:7e1b88/08 + cheat + description:P3 wrestler modifier - Scorpion + code:7e1b88/09 + cheat + description:P4 wrestler modifier - Jumbo + code:7e1b89/00 + cheat + description:P4 wrestler modifier - Biff + code:7e1b89/01 + cheat + description:P4 wrestler modifier - Gunloc + code:7e1b89/02 + cheat + description:P4 wrestler modifier - Oni + code:7e1b89/03 + cheat + description:P4 wrestler modifier - Titan + code:7e1b89/04 + cheat + description:P4 wrestler modifier - Stingray + code:7e1b89/05 + cheat + description:P4 wrestler modifier - Haggar + code:7e1b89/06 + cheat + description:P4 wrestler modifier - Grater + code:7e1b89/07 + cheat + description:P4 wrestler modifier - Rasta + code:7e1b89/08 + cheat + description:P4 wrestler modifier - Scorpion + code:7e1b89/09 + +cartridge sha256:7fb5236d10852125f0f37c2188b907d636647400a57bccbdb2f63098ffae8b2d + name:Scooby-Doo Mystery (USA) + cheat + description:Infinite health + code:81fb05/00 + cheat + description:Infinite lives + code:809313/ad + cheat + description:Most enemies are more frightening + code:81fb05/ff + cheat + description:Scooby snacks do nothing + code:818d04/ad + cheat + description:Scooby snacks reduce more fright + code:818d20/ff + cheat + description:Start with 1 life + code:808d4a/00 + cheat + description:Start with 5 lives + code:808d4a/04 + cheat + description:Start with 7 lives + code:808d4a/06 + cheat + description:Start with 10 lives + code:808d4a/09 + +cartridge sha256:39c69dfbba31086cee0c6a034186148c46e1e6c86fcb8e990fb5364a8845fbcd + name:SD Kidou Senshi Gundam - V Sakusen Shidou (Japan) + cheat + description:Invincibility + code:0182b7/60+01831c/60 + +cartridge sha256:8cd9eea0f01e2442727e4624199afaa42dceeb05b9084a4358cadbe4e5a04577 + name:SD The Great Battle - Aratanaru Chousen (Japan) + cheat + description:Invincibility + code:00af7c/60+00a964/a5 + cheat + description:Infinite lives + code:0086bf/a5 + +cartridge sha256:a4ab8cfad2f236675b1c0124f8484688e149f38e8628a3b38e9ec14d491ec07e + name:SeaQuest DSV (USA) + cheat + description:Infinite weapons / items + code:84a3a5/bf+84a4b8/bf + cheat + description:Start with 99 Darwin's Aqua Lungs + code:81f2a9/63 + cheat + description:Start with 99 HR Probes + code:81f2b1/63 + cheat + description:Start with 99 Sea Trucks + code:81f2af/63 + cheat + description:Start with 99 Sea Speeders + code:81f2ab/63 + cheat + description:Start with 99 Crabs + code:81f2a7/63 + cheat + description:Start with 99 Stingers + code:81f2ad/63 + +cartridge sha256:17c864a76d498feb6479eee8e7d6807b951c66225033228622bb66754baab1db + name:Secret of Evermore (USA) + cheat + description:Everyone is invincible, including enemies + code:8fc241/ad+908498/bd+908461/0d + cheat + description:Infinite Alchemy ingredients + code:91ce25/bf+91cdf8/bf + cheat + description:Alchemy levels up on every use + code:91cd5c/00 + cheat + description:View Boy's stats to get 131,074 Talons (don't use if you already have more than that) + code:8da323/a9+8da324/02+8da325/00+8da328/8d + cheat + description:Your dog starts with 99 HP + code:8c9517/63 + cheat + description:Your dog starts with 255 HP + code:8c9517/ff + cheat + description:Start with 99 attack points + code:8c935b/57 + cheat + description:Start with a lot of attack points + code:8c935b/ff + cheat + description:Start with 99 defense points + code:8c927d/63 + cheat + description:Start with a lot of defense points + code:8c927d/ff + cheat + description:Start with 99 magic defense points + code:8c9439/63 + cheat + description:Start with a lot of magic defense points + code:8c9439/ff + cheat + description:Start with 50 evade % points + code:8c8e27/32 + cheat + description:Start with 99 evade % points + code:8c8e27/63 + cheat + description:Start with 50 hit % points + code:8c8f05/32 + cheat + description:Start with 99 hit % points + code:8c8f05/63 + cheat + description:Start with 99 HP + code:8eb687/63+8c919f/63 + cheat + description:Start with 255 HP + code:8eb687/ff+8c919f/ff + cheat + description:Have all weapons + code:7e22da/ff+7e22db/ff + +cartridge sha256:4c15013131351e694e05f22e38bb1b3e4031dedac77ec75abecebe8520d82d5f + name:Secret of Mana (USA) + cheat + description:999 health - P1 + code:7ee182/e7+7ee183/03 + cheat + description:999 health - P2 + code:7ee382/e7+7ee383/03 + cheat + description:999 health - P3 + code:7ee582/e7+7ee583/03 + cheat + description:999 Max health - P1 + code:7ee184/e7+7ee185/03 + cheat + description:999 Max health - P2 + code:7ee384/e7+7ee385/03 + cheat + description:999 Max health - P3 + code:7ee584/e7+7ee585/03 + cheat + description:Infinite MP + code:7ee386/63+7ee586/63 + cheat + description:Infinite GP + code:7ecc6a/7f+7ecc6b/96+7ecc6c/98 + cheat + description:Protection from most hits (disable to kill enemies) + code:c040be/bd + cheat + description:Enemies die instantly + code:c03cf2/a0+c03cf3/00+c03cf4/00 + cheat + description:Hit anywhere + code:01ce3e/24+01d1a6/24 + cheat + description:Level 99 after first enemy + code:c04486/98+c039b6/00 + cheat + description:Max weapon damage + code:c049c9/9c+c049c8/a9 + cheat + description:Change screens to max out Strength, Agility, Constitution, Intelligence and Wisdom + code:c04be1/00 + cheat + description:Weapon bar never decreases + code:02c24a/bd+00f944/bd + cheat + description:Walk through walls + code:01bb7c/00+01ba7b/00 + cheat + description:Strength for level 16 is 90 + code:d0428b/5a + cheat + description:Agility for level 16 is 90 + code:d0428c/5a + cheat + description:Constitution for level 16 is 90 + code:d0428d/5a + cheat + description:Intelligence for level 16 is 90 + code:d0428e/5a + cheat + description:Wisdom for level 16 is 90 + code:d0428f/5a + cheat + description:Chest in elder's basement in Potos gives you 65360 GP + code:ca8e9f/ff + cheat + description:Staying at the inn in Potos is free if you have enough money + code:c03a2e/ad+c03a33/ad + cheat + description:Items in the shop at Potos are free if you have enough money + code:c07d1e/af + cheat + description:Candy costs nothing + code:d8fb9c/00 + cheat + description:Overalls costs nothing + code:d8fbe0/00 + cheat + description:Bandanna costs nothing + code:d8fbb6/00 + cheat + description:Cup Of Wishes costs nothing + code:d8fba6/00 + cheat + description:Medical Herb costs nothing + code:d8fba4/00 + cheat + description:Wristband costs nothing + code:d8fc30/00 + cheat + description:Hair Ribbon costs nothing + code:d8fbb8/00 + cheat + description:Rabite Cap costs nothing + code:d8fbba/00 + cheat + description:Faerie Walnut costs nothing + code:d8fba2/00+d8fba3/00 + cheat + description:Royal Jam costs nothing + code:d8fba0/00 + cheat + description:Chocolate costs nothing + code:d8fb9e/00 + cheat + description:Staying at Neko's costs nothing instead of 30 + code:c9cf9d/00 + cheat + description:Start with 255 GP + code:c0d7b3/ff + cheat + description:Start with 32,768 GP + code:c0d7b4/80 + cheat + description:Start with 65,280 GP + code:c0d7b4/ff + cheat + description:Start at Level 16 + code:c04e5d/81 + +cartridge sha256:ab3d724f3032337300c0cc10259447b173793b9dc25f1f250baf785e9c16bb7d + name: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 + name: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 + name:Shadowrun (USA) + cheat + description:Infinite health in the Matrix + code:81b17f/ad + cheat + description:Everything is free + code:80ccf7/80+80ccf8/11 + cheat + description:Karma not subtracted for spells/skills (must have enough to advance) + code:80f010/af + cheat + description:Karma not subtracted for shooting people (ignore message saying you lost karma) + code:80880f/af + cheat + description:Spell points not subtracted (works for all spell casters) (casting spells you aren't allowed to raises your spell points) + code:808b53/bf + cheat + description:Walk through walls + code:81860d/80 + cheat + description:Going up 1 body point adds 20 stamina instead of 10 + code:80f164/14 + cheat + description:Going up 1 body point adds 30 stamina instead of 10 + code:80f164/1e + cheat + description:Add 65,000 nuyen (if less than 65,000) + code:8095af/01+8095b1/0f+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Add about 131,000 nuyen (if less than 65,000) + code:8095af/02+8095b1/0f+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Add about 524,000 nuyen (if less than 65,000) + code:8095af/08+8095b1/0f+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Set stamina to 100 + code:8095af/64+8095b1/00+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Set stamina to 200 + code:8095af/c8+8095b1/00+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Set magic total possible to 10 (and spell points to 100) + code:8095af/0a+8095b1/fc+8095b2/3b+8095b0/8f+8095b3/7e + cheat + description:Set total possible magic to 20 (and spell points to 200) + code:8095af/14+8095b1/fc+8095b2/3b+8095b0/8f+8095b3/7e + cheat + description:Set total possible magic to 25 (and spell points to 250) + code:8095af/19+8095b1/fc+8095b2/3b+8095b0/8f+8095b3/7e + cheat + description:Set strength to 6 + code:8095af/06+8095b1/fd+8095b2/3b+8095b0/8f+8095b3/7e + cheat + description:Set charisma to 6 + code:8095af/06+8095b1/ff+8095b2/3b+8095b0/8f+8095b3/7e + cheat + description:Set karma to 10 (if karma is less than 32) + code:8095af/50+8095b1/11+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Set karma to 20 (if karma is less than 32) + code:8095af/a0+8095b1/11+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Set karma to 31 (if karma is less than 32) + code:8095af/ff+8095b1/11+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Add 32 karma (if karma is less than 32) + code:8095af/01+8095b1/12+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Add 64 karma (if karma is less than 32) + code:8095af/02+8095b1/12+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Add 96 karma (if karma is less than 32) + code:8095af/03+8095b1/12+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Add 192 karma (if karma is less than 32) + code:8095af/06+8095b1/12+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn powerball spell, level 6 + code:8095af/06+8095b1/07+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn heal spell, level 6 + code:8095af/06+8095b1/08+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn invisibility spell, level 6 + code:8095af/06+8095b1/09+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn armor spell, level 6 + code:8095af/06+8095b1/0a+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn summon spirit spell, level 6 + code:8095af/06+8095b1/0b+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn freeze spell, level 6 + code:8095af/06+8095b1/0c+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn firearms skill, level 5 + code:8095af/05+8095b1/01+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn firearms skill, level 10 + code:8095af/0a+8095b1/01+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn firearms skill, level 15 + code:8095af/0f+8095b1/01+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn computer skill, level 6 + code:8095af/06+8095b1/04+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn leadership skill, level 6 + code:8095af/06+8095b1/05+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn armed combat skill, level 6 + code:8095af/06+8095b1/03+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn unarmed combat skill, level 6 + code:8095af/06+8095b1/02+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Learn negotiation skill, level 6 + code:8095af/06+8095b1/06+8095b2/3c+8095b0/8f+8095b3/7e + cheat + description:Start with computer, firearms skills at level 2 + code:8098f3/02 + cheat + description:Start with computer, firearms skills at level 3 + code:8098f3/03 + cheat + description:Start with computer, firearms skills at level 4 + code:8098f3/04 + cheat + description:Start with computer, firearms skills at level 5 + code:8098f3/05 + cheat + description:Start with computer, firearms skills at level 6 + code:8098f3/06 + cheat + description:Start with 2 strength and charisma + code:8098a9/02 + cheat + description:Start with 4 strength and charisma + code:8098a9/04 + cheat + description:Start with 5 strength and charisma + code:8098a9/05 + cheat + description:Start with 6 strength and charisma + code:8098a9/06 + cheat + description:Start with 50 stamina + code:8098b3/32 + cheat + description:Start with 100 stamina + code:8098b3/64 + cheat + description:Lots of Nuyen + code:7e3c0d/7f+7e3c0e/96+7e3c0f/98 + cheat + description:Infinite / max HP + code:7e33de/c8+7e3c00/c8+7e3c01/01 + cheat + description:Debug room accessible + code:7e3bd3/ff+7e3bd4/ff + +cartridge sha256:b0fcef5b3e74ac20ac76720723e1affa5e0d4e3e864d09731ce7fe6f16b7fd28 + name:Shadowrun (USA) (Beta) + cheat + description:Debug room accessible + code:7e3bce/ff+7e3bcf/ff + +cartridge sha256:c73757eea258e169e506eaef989227a59918060f94117917f338183db14c50b6 + name:Shaq-Fu (USA) + cheat + description:Invincibility - P1 + code:c0b290/40+c0b292/d0+c0b28f/e0+c0b291/20 + cheat + description:Hit anywhere - P1 + code:c0b27c/40+c0b27b/e0+c0b27d/20+c0b282/00+c0b281/1c + cheat + description:Infinite continues - Duel Mode + code:c08355/ad + cheat + description:Blood enabled + code:c0958f/00+c094ea/00 + cheat + description:Start with no continues + code:c0cd81/00 + cheat + description:Start with 1 continues + code:c0cd81/01 + cheat + description:Start with 5 continues + code:c0cd81/05 + cheat + description:Start with 9 continues + code:c0cd81/09 + cheat + description:Start with 15 continues + code:c0cd81/0f + +cartridge sha256:dd94308d822636c6ddf73c5e2644c84f2eb8fb4d9201150fc5f37d44d6f423f1 + name:Shin Kidou Senki Gundam W - Endless Duel (Japan) + cheat + description:Hit anywhere - P1 + code:049ad4/47+049ad0/c0+049ad1/00+049ad2/00 + +cartridge sha256:40e25763288521509b2201f5b4e53f3e3bcdfa92e37cf5eeee4f00d8935d534a + name:Shin Nekketsu Kouha - Kunio-tachi no Banka (Japan) + cheat + description:Invincibility + code:82d19a/ad + 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:de2d5a952096c5f50368b9270d342aa6e7a39007ffbec27117e182e30ef4cf32 + name:Sid Meier's Civilization (USA) + cheat + description:Get a new skill every turn + code:c0e84b/00 + cheat + description:Have 42.0 moves until you specify no orders + code:c0d9b3/a9+c0d9b4/7e + cheat + description:Start with more money + code:cc4b24/99+cc4b25/99 + cheat + description:Start with a lot more money + code:cc4b24/ff+cc4b25/ff + cheat + description:Infinite time + code:7e75d7/00 + cheat + description:Max income + code:7e7630/ff + +cartridge sha256:d09ca5adaee65cfd686742482bc55b1a3ce9bc5ebed61f24c5631555151a7fc7 + name: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:d50a40576c5494c039d2da64c19353d5d075345199ae7a9a7a077fde33dbd70c + name:Silva Saga II - The Legend of Light and Darkness (Japan) + cheat + description:No random battles + code:80c769/ad + cheat + description:Walk anywhere + code:80c7ee/80+80c7ef/64 + +cartridge sha256:c0bd1b378337c32047a6b7122a3813beb646e496fbdb1fa5c87ab9856271e4c5 + name:SimAnt - The Electronic Ant Colony (USA) + cheat + description:Always have maximum energy + code:03b1b1/00 + cheat + description:Yellow ant always wins + code:03c639/00 + +cartridge sha256:e9c0bc05511e05a0d7c3e7cc42e761e1e8e532d46f59b9854b6902e1a2e9dd0a + name:SimCity (USA) + cheat + description:Money doesn't decrease for most types of spending + code:01bbc2/ad + cheat + description:Time goes faster + code:038037/00 + cheat + description:Time goes slower + code:038037/0f + cheat + description:Start easy game with $40,000 + code:03c691/40+03c692/9c + cheat + description:Start easy game with $60,000 + code:03c691/60+03c692/ea + cheat + description:Start easy game with $3,000 + code:03c691/b8+03c692/0b + cheat + description:Cheat menu at game exit + code:0188e7/a9+0188e8/80+0188e9/f0 + cheat + description:Infinite Gift Houses + code:7e03f5/01 + cheat + description:Infinite Gift Banks + code:7e03f5/02 + cheat + description:Infinite Gift Amusement Parks + code:7e03f5/03 + cheat + description:Infinite Gift Zoos + code:7e03f5/04 + cheat + description:Infinite Gift Casinos + code:7e03f5/05 + cheat + description:Infinite Gift Landfill + code:7e03f5/06 + cheat + description:Infinite Gift Police HQs + code:7e03f5/07 + cheat + description:Infinite Gift Fire Stations + code:7e03f5/08 + cheat + description:Infinite Gift Fountains + code:7e03f5/09 + cheat + description:Infinite Gift Mario Statue + code:7e03f5/0a + cheat + description:Infinite Gift Expo + code:7e03f5/0b + cheat + description:Infinite Gift Windmills + code:7e03f5/0c + cheat + description:Infinite Gift Libraries + code:7e03f5/0d + cheat + description:Infinite Gift Large Parks + code:7e03f5/0e + cheat + description:Infinite Gift Train Stations + code:7e03f5/0f + +cartridge sha256:bf74c58e4190faca2f3a967dc190fe529d13887d1262b72e057b5353e43cf67f + name:SimCity 2000 - The Ultimate City Simulator (USA) + cheat + description:Start with $99,999,999 on all the maps except the Land Of Freedom + code:c112ed/ff+c112ee/e0+c112f2/f5+c112f3/05 + cheat + description:Start with $99,999,999 on the Land Of Freedom + code:c112e1/ff+c112e2/e0+c112e6/f5+c112e7/05 + +cartridge sha256:446a1036d036986fdea7906c83832d3ba79ef63a6ed8c4e88b89ab9cb25daded + name:SimEarth - The Living Planet (USA) + cheat + description:Infinite Omega energy + code:7f9cd9/00 + +cartridge sha256:f0d98e9061d0f6a193bb856de8a592f336dada97c41966e8d03119ba97465413 + name:Simpsons, The - Bart's Nightmare (USA) + cheat + description:Infinite lives (Bartman and Itchy and Scratchy sub-games) + code:1f92f3/ad + cheat + description:Infinite Z's (main game) + code:15aee7/ad+15aeea/ad + cheat + description:Start with 2 bubbles + code:1588cf/02 + cheat + description:Start with 9 bubbles + code:1588cf/09 + 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:15ac96/b5 + cheat + description:All Pages + code:7e013f/08 + cheat + description:No Pages + code:7e013f/00 + +cartridge sha256:70008efe51185eb0a2f8d8d8ac2bdbb99bd3dfcc169dcc474962f82692998051 + name: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 + name:Skuljagger - Revolt of the Westicans (USA) + cheat + description:Invincibility + code:00aba8/60 + cheat + description:Infinite Red Jemeralds + code:00ab9c/02 + cheat + description:Don't lose Green Jemeralds when you fall and die + code:019a97/ad + cheat + description:Infinite time + code:008c95/00 + cheat + description:Infinite lives + code:00abc1/00+019a92/00 + cheat + description:Die when touched (regardless of Jemeralds) + code:00ab99/80+00aba8/80 + cheat + description:No enemies or Jemeralds (good for exploring, disable to advance) + code:01c690/b9 + cheat + description:Red jemeralds set to 10 after being hit (must have at least 1) + code:00ab9c/11 + cheat + description:Slower timer + code:008c87/70 + cheat + description:Faster timer + code:008c87/1e + cheat + description:Time goes by 2x as fast + code:008c95/02 + cheat + description:Time goes by 4x as fast + code:008c95/04 + cheat + description:Green Jemeralds worth 3 + code:00aadd/03 + cheat + description:Green Jemeralds worth 9 + code:00aadd/09 + cheat + description:Green Jemeralds worth 19 + code:00aadd/19 + cheat + description:Green Jemeralds worth 25 (extra life on each one) + code:00aadd/25 + cheat + description:10 Green Jemeralds gives an extra life + code:00aae3/10 + cheat + description:50 Green Jemeralds gives an extra life + code:00aae3/50 + cheat + description:1 Green Jemerald gives an extra life + code:00aae5/00 + cheat + description:Start with 1 life instead of 5 + code:01bcee/01 + cheat + description:Start with 3 lives + code:01bcee/03 + cheat + description:Start with 9 lives + code:01bcee/09 + cheat + description:Start with 19 lives + code:01bcee/19 + cheat + description:Start with 50 lives + code:01bcee/50 + cheat + description:Start with 99 lives + code:01bcee/99 + cheat + description:Invincibility (alt) + code:7e1a02/08 + cheat + description:Infinite time (alt) + code:7e02be/ff + +cartridge sha256:a4ba1483db79c3f6278082387bce216d8f3e3b11ca32d49516d27f5ac07135a5 + name: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:Hit anywhere + code:018c1e/00+018be8/80 + cheat + description:Get items from anywhere + code:02b7e4/80 + cheat + description:One hit kills + code:01fe7b/00 + cheat + description:Enemies die automatically + code:018b8d/80+018c1e/00+018be8/80+01fe7b/00 + cheat + description:All enemies frozen + code:7efa60/8d+7efa61/8d+7efa62/8d+7efa63/8d+7efa64/8d+7efa65/8d+7efa66/8d+7efa67/8d+7efa68/8d+7efa69/8d+7efa6a/8d+7efa6b/8d+7efa6c/8d+7efa6d/8d+7efa6e/8d+7efa6f/8d+7efa70/8d+7efa71/8d+7efa72/8d+7efa73/8d+7efa74/8d+7efa75/8d+7efa76/8d+7efa77/8d+7efa78/8d+7efa79/8d+7efa7a/8d+7efa7b/8d+7efa7c/8d+7efa7d/8d+7efa7e/8d+7efa7f/8d + 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 + +cartridge sha256:cbca00fa5dfd6c72db2f21d010255657c33f7ac48de2554262035ead11bdf314 + name:Smart Ball (USA) + cheat + description:Infinite lives + code:009155/ad + cheat + description:Protection from most enemies (lose no hearts) + code:009ffa/ad + cheat + description:Infinite red balls on pick-up - until continue + code:008d8b/ad + cheat + description:Go to any level + code:0081d9/33+0081d7/0f + cheat + description:Super-jump + code:00a0e6/fa + cheat + description:Mega-jump + code:00a0e6/f6 + cheat + description:Start with 1 life instead of 3 + code:00820e/01 + cheat + description:Start with 5 lives + code:00820e/05 + cheat + description:Start with 10 lives + code:00820e/0a + cheat + description:Start with 25 lives + code:00820e/19 + cheat + description:Start with 50 lives + code:00820e/32 + cheat + description:Start with 99 lives + code:00820e/63 + +cartridge sha256:6fe7c8d39fcfab7f0a18e837a7ee0dd162e0557d6989c6e0d10c81616d3a0b8b + name:Soldiers of Fortune (USA) + cheat + description:Infinite lives + code:c0a76a/a9 + cheat + description:Smaller food power-ups heal twice as much + code:c0f24f/0a + cheat + description:Smaller food power-ups heal four times as much + code:c0f24f/14 + cheat + description:Large food power-ups heal twice as much + code:c0f254/1e + cheat + description:Large food power-ups heal four times as much + code:c0f254/3c + cheat + description:Only 3 special powers can be stored instead of 6 (handicap) + code:c0f290/04 + cheat + description:Special power power-ups are worth 6 (always fill meter) + code:c0f291/80 + cheat + description:Special powers aren't used up + code:c0a28d/ea + cheat + description:Mercenary starts with much more health + code:cd2df8/60 + cheat + description:Brigand starts with much more health + code:cd2e2f/60 + cheat + description:Gentleman starts with much more health + code:cd2e66/60 + cheat + description:Navvie starts with much more health + code:cd2e9d/60 + cheat + description:Thug starts with much more health + code:cd2ed4/60 + cheat + description:Scientist starts with much more health + code:cd2f0b/60 + cheat + description:Extra lives cost 244 instead of 500 + code:cd1181/00 + cheat + description:Skill power-ups cost 44 instead of 300 + code:cd1183/00 + cheat + description:Health power-ups cost 1 instead of 75 + code:cd1184/01 + cheat + description:Health power-ups cost 25 instead of 75 + code:cd1184/19 + cheat + description:Speed power-ups cost 1 instead of 250 + code:cd1186/01 + cheat + description:Speed power-ups cost 100 instead of 250 + code:cd1186/64 + cheat + description:Wisdom power-ups cost 1 instead of 80 + code:cd1188/01 + cheat + description:Wisdom power-ups cost 25 instead of 80 + code:cd1188/19 + cheat + description:Special powers cost 1 instead of 150 + code:cd118a/01 + cheat + description:Special powers cost 50 instead of 150 + code:cd118a/32 + cheat + description:Weapon power-ups cost 1 instead of 250 + code:cd118e/01 + cheat + description:Weapon power-ups cost 100 instead of 250 + code:cd118e/64 + cheat + description:??? (New Special powers costs 44 instead of 300) + code:cd118d/00 + cheat + description:Brigand starts with Bomb special power + code:cd2f40/01 + cheat + description:Mercenary starts with Bomb special power + code:cd2f44/01 + cheat + description:Gentleman starts with Bomb special power + code:cd2f48/01 + cheat + description:Navvie starts with Bomb special power + code:cd2f4c/01 + cheat + description:Thug starts with Bomb special power + code:cd2f50/01 + cheat + description:Scientist starts with Bomb special power + code:cd2f54/01 + cheat + description:Brigand starts with Shot Burst special power + code:cd2f40/02 + cheat + description:Mercenary starts with Shot Burst special power + code:cd2f44/02 + cheat + description:Gentleman starts with Shot Burst special power + code:cd2f48/02 + cheat + description:Navvie starts with Shot Burst special power + code:cd2f4c/02 + cheat + description:Thug starts with Shot Burst special power + code:cd2f50/02 + cheat + description:Scientist starts with Shot Burst special power + code:cd2f54/02 + cheat + description:Brigand starts with Map special power (must still destroy nodes special power) + code:cd2f40/03 + cheat + description:Mercenary starts with Map special power (must still destroy nodes special power) + code:cd2f44/03 + cheat + description:Gentleman starts with Map special power (must still destroy nodes special power) + code:cd2f48/03 + cheat + description:Navvie starts with Map special power (must still destroy nodes special power) + code:cd2f4c/03 + cheat + description:Thug starts with Map special power (must still destroy nodes special power) + code:cd2f50/03 + cheat + description:Scientist starts with Map special power (must still destroy nodes special power) + code:cd2f54/03 + cheat + description:Brigand starts with Destroy Nodes special power + code:cd2f40/04 + cheat + description:Mercenary starts with Destroy Nodes special power + code:cd2f44/04 + cheat + description:Gentleman starts with Destroy Nodes special power + code:cd2f48/04 + cheat + description:Navvie starts with Destroy Nodes special power + code:cd2f4c/04 + cheat + description:Thug starts with Destroy Nodes special power + code:cd2f50/04 + cheat + description:Scientist starts with Destroy Nodes special power + code:cd2f54/04 + cheat + description:Brigand starts with Repel Monster special power + code:cd2f40/05 + cheat + description:Mercenary starts with Repel Monster special power + code:cd2f44/05 + cheat + description:Gentleman starts with Repel Monster special power + code:cd2f48/05 + cheat + description:Navvie starts with Repel Monster special power + code:cd2f4c/05 + cheat + description:Thug starts with Repel Monster special power + code:cd2f50/05 + cheat + description:Scientist starts with Repel Monster special power + code:cd2f54/05 + cheat + description:Brigand starts with First Aid special power + code:cd2f40/06 + cheat + description:Mercenary starts with First Aid special power + code:cd2f44/06 + cheat + description:Gentleman starts with First Aid special power + code:cd2f48/06 + cheat + description:Navvie starts with First Aid special power + code:cd2f4c/06 + cheat + description:Thug starts with First Aid special power + code:cd2f50/06 + cheat + description:Scientist starts with First Aid special power + code:cd2f54/06 + cheat + description:Brigand starts with Freeze Monster special power + code:cd2f40/07 + cheat + description:Mercenary starts with Freeze Monster special power + code:cd2f44/07 + cheat + description:Gentleman starts with Freeze Monster special power + code:cd2f48/07 + cheat + description:Navvie starts with Freeze Monster special power + code:cd2f4c/07 + cheat + description:Thug starts with Freeze Monster special power + code:cd2f50/07 + cheat + description:Scientist starts with Freeze Monster special power + code:cd2f54/07 + cheat + description:Brigand starts with Shield special power + code:cd2f40/08 + cheat + description:Mercenary starts with Shield special power + code:cd2f44/08 + cheat + description:Gentleman starts with Shield special power + code:cd2f48/08 + cheat + description:Navvie starts with Shield special power + code:cd2f4c/08 + cheat + description:Thug starts with Shield special power + code:cd2f50/08 + cheat + description:Scientists starts with Shield special power + code:cd2f54/08 + cheat + description:Brigand starts with Party Power special power + code:cd2f40/09 + cheat + description:Mercenary starts with Party Power special power + code:cd2f44/09 + cheat + description:Gentleman starts with Party Power special power + code:cd2f48/09 + cheat + description:Navvie starts with Party Power special power + code:cd2f4c/09 + cheat + description:Thug starts with Party Power special power + code:cd2f50/09 + cheat + description:Scientist starts with Party Power special power + code:cd2f54/09 + cheat + description:Brigand starts with Air Burst special power + code:cd2f40/0a + cheat + description:Mercenary starts with Air Burst special power + code:cd2f44/0a + cheat + description:Gentleman starts with Air Burst special power + code:cd2f48/0a + cheat + description:Navvie starts with Air Burst special power + code:cd2f4c/0a + cheat + description:Thug starts with Air Burst special power + code:cd2f50/0a + cheat + description:Scientist starts with Air Burst special power + code:cd2f54/0a + cheat + description:Brigand starts with Distract Monster special power + code:cd2f40/0b + cheat + description:Mercenary starts with Distract Monster special power + code:cd2f44/0b + cheat + description:Gentleman starts with Distract Monster special power + code:cd2f48/0b + cheat + description:Navvie starts with Distract Monster special power + code:cd2f4c/0b + cheat + description:Thug starts with Distract Monster special power + code:cd2f50/0b + cheat + description:Scientist starts with Distract Monster special power + code:cd2f54/0b + cheat + description:Brigand starts with Molotov special power + code:cd2f40/0c + cheat + description:Mercenary starts with Molotov special power + code:cd2f44/0c + cheat + description:Gentleman starts with Molotov special power + code:cd2f48/0c + cheat + description:Navvie starts with Molotov special power + code:cd2f4c/0c + cheat + description:Thug starts with Molotov special power + code:cd2f50/0c + cheat + description:Scientist starts with Molotov special power + code:cd2f54/0c + cheat + description:Brigand starts with Ground Mine special power + code:cd2f40/0d + cheat + description:Mercenary starts with Ground Mine special power + code:cd2f44/0d + cheat + description:Gentleman starts with Ground Mine special power + code:cd2f48/0d + cheat + description:Navvie starts with Ground Mine special power + code:cd2f4c/0d + cheat + description:Thug starts with Ground Mine special power + code:cd2f50/0d + cheat + description:Scientist starts with Ground Mine special power + code:cd2f54/0d + cheat + description:Brigand starts with Dynamite special power + code:cd2f40/0e + cheat + description:Mercenary starts with Dynamite special power + code:cd2f44/0e + cheat + description:Gentleman starts with Dynamite special power + code:cd2f48/0e + cheat + description:Navvie starts with Dynamite special power + code:cd2f4c/0e + cheat + description:Thug starts with Dynamite special power + code:cd2f50/0e + cheat + description:Scientist starts with Dynamite special power + code:cd2f54/0e + cheat + description:Brigand gets Party Power as a 4th special power + code:cd2f43/09 + cheat + description:Mercenary gets Party Power as a 4th special power + code:cd2f47/09 + cheat + description:Navvie gets Party Power as a 3rd special power + code:cd2f4e/09 + cheat + description:Thug gets Party Power as a 3rd special power + code:cd2f52/09 + 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 + name:Sonic Blast Man (USA) + cheat + description:Invincibility + code:00addf/d0 + cheat + description:Infinite health + code:00c15b/ad + cheat + description:Infinite health against most enemy hits + code:00c15b/ad + cheat + description:Infinite health against hits on the head when you're being held + code:00a1e3/ad + cheat + description:Infinite special + code:00a9ea/ad + cheat + description:Infinite Dynamite Punches + code:00a9ea/ad + cheat + description:Infinite lives + code:01c276/00 + cheat + description:Infinite lives (alt) + code:01c278/ad + cheat + description:Infinite credits + code:00cbab/ad + cheat + description:Hit anywhere + code:00c18f/23+00c18e/80 + cheat + description:Super glove worth nothing + code:00c556/ad + cheat + description:Hamburger worth nothing + code:00c52d/00 + cheat + description:Hamburger fully restores health + code:00c52d/50 + cheat + description:Apple worth nothing + code:00c519/00 + cheat + description:Apple fully restores health + code:00c519/50 + cheat + description:Continue with 3/4 health + code:009f79/3c + cheat + description:Continue with 1/2 health + code:009f79/28 + cheat + description:Continue with 1/4 health + code:009f79/14 + cheat + description:Start with 11 lives + code:00809a/03 + cheat + description:Start with 0 dynamite punches + code:00c700/00 + cheat + description:Start with 5 dynamite punches + code:00c700/05 + cheat + description:Start with 7 dynamite punches + code:00c700/07 + cheat + description:Start with 9 dynamite punches + code:00c700/09 + cheat + description:Start with 3/4 health + code:009d50/3c + cheat + description:Start with 1/2 health + code:009d50/28 + cheat + description:Start with 1/4 health + code:009d50/14 + cheat + description:Start on stage 2 + code:0095a5/ee + cheat + description:Start on stage 3 + code:0095a2/a9+0095a4/ea+0095a5/8d+0095a3/02 + cheat + description:Start on stage 4 + code:0095a2/a9+0095a4/ea+0095a5/8d+0095a3/03 + cheat + description:Start on stage 5 + code:0095a2/a9+0095a4/ea+0095a5/8d+0095a3/04 + +cartridge sha256:efe78f6fc68ddd0f6ef0ad9e0223d9417c14fcadece987dc8f50423fd6723b27 + name:Sonic Blast Man II (USA) + cheat + description:Invincibility + code:c04986/ad + cheat + description:Infinite health + code:c04f97/ad + cheat + description:Infinite lives + code:c05476/ad + 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 + name:Soul Blazer (USA) + cheat + description:Invincibility + code:008ef3/ad+00dde1/ad + cheat + description:Have all spirits after obtaining the first one + code:03a7ec/1f + cheat + description:Get max level + code:04f699/00 + cheat + description:Gems set to 999,999 every time one is obtained + code:04f6ba/00 + cheat + description:10 EXP required instead of 100 for level 2 + code:01fbbe/10+01fbbf/00 + cheat + description:180 EXP required instead of 280 for level 3 + code:01fbc3/01 + cheat + description:380 EXP required instead of 580 for level 4 + code:01fbc7/03 + cheat + description:600 EXP required instead of 1,000 for level 5 + code:01fbcb/06 + cheat + description:1,200 EXP required instead of 2,000 for level 6 + code:01fbcf/12 + cheat + description:2,400 EXP required instead of 3,200 for level 7 + code:01fbd3/24 + cheat + description:3,500 EXP required instead of 4,500 for level 8 + code:01fbd7/35 + cheat + description:4,800 EXP required instead of 5,800 for level 9 + code:01fbdb/48 + cheat + description:6,600 EXP required instead of 7,600 for level 10 + code:01fbdf/66 + cheat + description:8,600 EXP required instead of 9,600 for level 11 + code:01fbe3/86 + cheat + description:10,000 EXP required instead of 12,400 for level 12 + code:01fbe7/00 + cheat + description:13,000 EXP required instead of 15,000 for level 13 + code:01fbeb/30 + cheat + description:15,000 EXP required instead of 19,000 for level 14 + code:01fbef/50 + cheat + description:Start with 4 HP + code:04f986/04 + cheat + description:Start with 15 HP + code:04f986/0f + cheat + description:Start with 25 HP + code:04f986/19 + cheat + description:Start with 50 HP + code:04f986/32 + cheat + description:Start with 75 HP + code:04f986/4b + cheat + description:Start with 100 HP + code:04f986/64 + cheat + description:Start with 127 HP + code:04f986/7f + cheat + description:Infinite and max HP + code:7e1b88/64+7e1b8a/64 + cheat + description:Level up more quickly + code:7e1b78/ff + +cartridge sha256:24f3f22949f36ebf8ab4beaa8cba22db107efe7a7585f749343f2860bf041fe1 + name:Space Football - One on One (USA) + cheat + description:Infinite energy + code:00945f/ad + cheat + description:Instant acceleration + code:00df8c/69 + cheat + description:No pushback on firing + code:00a45a/ad + cheat + description:Push forward on firing + code:00a457/69 + +cartridge sha256:dc5353ddc350816619230f25f8c51bddabf7438e6dfba21662eb1c4794856735 + name:Space Invaders (USA) + cheat + description:Infinite lives + code:81871f/a9 + cheat + description:Enemies never move + code:7e03d5/00 + cheat + description:Infinite credits + code:7e03bf/02 + +cartridge sha256:f5b7418c00ccac44615cfc57c7e17d57533837056886f6d733e6b714c36dec1f + name:Space Megaforce (USA) + cheat + description:Invincibility + code:0280be/d0 + cheat + description:Infinite special lives (always respawn after dying as long as you have regular lives remaining) + code:0084a6/ad + cheat + description:Infinite bombs + code:028777/00 + cheat + description:Infinite ships + code:02890f/00 + cheat + description:Protection against enemy hits, and weapon goes to level 2 when hit + code:0288bb/a9+0288bc/06 + cheat + description:Protection against enemy hits, and weapon goes to level 6 when hit + code:0288bb/a9+0288bc/06+0288c8/06 + cheat + description:Hit anywhere + code:01aa01/60+01aa03/d0+01aa04/2c+01aa00/ad+01aa02/0d + cheat + description:Power shots (weapon type 6) last until you pick up another weapon or get hit + code:02b7f6/bd + cheat + description:Weapon capsules give you weapon type 1 + code:02a125/a9+02a126/00 + cheat + description:Weapon capsules give you weapon type 2 + code:02a125/a9+02a126/01 + cheat + description:Weapon capsules give you weapon type 3 + code:02a125/a9+02a126/02 + cheat + description:Weapon capsules give you weapon type 4 + code:02a125/a9+02a126/03 + cheat + description:Weapon capsules give you weapon type 5 + code:02a125/a9+02a126/04 + cheat + description:Weapon capsules give you weapon type 6 + code:02a125/a9+02a126/05 + cheat + description:Bomb capsules worth 0 + code:02a0f8/00 + cheat + description:Bomb capsules worth 2 + code:02a0f8/02 + cheat + description:Bomb capsules worth 4 + code:02a0f8/04 + cheat + description:Bomb capsules worth 6 + code:02a0f8/06 + cheat + description:Start with 0 bombs instead of 3 + code:02a051/00 + cheat + description:Start with 7 bombs + code:02a051/07 + cheat + description:Start with 10 bombs + code:02a051/10 + cheat + description:Start with 25 bombs + code:02a051/25 + cheat + description:Start with 50 bombs + code:02a051/50 + cheat + description:Start with 99 bombs + code:02a051/99 + cheat + description:Start with 2 ships + code:029ffb/01 + cheat + description:Start with 8 ships + code:029ffb/07 + cheat + description:Start with 11 ships + code:029ffb/10 + cheat + description:Start with 26 ships + code:029ffb/25 + cheat + description:Start with 51 ships + code:029ffb/50 + cheat + description:Start with 76 ships + code:029ffb/75 + cheat + description:Start with 100 ships + code:029ffb/99 + cheat + description:Start in area 2 + code:0081c1/a9+0081c2/02 + cheat + description:Start in area 3 + code:0081c1/a9+0081c2/03 + cheat + description:Start in area 4 + code:0081c1/a9+0081c2/04 + cheat + description:Start in area 5 + code:0081c1/a9+0081c2/05 + cheat + description:Start in area 6 + code:0081c1/a9+0081c2/06 + cheat + description:Start in area 7 + code:0081c1/a9+0081c2/07 + cheat + description:Start in area 8 + code:0081c1/a9+0081c2/08 + cheat + description:Start in area 9 + code:0081c1/a9+0081c2/09 + cheat + description:Start in area 10 + code:0081c1/a9+0081c2/0a + cheat + description:Start in area 11 + code:0081c1/a9+0081c2/0b + cheat + description:Start in area 12 + code:0081c1/a9+0081c2/0c + cheat + description:Enable debug mode + code:80fff0/ff + +cartridge sha256:14dc44687c8da35aec63b9edadbaac21bf7293f5171646f614139192e82ab071 + name:Spanky's Quest (USA) + cheat + description:Infinite lives + code:02cca5/24 + cheat + description:Start with 1 life + code:00e367/00 + cheat + description:Start with 6 lives + code:00e367/05 + cheat + description:Start with 10 lives + code:00e367/09 + cheat + description:Start with 1 key in all areas after 1-1 + code:00e514/a9+00e515/01 + cheat + description:Start on area 2-1 + code:00e37f/a9+00e380/01 + cheat + description:Start on area 3-1 + code:00e37f/a9+00e380/02 + cheat + description:Start on area 4-1 + code:00e37f/a9+00e380/03 + cheat + description:Start on area 5-1 + code:00e37f/a9+00e380/04 + +cartridge sha256:eaa06470734ea57eff9b888137aa468fcb7bb149a0870a85e68c9db123de4670 + name:Sparkster (USA) + cheat + description:Invincibility + code:82d234/00 + cheat + description:Invincibility (blinking) + code:82d233/a9+82d234/04 + cheat + description:Infinite health + code:82edff/ea+82d1f8/ea + cheat + description:Infinite health (alt) + code:7e0691/0e + cheat + description:Infinite lives (alt) + code:7e0168/09 + cheat + description:Hit anywhere + code:80e34a/80+8482cd/a5+80e325/00 + cheat + description:1 Jewel needed for 1-up + code:7e016a/63 + +cartridge sha256:fe2371bed45f5e244ce3ef8585894c0ffa4272e3f58c2f4795ef91fb1ee54b15 + name:Spectre (USA) + cheat + description:Infinite ammo + code:00a0b8/ad + cheat + description:Infinite lives + code:00b019/f4 + cheat + description:Infinite health + code:00ae6d/f4 + cheat + description:Infinite hyperspace + code:00a440/ad + cheat + description:Freeze bonus timer + code:00ebd3/ad + 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 + name:Speedy Gonzales - Los Gatos Bandidos (USA) (Rev 1) + cheat + description:Infinite health + code:809227/ad + cheat + description:Infinite time + code:80c25e/ea + cheat + description:Infinite continues + code:81888b/ad + cheat + description:Start with 99 lives + code:8080a8/63 + 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 + name: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 + name:SpellCraft - Aspects of Valor (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 + name:Spider-Man (USA) + cheat + description:Stay invincible after death + code:80a21d/ad + cheat + description:Infinite health + code:829f90/a5 + cheat + description:Infinite lives + code:829f6a/ad + cheat + description:Infinite webbing + code:80a5c6/ae+80acab/ad+80a5a7/ae+80ac1d/ad + cheat + description:Gain webbing instead of losing it + code:80a5c6/ee+80acab/ee+80a5a7/ee+80ac1d/ee + cheat + description:Hit anywhere + code:80ec57/80+80ec0e/80+80ec4f/00+80ec46/00 + cheat + description:Increase diagnol webbing with R button + code:80a5c6/ee + cheat + description:Increase straight webbing with X button + code:80acab/ee + +cartridge sha256:964d21996e385e032b5d18baf716692ba1db780245cd71956c212045c1b8eb9a + name:Spider-Man-Venom - Maximum Carnage (USA) + cheat + description:Invincibility + code:818224/ad + cheat + description:Infinite health + code:81c965/ad + cheat + description:Infinite lives + code:819992/ad + cheat + description:Infinite hero icons on pick-up + code:82d44f/bd + cheat + description:Jump higher + code:81bb46/30 + cheat + description:Hit anywhere + code:8183d3/00 + cheat + description:One hit kills + code:81c08e/80 + cheat + description:Get health pick-up from anywhere + code:82cdee/80+82cdef/33 + cheat + description:Super punch + code:85cd8c/09 + cheat + description:Power hit lasts longer + code:8184c5/04 + cheat + description:Start with 2x health + code:81a2aa/60 + cheat + description:Start with 3x health + code:81a2aa/90 + cheat + description:Start with 1 life + code:81a2b0/01 + cheat + description:Start with 6 lives + code:81a2b0/06 + cheat + description:Start with 9 lives + code:81a2b0/09 + cheat + description:Start with 9 continues + code:81a2b6/09 + cheat + description:Start with 6 continues + code:81a2b6/06 + 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 + name:Spider-Man - X-Men - Arcade's Revenge (USA) + cheat + description:Invincibility after first hit (blinking) - Spider-Man + code:188b60/ad + cheat + description:Infinite health against most hits - Spider-Man + code:18aa98/00 + cheat + description:Protects Spider-Man from ground hazard (looks like silver weeds) + code:18afa5/ad + cheat + description:Infinite lives - Spider-Man + code:18808d/ad + cheat + description:Infinite lives - Gambit + code:138105/ad + cheat + description:Infinite lives - Wolverine, Cyclops, Storm + code:00acde/ad + cheat + description:Spider-Man jumps higher (if you jump too high in some places you die) + code:188d57/a9+188d58/f8 + cheat + description:Start with 1 life instead of 3 + code:0082ba/00 + cheat + description:Start with 5 lives + code:0082ba/04 + cheat + description:Start with 7 lives + code:0082ba/06 + cheat + description:Start with 10 lives + code:0082ba/09 + cheat + description:Start with 26 lives + code:0082ba/19 + cheat + description:Start with 51 lives + code:0082ba/32 + cheat + description:Start with 100 lives + code:0082ba/63 + 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 + name:Spindizzy Worlds (USA) + cheat + description:Faster G.E.R.A.L.D. + code:008214/02 + cheat + description:Slower timer + code:009608/04 + cheat + description:More fuel lost from falling off landscape + code:008ca4/20 + cheat + description:Less fuel lost from falling off landscape + code:008ca4/05 + cheat + description:Almost zero fuel lost from falling off landscape + code:008ca4/00 + cheat + description:Don't lose fuel from anything + code:00f8a3/2c + +cartridge sha256:e0196201e432fa33d46a2681f84fe6a0b5f952ba43f8e4dc325f892bb4a0b39b + name:Spirou (Europe) (En,Fr,De,Es) + cheat + description:Infinite lives + code:7e064c/03 + +cartridge sha256:3857b5294ea8f7468849437bb2d8271564e8a0ff30774622e9c872bcbd53a84d + name:Star Fox (USA) + cheat + description:Invincible right wing + code:7e0402/05 + cheat + description:Invincible left wing + code:7e03cc/05 + cheat + description:Infinite Shield + code:7e0396/35 + cheat + description:Infinite Shield (alt) + code:7e0396/28 + cheat + description:Infinite Shield (alt 2) + code:7e0396/35 + cheat + description:Infinite Shield - Slippy + code:7e18a2/40 + cheat + description:Infinite Shield - Falco + code:7e18a1/40 + cheat + description:Infinite Shield - Peppy + code:7e18a0/40 + cheat + description:Infinite Nova Bombs out + code:7e1528/01 + cheat + description:Infinite Bombs + code:7e15af/05 + cheat + description:Infinite Bombs (alt) + code:7e15af/05 + cheat + description:Infinite lives + code:7e16ee/09 + cheat + description:Infinite lives (alt) + code:7e16ee/0a + cheat + description:All views available in all stages + code:7e14de/05 + cheat + description:Have Double Blaster + code:7e14da/12+7e14d9/01 + cheat + description:Have Double Blaster (alt) + code:7e14da/12 + cheat + description:Have Double Blaster B and infinite Shield + code:7e14d9/03 + +cartridge sha256:2c0bac12a7866fad1cb306da768a201c12f2520332df1ef51cba1576db21ff06 + name:Star Fox - Super Weekend (USA) + 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:82e39dfbb3e4fe5c28044e80878392070c618b298dd5a267e5ea53c8f72cc548 + name:Star Fox (USA) (Rev 2) + cheat + description:Infinite Shield + code:7e0396/35 + cheat + description:Infinite Shield (alt) + code:7e0396/28 + cheat + description:Infinite Shield - Slippy + code:7e18a2/40 + cheat + description:Infinite Shield - Falco + code:7e18a1/40 + cheat + description:Infinite Shield - Peppy + code:7e18a0/40 + cheat + description:Infinite Shield (alt 2) + code:7e0396/35 + +cartridge sha256:efae37be832d0ea1490784d57bef00761a8bf0b5bcef9c23f558e063441c3876 + name:Star Ocean (Japan) + cheat + description:No random battles + code:c27006/80 + cheat + description:Fight one battle for max level / EXP + code:c16ff8/00 + cheat + description:Fight one battle for max Fol + code:c16f1a/00 + 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:c825ba/00+c820ec/5b+c82137/61+c821e2/6d+c821c7/da + cheat + description:Infinite items when using item creation skills + code:cad2ee/bf + +cartridge sha256:3a16ad45ae3d89b13c9e53e21c2a4c725ff7cec7fbe7896d538d163f92cb4aac + name:Star Trek - Deep Space Nine - Crossroads of Time (USA) + cheat + description:Invincibility + code:19edf5/ea+19edf6/ea + cheat + description:Invincibility after first hit + code:19edf7/ad + cheat + description:Infinite energy + code:19eeac/ad + cheat + description:Sisko looks like O'brien + code:009512/04 + cheat + description:Start with 1/4 energy + code:009915/10+00951e/10 + cheat + description:Start with 1/2 energy + code:009915/1d+00951e/1d + cheat + description:Start with 3/4 energy + code:009915/27+00951e/27 + +cartridge sha256:22c907b56ac6f414365801ed375c3fbf75696ce7f34ec89e1724628dc5622957 + name:Star Trek - The Next Generation - Future's Past (USA) + cheat + description:Away Team - Medical packs aren't used up + code:82b46c/00+82b4b0/00 + cheat + description:Away Team - Start each away mission with 1 medical pack + code:80ddc0/01 + cheat + description:Away Team - Start each away mission with 2 medical packs + code:80ddc0/02 + cheat + description:Away Team - Start each away mission with 4 medical packs (only 3 shown) + code:80ddc0/04 + cheat + description:Away Team - Start each away mission with 5 medical packs (only 3 shown) + code:80ddc0/05 + cheat + description:Away Team - Phaser power doesn't go down + code:82c81a/00 + cheat + description:Away Team - Start away missions with phasers at 1/2 power + code:80ddca/18 + cheat + description:Away Team - Start away missions with phasers at 3/4 power + code:80ddca/24 + cheat + description:Away Team - Start away missions with phasers at 1/4 power + code:80ddca/0c + cheat + description:Away Team - Medical packs heal more + code:82b487/80 + cheat + description:Away Team - Medical packs heal twice as much + code:82b488/02 + cheat + description:Away Team - Medical packs heal completely + code:82b488/03 + cheat + description:Away Team - Crew members are immune to enemy fire + code:82c024/bf + cheat + description:Space Combat - Forward torpedoes reload much faster + code:849dd0/01 + cheat + description:Space Combat - Forward torpedoes reload faster + code:849dd0/02 + cheat + description:Space Combat - Aft torpedoes reload much faster + code:849db4/01 + cheat + description:Space Combat - Aft torpedoes reload faster + code:849db4/02 + cheat + description:Space Combat - Forward torpedoes don't require recharging + code:8483a4/ad + cheat + description:Space Combat - Aft torpedoes don't require recharging + code:84833b/ad + cheat + description:Space Combat - Enemy shields regenerate at half speed + code:849d27/08 + cheat + description:Space Combat - Enemy shields regenerate at 1/4 speed + code:849d27/04 + cheat + description:Space Combat - Enemy shields don't regenerate + code:849d27/00 + cheat + description:Space Combat - Enemy shields regenerate faster + code:849d27/18 + cheat + description:Space Combat - Forward phasers never lose power + code:8485c8/ea + cheat + description:Space Combat - Forward phasers don't recharge + code:849ce2/ad + cheat + description:Space Combat - Aft phasers never lose power + code:84855e/ea + cheat + description:Space Combat - Aft phasers don't recharge + code:849cf8/ad + cheat + description:Space Combat - Torpedoes do half damage + code:848923/03 + cheat + description:Space Combat - Torpedoes do less damage + code:848923/04 + cheat + description:Space Combat - Torpedoes do slightly more damage + code:848923/07 + cheat + description:Space Combat - Torpedoes do more damage + code:848923/08 + cheat + description:Space Combat - Torpedoes do much more damage + code:848923/09 + cheat + description:Space Combat - Torpedoes do double damage + code:848923/0c + +cartridge sha256:91f938b4989215b1cd39635797f23b59b9d7b6d36e583f9eb69d022abe537bfc + name: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 + name:Stone Protectors (USA) + cheat + description:Invincibility (blinking) + code:009d85/a9+009d86/05+009d87/9d+00d8de/24 + cheat + description:Don't lose health from special moves + code:00bd62/bd + cheat + description:Infinite lives - P1 + code:00bc6a/ad + cheat + description:Infinite health - P1 + code:7e13cc/b2 + +cartridge sha256:910a29f834199c63c22beddc749baba746da9922196a553255deade59f4fc127 + name:Street Fighter Alpha 2 (USA) + cheat + description:Invincibility (except throws and Akuma's special moves) + code:c0a180/ea+c0a181/e0+c0a182/80+c0a183/09+c0b046/e0+c0b047/00+c0b048/07 + cheat + description:Hit anywhere (except projectiles) - P1 + code:c0a231/e0+c0a232/80+c0a234/90+c0a233/09 + +cartridge sha256:2b34161e96ef3f0f48cecd67e531a9bb94310652d8686f301bac426e4ab97e77 + name:Street Fighter II (USA) + cheat + description:Invincibility (except against throws) - P1 + code:00da3d/80+00da3e/01+00e25d/24 + cheat + description:Win 1 bout to win the match instead of 2 out of 3 (disable before fighting M. Bison) + code:00bb42/01 + cheat + description:Hit anywhere (except projectiles) - P1 + code:00df5b/e0+00df5e/b0+00df5c/00+00df5d/0e + cheat + description:Dizziness wears off very quickly + code:0195f5/f0 + cheat + description:Dizziness lasts longer (on harder levels, won't work on computer) + code:0195f3/a5 + cheat + description:Championship mode on + code:07aa89/20 + cheat + description:Advance to next level when you continue (disable before you continue on M. Bison's stage) + code:00a81e/80+00a81f/11 + cheat + description:High throw and grab damage + code:00cc22/ea+00cc24/1f + cheat + description:Minimum throw and grab damage + code:00cc22/ea+00cc24/ff + cheat + description:Die after 2 hits - both players + code:00e5f8/74 + cheat + description:Round number does not advance (can't fight to a draw) + code:00a7ac/ad + cheat + description:1 draw ends fight in VS. battle + code:00bb6d/01 + cheat + description:Most punches and kicks do no damage + code:00e5f8/b5 + cheat + description:Players move faster + code:018075/6a + cheat + description:Some special moves are faster + code:018075/05 + cheat + description:Can do special moves in the air - both players + code:018663/00 + cheat + description:Dragon punch does not go as high + code:01c076/3e + cheat + description:Dragon punch goes higher + code:01c076/dc + 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:01b821/00 + cheat + description:No pause after throwing a Fireball + code:01c043/01+01c044/c0 + cheat + description:Players can hit each other no matter where they are + code:00df7a/80+00df7b/81 + cheat + description:Do special moves by just pressing buttons (may make Fireballs lower) + code:019bbe/0c + cheat + description:Fireballs are lower to the ground + code:079bb0/00 + cheat + description:Fireballs are higher off the ground + code:079bb0/60 + cheat + description:Fireballs, Sonic Booms and Yoga Fires always go to the right (thrown to the left, they go backwards) + code:01f8e5/00 + cheat + description:Light Fireballs, Sonic Booms and Yoga Fires are slower + code:079bbd/ff + cheat + description:Light Fireballs, Sonic Booms and Yoga Fires are faster + code:079bbd/f9 + cheat + description:Light Fireballs, Sonic Booms and Yoga Fires are super fast + code:079bbd/f0 + cheat + description:Medium Fireballs, Sonic Booms and Yoga Fires are slower + code:079bbf/ff + cheat + description:Medium Fireballs, Sonic Booms and Yoga Fires are faster + code:079bbf/f9 + cheat + description:Medium Fireballs, Sonic Booms and Yoga Fires are super fast + code:079bbf/f0 + cheat + description:Hard Fireballs, Sonic Booms and Yoga Fires are slower + code:079bc1/ff + cheat + description:Hard Fireballs, Sonic Booms and Yoga Fires are faster + code:079bc1/f9 + cheat + description:Hard Fireballs, Sonic Booms and Yoga Fires are super fast + code:079bc1/f0 + cheat + description:Light Sumo Head Butts and Rolling Attacks are slower + code:079868/00+07986e/ff + cheat + description:Light Sumo Head Butts and Rolling Attacks are faster + code:079868/09+07986e/f9 + cheat + description:Light Sumo Head Butts and Rolling Attacks are super fast + code:079868/15+07986e/f0 + cheat + description:Medium Sumo Head Butts and Rolling Attacks are slower + code:07986a/00+079870/ff + cheat + description:Medium Sumo Head Butts and Rolling Attacks are faster + code:07986a/0a+079870/f7 + cheat + description:Medium Sumo Head Butts and Rolling Attacks are super fast + code:07986a/16+079870/ee + cheat + description:Hard Sumo Head Butts and Rolling Attacks are slower + code:07986c/00+079872/ff + cheat + description:Hard Sumo Head Butts and Rolling Attacks are faster + code:07986c/0b+079872/f5 + cheat + description:Hard Sumo Head Butts and Rolling Attacks are super fast + code:07986c/17+079872/ed + cheat + description:Most special moves disabled (computer can still do them, Zangief can still do Spinning Clothesline) + code:00ce2d/80 + cheat + description:Invisible Fireballs, Sonic Booms, Yoga Fires and Yoga Flames + code:00896f/a9 + cheat + description:No Fireballs, Sonic Booms or Yoga Fires, makes Yoga Flame invisible + code:0289b2/6b + cheat + description:Always fight Ryu + code:00cb46/a9+00cb47/ff + cheat + description:Always fight Honda + code:00cb46/a9+00cb47/00 + cheat + description:Always fight Blanka + code:00cb46/a9+00cb47/01 + cheat + description:Always fight Guile + code:00cb46/a9+00cb47/02 + cheat + description:Always fight Ken + code:00cb46/a9+00cb47/03 + cheat + description:Always fight Chun-Li + code:00cb46/a9+00cb47/04 + cheat + description:Always fight Zangief + code:00cb46/a9+00cb47/05 + cheat + description:Always fight Dhalsim + code:00cb46/a9+00cb47/06 + cheat + description:Always fight Balrog + code:00cb46/a9+00cb47/09 + cheat + description:Always fight Vega + code:00cb46/a9+00cb47/0a + cheat + description:Always fight Sagat + code:00cb46/a9+00cb47/08 + cheat + description:Fight M. Bison + code:00cb45/95 + cheat + description:Always fight on bonus stage 1 + code:00cb29/00+00cb2e/80 + cheat + description:Always fight on bonus stage 2 + code:00cb35/00+00cb3b/00 + cheat + description:90 seconds per round instead of 99 + code:0782df/90 + cheat + description:80 seconds per round + code:0782df/80 + cheat + description:70 seconds per round + code:0782df/70 + cheat + description:60 seconds per round + code:0782df/60 + cheat + description:50 seconds per round + code:0782df/50 + cheat + description:40 seconds per round + code:0782df/40 + cheat + description:30 seconds per round + code:0782df/30 + cheat + description:20 seconds per round + code:0782df/20 + cheat + description:10 seconds per round + code:0782df/10 + cheat + description:99 seconds in 1st bonus round instead of 40 + code:0782e3/99 + cheat + description:90 seconds in 1st bonus round + code:0782e3/90 + cheat + description:80 seconds in 1st bonus round + code:0782e3/80 + cheat + description:70 seconds in 1st bonus round + code:0782e3/70 + cheat + description:60 seconds in 1st bonus round + code:0782e3/60 + cheat + description:50 seconds in 1st bonus round + code:0782e3/50 + cheat + description:30 seconds in 1st bonus round + code:0782e3/30 + cheat + description:20 seconds in 1st bonus round + code:0782e3/20 + cheat + description:10 seconds in 1st bonus round + code:0782e3/10 + cheat + description:Start with no health - both players + code:00cba4/00 + cheat + description:Start with no health - P1 + code:00cba6/00 + cheat + description:Start with 3/4 health (1/4 damage) - both players + code:00cba4/84 + cheat + description:Start with 1/2 health (1/2 damage) - both players + code:00cba4/58 + cheat + description:Start with 1/4 health (3/4 damage) - both players + code:00cba4/2c + +cartridge sha256:3e487f8ba48c0b5e31744e3281d6bce375089db6075c8eb3d9a929376b817381 + name:Street Fighter II Turbo (USA) + cheat + description:Invincibility (except against throws) - P1 + code:c055e8/80+c055e9/01+c05d5e/a9+c05d5f/00+c05d60/09+c05d61/24+c05d63/ea + cheat + description:Infinite time + code:c04875/00 + cheat + description:Hit anywhere (except projectiles) - P1 + code:c05abd/e0+c05ac0/b0+c05abe/00+c05abf/07 + cheat + description:Some special moves can be performed in the air (Don't perform Vega's wall leap) + code:c11062/00 + cheat + description:Most attacks do no damage (throws still work) + code:c0621b/b5 + cheat + description:Throws do no damage + code:c1ec29/a3 + cheat + description:1st throws do more damage (if you have enough health), others do less damage + code:c1ec29/14 + cheat + description:Players can walk through each other + code:c0e317/00 + cheat + description:1st hit of any kind defeats opponent + code:c061bd/00 + cheat + description:Winner of 2nd round wins the battle + code:c04523/01 + cheat + description:Enable 10 star turbo mode + code:c013a9/c0+c013aa/15 + cheat + description:No charging required for special moves (except Balrog's turn punch power) + code:c1336a/04 + cheat + description:Hard special moves become light + code:c1327a/00 + cheat + description:Hard special moves become medium + code:c13a7a/02 + cheat + description:Hard special moves become disabled + code:c3367a/08 + cheat + description:Invisible players + code:c106df/bf + cheat + description:Most special moves go nowhere + code:c1e4e3/a5 + cheat + description:Fireballs go nowhere + code:c19cbf/a5 + cheat + description:Hard Hurricane Kicks go faster and farther (to the right only) + code:80e15b/04 + cheat + description:Ryu's hard Dragon Punch doesn't go as far + code:80e143/01 + cheat + description:Ryu's hard Dragon Punch goes farther + code:80e143/08 + cheat + description:Ryu's medium Dragon Punch doesn't go as far + code:80e141/01 + cheat + description:Ryu's medium Dragon Punch goes farther + code:80e141/08 + cheat + description:Ryu's light Dragon Punch goes farther + code:80e13f/08 + cheat + description:Ryu jumps backward farther + code:80d583/07 + cheat + description:Ryu jumps forward farther + code:80d57b/f7 + cheat + description:Ken jumps backward farther + code:80d603/07 + cheat + description:Ken jumps forward farther + code:80d5fb/f7 + cheat + description:Ken's hard Dragon Punch doesn't go as far + code:80e14f/01 + cheat + description:Ken's hard Dragon Punch goes farther + code:80e14f/0e + cheat + description:Ken's medium Dragon Punch doesn't go as far + code:80e14d/01 + cheat + description:Ken's medium Dragon Punch goes farther + code:80e14d/0b + cheat + description:Ken's light Dragon Punch goes farther + code:80e14b/08 + cheat + description:Hard projectiles go faster (except tiger shots) + code:80e36f/ef + cheat + description:Hard projectiles go slower (except tiger shots) + code:80e36f/ff + cheat + description:Medium projectiles go faster (except tiger shots) + code:80e36d/ef + cheat + description:Medium projectiles go slower (except tiger shots) + code:80e36d/ff + cheat + description:Light projectiles go faster (except tiger shots) + code:80e36b/ef + cheat + description:Light projectiles go slower (except tiger shots) + code:80e36b/ff + cheat + description:Edmond Honda's hard Sumo Head Butts are faster + code:80e177/0f + cheat + description:Edmond Honda's hard Sumo Head Butts are slower + code:80e177/01 + cheat + description:Edmond Honda's medium Sumo Head Butts are faster + code:80e175/0f + cheat + description:Edmond Honda's medium Sumo Head Butts are slower + code:80e175/01 + cheat + description:Edmond Honda's light Sumo Head Butts are faster + code:80e173/0f + cheat + description:Edmond Honda's light Sumo Head Butts are slower + code:80e173/01 + cheat + description:Edmond Honda's hard Sumo Smashes are faster + code:80e180/12 + cheat + description:Edmond Honda's medium Sumo Smashes are faster + code:80e17e/12 + cheat + description:Edmond Honda's light Sumo Smashes are faster + code:80e17c/12 + cheat + description:Sagat's hard Tiger Uppercut goes farther + code:80e29d/08 + cheat + description:Sagat's medium Tiger Uppercut goes farther + code:80e29b/08 + cheat + description:Sagat's light Tiger Uppercut goes farther + code:80e299/08 + cheat + description:Sagat's high Tiger Shots are disabled (you can still do the move but no projectile comes out) + code:80e359/02 + cheat + description:Sagat's hard Tiger Knee goes farther + code:80e2b5/0b + cheat + description:Sagat's medium Tiger Knee goes farther + code:80e2ad/0b + cheat + description:Sagat's light Tiger Knee goes farther + code:80e2a5/0b + cheat + description:M. Bison's hard Psycho Crusher goes slower + code:80e259/01 + cheat + description:M. Bison's hard Psycho Crusher goes faster + code:80e259/0a + cheat + description:M. Bison's medium Psycho Crusher goes slower + code:80e257/01 + cheat + description:M. Bison's medium Psycho Crusher goes faster + code:80e257/0a + cheat + description:M. Bison's light Psycho Crusher goes slower + code:80e255/01 + cheat + description:M. Bison's light Psycho Crusher goes faster + code:80e255/0a + cheat + description:M. Bison's hard Scissor Kick goes slower (not in normal mode) + code:80e262/01 + cheat + description:M. Bison's hard Scissor Kick goes faster (not in normal mode) + code:80e262/0a + cheat + description:M. Bison's medium Scissor Kick goes slower (not in normal mode) + code:80e260/01 + cheat + description:M. Bison's medium Scissor Kick goes faster (not in normal mode) + code:80e260/0a + cheat + description:M. Bison's light Scissor Kick goes slower (not in normal mode) + code:80e25e/01 + cheat + description:M. Bison's light Scissor Kick goes faster (not in normal mode) + code:80e25e/0a + cheat + description:Balrog's first Dash Punch goes slower + code:c18850/01 + cheat + description:Balrog's first Dash Punch goes faster + code:c18850/0b + cheat + description:Balrog's first Turn Punch goes slower (and a little backward) + code:80e2d5/02 + cheat + description:Balrog's first Turn Punch goes faster + code:80e2d5/0a + cheat + description:Chun Li's hard Whirlwind Kick goes farther + code:80e1b6/0a + cheat + description:Chun Li's medium Whirlwind Kick doesn't go as far + code:80e1b4/01 + cheat + description:Chun Li's medium Whirlwind Kick goes farther + code:80e1b4/0a + cheat + description:Chun Li's light Whirlwind Kick doesn't go as far + code:80e1b2/01 + cheat + description:Chun Li's light Whirlwind Kick goes farther + code:80e1b2/0a + cheat + description:Blanka's hard Rolling Attack goes slower + code:80e198/01 + cheat + description:Blanka's hard Rolling Attack goes faster + code:80e198/0a + cheat + description:Blanka's medium Rolling Attack goes slower + code:80e196/01 + cheat + description:Blanka's medium Rolling Attack goes faster + code:80e196/0a + cheat + description:Blanka's light Rolling Attack goes slower + code:80e194/01 + cheat + description:Blanka's light Rolling Attack goes faster + code:80e194/0a + cheat + description:Blanka's hard Vertical Rolling Attack doesn't go as far + code:80e1a1/01 + cheat + description:Blanka's hard Vertical Rolling Attack goes out farther + code:80e1a1/0c + cheat + description:Blanka's medium Vertical Rolling Attack doesn't go as far + code:80e19f/01 + cheat + description:Blanka's medium Vertical Rolling Attack goes out farther + code:80e19f/0c + cheat + description:Blanka's light Vertical Rolling Attack doesn't go as far + code:80e19d/01 + cheat + description:Blanka's light Vertical Rolling Attack goes out farther + code:80e19d/0c + cheat + description:Start with 90 seconds + code:80c1ee/90 + cheat + description:Start with 70 seconds + code:80c1ee/70 + cheat + description:Start with 50 seconds + code:80c1ee/50 + cheat + description:Start with 30 seconds + code:80c1ee/30 + cheat + description:Start with 10 seconds + code:80c1ee/10 + cheat + description:Start with 3/4 health + code:c0536e/84 + cheat + description:Start with 1/2 health + code:c0536e/58 + cheat + description:Start with 1/4 health + code:c0536e/2c + cheat + description:1st bonus round is 99 seconds + code:80c1f0/99 + cheat + description:1st bonus round is 80 seconds + code:80c1f0/80 + cheat + description:1st bonus round is 60 seconds + code:80c1f0/60 + cheat + description:1st bonus round is 20 seconds + code:80c1f0/20 + cheat + description:2nd bonus round is 99 seconds + code:80c1f2/99 + cheat + description:2nd bonus round is 80 seconds + code:80c1f2/80 + cheat + description:2nd bonus round is 60 seconds + code:80c1f2/60 + cheat + description:2nd bonus round is 20 seconds + code:80c1f2/20 + 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:d1f61b6bb4bb6879a4fbd2c82d77390c546ee7f821edddc884fb9cc7463ad79b + name:Street Racer (USA) + cheat + description:Infinite time + code:7e1833/00 + cheat + description:Secret tracks + code:7e53b4/01 + cheat + description:P1 Infinite health + code:7e1821/00 + cheat + description:P1 Infinite health (alt) + code:7e5382/00 + cheat + description:P2 Infinite health + code:7e1823/00 + cheat + description:P2 Infinite health (alt) + code:7e5384/00 + cheat + description:P3 Infinite health + code:7e1825/00 + cheat + description:P3 Infinite health (alt) + code:7e5386/00 + cheat + description:P4 Infinite health + code:7e1827/00 + cheat + description:P4 Infinite health (alt) + code:7e5388/00 + cheat + description:P1 Infinite Nitros + code:7e16f1/63 + cheat + description:P1 No Nitros + code:7e16f1/00 + cheat + description:P2 Infinite Nitros + code:7e16f3/63 + cheat + description:P2 No Nitros + code:7e16f3/00 + cheat + description:P3 Infinite Nitros + code:7e16f5/63 + cheat + description:P3 No Nitros + code:7e16f5/00 + cheat + description:P4 Infinite Nitros + code:7e16f7/63 + cheat + description:P4 No Nitros + code:7e16f7/00 + cheat + description:P1 Infinite credits + code:7e1d2a/03 + cheat + description:P2 Infinite credits + code:7e1d2c/03 + cheat + description:P3 Infinite credits + code:7e1d2e/03 + cheat + description:P4 Infinite credits + code:7e1d30/03 + cheat + description:P1 No weapons + code:7e5372/00 + cheat + description:P2 No weapons + code:7e5374/00 + cheat + description:P3 No weapons + code:7e5376/00 + cheat + description:P4 No weapons + code:7e5378/00 + cheat + description:P1 No fighting + code:7e537a/00 + cheat + description:P2 No fighting + code:7e537c/00 + cheat + description:P3 No fighting + code:7e537e/00 + cheat + description:P4 No fighting + code:7e5380/00 + cheat + description:P1 No collisions + code:7e538a/00 + cheat + description:P2 No collisions + code:7e538c/00 + cheat + description:P3 No collisions + code:7e538e/00 + cheat + description:P4 No collisions + code:7e5390/00 + cheat + description:P1 On last lap + code:7e1bcf/05 + cheat + description:P2 On last lap + code:7e1bd1/05 + cheat + description:P3 On last lap + code:7e1bd3/05 + cheat + description:P4 On last lap + code:7e1bd5/05 + +cartridge sha256:05f14e6ed3394d9273e2397769a8acf1a9db646be6066e82269521e8eec53562 + name:Strike Gunner S.T.G (USA) + cheat + description:Infinite lives - P1 + code:00952e/ad + cheat + description:Infinite lives - P2 + code:0095ba/ad + cheat + description:Infinite continues + code:1e80d7/ad + cheat + description:Infinite special weapon energy - P1 + code:00f0ca/ad + cheat + description:Infinite special weapon energy - P2 + code:00f123/ad + cheat + description:Hit anywhere - main weapon + code:00d46a/24+00d46f/24+00e7fb/24+00e7e8/80+00e7e0/80 + cheat + description:Start on stage 2 + code:008059/a9+00805a/01+00805b/ea + cheat + description:Start on stage 3 + code:008059/a9+00805a/02+00805b/ea + cheat + description:Start on stage 4 + code:008059/a9+00805a/03+00805b/ea + cheat + description:Start on stage 5 + code:008059/a9+00805a/04+00805b/ea + cheat + description:Start on stage 6 + code:008059/a9+00805a/05+00805b/ea + cheat + description:Invincibility after first life - P1 + code:7e024e/05 + cheat + description:Invincibility after first life - P2 + code:7e024f/05 + +cartridge sha256:c04d80b84514202ff319384ca20641eb0189e975eed5612915bd9c224b2ab30a + name:Stunt Race FX (USA) (Rev 1) + cheat + description:Always first place + code:07ddfc/6b + cheat + description:Choose any car + code:0bc7f0/d0 + 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 + name:Sunset Riders (USA) + cheat + description:Invincibility + code:818682/ee + cheat + description:Infinite lives + code:80e7d1/bd + cheat + description:Start a new game for stage select and sound test + code:80887b/14 + +cartridge sha256:190999122aacc2cff20c5677b3f60ed938d8a36b696d16cc1bf416705efe151e + name:Super Adventure Island (USA) + cheat + description:Infinite lives + code:0090ea/ad + cheat + description:Infinite credits + code:00a105/ad + cheat + description:Fruit restores full time + code:0498f5/a9+0498f6/10 + cheat + description:Super-jump (don't use the game's super-jump feature) + code:00b0a5/35 + cheat + description:Mega-jump (don't use the game's super-jump feature) + code:00b0a5/24 + cheat + description:Hit anywhere + code:03b6eb/d0+03b6ea/80+03b6e9/a5+00d161/00+03b6ec/1e + cheat + description:Multi-jump + code:00fd26/05+00fd27/a9+00fd28/00+00fd29/fa+00fd2a/95+00fd2b/1a+00fd2c/68+00fd2d/60+00b2a8/20+00b2a9/20+00b2aa/fd+00fd20/ad+00fd21/f8+00fd22/0b+00fd23/48+00fd24/0a+00fd25/10 + cheat + description:Don't lose all weapon power when you die (may give you unusual weapons) + code:00a34c/35+00a388/35 + cheat + description:Start with 1 life instead of 3 + code:0086ca/00 + cheat + description:Start with 5 lives + code:0086ca/04 + cheat + description:Start with 10 lives + code:0086ca/09 + cheat + description:Start with 15 lives + code:0086ca/0e + cheat + description:Start with 25 lives + code:0086ca/18 + cheat + description:Start with 50 lives + code:0086ca/31 + cheat + description:Start with 99 lives + code:0086ca/62 + cheat + description:Start with 1 credit + code:0086cf/00 + cheat + description:Start with 6 credits + code:0086cf/05 + cheat + description:Start in area 1, stage 2 + code:008d84/03 + cheat + description:Start in area 1 bonus round + code:008d84/05 + cheat + description:Start in area 1, stage 3 + code:008d84/07 + cheat + description:Start in area 2, stage 1 + code:008d84/0a + cheat + description:Start in area 2, stage 2 + code:008d84/0c + cheat + description:Start in area 2 bonus round + code:008d84/0e + cheat + description:Start in area 2, stage 3 + code:008d84/11 + cheat + description:Start in area 3, stage 1 + code:008d84/14 + cheat + description:Start in area 3, stage 2 + code:008d84/18 + cheat + description:Start in area 3, stage 3 + code:008d84/1a + cheat + description:Start in area 4, stage 1 + code:008d84/1d + cheat + description:Start in area 4, stage 2 + code:008d84/1f + cheat + description:Start in area 4 bonus round + code:008d84/20 + cheat + description:Start in area 4, stage 3 + code:008d84/24 + cheat + description:Start in area 5, stage 1 + code:008d84/27 + cheat + description:Start in area 5, stage 2 + code:008d84/29 + cheat + description:Start in area 5, stage 3 + code:008d84/2b + cheat + description:Start in area 5, bonus round + code:008d84/2d + 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 + name:Super Adventure Island II (USA) + cheat + description:Infinite health + code:c05795/ad + cheat + description:Almost invincible after one hit + code:c20687/ad + cheat + description:Stacks of cash + code:c02372/a9 + cheat + description:Small potions don't restore health + code:cf9c22/ad + cheat + description:Fall slowly + code:c2146d/01 + cheat + description:Don't fall at all (disable to touch the ground again) + code:c2146d/00 + 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 + name:Super Alfred Chicken (USA) + cheat + description:Infinite time + code:81ac23/ad + cheat + description:Infinite lives + code:819fa4/ad + cheat + description:Infinite lives (alt) + code:7e0012/04 + cheat + description:Infinite time (alt) + code:7e0017/09 + cheat + description:Infinite balloons + code:81a4e1/ad + +cartridge sha256:e57aa265b2fbfb7ee7f5488a3df06ae771db202d59ebbd13df8fc2db80a856f3 + name:Super Back to the Future Part II (Japan) + cheat + description:Invincibility + code:7e1401/ff + cheat + description:Infinite health + code:7e009a/03 + +cartridge sha256:1622371a5a4001fff9690323e89b7a8d449cdc3cae6dcd1249f0c7dc8c651d33 + name:Super Baseball Simulator 1.000 (USA) + cheat + description:Infinite added points + code:02aa0a/00 + cheat + description:Fewer "HR" points to distribute - standard game + code:02e8f6/3b + cheat + description:Fewer "R" points to distribute - standard game + code:02e8f8/50 + cheat + description:Fewer "F" points to distribute - standard game + code:02e8fa/14 + cheat + description:More "AV" points to distribute - moderate game + code:02e91d/09 + cheat + description:More "HR" points to distribute - moderate game + code:02e91f/01+02e91e/90 + cheat + description:More "R" points to distribute - moderate game + code:02e920/68+02e921/01 + cheat + description:More "F" points to distribute - moderate game + code:02e922/64 + +cartridge sha256:a8239355631d303ecebfd43fc14e80f148e4ac9937234e29cc87d6f939b033a0 + name:Super Bases Loaded (USA) + cheat + description:Game lasts 1 inning + code:00c36a/00+00c34e/01+00f246/01 + cheat + description:Game lasts 2 innings + code:00c36a/02+00c34e/03+00f246/03 + cheat + description:Game lasts 3 innings + code:00c36a/04+00c34e/05+00f246/05 + cheat + description:Game lasts 5 innings + code:00c36a/08+00c34e/09+00f246/09 + cheat + description:Game lasts 7 innings + code:00c36a/0c+00c34e/0d+00f246/0d + cheat + description:1 strike and batter is out + code:00ce16/01+00cddc/00 + cheat + description:2 strikes and batter is out + code:00ce16/02+00cddc/01 + cheat + description:4 strikes and batter is out + code:00ce16/04+00cddc/03 + cheat + description:5 strikes and batter is out + code:00ce16/05+00cddc/04 + cheat + description:7 strikes and batter is out + code:00ce16/07+00cddc/06 + cheat + description:9 strikes and batter is out + code:00ce16/09+00cddc/08 + cheat + description:Batter never strikes out + code:00f0b5/ad + cheat + description:Batter walks on 1 ball + code:00ce75/01+00ce3e/00 + cheat + description:Batter walks on 2 balls + code:00ce75/02+00ce3e/01 + cheat + description:Batter walks on 3 balls + code:00ce75/03+00ce3e/02 + cheat + description:Batter walks on 5 balls + code:00ce75/05+00ce3e/04 + cheat + description:Batter walks on 6 balls + code:00ce75/06+00ce3e/05 + cheat + description:Batter walks on 9 balls + code:00ce75/09+00ce3e/08 + cheat + description:Batter never walks + code:00f0c9/ad + cheat + description:1 out per inning + code:00f13f/00 + cheat + description:2 outs per inning + code:00f13f/01 + cheat + description:4 outs per inning + code:00f13f/03 + cheat + description:5 outs per inning + code:00f13f/04 + cheat + description:7 outs per inning + code:00f13f/06 + cheat + description:9 outs per inning + code:00f13f/08 + +cartridge sha256:b21a161fed748920e54cd72c54095416b1d999636e0388d7d147884779c52833 + name:Super Bases Loaded 3 - License to Steal (USA) + cheat + description:No strikes + code:8188f1/ad + cheat + description:One strike to strike out + code:8188f8/01 + cheat + description:Ten strikes to strike out + code:8188f8/0a + cheat + description:Infinite strikes gives P1 a homerun + code:8188f2/77 + cheat + description:Infinite strikes gives opponent a homerun + code:8188f2/78 + cheat + description:Walk on one ball + code:818a1a/01 + cheat + description:Walk on ten balls + code:818a1a/0a + cheat + description:Infinite balls gives P1 a homerun + code:818a14/77 + cheat + description:Infinite balls gives opponent a homerun + code:818a14/78 + +cartridge sha256:165938810948f3226f7446978fa36ae8bc781616d95b39cd126d5c8afbf6e2ee + name:Super Batter Up (USA) + cheat + description:Batter never walks + code:0391d2/ad + cheat + description:Batter never strikes out + code:039208/ad + cheat + description:1 ball per walk + code:0391d9/01 + cheat + description:2 balls per walk + code:0391d9/02 + cheat + description:3 balls per walk + code:0391d9/03 + cheat + description:5 balls per walk + code:0391d9/05 + cheat + description:6 balls per walk + code:0391d9/06 + cheat + description:7 balls per walk + code:0391d9/07 + cheat + description:1 strike per out + code:03920f/01 + cheat + description:2 strikes per out + code:03920f/02 + cheat + description:4 strikes per out + code:03920f/04 + cheat + description:5 strikes per out + code:03920f/05 + +cartridge sha256:b68e865b0b5fe6af421a171e94fb1cb0006ae3e412b6361f6f858c44adaa304b + name: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 + name:Super Bomberman (USA) + cheat + description:Invincibility (normal game) + code:c414ac/b5 + cheat + description:Infinite lives (normal game) + code:c419fe/b5 + 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:Hit anywhere + code:c60c0f/40+c60c0b/66+c60c0a/ad+c60c0c/0d + cheat + description:Walk anywhere + code:c60b99/18 + cheat + description:Remove all blocks + code:c61aa9/01 + 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 + name: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:Hit anywhere + code:c150d4/40+c150d6/d0+c150d3/29+c150d0/c4+c150cf/a5 + cheat + description:Walk through chests + code:c0b3f4/97 + 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 + name:Super Bonk (USA) + cheat + description:Invincibility + code:82c3af/60+819378/80+819353/80 + cheat + description:Infinite lives + code:82f82f/ad + 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 + cheat + description:Press up to fly on any level + code:82ec65/a9+82ec67/ea + cheat + description:Hit anywhere + code:8191ee/80+88a589/00 + +cartridge sha256:946de556b4f877e54e16b5c828db89c038e50349cfd0ddf8ea96b6541f9d70fa + name:Super Bowling (USA) + cheat + description:No spin on ball + code:00a9ca/2c + cheat + description:Faster spin meter + code:00a073/06 + cheat + description:Slower spin meter + code:00a073/02 + cheat + description:Really slow spin meter + code:00a073/01 + cheat + description:Faster power meter + code:00a078/06 + cheat + description:Slower power meter + code:00a078/02 + cheat + description:Really slow power meter + code:00a078/01 + +cartridge sha256:dc233b2805f7f73b454b53e45eef50df18932a1753fc0b7bc846bbd70a8993c3 + name:Super Buster Bros. (USA) (Rev 1) + cheat + description:Extra credit after 2 food items instead of 10 + code:01d39c/02 + cheat + description:Extra credit after 4 food items + code:01d39c/04 + cheat + description:Extra credit after 6 food items + code:01d39c/06 + cheat + description:Extra credit after 8 food items + code:01d39c/08 + cheat + description:Food items never earn extra credit + code:01d39a/ea + 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 + name:Super Buster Bros. (USA) + cheat + description:Infinite lives + code:0099df/00 + cheat + description:Infinite credits + code:009a51/a5 + cheat + description:Clock runs faster + code:00b9e2/19 + cheat + description:Clock runs slower + code:00b9e2/64 + cheat + description:Clock runs much slower + code:00b9e2/c8 + cheat + description:Clock is frozen (no time limit) + code:00b9ed/00 + cheat + description:Food items never earn extra credit + code:01d39a/ea + cheat + description:Double harpoon pick-up gives you machine gun + code:02bf23/06 + cheat + description:Retain weapon after dying or advancing thru stages + code:0282f4/a5 + cheat + description:Panic mode has 2 levels instead of 99 + code:00b840/03+00b865/03 + cheat + description:Panic mode has 5 levels + code:00b840/06+00b865/06 + cheat + description:Panic mode has 10 levels + code:00b840/0b+00b865/0b + cheat + description:Panic mode has 20 levels + code:00b840/15+00b865/15 + cheat + description:Extra credit after 2 food items instead of 10 + code:01d39c/02 + cheat + description:Extra credit after 4 food items + code:01d39c/04 + cheat + description:Extra credit after 6 food items + code:01d39c/06 + cheat + description:Extra credit after 8 food items + code:01d39c/08 + cheat + description:1 credit + code:038161/00 + cheat + description:2 credits + code:038161/01 + cheat + description:3 credits + code:038161/02 + cheat + description:4 credits + code:038161/03 + cheat + description:6 credits + code:038161/05 + cheat + description:8 credits + code:038161/07 + cheat + description:No credits + code:038161/ff + cheat + description:Start with 2 lives + code:038160/01 + cheat + description:Start with 3 lives + code:038160/02 + cheat + description:Start with 5 lives + code:038160/04 + cheat + description:Start with 6 lives + code:038160/05 + cheat + description:Start with 8 lives + code:038160/07 + cheat + description:Start with 10 lives + code:038160/09 + cheat + description:Start with 1 life + code:038160/00 + 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 + name: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 + name:Super Castlevania IV (USA) + cheat + description:Invincibility + code:00da9e/d0+00a80e/d0 + cheat + description:Invincibility (blinking) + code:06b4fc/84+00daa0/a5 + cheat + description:Infinite health + code:00dd1c/ad + cheat + description:Infinite health against most enemies + code:00dd1c/0d + cheat + description:Infinite lives (disable to get password) + code:0280a2/00 + cheat + description:Infinite time + code:028005/80 + cheat + description:Infinite lives + code:0280a4/a5 + cheat + description:Infinite shots for most weapons + code:00bd54/c8 + cheat + description:Hit anywhere (cannot use whip to grab onto things, press Y to moon jump instead) + code:00dbb7/92+00dbb8/a3+00dbae/00+00db4f/80+00db66/80 + cheat + description:Fully powered whip with first power-up + code:00df24/00 + cheat + description:Increase heart capacity 2.5 times + code:00de93/ff+00de78/1a+00de8e/ff + cheat + description:Max hearts on pick-up + code:00de91/00 + cheat + description:Double Shot gives you a Triple Shot + code:00df9e/ff + cheat + description:Slower timer + code:028003/7f + cheat + description:Faster timer + code:028003/1f + cheat + description:Super-jump + code:00a978/10 + cheat + description:Mega-jump + code:00a978/20 + cheat + description:Multi-jump + code:028000/6b+00b7ca/ad+00a211/6b+00da91/28+00da92/0a+00da93/90+00da94/04+00da95/22+00da96/92+00da97/a3+00da98/00+00da99/ea + cheat + description:Start with and always keep Dagger + code:00c6c3/a9+00c6c4/01+00c6c6/85 + cheat + description:Start with and always keep Axe + code:00c6c3/a9+00c6c4/02+00c6c6/85 + cheat + description:Start with and always keep Holy Water + code:00c6c3/a9+00c6c4/03+00c6c6/85 + cheat + description:Start with and always keep Boomerang + code:00c6c3/a9+00c6c4/04+00c6c6/85 + cheat + description:Start with and always keep Stopwatch + code:00c6c3/a9+00c6c4/05+00c6c6/85 + cheat + description:Start with 99 hearts - first life only + code:0094e9/99 + cheat + description:Start with 50 hearts - first life only + code:0094e9/50 + cheat + description:Start with 10 lives - first game only + code:0094db/10 + cheat + description:Start with 1 life - first game only + code:0094db/01 + 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 + name: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 + name:Super Donkey Kong 2 - Dixie & Diddy (Japan) + cheat + description:Invincibility + code:b8d0d9/24 + +cartridge sha256:bcced1be76ef920b562a555696bcb4583d1c8cea4d4b057cab6e0e09be8ef8c4 + name:Super Double Dragon (USA) + cheat + description:Invincibility - both players + code:02811e/60 + cheat + description:Invincibility - P1 + code:028130/ad + cheat + description:Infinite lives - P1 + code:01be85/ad + cheat + description:Infinite lives - P1 (alt) + code:01be85/2c + cheat + description:Dragon power increases faster + code:059bec/00 + cheat + description:Prolonged maximum dragon power + code:059fde/03 + cheat + description:1 extra credit - 2P game A + code:02b5ad/01 + cheat + description:9 lives - 1P game + code:02b58d/09 + cheat + description:6 lives - 1P game + code:02b58d/06 + cheat + description:1 life - 1P game + code:02b58d/01 + cheat + description:9 lives - 2P game A + code:02b5b2/09 + cheat + description:6 lives - 2P game A + code:02b5b2/06 + cheat + description:1 life - 2P game A + code:02b5b2/01 + 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:4decfd480780d91f70f01c70552abd25a8ac0f8f6ceb49d1a5e72ba486203afc + name:Super Fire Pro Wrestling X Premium (Japan) + cheat + description:Infinite attribute points in wrestler edit (ignore display) + code:7e16be/00 + +cartridge sha256:7468c271d7240cf4e0d08c16e9969a1b1b1caf5adc0e5adc568d93c92651a057 + name: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:7e0276/02 + cheat + description:Invincibility (alt) + code:01d164/00 + cheat + description:Never lose Armor + code:7e044a/01+7e14ba/01 + cheat + description:Infinite time + code:01b985/cd + cheat + description:Infinite lives + code:01ab61/cd + cheat + description:Infinite double-jumps + code:01cf7b/ad + cheat + description:Infinite shield hits + code:02ff3a/80 + cheat + description:Infinite continues + code:04968c/00 + cheat + description:Hit anywhere + code:02fd1d/60+02fc7d/ad+02fbc9/ad + cheat + description:Very few Zombies appear + code:01939a/a5 + cheat + description:Most Zombies carry a basket + code:028c77/01+069f05/a9 + cheat + description:Slower timer + code:01b981/5e + cheat + description:Faster timer + code:01b981/1f + cheat + description:Start with 9 minutes + code:01adea/09 + cheat + description:Start with 1 continue + code:01ab49/01 + cheat + description:Start with 9 continues + code:01ab49/09 + 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 + cheat + description:Stage select enabled (in options menu) + code:7e02b9/32+7e02ba/16 + +cartridge sha256:33dda5838264c93341ef865512e4b86e16fd4a0387eda04e331517bfaecf1c0b + name:Super Godzilla (USA) + cheat + description:Infinite health - Battle + code:268d20/ad + cheat + description:Infinite health - Map + code:01d407/ad + cheat + description:Infinite time + code:01d2ff/ae + +cartridge sha256:3f8efb19eae68f24feb42c018b7dc7a819bfd8d993ab36899681caa7ee94b06e + name:Super James Pond (USA) + cheat + description:Infinite health + code:7eb130/03 + cheat + description:Infinite lives + code:7eb12e/03 + +cartridge sha256:a9e3e57d591e995e8e0dd228b619b6aed42205eaf55316fa8ff33f236b3a32b3 + name:Super Mario All-Stars (USA) + cheat + description:SMB - Invincibility (Starman effect) + code:03de9c/d5 + cheat + description:SMB - Invincibility does not last as long + code:03de13/08 + cheat + description:SMB - Invincibility lasts longer + code:03de13/50 + cheat + description:SMB - Infinite lives + code:03a06b/ad + cheat + description:SMB - Infinite time + code:03b825/80 + cheat + description:SMB - Fireballs hit anywhere + code:03dcb8/24 + cheat + description:SMB - Fireballs can kill Bullet Bill + code:03dd7f/24 + cheat + description:SMB - Fireballs can kill Buzzy Beetle + code:03dcf2/80 + cheat + description:SMB - Run without holding the dash button + code:03b5a1/80 + cheat + description:SMB - 1-up worth nothing + code:048596/ad + cheat + description:SMB - Jump lower (disable if you get stuck) + code:03b561/a9+03b562/fd+03b563/ea + cheat + description:SMB - Super-jump + code:03b561/a9+03b562/fa+03b563/ea + cheat + description:SMB - Mega-jump + code:03b561/a9+03b562/f8+03b563/ea + cheat + description:SMB - Multi-jump + code:03b4fc/d0 + cheat + description:SMB - Allows you to select any world for File A + code:700010/07 + cheat + description:SMB - Start File A game with 2 lives + code:700013/01 + cheat + description:SMB - Start File A game with 10 lives + code:700013/09 + cheat + description:SMB - Start File A game with 50 lives + code:700013/31 + cheat + description:SMB - Start File A game with 100 lives + code:700013/63 + cheat + description:SMB - Invincibility (Starman) + code:7e07af/0f + cheat + description:SMB - Infinite lives (alt) + code:7e075a/05 + cheat + description:LL - Invincible against most enemies + code:0dddca/d5 + cheat + description:LL - Invincibility (get a power-up when an enemy touches you) + code:0dddc2/b5 + cheat + description:LL - Infinite time + code:0db5b5/60 + cheat + description:LL - Multi-jump + code:0db286/00 + cheat + description:LL - Run without holding the dash button + code:0db348/80 + cheat + description:LL - Death Mushrooms are 1-Ups + code:0dbd59/af + cheat + description:LL - There are no Death Mushrooms + code:0dbd59/ad + cheat + description:LL - All breakable bricks are coins when you're small + code:0dbd6d/ad + cheat + description:LL - Allows you to select any world or level for File A + code:700019/0c+70001a/03 + cheat + description:LL - Start File A game with 2 lives + code:70001c/01 + cheat + description:LL - Start File A game with 10 lives + code:70001c/09 + cheat + description:LL - Start File A game with 50 lives + code:70001c/31 + cheat + description:LL - Start File A game with 100 lives + code:70001c/63 + cheat + description:LL - Invincibility (blinking) + code:7e07ae/0f + cheat + description:LL - Invincibility (Star effect) + code:7e07af/0f + cheat + description:LL - Always Fiery Mario + code:7e0756/02 + cheat + description:LL - Coins are worth 10 + code:7e07df/09 + cheat + description:SMB2 - Infinite lives + code:1280ff/ad + cheat + description:SMB2 - Infinite hearts + code:12e2d6/00 + cheat + description:SMB2 - Hit anywhere + code:12df40/43+12df3d/e0+12df3e/00 + cheat + description:SMB2 - Multi-jump - all characters + code:12828a/05 + cheat + description:SMB2 - Float - all characters + code:12833f/8d + cheat + description:SMB2 - Jumping in place charges super jump + code:128346/3c + cheat + description:SMB2 - Run without holding the dash button + code:128449/00+12845b/00 + cheat + description:SMB2 - Allows you to select any world for File A + code:700021/06 + cheat + description:SMB2 - 1 life after continue + code:11816c/01 + cheat + description:SMB2 - 9 lives after continue + code:11816c/09 + cheat + description:SMB2 - 25 lives after continue + code:11816c/19 + cheat + description:SMB2 - 50 lives after continue + code:11816c/32 + cheat + description:SMB2 - 99 lives after continue + code:11816c/63 + cheat + description:SMB2 - Continue with 3 hearts instead of 2 + code:118b97/01 + cheat + description:SMB2 - Continue with 4 hearts + code:118b97/02 + cheat + description:SMB2 - Invincibility + code:7e0085/3b + cheat + description:SMB2 - Infinite float time - all characters + code:7e04ca/ff + cheat + description:SMB2 - Always big + code:7e04c3/1f + cheat + description:SMB2 - Always small + code:7e04c3/0f + cheat + description:SMB3 - Infinite lives + code:20919a/bd + cheat + description:SMB3 - Infinite time + code:29e601/80 + cheat + description:SMB3 - Infinite items + code:29dd18/ad + cheat + description:SMB3 - Infinite flying time + code:23cb26/ff + cheat + description:SMB3 - Fly at any time (run meter always full) + code:23cb1f/00 + cheat + description:SMB3 - Fireballs hit anywhere + code:27b8ec/24+27b90c/24 + cheat + description:SMB3 - Fireballs can kill most enemies + code:27b926/24 + cheat + description:SMB3 - Tail hits anywhere + code:27a62b/24 + cheat + description:SMB3 - Multi-jump + code:23cacd/24 + cheat + description:SMB3 - Multi-jump (alt) + code:23cac9/80 + cheat + description:SMB3 - Power-jump + code:21eafd/c0 + cheat + description:SMB3 - Super-jump + code:21eafd/b8 + cheat + description:SMB3 - Mega-jump + code:21eafd/b0 + cheat + description:SMB3 - Ultra power-jump + code:21eafd/a8 + cheat + description:SMB3 - Mega power-jump + code:23cb51/00 + cheat + description:SMB3 - Mushrooms always go to the right when spawned from a block + code:288fab/10 + cheat + description:SMB3 - Change to Big Mario whenever you go to the map + code:208f59/a9+208f5a/01 + cheat + description:SMB3 - Change to Fire Mario whenever you go to the map + code:208f59/a9+208f5a/02 + cheat + description:SMB3 - Change to Raccoon Mario whenever you go to the map + code:208f59/a9+208f5a/03 + cheat + description:SMB3 - Change to Frog Mario whenever you go to the map + code:208f59/a9+208f5a/04 + cheat + description:SMB3 - Change to Tanooki Mario whenever you go to the map + code:208f59/a9+208f5a/05 + cheat + description:SMB3 - Change to Sledgehammer Mario when you go to the map + code:208f59/a9+208f5a/06 + cheat + description:SMB3 - All power-ups turn you into Shoe Mario + code:23c269/04+23c0e1/f6 + cheat + description:SMB3 - Collisions turn you into Big Mario + code:23c2bb/02 + cheat + description:SMB3 - Collisions turn you into Fiery Mario + code:23c2bb/03 + cheat + description:SMB3 - Collisions turn you into Raccoon Mario + code:23c2bb/04 + cheat + description:SMB3 - Collisions turn you into Frog Mario + code:23c2bb/05 + cheat + description:SMB3 - Collisions turn you into Tanooki Mario + code:23c2bb/06 + cheat + description:SMB3 - Collisions turn you into Sledgehammer Mario + code:23c2bb/07 + cheat + description:SMB3 - After getting star, invincible until end of level (may have to disable to jump) + code:20e29d/ad + cheat + description:SMB3 - 1 life after continue + code:209497/01 + cheat + description:SMB3 - 10 lives after continue + code:209497/09 + cheat + description:SMB3 - 26 lives after continue + code:209497/19 + cheat + description:SMB3 - 51 lives after continue + code:209497/32 + cheat + description:SMB3 - 100 lives after continue + code:209497/63 + cheat + description:SMB3 - Gain lots of lives with each 5 coins + code:29e6f8/05 + cheat + description:SMB3 - 5 coins needed for an extra life + code:29e6fd/05 + cheat + description:SMB3 - 10 coins needed for an extra life + code:29e6fd/0a + cheat + description:SMB3 - 25 coins needed for an extra life + code:29e6fd/19 + cheat + description:SMB3 - 50 coins needed for an extra life + code:29e6fd/32 + cheat + description:SMB3 - Move anywhere on the world map + code:238e5e/80+238ab0/80 + cheat + description:SMB3 - Re-enter already beaten levels + code:218ce3/00 + cheat + description:SMB3 - Re-enter already beaten fortresses + code:218ce2/60 + cheat + description:SMB3 - Re-enter already beaten mushroom houses and special levels + code:218ce1/40 + cheat + description:SMB3 - Select any world for File A game + code:70002a/07 + cheat + description:SMB3 - Start and continue as Big Mario + code:23c0e1/f6 + 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 Fiery 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 + name:Super Mario All-Stars + Super Mario World (USA) + cheat + description:SMB - Invincibility (Starman effect) + code:03de9c/d5 + cheat + description:SMB - Invincibility does not last as long + code:03de13/08 + cheat + description:SMB - Invincibility lasts longer + code:03de13/50 + cheat + description:SMB - Infinite lives + code:03a06b/ad + cheat + description:SMB - Infinite time + code:03b825/80 + cheat + description:SMB - Fireballs hit anywhere + code:03dcb8/24 + cheat + description:SMB - Fireballs can kill Bullet Bill + code:03dd7f/24 + cheat + description:SMB - Fireballs can kill Buzzy Beetle + code:03dcf2/80 + cheat + description:SMB - Run without holding the dash button + code:03b5a1/80 + cheat + description:SMB - 1-up worth nothing + code:048596/ad + cheat + description:SMB - Jump lower (disable if you get stuck) + code:03b561/a9+03b562/fd+03b563/ea + cheat + description:SMB - Super-jump + code:03b561/a9+03b562/fa+03b563/ea + cheat + description:SMB - Mega-jump + code:03b561/a9+03b562/f8+03b563/ea + cheat + description:SMB - Multi-jump + code:03b4fc/d0 + cheat + description:SMB - Allows you to select any world for File A + code:700010/07 + cheat + description:SMB - Start File A game with 2 lives + code:700013/01 + cheat + description:SMB - Start File A game with 10 lives + code:700013/09 + cheat + description:SMB - Start File A game with 50 lives + code:700013/31 + cheat + description:SMB - Start File A game with 100 lives + code:700013/63 + cheat + description:SMB - Invincibility (Starman) + code:7e07af/0f + cheat + description:SMB - Infinite lives (alt) + code:7e075a/05 + cheat + description:LL - Invincible against most enemies + code:0dddca/d5 + cheat + description:LL - Invincibility (get a power-up when an enemy touches you) + code:0dddc2/b5 + cheat + description:LL - Infinite time + code:0db5b5/60 + cheat + description:LL - Multi-jump + code:0db286/00 + cheat + description:LL - Run without holding the dash button + code:0db348/80 + cheat + description:LL - Death Mushrooms are 1-Ups + code:0dbd59/af + cheat + description:LL - There are no Death Mushrooms + code:0dbd59/ad + cheat + description:LL - All breakable bricks are coins when you're small + code:0dbd6d/ad + cheat + description:LL - Allows you to select any world or level for File A + code:700019/0c+70001a/03 + cheat + description:LL - Start File A game with 2 lives + code:70001c/01 + cheat + description:LL - Start File A game with 10 lives + code:70001c/09 + cheat + description:LL - Start File A game with 50 lives + code:70001c/31 + cheat + description:LL - Start File A game with 100 lives + code:70001c/63 + cheat + description:LL - Invincibility (blinking) + code:7e07ae/0f + cheat + description:LL - Invincibility (Star effect) + code:7e07af/0f + cheat + description:LL - Always Fiery Mario + code:7e0756/02 + cheat + description:LL - Coins are worth 10 + code:7e07df/09 + cheat + description:SMB2 - Infinite lives + code:1280ff/ad + cheat + description:SMB2 - Infinite hearts + code:12e2d6/00 + cheat + description:SMB2 - Hit anywhere + code:12df40/43+12df3d/e0+12df3e/00 + cheat + description:SMB2 - Multi-jump - all characters + code:12828a/05 + cheat + description:SMB2 - Float - all characters + code:12833f/8d + cheat + description:SMB2 - Jumping in place charges super jump + code:128346/3c + cheat + description:SMB2 - Run without holding the dash button + code:128449/00+12845b/00 + cheat + description:SMB2 - Allows you to select any world for File A + code:700021/06 + cheat + description:SMB2 - 1 life after continue + code:11816c/01 + cheat + description:SMB2 - 9 lives after continue + code:11816c/09 + cheat + description:SMB2 - 25 lives after continue + code:11816c/19 + cheat + description:SMB2 - 50 lives after continue + code:11816c/32 + cheat + description:SMB2 - 99 lives after continue + code:11816c/63 + cheat + description:SMB2 - Continue with 3 hearts instead of 2 + code:118b97/01 + cheat + description:SMB2 - Continue with 4 hearts + code:118b97/02 + cheat + description:SMB2 - Invincibility + code:7e0085/3b + cheat + description:SMB2 - Infinite float time - all characters + code:7e04ca/ff + cheat + description:SMB2 - Always big + code:7e04c3/1f + cheat + description:SMB2 - Always small + code:7e04c3/0f + cheat + description:SMB3 - Infinite lives + code:20919a/bd + cheat + description:SMB3 - Infinite time + code:29e601/80 + cheat + description:SMB3 - Infinite items + code:29dd18/ad + cheat + description:SMB3 - Infinite flying time + code:23cb26/ff + cheat + description:SMB3 - Fly at any time (run meter always full) + code:23cb1f/00 + cheat + description:SMB3 - Fireballs hit anywhere + code:27b8ec/24+27b90c/24 + cheat + description:SMB3 - Fireballs can kill most enemies + code:27b926/24 + cheat + description:SMB3 - Tail hits anywhere + code:27a62b/24 + cheat + description:SMB3 - Multi-jump + code:23cacd/24 + cheat + description:SMB3 - Multi-jump (alt) + code:23cac9/80 + cheat + description:SMB3 - Power-jump + code:21eafd/c0 + cheat + description:SMB3 - Super-jump + code:21eafd/b8 + cheat + description:SMB3 - Mega-jump + code:21eafd/b0 + cheat + description:SMB3 - Ultra power-jump + code:21eafd/a8 + cheat + description:SMB3 - Mega power-jump + code:23cb51/00 + cheat + description:SMB3 - Change to Big Mario whenever you go to the map + code:208f59/a9+208f5a/01 + cheat + description:SMB3 - Change to Fire Mario whenever you go to the map + code:208f59/a9+208f5a/02 + cheat + description:SMB3 - Change to Raccoon Mario whenever you go to the map + code:208f59/a9+208f5a/03 + cheat + description:SMB3 - Change to Frog Mario whenever you go to the map + code:208f59/a9+208f5a/04 + cheat + description:SMB3 - Change to Tanooki Mario whenever you go to the map + code:208f59/a9+208f5a/05 + cheat + description:SMB3 - Change to Sledgehammer Mario when you go to the map + code:208f59/a9+208f5a/06 + cheat + description:SMB3 - All power-ups turn you into Shoe Mario + code:23c269/04+23c0e1/f6 + cheat + description:SMB3 - Collisions turn you into Big Mario + code:23c2bb/02 + cheat + description:SMB3 - Collisions turn you into Fiery Mario + code:23c2bb/03 + cheat + description:SMB3 - Collisions turn you into Raccoon Mario + code:23c2bb/04 + cheat + description:SMB3 - Collisions turn you into Frog Mario + code:23c2bb/05 + cheat + description:SMB3 - Collisions turn you into Tanooki Mario + code:23c2bb/06 + cheat + description:SMB3 - Collisions turn you into Sledgehammer Mario + code:23c2bb/07 + cheat + description:SMB3 - After getting star, invincible until end of level (may have to disable to jump) + code:20e29d/ad + cheat + description:SMB3 - 1 life after continue + code:209497/01 + cheat + description:SMB3 - 10 lives after continue + code:209497/09 + cheat + description:SMB3 - 26 lives after continue + code:209497/19 + cheat + description:SMB3 - 51 lives after continue + code:209497/32 + cheat + description:SMB3 - 100 lives after continue + code:209497/63 + cheat + description:SMB3 - Gain lots of lives with each 5 coins + code:29e6f8/05 + cheat + description:SMB3 - 5 coins needed for an extra life + code:29e6fd/05 + cheat + description:SMB3 - 10 coins needed for an extra life + code:29e6fd/0a + cheat + description:SMB3 - 25 coins needed for an extra life + code:29e6fd/19 + cheat + description:SMB3 - 50 coins needed for an extra life + code:29e6fd/32 + cheat + description:SMB3 - Move anywhere on the world map + code:238e5e/80+238ab0/80 + cheat + description:SMB3 - Re-enter already beaten levels + code:218ce3/00 + cheat + description:SMB3 - Re-enter already beaten fortresses + code:218ce2/60 + cheat + description:SMB3 - Re-enter already beaten mushroom houses and special levels + code:218ce1/40 + cheat + description:SMB3 - Select any world for File A game + code:70002a/07 + cheat + description:SMB3 - Start and continue as Big Mario + code:23c0e1/f6 + 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 Fiery 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 + cheat + description:SMW - Infinite flying time for Yoshi + code:01f1ad/ad + cheat + description:SMW - Nintendo's debug + code:00cc85/00 + 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 Fiery Mario + code:7e0019/03 + cheat + description:SMW - Always have Yoshi + code:7e0dc1/01 + 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 - Multi-jump and float down (disable in water and to get on Yoshi) + code:7e1471/01 + cheat + description:SMW - Jump to automatically fly + code:7e13e4/70 + 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 - Automatically finish level + code:7e1493/01 + cheat + description:SMW - 8000 points for each enemy stomped + code:7e1697/06 + +cartridge sha256:2ada8919688087be60a6a48cace8f877add60c45d2e5d09e2442faa55be62a49 + name:Super Mario Kart (USA) + cheat + description:Invincibility + code:80eaf3/6c + cheat + description:All karts except yours do not move + code:80b048/55 + cheat + description:Drive through walls + code:80fa93/21 + cheat + description:Drive through opponents + code:80c283/53 + 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 + name:Super Mario RPG - Legend of the Seven Stars (USA) + cheat + description:Infinite tries in action sequences + code:c0bcfd/c5 + 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:Walk through walls + code:c97a55/80+c97a79/80+c97a1f/80+c979f7/80 + 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 + name:Super Mario World (USA) + cheat + description:Start and stay invincible most of the time + code:00e2d3/00 + cheat + description:Invincibility - Yoshi + code:01f724/b5+02a488/b5 + cheat + description:Infinite flying time - Yoshi + code:01f1ad/ad + cheat + description:Infinite time (disable for puzzles that use the timer) + code:008e28/ad + cheat + description:Infinite lives + code:00d0d8/ad + cheat + description:Cape hits anywhere + code:0293f2/24 + cheat + description:Fireballs hit anywhere + code:02a0df/24 + cheat + description:Fireballs shoot straight + code:00fec5/00+029fd4/00 + cheat + description:Fireballs turn most enemies into Flowers + code:02a12a/75 + cheat + description:Fireballs turn most enemies into 1-Up Mushrooms + code:02a12a/78 + cheat + description:Fireballs turn most enemies into Starmen + code:02a12a/76 + cheat + description:Multi-jump + code:00d5f4/80 + cheat + description:Spin jump in mid-air (hold to float down) + code:00ee1e/17+00ee1f/00 + cheat + description:Low jump + code:00d7a6/04 + cheat + description:Super-jump + code:00d7a6/02 + cheat + description:Mega-jump + code:00d7a6/01 + cheat + description:Swim in every level + code:00f2c3/a9 + cheat + description:Press R to scroll through items in the items box + code:00ce14/63+00ce1a/60+00ce17/8d+00ce0f/c2+00ce0c/c2+00ce18/c2+00ce15/a9+00ce12/06+00ce0d/0d+00ce19/0d+00ce10/0d+00ce16/01 + cheat + description:Little Yoshi grows after eating 1 enemy instead of 5 + code:01a2fb/01 + cheat + description:Little Yoshi grows after eating 2 enemies + code:01a2fb/02 + cheat + description:Little Yoshi grows after eating 3 enemies + code:01a2fb/03 + cheat + description:Little Yoshi grows after eating 4 enemies + code:01a2fb/04 + cheat + description:1-Up at 5 coins instead of 100 + code:008f2c/05+008f37/05 + cheat + description:1-Up at 10 coins + code:008f2c/0a+008f37/0a + cheat + description:1-Up at 20 coins + code:008f2c/14+008f37/14 + cheat + description:1-Up at 50 coins + code:008f2c/32+008f37/32 + cheat + description:1-Up at 1 dragon coin instead of 5 + code:00f37f/0d + cheat + description:Start as Super Mario + code:009e35/e6 + cheat + description:Start as Cape Mario + code:009e32/a9+009e33/02+009e34/ea+009e35/85 + cheat + description:Start as Fire Mario + code:009e32/a9+009e33/03+009e34/ea+009e35/85 + cheat + description:Start with 1 life instead of 5 + code:009e25/00 + cheat + description:Start with 9 lives + code:009e25/08 + cheat + description:Start with 15 lives + code:009e25/0e + cheat + description:Start with 25 lives + code:009e25/18 + cheat + description:Start with 50 lives + code:009e25/31 + cheat + description:Start with 99 lives + code:009e25/62 + cheat + description:Nintendo's Debug + code:00a268/00+00a273/00 + cheat + description:Nintendo's Debug 2 + code:00cc85/00 + 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:Always have 100 bonus points + code:7e0f48/64 + cheat + description:Multi-jump and float down (disable in water and to get on Yoshi) + code:7e1471/01 + cheat + description:Swim on every level + code:00f2c3/a9 + 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 + name:Super Mario World 2 - Yoshi's Island (USA) (Rev 1) + cheat + description:Infinite lives + code:04f6f9/ad + cheat + description:All levels are completed with 100 points + code:108152/a9+108153/e4 + cheat + description:Always score 100 points + code:01bec8/a9+01bec9/64+01beca/ea + cheat + description:Power-ups don't get used up + code:01db87/60 + cheat + description:Mario's crying disabled + code:06c64f/22 + cheat + description:Horizontal one-way pinball doors open from both sides + code:0d9e85/80 + cheat + description:Infinite lives/Start at Middle Ring (when you die) + code:04f6fa/ad + cheat + description:After using the magnifying glass, red coins and hidden items are always revealed + code:01afba/ad + cheat + description:Red switches stay on for over twice as long + code:0eb7c4/05 + cheat + description:Red switches stay on for over four times as long + code:0eb7c4/09 + cheat + description:Red switches stay on for a very, very long time + code:0eb7c4/7f + cheat + description:Disable autoscroll + code:03d848/ad + cheat + description:Don't get crushed + code:04ac9f/6b + cheat + description:Multi-jump + code:06d06c/8e+06d06d/ab+06d06e/60+06d063/72+06d064/60+06d065/29+06d066/00+06d067/80+06d068/f0+06d069/05+06d06a/a2+06d06b/fb + 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 + name:Super Mario World 2 - Yoshi's Island (USA) + cheat + description:Infinite lives + code:04f6f9/ad + cheat + description:Infinite lives and start at middle ring when you die + code:04f6fa/ad + cheat + description:All levels are completed with 100 points + code:108152/a9+108153/e4 + cheat + description:Always score 100 points + code:01bec8/a9+01bec9/64+01beca/ea + cheat + description:Power-ups don't get used up + code:01db87/60 + cheat + description:Mario's crying disabled + code:06c64f/22 + cheat + description:Horizontal one-way pinball doors open from both sides + code:0d9e85/80 + cheat + description:After using the magnifying glass, red coins and hidden items are always revealed + code:01afba/ad + cheat + description:Red switches stay on for over twice as long + code:0eb7c4/05 + cheat + description:Red switches stay on for over four times as long + code:0eb7c4/09 + cheat + description:Disable autoscroll + code:03d848/ad + cheat + description:Don't get crushed + code:04ac9f/6b + cheat + description:Multi-jump + code:06d06c/8e+06d06d/ab+06d06e/60+06d063/72+06d064/60+06d065/29+06d066/00+06d067/80+06d068/f0+06d069/05+06d06a/a2+06d06b/fb + cheat + description:Continue with 5 lives + code:10e189/0a + cheat + description:Continue with 10 lives + code:10e189/19 + cheat + description:Continue with 25 lives + code:10e189/32 + cheat + description:Continue with 50 lives + code:10e189/63 + cheat + description:Continue with 99 lives + code:10e189/63 + cheat + description:Start with 5 lives + code:179933/05 + cheat + description:Start with 10 lives + code:179933/0a + cheat + description:Start with 25 lives + code:179933/19 + cheat + description:Start with 50 lives + code:179933/32 + cheat + description:Start with 99 lives + code:179933/63 + 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 + name:Super Metroid (Japan, USA) (En,Ja) + cheat + description:Invincibility (except for acid and when bosses grab you) + code:7e18a8/01 + cheat + description:Infinite energy (except for acid) + code:91df71/ad + cheat + description:Infinite Missiles + code:90bebf/ad + cheat + description:Infinite Super Missiles + code:90bec4/ad + cheat + description:Infinite Power Bombs + code:90c02d/ea + cheat + description:Infinite Power Bombs (alt) + code:7e09ce/63 + cheat + description:Hit anywhere + code:a0a1bc/24+a0976a/80+a0a1d4/80 + cheat + description:Super-jumps don't drain energy + code:90d0ce/ad + cheat + description:Enemies die on contact (Speed Booster effect) + code:a0a4b8/80+a0a4a4/80 + cheat + description:Switching areas fills the map + code:808597/af+80859a/03 + cheat + description:Automatically collect secret and/or special items in current room (Missiles, Energy Tanks, etc.) + code:84df92/24+84dff4/24 + cheat + description:View all hidden blocks with X-ray Scope regardless of your viewing direction + code:88817c/0f + cheat + description:Can access Tourain from sunken statues room + code:7ed820/c1+7ed821/1f + cheat + description:Disabled water + code:88c4b8/a9+88c4b9/ff+88c4ba/ff + cheat + description:Full movement in Maridia sand + code:84b518/80+90981d/00 + cheat + description:Multi-jump (when using button A) + code:90eee7/a5+90eee8/8e+90eee9/0a+90eeea/90+90eeeb/04+90eeec/22+90eeed/bc+90eeee/98+90eeef/90 + cheat + description:Multi-jump (when using button B) + code:90eee7/a5+90eee8/8f+90eee9/0a+90eeea/90+90eeeb/04+90eeec/22+90eeed/bc+90eeee/98+90eeef/90 + cheat + description:Metroids can be killed without being frozen first + code:a3ef1c/24+a3ef27/80 + cheat + description:Skip intro and start on Planet Zebes on new game + code:82eebb/00 + cheat + description:Select area when loading saved game A (press right on map screen) + code:81a81a/00+81a8af/80 + cheat + description:0 hours played + code:70004e/00 + cheat + description:Display entire map + code:82947f/80+8294ef/80+8085ae/a9 + cheat + description:Brinstar mapped + code:7ed909/ff + cheat + description:Crateria mapped + code:7ed908/ff + cheat + description:Maridia mapped + code:7ed90c/ff + cheat + description:Norfair mapped + code:7ed90a/ff + cheat + description:Tourain mapped + code:7ed90d/ff + cheat + description:Wrecked Ship mapped + code:7ed90b/ff + cheat + description:Maximum 99 Power Bombs + code:7e09d0/63 + cheat + description:Maximum 99 Super Missiles + code:7e09cc/63 + cheat + description:Maximum Missiles=10 + code:700036/0a + cheat + description:Maximum Missiles=100 + code:700036/64 + cheat + description:Maximum Missiles=125 + code:700036/7d + cheat + description:Maximum Missiles=150 + code:700036/96 + cheat + description:Maximum Missiles=175 + code:700036/af + cheat + description:Maximum Missiles=200 + code:700036/c8 + cheat + description:Maximum Missiles=25 + code:700036/19 + cheat + description:Maximum Missiles=50 + code:700036/32 + cheat + description:Maximum Missiles=75 + code:700036/4b + cheat + description:Maximum Power Bombs=10 + code:70003e/0a + cheat + description:Maximum Power Bombs=25 + code:70003e/19 + cheat + description:Maximum Power Bombs=5 + code:70003e/05 + cheat + description:Maximum Power Bombs=50 + code:70003e/32 + cheat + description:Maximum Super Missiles=10 + code:70003a/0a + cheat + description:Maximum Super Missiles=25 + code:70003a/19 + cheat + description:Maximum Super Missiles=5 + code:70003a/05 + cheat + description:Maximum Super Missiles=50 + code:70003a/32 + cheat + description:Start with about 500 Energy Tanks on saved game A + code:700033/f3+700032/01 + cheat + description:Start with about 700 Energy Tanks on saved game A + code:700033/bb+700032/02 + cheat + description:Start with about 1000 Energy Tanks on saved game A + code:700033/e7+700032/03 + cheat + description:Start with about 1200 Energy Tanks on saved game A + code:700033/af+700032/04 + cheat + description:Start with about 1500 Energy Tanks on saved game A + code:700033/db+700032/05 + 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:70015a/ff + 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 + name:Super Ninja Boy (USA) + cheat + description:Protection from most hazards (makes some side-view enemies invincible) + code:05d1fe/bd + cheat + description:Don't subtract money (must have enough to buy) + code:02c018/60 + cheat + description:All stats are 20 (attack, defense, energy, max HP, max NP) + code:02db1d/a9+02db1f/ea+02db1e/14 + cheat + description:All stats for every level are 50 + code:02db1d/a9+02db1f/ea+02db1e/32 + cheat + description:All stats for every level are 100 + code:02db1d/a9+02db1f/ea+02db1e/64 + cheat + description:All stats for every level are 255 + code:02db1d/a9+02db1f/ea+02db1e/ff + cheat + description:1 experience point required for level 2 + code:02db2b/01 + cheat + description:1 experience point required for level 3 + code:02db2e/01 + cheat + description:1 experience point required for level 4 + code:02db31/01 + cheat + description:1 experience point required for level 5 + code:02db34/01 + cheat + description:Don't subtract M's for ninja cyclone attack + code:058c6f/00 + cheat + description:Don't subtract M's for mighty balls attack + code:05c97b/00 + cheat + description:Skulls subtract 2 M's + code:05e23b/02 + cheat + description:Skulls don't subtract an M + code:05e23b/00 + cheat + description:M power-ups worth nothing (handicap) + code:05e24f/00 + cheat + description:M power-ups worth 2 + code:05e24f/02 + cheat + description:M power-ups worth 3 + code:05e24f/03 + cheat + description:M power-ups worth 4 + code:05e24f/04 + cheat + description:M power-ups worth 5 + code:05e24f/05 + cheat + description:M power-ups set to 15 + code:05e24f/15 + cheat + description:Start with 250 cash + code:01b766/fa + cheat + description:Start with 40,960 cash + code:01b768/85 + +cartridge sha256:a8acbbd6f8afbf289a6b837da6cd8bd109a00cd38625c956ab8ff739732d9e4f + name:Super Nova (USA) + cheat + description:Invincibility + code:80be2b/4c+80be2c/35+80be2d/be + cheat + description:Infinite lives + code:8a80bd/cd + cheat + description:Hit anywhere + code:80cd53/80+89b930/00+80cc74/00 + cheat + description:Keep main weapon after dying + code:8a80a8/ad + cheat + description:Start with strongest main weapon + code:8aa124/8d + +cartridge sha256:24b687f95bb9737d223738f13c00aeaa7d697fa9e2fd50597b81d0cfa2160daa + name:Super Off Road (USA) + cheat + description:Infinite nitros + code:00953f/02+009544/dd + cheat + description:Infinite cash - P1 + code:00aecd/d9 + cheat + description:Infinite cash - P2 + code:00b020/d9 + cheat + description:Start with $500,000 + code:00b631/05 + cheat + description:Start with $900,000 + code:00b631/09 + +cartridge sha256:16f9c90d75bd23d0620be00ecf818fcb25c5935d4ee26b1fe17b926f8987aa65 + name:Super Off Road - The Baja (USA) + cheat + description:Infinite nitros + code:80c642/ea + cheat + description:Indestructible engine + code:80bfe8/ad + cheat + description:Indestructible shocks + code:80bfc2/ad + cheat + description:Indestructible tires + code:80bfa0/ad + cheat + description:Vehicle can take only about 60% damage + code:80bf6c/60 + cheat + description:Vehicle can take only about 35% damage + code:80bf6c/30 + cheat + description:$9,000 for brakes + code:809584/09 + cheat + description:$2,000 for brakes + code:809584/02 + cheat + description:$9,000 for tires + code:809586/09 + cheat + description:$2,000 for tires + code:809586/02 + cheat + description:$2,000 for shocks + code:809588/02 + cheat + description:$9,000 for shocks + code:809588/09 + cheat + description:$2,000 for lights + code:80958a/02 + cheat + description:$9,000 for lights + code:80958a/09 + cheat + description:$2,000 for engine + code:80958c/02 + cheat + description:$4,000 for engine + code:80958c/04 + +cartridge sha256:5a4b0c89606f71182fa5552ac476cc3bbda5ddc7d44e33f9184114aaea38020d + name:Super Play Action Football (USA) + cheat + description:One timeout each team + code:009c38/01 + cheat + description:No timeouts - P1 + code:009c39/64 + cheat + description:No timeouts - P2 + code:009c3b/64 + cheat + description:Infinite time to select play + code:008234/24 + cheat + description:Less time to select play + code:008231/1e + cheat + description:More time to select play + code:008231/70 + +cartridge sha256:a3d803b8c6b0b6ac55085671040b840f993543915c7f802e14fb651beabe9b63 + name:Super Punch-Out!! (USA) + cheat + description:Invincibility against normal attacks + code:00c3fd/00 + cheat + description:Infinite health against most punches + code:00c824/ad + cheat + description:Gain max health after connecting a hit - both players + code:00c803/05 + cheat + description:Infinite time + code:00f2e8/a5 + cheat + description:Opponent has no health + code:00f0aa/9c + cheat + description:Most opponents stay down for the count + code:00c394/01 + cheat + description:Opponent does almost nothing + code:018064/80 + cheat + description:Some special attacks don't damage as much + code:00c494/ad + cheat + description:Super Punch anytime + code:00cf6e/00 + cheat + description:Max power after one hit + code:00ef21/a9+00ef22/1b+00ef23/ea + cheat + description:Infinite rematches + code:019ebb/ad + cheat + description:No rematches + code:00993d/00 + cheat + description:Fix game genied world circuit + code:00bc23/a9+00bc24/00 + cheat + description:Start with 5 rematches + code:00993d/06 + cheat + description:Start with 8 rematches + code:00993d/09 + cheat + description:Start with half health - both players + code:0096a6/25 + cheat + description:Start with very little health - both players + code:0096a6/01 + cheat + description:Start on world circuit + code:01b8cb/09+01b8cc/02+01b8cd/ea + 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 + name:Super R-Type (USA) + cheat + description:Start with Invincibility (blinking) + code:01a8d6/bd + cheat + description:Infinite lives + code:00a631/ad + cheat + description:Infinite FORCE once obtained + code:018738/ad + cheat + description:One hit kills + code:009e15/80 + cheat + description:Hit anywhere + code:009d6a/24+009d78/24+009d7f/24+009d71/24+009d86/24 + cheat + description:Always fire charged shots (hold B) + code:01b934/3d+01b932/00 + cheat + description:Spiral motion gun takes less time to power up + code:01ba40/80+01ba41/00 + cheat + description:Spiral motion gun takes much less time to power up + code:01ba43/00 + cheat + description:Spiral motion gun can't get over-charged + code:01ba25/80 + cheat + description:All FORCE satellites have 1 unit of power (but can't exceed 1 unit) + code:0286b0/00+0286af/a9+0286b2/30 + cheat + description:All FORCE satellites have 2 units of power (but can't exceed 2 units) + code:0286b0/01+0286af/a9+0286b2/30 + cheat + description:All FORCE satellites have 3 units of power + code:0286b0/02+0286af/a9+0286b2/30 + cheat + description:Start with 1 life instead of 3 + code:018185/01+018184/a9+018186/00 + cheat + description:Start with 2 lives + code:018185/02+018184/a9+018186/00 + cheat + description:Start with 4 lives + code:018185/04+018184/a9+018186/00 + cheat + description:Start with 5 lives + code:018185/05+018184/a9+018186/00 + cheat + description:Start with 7 lives + code:018185/07+018184/a9+018186/00 + cheat + description:Start with 9 lives + code:018185/09+018184/a9+018186/00 + cheat + description:Continue with 1 life instead of 3 + code:0187ad/01+0187ac/a9+0187ae/00 + cheat + description:Continue with 2 lives + code:0187ad/02+0187ac/a9+0187ae/00 + cheat + description:Continue with 4 lives + code:0187ad/04+0187ac/a9+0187ae/00 + cheat + description:Continue with 5 lives + code:0187ad/05+0187ac/a9+0187ae/00 + cheat + description:Continue with 7 lives + code:0187ad/07+0187ac/a9+0187ae/00 + cheat + description:Continue with 9 lives + code:0187ad/09+0187ac/a9+0187ae/00 + cheat + description:Stage select enabled (Pause, A+R+Select) + code:7e16f5/ff+7e16f6/ff + cheat + description:Start with Invincibility (blinking) (alt) + code:7e15bd/00 + +cartridge sha256:7a8ffaf8bb549b400ec2f0bda9f3c0dbf5852c38618cdb21cd783c368383e2c7 + name:Super Scope 6 (USA) + cheat + description:Add 1 bullets at a time (Blastris A) + code:10a98c/01 + cheat + description:Add 3 bullets at a time (Blastris A) + code:10a98c/03 + cheat + description:Add 5 bullets at a time (Blastris A) + code:10a98c/05 + cheat + description:Add 7 bullets at a time (Blastris A) + code:10a98c/07 + cheat + description:Add 9 bullets at a time (Blastris A) + code:10a98c/09 + cheat + description:Infinite bullets (Blastris A) + code:10a4da/a5 + cheat + description:Clear 1 line instead of 5 to advance to next level (Blastris A) + code:10a55e/01 + cheat + description:Clear 2 lines to advance to next level (Blastris A) + code:10a55e/02 + cheat + description:Clear 3 lines to advance to next level (Blastris A) + code:10a55e/03 + cheat + description:Clear 4 lines to advance to next level (Blastris A) + code:10a55e/04 + cheat + description:Select low mode to start on level 5 (Blastris B, Type B) + code:1180b9/05 + cheat + description:Select low mode to start on level 15 (Blastris B, Type B) + code:1180b9/0f + cheat + description:Select low mode to start on level 25 (Blastris B, Type B) + code:1180b9/19 + cheat + description:Select low mode to start on level 30 (Blastris B, Type B) + code:1180b9/1e + cheat + description:Select low mode to start on level 35 (Blastris B, Type B) + code:1180b9/23 + cheat + description:Select low mode to start on level 40 (Blastris B, Type B) + code:1180b9/28 + cheat + description:Clear stage after 1 Molian is hit (Mole Patrol, Stage Mode) + code:10c188/9c + cheat + description:Take no damage (LazerBlazer, Type A) + code:018adb/bd + cheat + description:Take no damage (LazerBlazer Game, Type B) + code:02964d/ea + cheat + description:Take no damage (LazerBlazer Game, Type C) + code:038e5c/ad + +cartridge sha256:72268d692f03f9c012844edac1febe0b77932268b3b37ad55d6ccf631cda8483 + name:Super Shadow of the Beast (USA) (Proto) + cheat + description:Invincibility + code:008917/ad+0088f3/8d+008902/d0 + cheat + description:Infinite health + code:008921/c5 + cheat + description:Infinite lives + code:008921/a5 + cheat + description:Infinite credits + code:00817a/c5 + cheat + description:Moon-jump + code:009e42/ad+008e97/ad + +cartridge sha256:8b75ab4bb1b63c45a56e7a4c5a37c0864f14375ab3131edc33489764426ad888 + name:Super Smash T.V. (USA) + cheat + description:Invincibility on mobile force field pick-up + code:038a79/80+038a7a/01 + cheat + description:Weapons gauge doesn't lose power until you die (don't combine with don't lose weapon power code) + code:00beec/bd + cheat + description:Don't lose weapon power after death (don't combine with weapons gauge doesn't lose power code) + code:0098b9/80+0098ba/01 + cheat + description:Infinite credits (if continue timer runs out and player starts, a credit gets used) + code:0ed4ee/ad + cheat + description:Infinite lives + code:009891/bd + cheat + description:Bonus life worth nothing + code:03bb25/bd + cheat + description:Join in with 2 lives - P1 + code:00981f/ff + cheat + description:Join in with 3 lives - P1 + code:00981f/00 + cheat + description:Join in with 4 lives - P1 + code:00981f/01 + cheat + description:Join in with 5 lives - P1 + code:00981f/02 + cheat + description:Join in with 7 lives - P1 + code:00981f/04 + cheat + description:Join in with 8 lives - P1 + code:00981f/05 + cheat + description:Join in with 9 lives - P1 + code:00981f/06 + cheat + description:2 lives after continue - P1 + code:00986f/ff + cheat + description:3 lives after continue - P1 + code:00986f/00 + cheat + description:4 lives after continue - P1 + code:00986f/01 + cheat + description:5 lives after continue - P1 + code:00986f/02 + cheat + description:7 lives after continue - P1 + code:00986f/04 + cheat + description:8 lives after continue - P1 + code:00986f/05 + cheat + description:9 lives after continue - P1 + code:00986f/06 + cheat + description:10 lives after continue - P1 + code:00986f/07 + cheat + description:2 lives after continue - P2 + code:009843/ff + cheat + description:3 lives after continue - P2 + code:009843/00 + cheat + description:4 lives after continue - P2 + code:009843/01 + cheat + description:5 lives after continue - P2 + code:009843/02 + cheat + description:7 lives after continue - P2 + code:009843/04 + cheat + description:8 lives after continue - P2 + code:009843/05 + cheat + description:9 lives after continue - P2 + code:009843/06 + cheat + description:10 lives after continue - P2 + code:009843/07 + cheat + description:Start with 0 continues + code:0081d5/00 + cheat + description:Start with 1 continue + code:0081d5/01 + cheat + description:Start with 2 continues + code:0081d5/02 + cheat + description:Start with 3 continues + code:0081d5/03 + cheat + description:Start with 5 continues + code:0081d5/05 + cheat + description:Start with 6 continues + code:0081d5/06 + cheat + description:Start with 7 continues + code:0081d5/07 + cheat + description:Start with 8 continues + code:0081d5/08 + cheat + description:Start with 9 continues + code:0081d5/09 + cheat + description:Start with 3 lives + code:0081de/00 + cheat + description:Start with 4 lives + code:0081de/01 + cheat + description:Start with 5 lives + code:0081de/02 + cheat + description:Start with 7 lives + code:0081de/04 + cheat + description:Start with 8 lives + code:0081de/05 + cheat + description:Start with 9 lives + code:0081de/06 + cheat + description:Start with 10 lives + code:0081de/07 + 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 + name:Super Soccer (USA) + cheat + description:Each goal worth 2 - P1 + code:01ddc6/1a+01ddc7/ea + cheat + description:Each goal worth 3 - P1 + code:01ddc6/1a+01ddc7/1a + cheat + description:Each goal worth 4 - P1 + code:01ddc6/69+01ddc7/03 + cheat + description:Each goal worth 5 - P1 + code:01ddc6/69+01ddc7/04 + cheat + description:Each goal worth 6 - P1 + code:01ddc6/69+01ddc7/05 + cheat + description:Each goal worth 7 - P1 + code:01ddc6/69+01ddc7/06 + cheat + description:Each goal worth 8 - P1 + code:01ddc6/69+01ddc7/07 + cheat + description:Each goal worth 9 - P1 + code:01ddc6/69+01ddc7/08 + cheat + description:Each goal worth 2 - P2 + code:01ddda/1a+01dddb/ea + cheat + description:Each goal worth 3 - P2 + code:01ddda/1a+01dddb/1a + cheat + description:Each goal worth 4 - P2 + code:01ddda/69+01dddb/03 + cheat + description:Each goal worth 5 - P2 + code:01ddda/69+01dddb/04 + cheat + description:Each goal worth 6 - P2 + code:01ddda/69+01dddb/05 + cheat + description:Each goal worth 7 - P2 + code:01ddda/69+01dddb/06 + cheat + description:Each goal worth 8 - P2 + code:01ddda/69+01dddb/07 + cheat + description:Each goal worth 9 - P2 + code:01ddda/69+01dddb/08 + cheat + description:Timer continues to count when it is normally stopped (pause can still stop time) + code:01c980/00 + +cartridge sha256:5eb9736d66b3ac730ebbfdd19ef2397282b5f1a62dc0048093e041e23b807741 + name:Super Soccer Champ (USA) + cheat + description:Faster timer + code:01d099/1e + cheat + description:Slower timer + code:01d099/70 + cheat + description:Faster Brazil strikers + code:0cf633/02 + cheat + description:Faster USA strikers + code:0cf643/02 + cheat + description:Faster England strikers + code:0cf603/02 + cheat + description:Faster Germany strikers + code:0cf5e3/02 + cheat + description:Faster Italy strikers + code:0cf613/02 + cheat + description:Faster Holland strikers + code:0cf623/02 + cheat + description:Faster Argentina strikers + code:0cf5f3/02 + cheat + description:Faster France strikers + code:0cf653/02 + +cartridge sha256:5985cdad45958a5b8c5967ad39efe51569f560bf237a4e9864f21111082a8500 + name:Super Solitaire (USA) (En,Fr,De,Es,It) + cheat + description:Move cards to any pile - Klondike + code:80b4ae/80+80b3cb/00+80b3b1/00 + cheat + description:Move cards to any pile - Free Cell + code:80b81b/80 + +cartridge sha256:5670ad514d086359e28f41d79a05ae93309b382d6d56d42a6a0e493e6107111b + name:Super Soukoban (Japan) + cheat + description:Infinite steps + code:02a6ab/ad + cheat + description:Walk through walls + code:02b0bb/00+02b0bd/00 + +cartridge sha256:298b643fec4208f33d02a7afbb05c6f757b0086be533f8ca739466cbe96ae918 + name:Super Star Wars (USA) (Rev 1) + cheat + description:Protection against most damage + code:80ea2d/60 + cheat + description:Infinite lives + code:80e9d8/ad+808fae/a9 + cheat + description:Infinite continues + code:81dd68/2c + cheat + description:Blaster power-ups remain after dying + code:80e9ce/77 + cheat + description:Hit anywhere - Side-scrolling levels + code:80bd59/60+80bd58/d0+80bd55/c0+80bd63/00+80bd56/00+80bd57/00 + cheat + description:Invincibility + hit anywhere + code:80a5a3/e0+80a5a6/30+80a5a5/00+80a5a4/1d + cheat + description:Only 1 Jawa needed to pass landspeeder levels + code:808437/01+808442/01 + cheat + description:Only 5 Jawas needed to pass landspeeder levels + code:808437/05+808442/05 + cheat + description:Only 10 Jawas needed to pass landspeeder levels + code:808437/0a+808442/0a + cheat + description:25 Jawas needed to pass landspeeder levels + code:808437/19+808442/19 + cheat + description:50 Jawas needed to pass landspeeder levels + code:808437/32+808442/32 + cheat + description:No fuel maximum for fuel power-ups + code:80c871/80 + cheat + description:Fuel power-ups completely refill the landspeeder + code:80c86c/24 + cheat + description:Small hearts restore 1/2 health (easy level) + code:81e295/02 + cheat + description:Small hearts restore 1/2 health (brave level) + code:81e297/01 + cheat + description:Small hearts restore 1/2 health (Jedi level) + code:81e299/01 + cheat + description:Small hearts restore 2x health (easy level) + code:81e295/06 + cheat + description:Small hearts restore 2x health (brave level) + code:81e297/04 + cheat + description:Small hearts restore 2x health (Jedi level) + code:81e299/04 + cheat + description:Small hearts restore 4x health (easy level) + code:81e295/0c + cheat + description:Small hearts restore 4x health (brave level) + code:81e297/08 + cheat + description:Small hearts restore 4x health (Jedi level) + code:81e299/08 + cheat + description:Han Solo and Chewbacca start with a blaster + code:81bfbf/00 + cheat + description:Han Solo and Chewbacca start with a seeker gun + code:81bfbf/02 + cheat + description:Han Solo and Chewbacca start with a rapid ion gun + code:81bfbf/03 + cheat + description:Han Solo and Chewbacca start with a plasma gun + code:81bfbf/04 + cheat + description:Have character select menu on a new game + code:809e56/00 + cheat + description:Have Lightsaber on a new game + code:809e4e/00 + cheat + description:Start with 1/2 fuel on landspeeder levels + code:808431/12 + cheat + description:Start with 2x fuel on landspeeder levels + code:808431/48 + cheat + description:Start with 2 lives + code:81e273/01 + cheat + description:Start with 6 lives + code:81e273/05 + cheat + description:Start with 8 lives + code:81e273/07 + cheat + description:Start with 11 lives + code:81e273/0a + cheat + description:Start with 16 lives + code:81e273/0f + cheat + description:Start with 26 lives + code:81e273/19 + cheat + description:Start with 51 lives + code:81e273/32 + cheat + description:Start with 100 lives + code:81e273/63 + cheat + description:Start with no continues + code:81e29e/00 + cheat + description:Start with 5 continues + code:81e29e/05 + cheat + description:Start with 7 continues + code:81e29e/07 + cheat + description:Start with 10 continues + code:81e29e/0a + cheat + description:Start with 15 continues + code:81e29e/0f + cheat + description:Start with 25 continues + code:81e29e/19 + cheat + description:Start with 50 continues + code:81e29e/32 + cheat + description:Start with 99 continues + code:81e29e/63 + cheat + description:Start with 1/2 health (easy level) + code:81e277/12 + cheat + description:Start with 1/2 health (brave level) + code:81e279/10 + cheat + description:Start with 1/2 health (Jedi level) + code:81e27b/0e + cheat + description:Start with 2x health (easy level) + code:81e277/48 + cheat + description:Start with 2x health (brave level) + code:81e279/40 + cheat + description:Start with 2x health (Jedi level) + code:81e27b/38 + 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 + name:Super Star Wars (USA) + cheat + description:Hit anywhere - Side-scrolling levels + code:80bd9a/60+80bd99/d0+80bd96/c0+80bd98/00+80bd97/00+80bda4/00 + 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 + name:Super Star Wars - Return of the Jedi (USA) (Rev 1) + cheat + description:Infinite lives + code:80e645/ad + cheat + description:Infinite Force power when you use the Force Saber + code:83e32b/ad + cheat + description:Always have shield + code:8088fd/a9 + cheat + description:Once you have thermal detonator you keep it (disable to use force power) + code:81d7de/ad + cheat + description:Infinite Force power when you use the Freeze Force + code:85b762/ad + cheat + description:Finish the first level almost instantly + code:839a0d/69+839a0e/ff+839a0f/ff + cheat + description:Start with 1 life + code:85bade/00 + cheat + description:Start with 5 lives + code:85bade/04 + cheat + description:Start with 10 lives + code:85bade/09 + cheat + description:Start with 25 lives + code:85bade/18 + cheat + description:Start with very little health + code:85bbf3/a9+85bbf4/01+85bbf5/00 + cheat + description:Start with about 1/4 health + code:85bbf3/a9+85bbf4/0f+85bbf5/00 + cheat + description:Start with about 1/2 health + code:85bbf3/a9+85bbf4/10+85bbf5/00 + cheat + description:Start with about 3/4 health + code:85bbf3/a9+85bbf4/1f+85bbf5/00 + +cartridge sha256:46370b3bd6ff9ee04c425eef0f482f521f3b61bd4b058f2f4e9d322253d7b5de + name:Super Star Wars - The Empire Strikes Back (USA) (Rev 1) + cheat + description:Almost invincible - except spikes (works for enemy too) + code:80e71e/2b + cheat + description:Infinite lives + code:80e6bd/ad + cheat + description:Infinite continues + code:81d850/ad + cheat + description:Infinite thermal detonators + code:80f45f/80 + cheat + description:Elevation and Freeze don't drain force bar + code:85d558/ad + cheat + description:Saber control doesn't drain force bar + code:83a1a0/00 + cheat + description:Mind control, Slow, Deflect and Invisible don't drain force bar + code:85d61c/ad + cheat + description:Keep gun power-ups after dying + code:80e6b2/ad + cheat + description:Shield power-ups don't last as long + code:80bb60/00 + cheat + description:Shield power-ups last longer + code:80bb60/02 + cheat + description:Shield power-ups last much longer + code:80bb60/03 + cheat + description:Shield power-ups last a very long time + code:80bb60/0f + cheat + description:Health sword power-ups add 1/2 as much + code:80bb2f/02 + cheat + description:Health sword power-ups add 2x as much + code:80bb2f/08 + cheat + description:Health sword power-ups add 4x as much + code:80bb2f/10 + cheat + description:Force orbs add 1/2 as much + code:80bb9e/18 + cheat + description:Force orbs add 2x as much + code:80bb9e/60 + cheat + description:Force orbs fill force bar + code:80bb9e/ff + cheat + description:Small hearts heal less on Easy + code:81de9a/01 + cheat + description:Small hearts heal 2x as much on Easy + code:81de9a/06 + cheat + description:Small hearts heal 4x as much on Easy + code:81de9a/0c + cheat + description:Small hearts heal very much on Easy + code:81de9a/20 + cheat + description:Small hearts heal completely on Easy + code:81de9a/44 + cheat + description:Small hearts heal less on Brave level + code:81de9c/01 + cheat + description:Small hearts heal 2x as much on Brave + code:81de9c/04 + cheat + description:Small hearts heal 4x as much on Brave + code:81de9c/08 + cheat + description:Small hearts heal very much on Brave + code:81de9c/20 + cheat + description:Small hearts heal completely on Brave + code:81de9c/44 + cheat + description:Small hearts heal less on Jedi level + code:81de9e/01 + cheat + description:Small hearts heal 2x as much on Jedi + code:81de9e/04 + cheat + description:Small hearts heal 4x as much on Jedi + code:81de9e/08 + cheat + description:Small hearts heal very much on Jedi + code:81de9e/20 + cheat + description:Small hearts heal completely on Jedi + code:81de9e/44 + cheat + description:Big hearts heal 1/2 your health instead of 1/4 + code:80bb01/ea + cheat + description:Big hearts heal completely + code:80bb01/0a + cheat + description:Continue with 2 lives on Easy + code:81de6a/01 + cheat + description:Continue with 6 lives on Easy + code:81de6a/05 + cheat + description:Continue with 21 lives on Easy + code:81de6a/14 + cheat + description:Continue with 51 lives on Easy + code:81de6a/32 + cheat + description:Continue with 2 lives on Jedi + code:81de6e/01 + cheat + description:Continue with 6 lives on Jedi + code:81de6e/05 + cheat + description:Continue with 21 lives on Jedi + code:81de6e/14 + cheat + description:Continue with 100 lives on Jedi + code:81de6e/63 + cheat + description:Tauntaun starts with 1/2 usual health + code:84d647/20 + cheat + description:Tauntaun starts with 3/4 usual health + code:84d647/30 + cheat + description:Tauntaun starts with a little more health than usual + code:84d647/44 + cheat + description:Start with all force abilities + code:85d4ec/80 + cheat + description:Start with Flame gun - 1st life only + code:81d0ac/8d + cheat + description:Start with 2 lives on Brave + code:81de6c/01 + cheat + description:Start with 6 lives on Brave + code:81de6c/05 + cheat + description:Start with 21 lives on Brave + code:81de6c/14 + cheat + description:Start with 100 lives on Brave + code:81de6c/63 + cheat + description:Start with 1 continue + code:81dea3/01 + cheat + description:Start with 5 continues + code:81dea3/05 + cheat + description:Start with 9 continues + code:81dea3/09 + cheat + description:Start with 1/2 as much health on Easy + code:81de70/12 + cheat + description:Start with 3/4 as much health on Easy + code:81de70/18 + cheat + description:Start with more health on Easy + code:81de70/2a + cheat + description:Start with much more health on Easy + code:81de70/30 + cheat + description:Start with maximum health on Easy + code:81de70/44 + cheat + description:Start with 1/2 as much health on Brave + code:81de72/10 + cheat + description:Start with 3/4 as much health on Brave + code:81de72/18 + cheat + description:Start with more health on Brave + code:81de72/2a + cheat + description:Start with much more health on Brave + code:81de72/30 + cheat + description:Start with maximum health on Brave + code:81de72/44 + cheat + description:Start with half as much health on Jedi + code:81de74/0e + cheat + description:Start with 3/4 as much health on Jedi + code:81de74/15 + cheat + description:Start with no continues + code:81dea3/00 + cheat + description:Start on level 1-2 + code:808d5d/02 + cheat + description:Start on level 1-3 + code:808d5d/06 + cheat + description:Start on level 1-4 + code:808d5d/03 + cheat + description:Start on level 1-5 + code:808d5d/05 + cheat + description:Start on level 1-6 + code:808d5d/04 + cheat + description:Start on level 1-7 + code:808d5d/09 + cheat + description:Start on level 1-8 + code:808d5d/15 + cheat + description:Start on level 1-10 + code:808d5d/07 + cheat + description:Start on Hoth 3D level + code:808d5c/0e+808d5d/0a + cheat + description:Start on level 1-11 + code:808d5d/08 + cheat + description:Start on Asteroids level + code:808d5c/12+808d5d/00 + cheat + description:Start on level 3-1 + code:808d5d/0c + cheat + description:Start on level 3-2 + code:808d5d/0d + cheat + description:Start on level 3-3 + code:808d5d/0e + cheat + description:Start on Cloud City 3D level + code:808d5c/0e+808d5d/1a + cheat + description:Start on level 4-2 + code:808d5d/0f + cheat + description:Start on level 4-3 + code:808d5d/13 + cheat + description:Start on level 4-4 + code:808d5d/12 + cheat + description:Start on level 4-5 + code:808d5d/10 + cheat + description:Start on level 4-6 + code:808d5d/17 + cheat + description:Start on level 4-7 + code:808d5d/18 + cheat + description:Start on Darth Vader level + code:808d5d/16 + +cartridge sha256:d17cb5c73174060fcbd9cba6c705643f19c3b8be24d0f7ee43aee674ff1ea38e + name:Super Street Fighter II (USA) + cheat + description:Invincibility (except against throws, projectiles don't work) - P1 + code:c05ea2/80+c05ea3/01+c1ce64/80+c1ce65/02+c1cc19/80+c1cc1a/02 + cheat + description:Infinite health - P1 + code:c05080/a9+c05081/b0+c05082/8d+c05083/31+c05084/05 + cheat + description:Don't take damage except from throws or grabs - both players + code:c06c4a/ea+c06c4b/ea + cheat + description:Hit anywhere (except projectiles) - P1 + code:c06500/e0+c06503/b0+c06501/40+c06502/07 + cheat + description:1st normal hit wins - except throws or grabs + code:c06c4d/00 + cheat + description:No charging required for some special moves + code:c14fd0/04 + cheat + description:Some special moves can be done in the air + code:c12a30/00 + cheat + description:Dizziness doesn't last + code:c13836/64 + cheat + description:Every hit sets opponent on fire + code:c06237/a9+c06238/30 + cheat + description:Every hit sets the opponent on fire and knocks him down + code:c06237/a9+c06238/18 + cheat + description:Every hit zaps the opponent and knocks him down + code:c06237/a9+c06238/1a + cheat + description:Every hit knocks the opponent down + code:c06237/a9+c06238/1c + cheat + description:Every hit is a "hard hit" - opponent almost never gets knocked down + code:c06237/a9+c06238/0a + cheat + description:Players jump slower (not functional for CPU) + code:c13b56/a9+c13b57/07 + cheat + description:Players jump faster (not functional for CPU) + code:c13b56/a9+c13b57/0b + cheat + description:Each battle lasts only 1 round + code:c0bb69/01 + cheat + description:Speed up timer + code:c040a4/1f + cheat + description:Slow down timer + code:c040a4/5a + cheat + description:P2 starts right in front of P1 + code:c1d3de/16 + cheat + description:Start with 1/4 health - both players + code:c054a4/2c + cheat + description:Start with 1/2 health - both players + code:c054a4/58 + cheat + description:Start with 3/4 health - both players + code:c054a4/84 + cheat + description:Balrog - Fierce charging punch, does heavy damage + code:c583c5/8f + cheat + description:Balrog - Roundhouse charging uppercut, does heavy damage + code:c583dd/8f + cheat + description:Balrog - Fierce shoulder butt, does heavy damage + code:c5855d/8f + cheat + description:Balrog - Faster turn punch - roundhouse + code:c1bca8/06 + cheat + description:Balrog - Superfast turn punch - roundhouse + code:c1bca8/09 + cheat + description:Blanka - Fierce forward ball, does heavy damage + code:c563af/8f + cheat + description:Blanka - Beast leap, does heavy damage + code:c56493/8f + cheat + description:Blanka - Jab zap, does heavy damage + code:c56373/8f + cheat + description:Cammy - Fierce spin knuckle, does heavy damage + code:c591e7/8f + cheat + description:Cammy - Roundhouse front kick, does heavy damage + code:c5919f/8f + cheat + description:Cammy - Roundhouse cannon drill, from far away, does heavy damage + code:c5911b/8f + cheat + description:Cammy - Erratic cannon drill + code:c193ff/06 + cheat + description:Cammy - Superfast cannon drill + code:c193fe/00 + cheat + description:Cammy - Superfast front kick - fierce + code:87d14c/08 + cheat + description:Cammy - Superfast front kick - strong + code:87d149/08 + cheat + description:Cammy - Superfast front kick - jab + code:87d148/08 + cheat + description:Chun-Li - Fierce fireball, does heavy damage + code:c57003/8f + cheat + description:Chun-Li - Down step, does heavy damage + code:c56d4b/0f + cheat + description:Chun-Li - Short lightning kick, does heavy damage + code:c56e6b/8f + cheat + description:Chun Li - Faster whirlwind kick - roundhouse + code:c172f6/06 + cheat + description:Chun Li - Superfast whirlwind kick - roundhouse + code:c172f6/09 + cheat + description:Dee Jay - Fierce hyper fist (1st hit), does heavy damage + code:c5a775/8f + cheat + description:Dee Jay - Fierce Max Out, does heavy damage + code:c5a811/8f + cheat + description:Dee Jay - Roundhouse dread kick, does heavy damage + code:c5a6e5/8f + cheat + description:Dee Jay - Dread kick is faster - fierce + code:87d1ed/09 + cheat + description:Dee Jay - Dread kick is faster - strong + code:87d1e5/09 + cheat + description:Dhalsim - Yoga spear, does heavy damage + code:c576ff/0f + cheat + description:Dhalsim - Strong yoga flame (solid hit), does heavy damage + code:c577fb/8f + cheat + description:Dhalsim - Fierce yoga fire, does heavy damage + code:c577bf/8f + cheat + description:E Honda - Jab hundred-hand slap, does heavy damage + code:c55e5d/8f + cheat + description:E Honda - Fierce torpedo, does heavy damage + code:c55f89/8f + cheat + description:E Honda - Fierce sumo splash, does heavy damage + code:c55fdd/8f + cheat + description:Fei Long - Fierce slide punch (1st hit), does heavy damage + code:c5a137/8f + cheat + description:Fei Long - Fierce slide punch (2nd hit), does heavy damage + code:c5a143/8f + cheat + description:Fei Long - Fierce slide punch (3rd hit), does heavy damage + code:c5a14f/8f + cheat + description:Fei Long - Roundhouse dragon kick, does heavy damage + code:c5a0fb/8f + cheat + description:Fei Long - Superfast rekka-ken - strong + code:87d1b3/07 + cheat + description:Fei Long - Superfast rekka-ken - fierce + code:87d137/08 + cheat + description:Guile - Fierce sonic boom, does heavy damage + code:c56989/8f + cheat + description:Guile - Roundhouse sonic kick, extremely close range, does heavy damage + code:c568f9/8f + cheat + description:Hawk - The Hawk, does heavy damage + code:c599e5/8f + cheat + description:Ken - Fierce dragon punch, close to opponent, does heavy damage + code:c55a8f/8f + cheat + description:Ken - Fierce fireballs, close to opponent, does heavy damage + code:c55ad7/8f + cheat + description:Ken - Roundhouse hurricane kick while on the ground, does heavy damage + code:c559cf/8f + cheat + description:Ken - No delay after throwing fireball + code:c18d5f/e6 + cheat + description:Ken - Hurricane kicks rise higher when done in mid-air + code:c18f49/64 + cheat + description:Ken - Faster hurricane kicks - roundhouse + code:87c152/06 + cheat + description:Ken - Super fast hurricane kicks - roundhouse + code:87c152/09 + cheat + description:M. Bison - Super fast psycho crusher - fierce + code:87d211/09 + cheat + description:M. Bison - Psycho crusher in one place - fierce + code:c1b181/64 + cheat + description:Ryu - Jab dragon punch, close to opponent, does heavy damage + code:c5560f/8f + cheat + description:Ryu - Fierce red fireballs from far away, does heavy damage + code:c5579b/8f + cheat + description:Ryu - Roundhouse hurricane kick in the air, does heavy damage + code:c5570b/8f + cheat + description:Ryu - No delay after throwing fireball + code:c18d5f/e6 + cheat + description:Ryu - Hurricane kicks rise higher when done in mid-air + code:c18f49/64 + cheat + description:Ryu - Faster hurricane kicks - roundhouse + code:87c152/06 + cheat + description:Ryu - Super fast hurricane kicks - roundhouse + code:87c152/09 + cheat + description:Sagat - Roundhouse low tiger, from far away, does heavy damage + code:c58127/8f + cheat + description:Sagat - Fierce high tiger, from far away, does heavy damage + code:c580df/8f + cheat + description:Sagat - Short tiger knee, does heavy damage + code:c57fe3/8f + cheat + description:Sagat - Jab projectiles move slower for everyone but Sagat, does heavy damage + code:87dc3d/ff + cheat + description:Sagat - Jab projectiles move slower for Sagat, does heavy damage + code:87dc43/ff + cheat + description:Sagat - Fierce projectiles move faster for everyone but Sagat, does heavy damage + code:87dc41/fa + cheat + description:Sagat - Fierce projectiles move faster for Sagat, does heavy damage + code:87dc47/f7 + cheat + description:Vega - Fierce claw dive, does heavy damage + code:c58ac9/cf + cheat + description:Vega - Rolling claw attack, does heavy damage + code:c58ad5/8f + cheat + description:Vega - Claw thrust, does heavy damage + code:c58bf5/8f + cheat + description:Vega - Superfast claw roll + code:c171e5/07 + cheat + description:Vega - Claw roll in one place + code:c171ee/64 + cheat + description:Zangief - Double spinning lariat (only certain hits), does heavy damage + code:c57365/8f + cheat + description:Zangief - Spinning clothesline, does heavy damage + code:c57311/8f + 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 + name:Super Strike Eagle (USA) + cheat + description:Infinite fuel + code:80980f/a5 + cheat + description:Infinite ammo - air-to-air mode + code:80dbc2/00 + cheat + description:Infinite Maverick Missiles + code:80af04/bd + cheat + description:Infinite Sidewinder Missiles + code:80dc1b/a5 + cheat + description:Infinite Chaff + code:80dccd/ea + cheat + description:Infinite Flares + code:80dc84/ea + cheat + description:Use up ammo faster - air-to-air mode + code:80dbc2/0a + cheat + description:Start with 0 Chaff instead of 12 + code:01e916/00 + cheat + description:Start with 6 Chaff + code:01e916/06 + cheat + description:Start with 50 Chaff + code:01e916/32 + cheat + description:Start with 99 Chaff + code:01e916/63 + cheat + description:Start with 0 Flares instead of 12 + code:01e91b/00 + cheat + description:Start with 6 Flares + code:01e91b/06 + cheat + description:Start with 50 Flares + code:01e91b/32 + cheat + description:Start with 99 Flares + code:01e91b/63 + cheat + description:Start with 2 Sidewinder missiles instead of 12 + code:01e939/02 + cheat + description:Start with 25 Sidewinder Missiles + code:01e939/19 + cheat + description:Start with 50 Sidewinder Missiles + code:01e939/32 + cheat + description:Start with 99 Sidewinder Missiles + code:01e939/63 + cheat + description:Start with less fuel + code:01e90d/40 + +cartridge sha256:6e45a80ea148654514cb4e8604a0ffcbc726946e70f9e0b9860e36c0f3fa4877 + name:Super Tennis (USA) + cheat + description:Super speed - Matt + code:008747/04+008767/03+01dd2f/00 + cheat + description:Super speed - Amy + code:008747/04+008767/03+01df2f/00 + cheat + description:Super speed - Brian + code:008747/04+008767/03+01dd3f/00 + cheat + description:Super speed - Ki + code:008747/04+008767/03+01df3f/00 + cheat + description:Super speed - Phil + code:008747/04+008767/03+01dd4f/00 + cheat + description:Super speed - Lisa + code:008747/04+008767/03+01df4f/00 + cheat + description:Super speed - John + code:008747/04+008767/03+01dd5f/00 + cheat + description:Super speed - Erin + code:008747/04+008767/03+01df5f/00 + cheat + description:Super speed - Meyer + code:008747/04+008767/03+01dd6f/00 + cheat + description:Super speed - Donna + code:008747/04+008767/03+01df6f/00 + cheat + description:Super speed - Rich + code:008747/04+008767/03+01dd7f/00 + cheat + description:Super speed - Debbie + code:008747/04+008767/03+01df7f/00 + cheat + description:Super speed - Hiro + code:008747/04+008767/03+01dd8f/00 + cheat + description:Super speed - Colette + code:008747/04+008767/03+01df8f/00 + cheat + description:Super speed - Steve + code:008747/04+008767/03+01dd9f/00 + cheat + description:Super speed - Nancy + code:008747/04+008767/03+01df9f/00 + cheat + description:Super speed - Rob + code:008747/04+008767/03+01ddaf/00 + cheat + description:Super speed - Yuka + code:008747/04+008767/03+01dfaf/00 + cheat + description:Super speed - Mar + code:008747/04+008767/03+01ddbf/00 + cheat + description:Super speed - Barb + code:008747/04+008767/03+01dfbf/00 + cheat + description:Play as Don J (Boss player) - P1 + code:7e0802/40 + cheat + description:Play as Don J (Boss player) - P2 + code:7e0842/40 + cheat + description:Play as Don J (Boss player) - P3 + code:7e0882/40 + cheat + description:Play as Don J (Boss player) - P4 + code:7e08c2/40 + cheat + description:CPU can't hit the ball + code:7e00ef/00 + cheat + description:CPU scared of the ball + code:7e00ec/00 + +cartridge sha256:8dda3b0888a32005041f2feb9be4e14807d40291f951a4612461cf41dac9cb78 + name:Super Tetris 2 + Bombliss (Japan) + cheat + description:Drop pieces on left side of the board to clear that line + code:009e28/01 + +cartridge sha256:02cb7f1ed21ed6bfb9eaa0e91df2adb063a9bf4cbd6feb6cd024d676829e227e + name: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 + name:Super Turrican (USA) + cheat + description:Invincibility + code:00d880/ad + cheat + description:Infinite time + code:00d7b0/80 + cheat + description:Infinite lives + code:00d700/ad + cheat + description:Infinite continues + code:008482/ad + cheat + description:Infinite wheel time + code:00d909/ad + cheat + description:Infinite Smart Lines + code:00d88d/ad + cheat + description:Hit anywhere + code:00b9ad/78+00b9ac/80+00ba4c/ad + cheat + description:Don't decrease weapon power after dying + code:00d6d9/80+00d6da/16 + cheat + description:Never change weapon type + code:00b3d5/2c + cheat + description:Start with blue weapon + code:00b2e1/01 + cheat + description:Start with yellow weapon + code:00b2e1/02 + cheat + description:Start with all weapons at maximum power (4 power-ups) + code:00b2e1/04+00b2ec/9c + cheat + description:Start with 1 life - Normal/Hard only + code:008261/00 + cheat + description:Start with 2 lives - Normal/Hard only + code:008261/01 + cheat + description:Start with 5 lives - Normal/Hard only + code:008261/04 + cheat + description:Start with 10 lives - Normal/Hard only + code:008261/09 + cheat + description:Start with 25 lives - Normal/Hard only + code:008261/18 + cheat + description:Start with 50 lives - Normal/Hard only + code:008261/31 + cheat + description:Start with 99 lives - Normal/Hard only + code:008261/62 + cheat + description:Start with 1 continue - Easy/Normal only + code:008210/01 + cheat + description:Start with 2 continues - Easy/Normal only + code:008210/02 + cheat + description:Start with 5 continues - Easy/Normal only + code:008210/05 + cheat + description:Start with 10 continues - Easy/Normal only + code:008210/0a + cheat + description:Start with 25 continues - Easy/Normal only + code:008210/19 + cheat + description:Start with 50 continues - Easy/Normal only + code:008210/32 + cheat + description:Start with 99 continues - Easy/Normal only + code:008210/63 + cheat + description:Start with no Smart Lines + code:00b2f0/00 + cheat + description:Start with 1 Smart Line + code:00b2f0/01 + cheat + description:Start with 2 Smart Lines + code:00b2f0/02 + cheat + description:Start with 4 Smart Lines - only 3 shown at once + code:00b2f0/04 + cheat + description:Start with 5 Smart Lines - only 3 shown at once + code:00b2f0/05 + cheat + description:Start with 10 Smart Lines - only 3 shown at once + code:00b2f0/0a + cheat + description:Start with 25 Smart Lines - only 3 shown at once + code:00b2f0/19 + cheat + description:Start with 50 Smart Lines - only 3 shown at once + code:00b2f0/32 + cheat + description:Start with 99 Smart Lines - only 3 shown at once + code:00b2f0/63 + cheat + description:Start on level 2 + code:008208/02 + cheat + description:Start on level 3 + code:008208/03 + cheat + description:Start on level 4 + code:008208/04 + cheat + description:Start on level 5 + code:008208/05 + cheat + description:Start on level 6 + code:008208/06 + cheat + description:Start on level 7 + code:008208/07 + cheat + description:Start on level 8 + code:008208/08 + cheat + description:Start on level 9 + code:008208/09 + cheat + description:Start on level 10 + code:008208/0a + cheat + description:Start on level 11 + code:008208/0b + cheat + description:Start on level 12 + code:008208/0c + 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 + name: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:fddc6634f727899152a5b8b1ca3b8938a4e4ccdd5a6adb9e1579363e3b676f20 + name:Super Uno (Japan) + cheat + description:Place any card on the stack regardless of color + code:01a092/80 + +cartridge sha256:792e615a34ceae5a1b9a4f54c5a5d9b53e39299332fece83e4bceca2c22efb21 + name:Super Valis IV (USA) + cheat + description:Allows you to select easy mode on the options screen + code:00dfa0/42 + cheat + description:Infinite usage for all special attacks + code:008f8f/00 + cheat + description:Protection from most enemy attacks + code:00c5c3/ad + cheat + description:Infinite hits on armor + code:00c5c7/ad + cheat + description:Hit anywhere + code:00b001/00+00c498/00 + cheat + description:Get items from anywhere + code:00bfc6/80 + cheat + description:Heart worth more + code:00b125/18 + cheat + description:Heart worth much more + code:00b125/28 + cheat + description:Selecting an item does not remove it from the menu of available items + code:008f1a/bd + cheat + description:Enables level select + code:00cea9/ea + cheat + description:Get any score for maximum score + code:00ac9f/00 + cheat + description:Item is always search + code:008ede/a9+008edf/03 + cheat + description:Item is always three-way beam + code:008ede/a9+008edf/01 + cheat + description:Item is always bomber + code:008ede/a9+008edf/02 + cheat + description:Item is always homing + code:008ede/a9+008edf/04 + cheat + description:Item is always heart + code:008ede/a9+008edf/05 + cheat + description:Item is always armor + code:008ede/a9+008edf/06 + 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 + name:Super Widget (USA) + cheat + description:Invincibility + code:009155/00 + cheat + description:Infinite lives + code:0083b4/ad + cheat + description:Infinite time + code:008292/ad + cheat + description:1 W gives 1 life + code:009cc8/03 + +cartridge sha256:d802715fb4f09d7e499b5b3e577af641598a723dae7cedeaa93943bb53c6edbb + name:SWAT Kats - The Radical Squadron (USA) + cheat + description:Invincibility after first hit + code:c05313/bd + cheat + description:Invincible while flying the jet + code:c1f594/6b+c1f5d7/6b+c1f60b/6b + cheat + description:Almost infinite health + code:c0cc5a/34 + cheat + description:Gain levels quickly + code:c13d60/69 + cheat + description:World 5 - Dark Kat always enabled + code:c0ecd6/05 + +cartridge sha256:40916fe512541aafba354e39c4ef63a9114de235526de5bb949a239a9257490e + name:Sword Maniac (Japan) + cheat + description:Infinite time + code:008bf8/ad + cheat + description:Infinite health + code:7e0a18/a0 + cheat + description:Infinite lives + code:7e0a3e/09 + cheat + description:Attack really fast + code:7e101e/01 + +cartridge sha256:c2015d03dd3db08069b2a6ea1ed6b3e1ac1e3a5f804b02295c3cd3717add91ef + name:Syndicate (USA) + cheat + description:Start with Mega-cash + code:80a1e4/30+80a1e5/30 + cheat + description:All agents have infinite ammo for pistols + code:81ca91/a9 + +cartridge sha256:365f10f9d9f68cc59e769eeb451c417e1ff7415022a625de9976a3b924c0bd61 + name:T2 - The Arcade Game (USA) + cheat + description:Infinite health (alt) - P1 + code:82e0ec/80 + cheat + description:Infinite health (alt) - P2 + code:82e113/80 + cheat + description:Infinite gunpower - P1 + code:809d39/a5 + cheat + description:Infinite gunpower - P2 + code:809d5c/a5 + cheat + description:Infinite missiles - P1 + code:82d4ce/00 + cheat + description:Infinite missiles - P2 + code:82d4f0/00 + cheat + description:Shields lasts longer + code:80dc3b/7f + cheat + description:Plasma Pulse Energizer lasts longer - P1 + code:80dc96/08 + cheat + description:Plasma Pulse Energizer lasts longer - P2 + code:80dcbc/08 + cheat + description:Keep P.P.E. for that level once picked up - P1 + code:818c3f/ad + cheat + description:Keep P.P.E. for that level once picked up - P2 + code:818c4e/ad + cheat + description:Get 6 missiles for each 1 - P1 + code:80dc0d/06 + cheat + description:Get 9 missiles for each 1 - P1 + code:80dc0d/09 + cheat + description:Get 9 missiles for each 1 - P2 + code:80dc22/06 + cheat + description:Get 6 missiles for each 1 - P2 + code:80dc22/09 + cheat + description:Gunpower replenishes slower - P1 + code:8094ee/10 + cheat + description:Gunpower replenishes slower - P2 + code:809545/10 + cheat + description:10 credits + code:83eaff/10 + cheat + description:15 credits + code:83eaff/15 + cheat + description:20 credits + code:83eaff/20 + cheat + description:P.P.E. does extra damage - P1 + code:80dc9b/06 + cheat + description:P.P.E. does massive damage - P1 + code:80dc9b/12 + cheat + description:Infinite health - P1 + code:7e007f/7f + cheat + description:Infinite health - P2 + code:7e0081/7f + +cartridge sha256:1711fe9010232b41ec406900e5b4ef528dd2beaa97b27d94ed7eef57d63904a0 + name:Taz-Mania (USA) (Rev 1) + cheat + description:Infinite health + code:99e072/a5 + cheat + description:Infinite time + code:99e292/00 + cheat + description:Infinite continues (don't combine with start on act codes) + code:99e1b8/ad + cheat + description:Advance to next level after getting 1 kiwi + code:96bb59/84 + cheat + description:Faster timer + code:99e27c/04 + cheat + description:1 minute to complete act 1, level 1 + code:99802a/01 + cheat + description:5 minutes to complete act 1, level 1 + code:99802a/05 + cheat + description:Kiwi's worth 2 + code:96bb59/fe + cheat + description:Kiwi's worth 4 + code:96bb59/fc + cheat + description:Kiwi's worth 5 + code:96bb59/fb + cheat + description:Kiwi's worth 7 + code:96bb59/f9 + cheat + description:Red bird worth 0 seconds instead of 10 + code:99e245/00 + cheat + description:Red bird worth 20 seconds + code:99e245/02 + cheat + description:Red bird worth 30 seconds + code:99e245/03 + cheat + description:Red bird worth 40 seconds + code:99e245/04 + cheat + description:Red bird worth 50 seconds + code:99e245/05 + cheat + description:Start with 1/4 normal health + code:99dfdc/07 + cheat + description:Start with 1/2 normal health + code:99dfdc/0f + cheat + description:Start with 3/4 normal health + code:99dfdc/15 + cheat + description:Start with 1 continue (don't combine with start on act codes) + code:99e11e/01 + cheat + description:Start with 5 continues (don't combine with start on act codes) + code:99e11e/05 + cheat + description:Start with 7 continues (don't combine with start on act codes) + code:99e11e/07 + cheat + description:Start with 9 continues (don't combine with start on act codes) + code:99e11e/09 + cheat + description:Start with 50 continues (don't combine with start on act codes) + code:99e11e/32 + cheat + description:Start with 99 continues (don't combine with start on act codes) + code:99e11e/63 + cheat + description:Start on act 1, level 2 + code:99e188/2c+99e189/30+99e11e/01 + cheat + description:Start on act 1, level 3 + code:99e188/2c+99e189/30+99e11e/02 + cheat + description:Start on act 1 bonus level + code:99e188/2c+99e189/30 + cheat + description:Start on act 2, level 1 + code:99e188/2c+99e189/30+99e11e/04 + cheat + description:Start on act 2, level 2 + code:99e188/2c+99e189/30+99e11e/05 + cheat + description:Start on act 2, level 3 + code:99e188/2c+99e189/30+99e11e/06 + cheat + description:Start on act 2 bonus level + code:99e188/2c+99e189/30+99e11e/07 + cheat + description:Start on act 3, level 1 + code:99e188/2c+99e189/30+99e11e/08 + cheat + description:Start on act 3, level 2 + code:99e188/2c+99e189/30+99e11e/09 + cheat + description:Start on act 3, level 3 + code:99e188/2c+99e189/30+99e11e/0a + cheat + description:Start on act 3 bonus level + code:99e188/2c+99e189/30+99e11e/0b + cheat + description:Start on act 4, level 1 + code:99e188/2c+99e189/30+99e11e/0c + cheat + description:Start on act 4, level 2 + code:99e188/2c+99e189/30+99e11e/0d + cheat + description:Start on act 4, level 3 + code:99e188/2c+99e189/30+99e11e/0e + cheat + description:Start on act 4 bonus level + code:99e188/2c+99e189/30+99e11e/0f + cheat + description:Start on act 5, level 1 + code:99e188/2c+99e189/30+99e11e/10 + cheat + description:Start on act 5, level 2 + code:99e188/2c+99e189/30+99e11e/11 + cheat + description:Start on act 5, level 3 + code:99e188/2c+99e189/30+99e11e/12 + cheat + description:Infinite health (alt) + code:7e0096/1d + cheat + description:Infinite time (alt) + code:7e0098/99 + +cartridge sha256:e3bd2296b860a547bb8594485048d3e1326a416405ed9e91139c75f8927acfe3 + name:Taz-Mania (USA) + cheat + description:Infinite health + code:99e072/a5 + cheat + description:Infinite time + code:99e292/00 + cheat + description:Infinite continues (don't combine with start on act codes) + code:99e1b8/ad + cheat + description:Advance to next level after getting 1 kiwi + code:96bb59/84 + cheat + description:Faster timer + code:99e27c/04 + cheat + description:1 minute to complete act 1, level 1 + code:99802a/01 + cheat + description:5 minutes to complete act 1, level 1 + code:99802a/05 + cheat + description:Kiwi's worth 2 + code:96bb59/fe + cheat + description:Kiwi's worth 4 + code:96bb59/fc + cheat + description:Kiwi's worth 5 + code:96bb59/fb + cheat + description:Kiwi's worth 7 + code:96bb59/f9 + cheat + description:Red bird worth 0 seconds instead of 10 + code:99e245/00 + cheat + description:Red bird worth 20 seconds + code:99e245/02 + cheat + description:Red bird worth 30 seconds + code:99e245/03 + cheat + description:Red bird worth 40 seconds + code:99e245/04 + cheat + description:Red bird worth 50 seconds + code:99e245/05 + cheat + description:Start with 1/4 normal health + code:99dfdc/07 + cheat + description:Start with 1/2 normal health + code:99dfdc/0f + cheat + description:Start with 3/4 normal health + code:99dfdc/15 + cheat + description:Start with 1 continue (don't combine with start on act codes) + code:99e11e/01 + cheat + description:Start with 5 continues (don't combine with start on act codes) + code:99e11e/05 + cheat + description:Start with 7 continues (don't combine with start on act codes) + code:99e11e/07 + cheat + description:Start with 9 continues (don't combine with start on act codes) + code:99e11e/09 + cheat + description:Start with 50 continues (don't combine with start on act codes) + code:99e11e/32 + cheat + description:Start with 99 continues (don't combine with start on act codes) + code:99e11e/63 + cheat + description:Start on act 1, level 2 + code:99e188/2c+99e189/30+99e11e/01 + cheat + description:Start on act 1, level 3 + code:99e188/2c+99e189/30+99e11e/02 + cheat + description:Start on act 1 bonus level + code:99e188/2c+99e189/30 + cheat + description:Start on act 2, level 1 + code:99e188/2c+99e189/30+99e11e/04 + cheat + description:Start on act 2, level 2 + code:99e188/2c+99e189/30+99e11e/05 + cheat + description:Start on act 2, level 3 + code:99e188/2c+99e189/30+99e11e/06 + cheat + description:Start on act 2 bonus level + code:99e188/2c+99e189/30+99e11e/07 + cheat + description:Start on act 3, level 1 + code:99e188/2c+99e189/30+99e11e/08 + cheat + description:Start on act 3, level 2 + code:99e188/2c+99e189/30+99e11e/09 + cheat + description:Start on act 3, level 3 + code:99e188/2c+99e189/30+99e11e/0a + cheat + description:Start on act 3 bonus level + code:99e188/2c+99e189/30+99e11e/0b + cheat + description:Start on act 4, level 1 + code:99e188/2c+99e189/30+99e11e/0c + cheat + description:Start on act 4, level 2 + code:99e188/2c+99e189/30+99e11e/0d + cheat + description:Start on act 4, level 3 + code:99e188/2c+99e189/30+99e11e/0e + cheat + description:Start on act 4 bonus level + code:99e188/2c+99e189/30+99e11e/0f + cheat + description:Start on act 5, level 1 + code:99e188/2c+99e189/30+99e11e/10 + cheat + description:Start on act 5, level 2 + code:99e188/2c+99e189/30+99e11e/11 + cheat + description:Start on act 5, level 3 + code:99e188/2c+99e189/30+99e11e/12 + cheat + description:Infinite health (alt) + code:7e0096/1d + cheat + description:Infinite time (alt) + code:7e0098/99 + +cartridge sha256:7da4a3cfa5de4bb4722a6e2a42c26aae322b5e668f1645d8c870fb99e6080600 + name:Tecmo Secret of the Stars (USA) + cheat + description:Reach level 99 after one battle + code:00af03/00 + cheat + description:Kill one enemy to win battle (you only get exp for that one enemy) + code:00dd8c/00 + +cartridge sha256:35dd020cf57fc402417ab6e4a6c49866c5a86bba25218c0aaf7ce85cb134bcf8 + name:Tecmo Super Bowl (USA) + cheat + description:Always 1st down + code:8299c8/a5 + cheat + description:1 play to get a 1st down + code:8299cd/01 + cheat + description:2 plays to get a 1st down + code:8299cd/02 + cheat + description:3 plays to get a 1st down + code:8299cd/03 + cheat + description:5 plays to get a 1st down + code:8299cd/05 + cheat + description:7 plays to get a 1st down + code:8299cd/07 + cheat + description:Extra points worth 0 points - P1 + code:828b68/00 + cheat + description:Extra points worth 3 points - P1 + code:828b68/03 + cheat + description:Extra points worth 5 points - P1 + code:828b68/05 + cheat + description:Extra points worth 9 points - P1 + code:828b68/09 + cheat + description:Extra points worth 0 points - P2 + code:82977b/00 + cheat + description:Extra points worth 3 points - P2 + code:82977b/03 + cheat + description:Extra points worth 5 points - P2 + code:82977b/05 + cheat + description:Extra points worth 9 points - P2 + code:82977b/09 + cheat + description:Field goals worth 0 points - P1 + code:8287ef/00 + cheat + description:Field goals worth 1 points - P1 + code:8287ef/01 + cheat + description:Field goals worth 5 points - P1 + code:8287ef/05 + cheat + description:Field goals worth 9 points - P1 + code:8287ef/09 + cheat + description:Field goals worth 0 points - P2 + code:829400/00 + cheat + description:Field goals worth 1 points - P2 + code:829400/01 + cheat + description:Field goals worth 5 points - P2 + code:829400/05 + cheat + description:Field goals worth 9 points - P2 + code:829400/09 + cheat + description:Safeties worth 0 points - P1 + code:82954f/00 + cheat + description:Safeties worth 1 points - P1 + code:82954f/01 + cheat + description:Safeties worth 5 points - P1 + code:82954f/05 + cheat + description:Safeties worth 9 points - P1 + code:82954f/09 + cheat + description:Safeties worth 0 points - P2 + code:82893c/00 + cheat + description:Safeties worth 1 points - P2 + code:82893c/01 + cheat + description:Safeties worth 5 points - P2 + code:82893c/05 + cheat + description:Safeties worth 9 points - P2 + code:82893c/09 + cheat + description:Touchdowns worth 0 points - P1 + code:82898b/00 + cheat + description:Touchdowns worth 3 points - P1 + code:82898b/03 + cheat + description:Touchdowns worth 5 points - P1 + code:82898b/05 + cheat + description:Touchdowns worth 8 points - P1 + code:82898b/08 + cheat + description:Touchdowns worth 0 points - P2 + code:82affb/00+82959e/00 + cheat + description:Touchdowns worth 3 points - P2 + code:82affb/03+82959e/03 + cheat + description:Touchdowns worth 5 points - P2 + code:82affb/05+82959e/05 + cheat + description:Touchdowns worth 9 points - P2 + code:82affb/09+82959e/09 + cheat + description:0 timeouts for the first half - both players + code:84c177/00 + cheat + description:2 timeouts for the first half - both players + code:84c177/02 + cheat + description:7 timeouts for the first half - both players + code:84c177/07 + cheat + description:9 timeouts for the first half - both players + code:84c177/09 + cheat + description:0 timeouts for the first half - P1 + code:84c178/64 + cheat + description:0 timeouts for the first half - P2 + code:84c17a/64 + cheat + description:0 timeouts for the second half - both players + code:84c1c8/00 + cheat + description:2 timeouts for the second half - both players + code:84c1c8/02 + cheat + description:7 timeouts for the second half - both players + code:84c1c8/07 + cheat + description:9 timeouts for the second half - both players + code:84c1c8/09 + cheat + description:0 timeouts for the second half - P1 + code:84c1c9/64 + cheat + description:0 timeouts for the second half - P2 + code:84c1cb/64 + cheat + description:Timeouts are not reset at half-time - P1 + code:84c1c9/a5 + cheat + description:Timeouts are not reset at half-time - P2 + code:84c1cb/a5 + cheat + description:Quarters start at 2 minutes 30 seconds + code:819eed/30+819eee/02 + +cartridge sha256:8cfd4c5525f4bd4bba5af7e2323f1e61f27ce97c6d5617cfa685c9276fbf6407 + name:Tecmo Super Bowl III - Final Edition (USA) + cheat + description:Infinite ability points in the edit menu + code:bce2b5/ea + +cartridge sha256:14bce564f976d1431127259edbcb23c52c79361fed9814d307d627c4650e800e + name:Tecmo Super NBA Basketball (USA) + cheat + description:Never miss a shot (hold Y and press the shot button) + code:8c8e53/30+8c8e50/ad+8c8e51/0b+8c8e52/0a+8c8e54/11 + +cartridge sha256:5b82cdd6f2da56f43680d6a5021faebe2e06036d30602c1a7917aa414cf8b5f4 + name:Teenage Mutant Ninja Turtles IV - Turtles in Time (USA) + cheat + description:Invincibility + code:00b98e/ea+00b992/95+00b98f/a9+00b990/02+00b991/00 + cheat + description:Infinite health + code:00dd10/b5 + cheat + description:Infinite lives + code:00cea6/00 + cheat + description:Infinite Special Attack - Both Players + code:00c297/b5 + cheat + description:One hit kills (disable during Shredder's first fight) + code:0485a7/80 + cheat + description:Hit anywhere - P1 + code:03828f/fc + cheat + description:Hit anywhere - P2 + code:03829f/fc + cheat + description:Start with 1 life instead of 3 + code:01d6bc/00 + cheat + description:Start with 5 lives + code:01d6bc/04 + cheat + description:Start with 10 lives + code:01d6bc/09 + cheat + description:Start with 25 lives + code:01d6bc/24 + cheat + description:Start with 50 lives + code:01d6bc/49 + cheat + description:Start with 75 lives + code:01d6bc/74 + cheat + description:Start with 100 lives + code:01d6bc/99 + cheat + description:Start on level 2 + code:0497bb/85+0497bc/81+0497bd/00+0497ba/01 + cheat + description:Start on level 4 + code:0497bb/85+0497bc/81+0497bd/00+0497ba/03 + cheat + description:Start on level 5 + code:0497bb/85+0497bc/81+0497bd/00+0497ba/04 + cheat + description:Start on level 6 + code:0497bb/85+0497bc/81+0497bd/00+0497ba/05 + cheat + description:Start on level 7 + code:0497bb/85+0497bc/81+0497bd/00+0497ba/06 + cheat + description:Start on level 8 + code:0497bb/85+0497bc/81+0497bd/00+0497ba/07 + cheat + description:Start on level 9 + code:0497bb/85+0497bc/81+0497bd/00+0497ba/08 + cheat + description:Start on level 10 + code:0497bb/85+0497bc/81+0497bd/00+0497ba/09 + cheat + description:Infinite health (alt) (enable after level starts) + code:7e044a/56 + cheat + description:Infinite time + code:7e0096/99 + cheat + description:Infinite time (alt) + code:7e0098/02 + +cartridge sha256:849141370f164d6db3e5709da670726f958ce13ffef69319564db3fb0b12c69d + name:Teenage Mutant Ninja Turtles - Tournament Fighters (USA) + cheat + description:Health doesn't decrease over time + code:83a961/00 + cheat + description:Automatic and infinite continues + code:80c887/bd + cheat + description:Hit anywhere - P1 + code:848559/80 + cheat + description:Hit anywhere - P2 + code:8485f5/80 + cheat + description:Leonardo is replaced by Rat King + code:81adc9/0a + cheat + description:Leonardo is replaced by Karai + code:81adc9/0b + cheat + description:Raphael is replaced by Rat King + code:81adcb/0a + cheat + description:Raphael is replaced by Karai + code:81adcb/0b + cheat + description:Donatello is replaced by Rat King + code:81adcd/0a + cheat + description:Donatello is replaced by Karai + code:81adcd/0b + cheat + description:Matches are 10 seconds long (leave menu option on 60) + code:81b085/10 + cheat + description:Matches are 15 seconds long (leave menu option on 60) + code:81b085/15 + cheat + description:Matches are 20 seconds long (leave menu option on 60) + code:81b085/20 + cheat + description:Matches are 75 seconds long (leave menu option on 60) + code:81b085/75 + cheat + description:Ultimate attack can be done any time + code:83a8cb/01 + cheat + description:Ultimate attack can be done with about 1/4 health + code:83a8cb/14 + cheat + description:Ultimate attack can be done with about 1/2 health + code:83a8cb/28 + cheat + description:Ultimate attack can be done with about 3/4 health + code:83a8cb/3c + cheat + description:Health decreases twice as fast + code:83a961/02 + cheat + description:After doing an ultimate attack, health bar goes to about 1/4 + code:83a8ea/14 + cheat + description:After doing an ultimate attack, health bar goes to about 1/2 + code:83a8ea/28 + cheat + description:After doing an ultimate attack, health bar goes to about 3/4 + code:83a8ea/3c + cheat + description:Start with 1/4 health - both players + code:85ff53/18 + cheat + description:Start with 1/2 health - both players + code:85ff53/30 + cheat + description:Start with 3/4 health - both players + code:85ff53/48 + cheat + description:Start with no continues (leave menu option on 3) + code:819266/00 + cheat + description:Start with 1 continue + code:819266/02 + cheat + description:Start with 3 continues + code:819266/04 + cheat + description:Start with 5 continues + code:819266/06 + cheat + description:Start with 7 continues + code:819266/08 + cheat + description:Infinite health + code:7e0ee4/60 + cheat + description:Full power bar + code:7e1ac0/60 + cheat + description:Empty power bar - opponent + code:7e1b10/00 + cheat + description:Opponent dizzy after every knockdown + code:7e0fc2/10 + cheat + description:Win one round to win match + code:7e1950/02 + +cartridge sha256:8620203da71d32d017bb21f542864c1d90705b87eb67815d06b43f09120318aa + name: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 + name:Terminator, The (USA) + cheat + description:Infinite lives (not on car stages) + code:80b18c/ad + cheat + description:Infinite Grenades + code:06c1e5/2c + cheat + description:Infinite Missiles + code:06cd71/ad + cheat + description:10 Grenades on pick-up + code:06cb9c/0a + cheat + description:2 Grenades on pick-up + code:06cb9c/02 + cheat + description:Longer invulnerability after being hit + code:06b961/ff + cheat + description:Shorter invulnerability after being hit + code:06b961/1f + cheat + description:Don't lose Grenades on dying + code:06c158/2c + cheat + description:Don't lose Missiles on dying + code:06c155/2c + cheat + description:Get Rapid Fire on dying + code:06c151/03 + cheat + description:Start with Rapid Fire + code:808237/03 + cheat + description:Start with 9 lives + code:80c6db/09 + cheat + description:Start with 1 life + code:80c6db/01 + +cartridge sha256:06db3be569a587d79b51bfc684fd2ebdea977863875aedec88218fbb4169c21b + name: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 + name:Tetris & Dr. Mario (USA) + cheat + description:Tetris - Level never increases + code:819d26/80 + cheat + description:Tetris - After the first level your level increases every line + code:819d29/01 + cheat + description:Tetris - The same piece always drops + code:81923a/a9+81923b/02+81923c/00 + cheat + description:Tetris - Always at high speed + code:8197d3/a9+8197d4/0a+8197d5/ea + cheat + description:Dr. Mario - Drop pieces anywhere to complete level + code:82a343/80+82a34f/a9 + cheat + description:Dr. Mario - The same piece always drops until you hit the change button + code:82a05a/a9+82a05b/0a+82a05c/ea + cheat + description:Dr. Mario - The same piece always drops + code:828b3c/a9+828b3d/0a+828b3e/ea + cheat + description:Tetris 2 - Select any round - 1P (at round select meter, keep pressing right) + code:849b00/50 + cheat + description:Tetris 2 - Tile speed always at 0 + code:82a874/a9+82a875/00+82a876/00 + cheat + description:Tetris 2 - Tile speed always at 255 + code:82a874/a9+82a875/ff+82a876/00 + 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:82976a/80 + +cartridge sha256:70dea29a928c1625def31c862dc74960e39e587e416b45829efc21f13ebd9630 + name:Tetris 2 (USA) (Rev 1) + cheat + description:Select any round + code:849b00/50 + cheat + description:Tile speed always at 0 + code:82a874/a9+82a875/00+82a876/00 + cheat + description:Tile speed always at 255 + code:82a874/a9+82a875/ff+82a876/00 + cheat + description:More time to place the blocks where you want them + code:82976a/80 + +cartridge sha256:accc836c3adabadc810fbe35702c6a64d50a09f4c672d2734fa58b251d7a20aa + name:Tetris 2 (USA) + cheat + description:Select any round + code:849b00/50 + cheat + description:Tile speed always at 0 + code:82a874/a9+82a875/00+82a876/00 + cheat + description:Tile speed always at 255 + code:82a874/a9+82a875/ff+82a876/00 + cheat + description:More time to place the blocks where you want them + code:82976a/80 + +cartridge sha256:4aee5b05ae11643fc6cb7ed32dfd4e82bbb52d03b12aabb080af35e2df6f562f + name:Tetsuwan Atom (Japan) + cheat + description:Invincibility + code:9c8271/d0 + cheat + description:Infinite health + code:81a812/ad + cheat + description:Infinite lives + code:81a569/ad + +cartridge sha256:d50aaa41e153ca356eee16a9deccb1a763ee56ebbe6c80cd28c5ad1db66a5316 + name:Thunder Spirits (USA) + cheat + description:Infinite lives + code:00ada9/a9 + cheat + description:Infinite lives (alt) + code:c0ada9/ad + cheat + description:Infinite credits + code:00c6ac/ea + cheat + description:Infinite credits (alt) + code:c0c6b1/ad + cheat + description:Hit anywhere + code:00ae70/24+00ae89/24+00ae57/24+00aea2/24+00ae1e/24 + cheat + description:Keep captured weapon until game ends (except claw and shield) + code:00adb9/ad+00adbe/ad + cheat + description:Continue with 1 life + code:00c700/9c + cheat + description:Continue with 2 lives + code:00c6fd/00+00c6fc/a9 + cheat + description:Continue with 5 lives + code:00c6fd/03+00c6fc/a9 + cheat + description:Continue with 7 lives + code:00c6fd/05+00c6fc/a9 + cheat + description:Continue with 9 lives + code:00c6fd/07+00c6fc/a9 + cheat + description:Start with 1 credit + code:009113/a3 + cheat + description:Start with 2 credits + code:009113/b2 + cheat + description:Start with 3 credits + code:009113/92 + cheat + description:Start with 5 credits + code:009113/9f + cheat + description:Start with 8 credits + code:009112/8b+009113/a2 + cheat + description:Start with 12 credits + code:009112/04+009113/ae + cheat + description:Start with 1 life + code:0090e1/ff+0090e0/a9 + cheat + description:Start with 2 lives + code:0090e1/00+0090e0/a9 + cheat + description:Start with 5 lives + code:0090e1/03+0090e0/a9 + cheat + description:Start with 7 lives + code:0090e1/05+0090e0/a9 + cheat + description:Start with 9 lives + code:0090e1/07+0090e0/a9 + cheat + description:Start with 25 lives + code:0090e1/17+0090e0/a9 + cheat + description:Start with 50 lives + code:0090e1/30+0090e0/a9 + cheat + description:Start with 100 lives + code:0090e1/62+0090e0/a9 + cheat + description:Stage modifier + code:7e1a98/00 + cheat + description:Start on stage 2 + code:008a7c/01+008a7b/a9+008a7d/00+008a7e/ea + cheat + description:Start on stage 3 + code:008a7c/02+008a7b/a9+008a7d/00+008a7e/ea + cheat + description:Start on stage 4 + code:008a7c/03+008a7b/a9+008a7d/00+008a7e/ea + cheat + description:Start on stage 5 + code:008a7c/04+008a7b/a9+008a7d/00+008a7e/ea + cheat + description:Start on stage 6 + code:008a7c/05+008a7b/a9+008a7d/00+008a7e/ea + cheat + description:Start on stage 7 + code:008a7c/06+008a7b/a9+008a7d/00+008a7e/ea + cheat + description:Start on stage 8 + code:008a7c/07+008a7b/a9+008a7d/00+008a7e/ea + cheat + description:Invincibility + code:7e0418/7b + cheat + description:Invincibility (alt) + code:00ad90/77 + +cartridge sha256:eb958801fd1f08771e5a0933f7701d633262efbfe8d47de21dda18e3b77670de + name:Tick, The (USA) + cheat + description:Infinite lives + code:80a536/00 + cheat + description:Most kicks are stronger + code:bf8549/0c + cheat + description:Most kicks kill most enemies + code:bf8549/1f + +cartridge sha256:8e82f98d2e62bc1e5fcf2386c2b5ca54998398220efcedd67858aaaa92289a42 + name:Time Slip (USA) + cheat + description:Invincibility + code:01a4de/ea + cheat + description:Infinite health + code:019230/ad + cheat + description:Infinite lives + code:00ddfb/ad + cheat + description:Infinite ammo + code:01a3e4/ad + cheat + description:Infinite TGS meter + code:01b729/ad + cheat + description:Hit anywhere + code:00955f/80+009560/16+009594/ad+00959e/ad + cheat + description:Keep gun power-ups after dying + code:00de2f/a0+00de2a/a0 + cheat + description:Flash 2x longer when hit + code:01923a/80 + cheat + description:Barely flash at all when hit + code:01923a/10 + cheat + description:Fewer enemies + code:018a14/ad+0189af/ad+018b10/ad+0189a7/ad + cheat + description:Start with all weapons and 9 rounds + code:0082b1/09 + cheat + description:Start with 16 lives + code:00829d/ff + cheat + description:Start with 4 health bars - after 1st life + code:00ddf6/0f + cheat + description:Start with 3 health bars - after 1st life + code:00ddf6/07 + cheat + description:Start with 4 health bars - 1st life + code:0082a5/0f + cheat + description:Start with 3 health bars - 1st life + code:0082a5/07 + cheat + description:Start on stage - Cretaceous + code:00dc2d/a9+00dc2f/00+00dc30/8d+00dc2e/01 + cheat + description:Start on stage - Egypt + code:00dc2d/a9+00dc2f/00+00dc30/8d+00dc2e/02 + cheat + description:Start on stage - Rome + code:00dc2d/a9+00dc2f/00+00dc30/8d+00dc2e/03 + cheat + description:Start on stage - Invasion 2147 + code:00dc2d/a9+00dc2f/00+00dc30/8d+00dc2e/04 + cheat + description:Start on stage - Tirmat + code:00dc2d/a9+00dc2f/00+00dc30/8d+00dc2e/05 + +cartridge sha256:fa7e2b40093f0cc7233cc77e95bbbea2144c8183dec10446590396fffd7cda37 + name:Time Trax (USA) + cheat + description:Infinite health + code:81f1b6/ad + cheat + description:Infinite lives + code:81f314/ad + 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 + name:Timecop (USA) + cheat + description:Invincibility + code:809ec8/00 + cheat + description:Don't flash when invincible + code:809ed1/80 + 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:271a67b32b3bb00ceb0f4e7d81494888d0d821635f0f936d481dfbe671567c08 + name:Timon & Pumbaa's Jungle Games (USA) + cheat + description:Infinite ammo/balls + code:7e00dc/09 + +cartridge sha256:0503cd93b4d211a825acd47ff3813668b4ce68890c8be2fbfe5ac2b46882dfcf + name: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 + name:Tinhead (Europe) (Proto) + cheat + description:Infinite health + code:009803/ad + cheat + description:Infinite lives + code:0087f6/ad + cheat + description:Infinite Bombs + code:0097f0/ad + +cartridge sha256:71de4dec6a8e8be685627b6e929317f7cefb836997059bbd3b438ccc07a60044 + name:Tintin - Prisoners of the Sun (Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:80823c/d0+828591/d0 + cheat + description:Infinite health + code:82bb5e/cd + cheat + description:Infinite time + code:82be5b/af + cheat + description:Infinite lives + code:82bb7f/cd + cheat + description:Infinite health (alt) + code:7e059b/04 + cheat + description:Infinite time (alt) + code:7f5b7f/63 + +cartridge sha256:da8b8bccebf51b70213adecda37387d1bdb55aeb7bc0805bb1be1cd9b514daf6 + name: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 + name:Tiny Toon Adventures - Buster Busts Loose! (USA) + cheat + description:Infinite health (when hit, a fake empty heart appears) + code:8ff05a/ea + cheat + description:Infinite lives (except football level) + code:80ef2c/00 + cheat + description:Infinite lives (football level) + code:80af45/00 + cheat + description:Infinite dash meter + code:80d03f/a5 + cheat + description:Five heart maximum on challenge level + code:81ba2b/06 + cheat + description:1-up gives 2-up (not on mystery weight challenge level, or by collecting stars) + code:808697/02 + cheat + description:Small star worth 2 + code:8feefa/02 + cheat + description:Small star worth 5 + code:8feefa/05 + cheat + description:Small star worth 10 + code:8feefa/10 + cheat + description:Gold Gogo Dodo Trophy lasts 1/2 as long + code:83812b/01 + cheat + description:Gold Gogo Dodo Trophy lasts 2x as long + code:83812b/04 + cheat + description:Choose bonus level after completing a level + code:80a5f5/a5 + cheat + description:Passwords work on any difficulty level (not just Children level) + code:91ea81/34 + cheat + description:Continue with 1 life + code:80a647/01 + cheat + description:Continue with 5 lives + code:80a647/05 + cheat + description:Continue with 10 lives + code:80a647/10 + cheat + description:Continue with 25 lives + code:80a647/25 + cheat + description:Continue with 50 lives + code:80a647/50 + cheat + description:Continue with 99 lives + code:80a647/99 + cheat + description:Start with 1 life + code:808518/01 + cheat + description:Start with 5 lives + code:808518/05 + cheat + description:Start with 10 lives + code:808518/10 + cheat + description:Start with 25 lives + code:808518/25 + cheat + description:Start with 50 lives + code:808518/50 + cheat + description:Start with 99 lives + code:808518/99 + cheat + description:Start with no continues on normal level - handicap + code:81800c/00 + cheat + description:Start with 7 continues on normal level + code:81800c/07 + cheat + description:Start with 9 continues on normal level + code:81800c/09 + cheat + description:Start with no continues on challenge level + code:81800d/00 + cheat + description:Start with 5 continues on challenge level + code:81800d/05 + cheat + description:Start with 7 continues on challenge level + code:81800d/07 + cheat + description:Start with 9 continues on challenge level + code:81800d/09 + cheat + description:Start with 1 heart on Children or Normal difficulty levels (don't pick challenge level) + code:80a407/01 + cheat + description:Start with 4 hearts on Children or Normal difficulty levels, 2 on Challenge + code:80a407/04 + cheat + description:Start with 5 hearts on Children or Normal difficulty levels, 3 on Challenge + code:80a407/05 + +cartridge sha256:08d808e9c5851e4301a38a56b350a20ea9e3adbef51546e87e1785d691d0f2d5 + name:TKO Super Championship Boxing (USA) + cheat + description:Infinite punch meters - both players + code:01b3b5/24 + cheat + description:Infinite punch meter - P1 + code:009118/24 + cheat + description:Infinite punch meter - P2 + code:00914e/24 + cheat + description:9 minutes per round + code:008b4c/09 + cheat + description:6 minutes per round + code:008b4c/06 + cheat + description:1 minute per round + code:008b4c/01 + cheat + description:Allowed only 3 punches in punch meter - P1 + code:009122/03+008b7e/03 + cheat + description:Allowed only 3 punches in punch meter - P2 + code:009158/03+008b7e/03 + +cartridge sha256:32d0f1ca5b91fd9b2caf81422fb9e8fb30bc091f0b2a429b9269dd307fcba4fd + name:Todd McFarlane's Spawn - The Video Game (USA) + cheat + description:Invincibility after one hit (invisible) + code:c14ae8/ad + cheat + description:Almost invincible (blinking) + code:c14ae6/ea + cheat + description:Infinite health + code:c14abc/ad + cheat + description:Infinite special moves + code:c13a0d/ad + cheat + description:Hit anywhere + code:c512ba/24 + cheat + description:Don't blink after getting hit + code:c50596/10 + cheat + description:Falling doesn't use life points + code:c11824/ad + cheat + description:Special moves don't use life points + code:c13a0d/ad + cheat + description:Some bullets do 2x damage + code:c50237/08 + cheat + description:Some bullets do no damage + code:c50237/00 + cheat + description:Some bullets kill you + code:c50237/ff + cheat + description:Some enemy punches electrocute you + code:c532ba/09 + cheat + description:Some enemy punches do no damage + code:c532ba/00 + cheat + description:Some enemy punches kill you + code:c532ba/ff + cheat + description:Guys with pipes do 2x damage + code:c39b47/09+c3aa1e/09 + cheat + description:Guys with pipes do no damage + code:c39b47/00+c3aa1e/00 + cheat + description:Guys with pipes kill + code:c39b47/ff+c3aa1e/ff + cheat + description:Flaming bottles do 2x damage + code:c52890/09+c527e8/09 + cheat + description:Flaming bottles do no damage + code:c52890/00+c527e8/00 + cheat + description:Flaming bottles kill + code:c52890/ff+c527e8/ff + cheat + description:Start with 1/4 health + code:c29748/10 + cheat + description:Start with 1/2 health + code:c29748/2a + cheat + description:Start with 3/4 health + code:c29748/3e + cheat + description:Invincibility + code:7e1f56/1f + cheat + description:Infinite health (alt) + code:7e1f00/63 + +cartridge sha256:4f500da19dbb1557a7bc0ce14437098c1402478d573fb569303b81c011f86fbf + name:Tom and 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 + +cartridge sha256:ca9889f17f184b3d99a2eaaa82af73e366f03ed00313fdd369e5e023b208e788 + name:Top Gear (USA) + cheat + description:Always finish first + code:00a1f2/18 + cheat + description:Infinite fuel - P1 + code:05d67b/ad + cheat + description:Infinite fuel - P2 + code:05dee1/ad + cheat + description:Infinite nitro boosts - P1 + code:00ba22/ea + cheat + description:Infinite nitro boosts - P2 + code:00ba8b/ea + cheat + description:Nitro boost lasts until end of race - P1 + code:00ba47/ad + cheat + description:Nitro boost lasts until end of race - P2 + code:00bab0/ad + cheat + description:Race in any country + code:0f9337/80 + cheat + description:Don't slow down offroad + code:05d858/ad + cheat + description:Don't slow down against obstacles + code:05d6e9/00 + cheat + description:Don't slow down against cars + code:05e4bc/00+05e4b7/00 + cheat + description:Start with 1/2 fuel + code:00d996/53 + cheat + description:Start with 3/4 fuel + code:00d996/7c + cheat + description:Start with no nitro boosts instead of 3 + code:0082e0/00 + cheat + description:Start with 1 nitro boost + code:0082e0/01 + cheat + description:Start with 2 nitro boosts + code:0082e0/02 + cheat + description:Start with 6 nitro boosts + code:0082e0/06 + cheat + description:Start with 9 nitro boosts + code:0082e0/09 + +cartridge sha256:76b2702c4be8b668c1017f2817c280283c275eaa41535bf6ffa2b8d2220b68c6 + name:Top Gear 2 (USA) + cheat + description:Infinite nitro + code:808e31/cd + cheat + description:Infinite nitros - P1 + code:808e31/ad + cheat + description:Infinite nitros - P2 + code:80a695/ad + cheat + description:Infinite fuel + code:809a39/ad + cheat + description:Infinite money + code:9fac27/bd + cheat + description:Fuel never runs out + code:809905/a5 + cheat + description:Always finish first + code:80defe/8e + cheat + description:1st place gives $50,000 instead of $10,000 + code:9fef46/32 + cheat + description:2nd place gives $50,000 instead of $6,000 + code:9fef48/32 + cheat + description:3rd place gives $50,000 instead of $4,000 + code:9fef4a/32 + cheat + description:4th place gives $50,000 instead of $3,000 + code:9fef4c/32 + cheat + description:5th place gives $50,000 instead of $2,000 + code:9fef4e/32 + cheat + description:6th place gives $50,000 instead of $1,000 + code:9fef50/32 + cheat + description:7th place gives $50,000 instead of $0 + code:9fef52/32 + cheat + description:8th place gives $50,000 instead of $0 + code:9fef54/32 + cheat + description:9th place gives $50,000 instead of $0 + code:9fef56/32 + cheat + description:10th place gives $50,000 instead of $0 + code:9fef58/32 + cheat + description:1st place is worth 20 points instead of 10 + code:9fe35d/14 + cheat + description:2nd place is worth 20 points instead of 6 + code:9fe35f/14 + cheat + description:3rd place is worth 20 points instead of 4 + code:9fe361/14 + cheat + description:4th place is worth 20 points instead of 3 + code:9fe363/14 + cheat + description:5th place is worth 20 points instead of 2 + code:9fe365/14 + cheat + description:6th place is worth 20 points instead of 1 + code:9fe367/14 + cheat + description:7th place is worth 20 points instead of 0 + code:9fe369/14 + cheat + description:8th place is worth 20 points instead of 0 + code:9fe36b/14 + cheat + description:9th place is worth 20 points instead of 0 + code:9fe36d/14 + cheat + description:10th place is worth 20 points instead of 0 + code:9fe36f/14 + cheat + description:Everything is free (must have enough to buy) + code:9fac27/49+9fabe2/7d + cheat + description:2nd engine costs $1K instead of $30K + code:9fac71/01 + cheat + description:2nd engine costs $15K instead of $30K + code:9fac71/0f + cheat + description:3rd engine costs $1K instead of $50K + code:9fac73/01 + cheat + description:3rd engine costs $25K instead of $50K + code:9fac73/19 + cheat + description:4th engine costs $1K instead of $80K + code:9fac75/01 + cheat + description:4th engine costs $40K instead of $80K + code:9fac75/28 + cheat + description:2nd wet tires are free + code:9fac79/00 + cheat + description:3rd wet tires are free + code:9fac7b/00 + cheat + description:4th wet tires are free + code:9fac7d/00 + cheat + description:2nd dry tires are free + code:9fac81/00 + cheat + description:3rd dry tires are free + code:9fac83/00 + cheat + description:4th dry tires are free + code:9fac85/00 + cheat + description:2nd gear box costs $1K instead of $10K + code:9fac89/01 + cheat + description:2nd gear box costs $5K instead of $10K + code:9fac89/05 + cheat + description:3rd gear box costs $1K instead of $30K + code:9fac8b/01 + cheat + description:3rd gear box costs $15K instead of $30K + code:9fac8b/0f + cheat + description:4th gear box costs $1K instead of $50K + code:9fac8d/01 + cheat + description:4th gear box costs $25K instead of $50K + code:9fac8d/19 + cheat + description:2nd nitro costs $1K instead of $5K + code:9fac91/01 + cheat + description:2nd nitro costs $2K instead of $5K + code:9fac91/02 + cheat + description:3rd nitro costs $1K instead of $15K + code:9fac93/01 + cheat + description:3rd nitro costs $7K instead of $15K + code:9fac93/07 + cheat + description:4th nitro costs $1K instead of $30K + code:9fac95/01 + cheat + description:4th nitro costs $15K instead of $30K + code:9fac95/0f + cheat + description:2nd side armor costs $1K instead of $5K + code:9faca1/01 + cheat + description:2nd side armor costs $2K instead of $5K + code:9faca1/02 + cheat + description:3rd side armor costs $1K instead of $10K + code:9faca3/01 + cheat + description:3rd side armor costs $5K instead of $10K + code:9faca3/05 + cheat + description:4th side armor costs $1K instead of $20K + code:9faca5/01 + cheat + description:4th side armor costs $10K instead of $20K + code:9faca5/0a + cheat + description:2nd rear armor costs $1K instead of $5K + code:9faca9/01 + cheat + description:2nd rear armor costs $2K instead of $5K + code:9faca9/02 + cheat + description:3rd rear armor costs $1K instead of $10K + code:9facab/01 + cheat + description:3rd rear armor costs $5K instead of $10K + code:9facab/05 + cheat + description:4th rear armor costs $1K instead of $20K + code:9facad/01 + cheat + description:4th rear armor costs $10K instead of $20K + code:9facad/0a + cheat + description:2nd front armor costs $1K instead of $5K + code:9facb1/01 + cheat + description:2nd front armor costs $2K instead of $5K + code:9facb1/02 + cheat + description:3rd front armor costs $1K instead of $10K + code:9facb3/01 + cheat + description:3rd front armor costs $5K instead of $10K + code:9facb3/05 + cheat + description:4th front armor costs $1K instead of $20K + code:9facb5/01 + cheat + description:4th front armor costs $10K instead of $20K + code:9facb5/0a + cheat + description:Start with 0 nitros + code:80d0c2/00 + cheat + description:Start with 2 nitros + code:80d0c2/02 + cheat + description:Start with 4 nitros + code:80d0c2/04 + cheat + description:Start with 8 nitros + code:80d0c2/08 + cheat + description:Start with 10 nitros + code:80d0c2/0a + +cartridge sha256:6be49983976564f1fd9eff2f14f5bb41d3a0ff48573e39318088ecce286aca62 + name:Top Gear 3000 (USA) + cheat + description:Always finish first + code:81f1ad/ae + cheat + description:Infinite fuel + code:83ed82/a5 + cheat + description:Infinite Nitro + code:83eb4a/c5 + cheat + description:Infinite time + code:7e005b/00 + cheat + description:Infinite money + code:7e0390/75+7e038f/30 + +cartridge sha256:9bf884be5627d38f060ad7f3a61ea1fea1474d416e1d037d33014ca9d5205c1d + name:Total Carnage (USA) + cheat + description:Invincibility + code:8bdc39/80 + cheat + description:Infinite lives + code:8befd9/a5 + cheat + description:Infinite Time Bombs + code:8bd755/24 + cheat + description:Shields last longer + code:809aee/08 + cheat + description:Shields don't last last as long + code:809aee/00 + cheat + description:Weapons don't run out until you die or change weapons + code:8be040/a5 + cheat + description:Join in with 2 lives and 3 Time Bombs + code:8098ac/01 + cheat + description:Join in with 10 lives and 9 Time Bombs + code:8098ac/09 + cheat + description:Start with 2 lives + code:83a4e8/01 + cheat + description:Start with 10 lives + code:83a4e8/09 + cheat + description:Start with 1 Time Bomb + code:83a500/01+809970/24 + cheat + description:Start with 9 Time Bombs + code:83a500/09 + 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 + name:Toy Story (USA) + cheat + description:Invincibility + code:989b35/ad + cheat + description:Infinite lives + code:989b55/af + cheat + description:Start with 5 more lives than usual + code:87e20e/08 + cheat + description:Start with 10 more lives than usual + code:87e20e/0f + cheat + description:Start with 25 more lives than usual + code:87e20e/1e + cheat + description:Start with 50 more lives than usual + code:87e20e/37 + cheat + description:Start on level 2 + code:88cb82/01 + cheat + description:Start on level 3 + code:88cb82/02 + cheat + description:Start on level 4 + code:88cb82/03 + cheat + description:Start on level 5 + code:88cb82/04 + cheat + description:Start on level 6 + code:88cb82/05 + cheat + description:Start on level 7 + code:88cb82/06 + cheat + description:Start on level 8 + code:88cb82/07 + cheat + description:Start on level 9 + code:88cb82/08 + cheat + description:Start on level 10 + code:88cb82/09 + cheat + description:Start on level 11 + code:88cb82/0a + cheat + description:Start on level 12 + code:88cb82/0b + cheat + description:Start on level 13 + code:88cb82/0c + cheat + description:Start on level 14 + code:88cb82/0d + cheat + description:Start on level 15 + code:88cb82/0e + cheat + description:Start on level 16 + code:88cb82/0f + cheat + description:Start on level 17 + code:88cb82/10 + +cartridge sha256:7a6e5da46b026900fba4584a32ad40d940b9ecf9fccfb11f96a205a914014784 + name:Toys - Let the Toy Wars begin! (USA) + cheat + description:Infinite lives + code:8e8760/ad + cheat + description:Protection against most hazards + code:8e9b85/ad+8ecb26/ad + cheat + description:Fewer toys gained from floor boxes + code:88b873/0a + cheat + description:More toys gained from floor boxes + code:889873/6f+809479/ff + cheat + description:Lots more toys gained from floor boxes + code:88b873/35+809479/ff + cheat + description:Fewer toys gained from carousel + code:888e54/0a + cheat + description:More toys gained from carousel + code:888e54/35 + cheat + description:Lots more toys gained from carousel + code:888e54/6f + cheat + description:Start with 1 life + code:82db0f/01 + cheat + description:Start with 9 lives + code:82db0f/09 + +cartridge sha256:683f5755fdce9c073561d5907f9182884eb203d4e52f84488440dd8dd8223005 + name:Treasure Hunter G (Japan) + cheat + description:Quick level up + code:90a123/a9+90a125/ea + cheat + description:Always win frog race + code:878d79/a9+878d7a/34 + cheat + description:C.1 Full Element Set + code:83da0d/0f + cheat + description:C.2 Full Element Set + code:83da26/0f + cheat + description:C.3 Full Element Set + code:83da3f/0f + cheat + description:C.4 Full Element Set + code:83da58/0f + cheat + description:Instant win battles + code:81a48e/9c + cheat + description:Instant win Frog Dodgeball, Fly Catching + code:879b25/80 + cheat + description:Defeat one enemy to win battle + code:90dab3/9c + cheat + description:Walk through walls - towns/dungeons + code:8196b6/00 + cheat + description:Walk through walls - world map + code:84c1c4/00+84c16d/80+84c0b9/80+84c110/00 + +cartridge sha256:4070a7702dc506a1ceb6f65b5c330b3a162df6f01735c8f206934fd47b810ed4 + name:Troddlers (USA) + cheat + description:Infinite time + code:008a5a/ad + +cartridge sha256:5c7b28bb24bad697156ad444ff23bd15ad6744dbf9899b3cccf2aa36d559d825 + name:True Golf Classics - Pebble Beach Golf Links (USA) + cheat + description:All holes are par 4 + code:03887e/af + cheat + description:Course is generally harder (par goes down randomly for some holes) + code:03887f/b8+03d1b8/03 + +cartridge sha256:72088194a65fc057f2910945a33d9f071682a4cecac8996f0bdabcdb5ef39962 + name:True Golf Classics - Waialae Country Club (USA) + cheat + description:Most holes have new par values + code:0186cc/6a+03b16a/04 + cheat + description:All holes are par 5 + code:0186cb/af + cheat + description:All holes are par 4 + code:0186cb/af+0186cc/6c + +cartridge sha256:47dd8ea2d12a6bb2a9774de1d492259fc4fb9f8ec7976383bbfd922532671f6b + name:True Lies (USA) + cheat + description:Infinite health + code:7e2d38/17 + cheat + description:Infinite lives + code:7e1a57/05 + cheat + description:Infinite Aircraft Missiles + code:7e1a61/06 + cheat + description:Infinite Big Gun ammo + code:7e00a9/73 + cheat + description:Infinite Flamethrower fuel + code:7e00af/63 + cheat + description:Infinite Grenades + code:7e00ab/09 + cheat + description:Infinite Mines + code:7e00ad/09 + cheat + description:Infinite Pistol ammo + code:7e00a5/0f + cheat + description:Infinite Shotgun Shells + code:7e00a7/63 + cheat + description:Infinite Uzi ammo + code:7e00aa/0a + cheat + description:Have all weapons + code:7e1a55/ff + cheat + description:No civilian kill limit (warning on first two deaths) + code:7e1a2a/00 + +cartridge sha256:8f62d014f513a7dcbca5aa76cbe476c3e4526100f34913af831bc05dab029bd1 + name:Tuff E Nuff (USA) + cheat + description:Invincibility + code:8181cb/80 + cheat + description:One hit kills + code:818537/a9+818539/ff + 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:81cef3/00 + cheat + description:Allows you to select any character in a vs. computer game + code:81caef/ff + cheat + description:Syoh and Zazi's High Fist Thrust does more damage + code:a7d8f0/18 + cheat + description:Syoh and Zazi's Sliding Heel Kick does more damage + code:a7db24/24 + cheat + description:Syoh and Zazi's Big Head Thrust Punch does more damage - from close up only + code:a7dd10/24 + cheat + description:Syoh and Zazi's Big Head Thrust Punch does no damage + code:a7dd10/00 + cheat + description:Syoh and Zazi's Flying Side Kick does more damage - from close up only + code:a7de4a/24 + cheat + description:Syoh and Zazi's Ball of Energy does more damage + code:a7e145/24 + cheat + description:Syoh and Zazi's Palm Hit Drop does more damage + code:a7ddf7/2a + cheat + description:Zazi's Blue Thunder Punch and Syoh's Dragon Blade does more damage + code:a7e308/24 + cheat + description:Kotono's Straight Line Slash does more damage + code:a8dfd1/1e + cheat + description:Kotono's Sweeping Knee Kick does more damage + code:a8dee9/18 + cheat + description:Kotono's Flying Swallow Double Drop does more damage + code:a8eb51/1e + cheat + description:Kotono's Flying Side Kick does more damage + code:a8df2b/18 + cheat + description:Kotono's Flying Swallow Point Break does more damage + code:a8ebd4/1e + cheat + description:Kotono's Drawn Sword Mist Slash does more damage + code:a8e5fb/1e + cheat + description:Kotono's Double Edge does more damage + code:a8ebe5/18 + cheat + description:Kotono's Special Kick does more damage + code:a8e790/24 + cheat + description:Vortz's Middle Kick does more damage + code:a9e496/2a + cheat + description:Vortz's Low Kick does more damage + code:a9e444/18 + cheat + description:Vortz's Low Aerial Drop Kick does more damage + code:a9e3af/2a + cheat + description:Vortz's Big Double Sledge Hammer does more damage + code:a9e265/24 + cheat + description:Vortz's Diving Knee Pad does more damage + code:a9e30b/1e + cheat + description:Vortz's Diving Elbow does more damage + code:a9e297/2a + cheat + description:Vortz's Lightning Tackle does more damage + code:a9e54e/2a + cheat + description:Each round is 80 seconds + code:808978/80 + cheat + description:Each round is 60 seconds + code:808978/60 + cheat + description:Each round is 40 seconds + code:808978/40 + cheat + description:Each round is 20 seconds + code:808978/20 + cheat + description:Start with 1/4 health - P1 + code:81a5f4/16 + cheat + description:Start with 1/2 health - P1 + code:81a5f4/2c + cheat + description:Start with 3/4 health - P1 + code:81a5f4/42 + cheat + description:Play stage 2 in story (brings you back to level 1) + code:80848a/04 + cheat + description:Play stage 3 in story (brings you back to level 1) + code:80848a/06 + cheat + description:Play stage 4 in story (brings you back to level 1) + code:80848a/08 + cheat + description:Play stage 5 in story (brings you back to level 1) + code:80848a/0a + cheat + description:Play stage 6 in story (brings you back to level 1) + code:80848a/0c + cheat + description:Play stage 7 in story (brings you back to level 1) + code:80848a/0e + cheat + description:Play stage 8 in story (brings you back to level 1) + code:80848a/10 + cheat + description:Play stage 9 in story (brings you back to level 1) + code:80848a/12 + cheat + description:Play final stage in story (brings you back to level 1) + code:80848a/14 + 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 + name: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 + name: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 + name: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 + cheat + description:Hit anywhere + code:848363/00 + cheat + description:Multi-jump + code:829d5e/30+829d5d/fc + +cartridge sha256:259c25d4613f97f5fa7992900fb583625d7fb912c7ae09fa9def2e682834dc9f + name:Twisted Tales of Spike McFang, The (USA) + cheat + description:Invincibility + code:80c778/af + cheat + description:Infinite money + code:82834e/ad + 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 + name: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 + name:U.N. Squadron (USA) + cheat + description:Invincibility + code:00e43e/00+04e52c/80 + cheat + description:Infinite lives + code:00d4e0/c5+00d4e2/c5 + cheat + description:Infinite continues + code:00d5a1/c0 + cheat + description:Infinite shots for all weapons + code:04e7bf/dd + cheat + description:Infinite money + code:00b9fc/c5 + cheat + description:Hit anywhere + code:04e74d/6b+00e37b/e2+00e310/e2+00e37c/20+00e311/20 + cheat + description:Shoot without stopping + code:04e56e/a5 + cheat + description:Max power on first pellet pick-up + code:04fb7d/00 + cheat + description:Start with no money + code:00b143/00 + cheat + description:Start with $9,000 + code:00b143/90 + cheat + description:Start with 1 life and 1 continue + code:00b159/01 + cheat + description:Start with 5 lives and 5 continues + code:00b159/05 + cheat + description:Start with 9 lives and 9 continues + code:00b159/09 + 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 + name:Ultima - Runes of Virtue II (USA) + cheat + description:Infinite energy - makes enemies invincible too (Shamino in easy mode) + code:80acef/ad + cheat + description:Stars never recharge (Shamino in easy mode) + code:80e99a/a9 + cheat + description:Almost infinite stars (Shamino in easy mode) + code:808b3e/a9 + cheat + description:Start with a stronger armor (Shamino in easy mode) + code:828ca2/a9+828ca3/2c + cheat + description:Start with less stars (Shamino in easy mode) + code:828c54/01 + cheat + description:Start with Crossbow instead of the Axe (Shamino in easy mode) + code:828c4c/33 + cheat + description:Start with Longbow instead of the Axe (Shamino in easy mode) + code:828c4c/34 + cheat + description:Start with Fireball wand instead of the Axe (Shamino in easy mode) + code:828c4c/37 + cheat + description:Start with Boomerang instead of the Axe (Shamino in easy mode) + code:828c4c/38 + cheat + description:Start with Shuriken instead of the Axe (Shamino in easy mode) + code:828c4c/2f + cheat + description:Start with 30 intelligence (Shamino in easy mode) + code:828c4e/30 + cheat + description:Start with 5 intelligence (Shamino in easy mode) + code:828c4e/05 + +cartridge sha256:11659bd8dd620d50400d16042aeb2d0ddb00c7183fc1ecb95b1a34f07db0431b + name:Ultima - The False Prophet (USA) + cheat + description:Infinite time + code:00a0be/b5 + 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 + name:Ultima - 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 + name:Ultimate Fighter (USA) + cheat + description:Invincibility (except projectiles) - P1 + code:86b72b/00 + cheat + description:Invincibility (except projectiles) - P2 + code:86b53e/00 + cheat + description:Infinite health + code:7e1402/c8 + cheat + description:Hit anywhere (except projectiles) - P1 + code:86b53d/80 + cheat + description:Hit anywhere (except projectiles) - P2 + code:86b72a/80 + cheat + description:Infinite lives - story mode + code:7e09c9/63 + cheat + description:Start with 60,000 score + code:7e09b9/60+7e09ba/ea + +cartridge sha256:cb2fdfce61858063bf4c9da4228381c3ec3abe423f4d378cddd174ae4adb261e + name:Ultimate Mortal Kombat 3 (USA) + cheat + description:Invincibility (throws damage CPU) + code:84e6ad/e0+84e7e2/80+84e6b0/30+84e6ae/01+84e6b1/f6 + cheat + description:Infinite health - P1 + code:7e36d4/a6 + cheat + description:Infinite health - P2 + code:7e3898/a6 + cheat + description:Infinite run - P1 + code:7e36d8/30 + cheat + description:Infinite run - P2 + code:7e389c/30 + cheat + description:Max fatality time + code:7e3be0/01 + cheat + description:Hit anywhere - P1 + code:84ff92/00+84ff94/03+84ff93/f0+84e6aa/ff+84ff95/4c+84ff98/4c+84ff9a/e6+84ff97/e7+84ff90/e0+84ff96/28+84ff99/b2+84e6a9/90+84ff91/02 + cheat + description:Blank versus screen + code:83e635/ff + cheat + description:Scrambled backgrounds + code:849566/ad + cheat + description:Black background (wait for title screen to appear before proceeding) + code:849584/ad + cheat + description:Press Left on main menu for Sound Test menu + code:83b6db/02 + cheat + description:Press Right on main menu for Kool Stuff menu + code:83b70f/02 + cheat + description:Press Up on main menu for Kooler Stuff menu + code:83b743/02 + cheat + description:Press B on main menu for Scotts Stuff menu + code:83b777/02 + cheat + description:First round / one button fatalities + code:7e3be3/01 + +cartridge sha256:e9fae4c2e171a1fc4f2bd800abd9e42750aaf7a4db9e40c5b9142e15029500bd + name:Ultraman (USA) + cheat + description:Infinite health + code:0096cc/2c + cheat + description:Infinite health - P1 + code:7e07ee/53 + cheat + description:No health - P2 + code:7e084e/00 + cheat + description:Infinite chances + code:00de27/24 + cheat + description:Infinite time (seconds) + code:7e00a3/63 + cheat + description:Infinite time (minutes) + code:7e00a4/09 + cheat + description:Quicker health replenishment + code:00b015/00 + cheat + description:Less health replenishment for enemies + code:00b040/ea + cheat + description:Weaker punch + code:03ccae/01 + cheat + description:Weaker kick + code:03ccb0/01 + cheat + description:9 minutes per stage + code:009022/09 + cheat + description:6 minutes per stage + code:009022/06 + cheat + description:2 minutes per stage + code:009022/02 + cheat + description:Start with 1 chance + code:008daa/00 + cheat + description:Start with 6 chances + code:008daa/05 + cheat + description:Start with 9 chances + code:008daa/09 + 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 + name:Uncharted Waters (USA) + cheat + description:Start with 65,000 Gold + code:01fc1c/fd + +cartridge sha256:64bc4707f422661a66618088887e2363a5f896ea683c58984fffd96dd21ab5f0 + name:New Horizons (USA) + cheat + description:Joao starts with 156 Leadership instead of 78 + code:c8820f/9c + cheat + description:Joao starts with 250 Leadership instead of 78 + code:c8820f/fa + cheat + description:Joao starts with 150 Seamanship instead of 75 + code:c88210/96 + cheat + description:Joao starts with 250 Seamanship instead of 75 + code:c88210/fa + cheat + description:Joao starts with 146 Knowledge instead of 73 + code:c88211/92 + cheat + description:Joao starts with 250 Knowledge instead of 73 + code:c88211/fa + cheat + description:Joao starts with 170 Intuition instead of 85 + code:c88212/aa + cheat + description:Joao starts with 250 Intuition instead of 85 + code:c88212/fa + cheat + description:Joao starts with 164 Courage instead of 82 + code:c88213/a4 + cheat + description:Joao starts with 250 Courage instead of 82 + code:c88213/fa + cheat + description:Joao starts with 164 Dueling Skill instead of 82 + code:c88214/a4 + cheat + description:Joao starts with 250 Dueling Skill instead of 82 + code:c88214/fa + cheat + description:Joao starts with 178 Likability (Charm) instead of 89 + code:c88215/b2 + cheat + description:Joao starts with 250 Likability (Charm) instead of 89 + code:c88215/fa + cheat + description:Catalina starts with 24 Sail Level instead of 8 + code:c88249/18 + cheat + description:Catalina starts with 80 Sail Level instead of 8 + code:c88249/50 + cheat + description:Catalina starts with 30 Battle Level instead of 10 + code:c8824a/1e + cheat + description:Catalina starts with 100 Battle Level instead of 10 + code:c8824a/64 + cheat + description:Catalina starts with 160 Leadership instead of 80 + code:c88241/a0 + cheat + description:Catalina starts with 250 Leadership instead of 80 + code:c88241/fa + cheat + description:Catalina starts with 158 Seamanship instead of 79 + code:c88242/9e + cheat + description:Catalina starts with 250 Seamanship instead of 79 + code:c88242/fa + cheat + description:Catalina starts with 130 Knowledge instead of 65 + code:c88243/82 + cheat + description:Catalina starts with 250 Knowledge instead of 65 + code:c88243/fa + cheat + description:Catalina starts with 104 Intuition instead of 52 + code:c88244/68 + cheat + description:Catalina starts with 250 Intuition instead of 52 + code:c88244/fa + cheat + description:Catalina starts with 172 Courage instead of 86 + code:c88245/ac + cheat + description:Catalina starts with 250 Courage instead of 86 + code:c88245/fa + cheat + description:Catalina starts with 184 Dueling Skill instead of 92 + code:c88246/b8 + cheat + description:Catalina starts with 250 Dueling Skill instead of 92 + code:c88246/fa + cheat + description:Catalina starts with 190 Likability instead of 95 + code:c88247/be + cheat + description:Catalina starts with 250 Likability instead of 95 + code:c88247/fa + cheat + description:Ali Vezas starts with 160 Leadership (instead of 80) + code:c88309/a0 + cheat + description:Ali Vezas starts with 250 Leadership (instead of 80) + code:c88309/fa + cheat + description:Ali Vezas starts with 172 Seamanship (instead of 86) + code:c8830a/ac + cheat + description:Ali Vezas starts with 250 Seamanship (instead of 86) + code:c8830a/fa + cheat + description:Ali Vezas starts with 168 Knowledge (instead of 84) + code:c8830b/a8 + cheat + description:Ali Vezas starts with 250 Knowledge (instead of 84) + code:c8830b/fa + cheat + description:Ali Vezas starts with 130 Intuition (instead of 65) + code:c8830c/82 + cheat + description:Ali Vezas starts with 250 Intuition (instead of 65) + code:c8830c/fa + cheat + description:Ali Vezas starts with 106 Courage (instead of 53) + code:c8830d/6a + cheat + description:Ali Vezas starts with 250 Courage (instead of 53) + code:c8830d/fa + cheat + description:Ali Vezas starts with 84 Dueling Skill (instead of 42) + code:c8830e/54 + cheat + description:Ali Vezas starts with 250 Dueling Skill (instead of 42) + code:c8830e/fa + cheat + description:Ali Vezas starts with 160 Likability (instead of 80) + code:c8830f/a0 + cheat + description:Ali Vezas starts with 250 Likability (instead of 80) + code:c8830f/fa + cheat + description:Start a new game with $250 Gold + code:c881eb/fa + cheat + description:Start a new game with $1,024 Gold + code:c881ec/04 + cheat + description:Start a new game with $9,984 Gold + code:c881ec/27 + cheat + description:Start a new game with $64,000 Gold + code:c881ec/fa + cheat + description:Start a new game with $196,608 Gold + code:c881ed/03 + cheat + description:Start a new game with over one Million Gold + code:c881ed/10 + 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 + name:Undercover Cops (Japan) + cheat + description:Infinite health + code:c08d8c/ad + cheat + description:Infinite lives + code:c0fcef/ad + cheat + description:Infinite time + code:c10a26/ad + cheat + description:Infinite continues + code:c14beb/ad + cheat + description:Hit anywhere + code:c0d4fd/80+c0d4fe/3e + cheat + description:one hit kils + code:c0d54a/00 + 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 + name:Uniracers (USA) + cheat + description:No timer in almost every race + code:81c726/ea + cheat + description:No timer in almost every race (alt) + code:81c726/ea + +cartridge sha256:cf587d72123277f72f658829f1efdb4f52f3bec012a316c1fea25e1f9c292575 + name:Universal Soldier (USA) (Proto) + cheat + description:Infinite health + code:00f5e6/ad + cheat + description:Infinite lines + code:018505/ad + +cartridge sha256:ecefb4117a6aae117e033c8cc07f0db2797d6be93dd5cdcefc23692a21fae02e + name:Untouchables, The (USA) + cheat + description:Infinite lives + code:7e1b86/09 + cheat + description:Infinite ammo + code:7e1b89/63 + +cartridge sha256:8b3ff3a0ca1c85facb71f42886291dfa916ca74245702c79ca8ae635f28bc864 + name: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 + name:Utopia - The Creation of a Nation (USA) + cheat + description:1-day buildings + code:009691/00 + cheat + description:Have 655360000 cash (enable while on map then disable) + code:00a5e9/a9+00a5ec/85+00a5ed/71 + +cartridge sha256:78bf9d79fb2ff3f9d03ecc1176d070e53ddaca2c6b0cda69e74c19a4e50b195b + name:Vegas Stakes (USA) + cheat + description:Only $34,464 needed for highroller status (glitchy) + code:00c34b/00 + cheat + description:Only $38,527 needed to win the game instead of $10 million + code:00c2b9/00 + cheat + description:Only $5,019,263 needed to win the game + code:00c2b9/4c + cheat + description:Player wins pushes in Blackjack + code:0eb93b/00 + cheat + description:Dealer wins pushes in Blackjack + code:0eb93b/01 + cheat + description:Start with $488 - P1 + code:00bf68/01 + cheat + description:Start with $488 - P2 + code:00bf95/01 + cheat + description:Start with $488 - P3 + code:00bfc2/01 + cheat + description:Start with $488 - P4 + code:00bfef/01 + cheat + description:Start with $2280 - P1 + code:00bf68/08 + cheat + description:Start with $2280 - P2 + code:00bf95/08 + cheat + description:Start with $2280 - P3 + code:00bfc2/08 + cheat + description:Start with $2280 - P4 + code:00bfef/08 + cheat + description:Start with $9960 - P1 + code:00bf68/26 + cheat + description:Start with $9960 - P2 + code:00bf95/26 + cheat + description:Start with $9960 - P3 + code:00bfc2/26 + cheat + description:Start with $9960 - P4 + code:00bfef/26 + cheat + description:Start with $132,072 (highroller status) - P1 + code:00bf6d/02 + cheat + description:Start with $132,072 - P2 + code:00bf9a/02 + cheat + description:Start with $132,072 - P3 + code:00bfc7/02 + cheat + description:Start with $132,072 - P4 + code:00bff4/02 + +cartridge sha256:b72fbbfe737eff49f59dcef9f13b963e50c5bc322d7eb0e7b4c25f3a71aa0815 + name:Venom-Spider-Man - Separation Anxiety (USA) + cheat + description:Infinite health - P1 + code:82e174/b5 + cheat + description:Infinite lives - P1 + code:81a554/79 + cheat + description:Infinite health - P2 + code:7e0a5a/99 + cheat + description:Infinite lives - P2 + code:7e1a8b/06 + 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:Use helpers multiple times + code:7e1bc4/00 + cheat + description:Hard mode enabled + code:7e1c3c/ff + cheat + description:Stage select enabled + code:7e1c40/ff + cheat + description:Hit anywhere + code:82ab25/24 + 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 + name:Virtual Bart (USA) + cheat + description:Infinite time + code:80e75f/ad + cheat + description:Infinite health and Tomatoes (Baby Bart takes damage when he walks on grass) + code:80e8fb/47 + cheat + description:Infinite continues + code:80e8bb/ad + cheat + description:Infinite lives + code:80e8ad/ad + +cartridge sha256:41b5561de9e4984276e52987ea46c5f4fa8526d8141c70c738875a9eb9fe9d70 + name: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 + name:Warlock (USA) + cheat + description:Invincibility + code:009ff8/a9+00a8a2/ee + cheat + description:Infinite items on pick-up + code:02887a/ea + cheat + description:Enter the password GRKKL to go to the final battle + code:04c4a3/31 + cheat + description:Enter the password GRKKL to go to the ending + code:04c4a3/32 + +cartridge sha256:0fadb3b67bfb7d750d873e7601dd5ffdfd33b8ebda833a18a3c999c7f8aa9e15 + name:Waterworld (Europe) + cheat + description:Invincibility underwater + code:81a69f/00 + cheat + description:Infinite health underwater + code:81933b/ad + cheat + description:Infinite health - Overworld + code:7e0288/7f + cheat + description:Hit anywhere + code:80c17d/80+80c17e/2a+80c1ac/60 + cheat + description:Get items from anywhere + code:81e283/80+81e284/18 + +cartridge sha256:56ba3d585bf6b701e342d86a0bd164ab0a97dfbd5df46b3a964506842633459c + name:Wayne's World (USA) + cheat + description:Infinite Worthiness + code:069caf/ad + cheat + description:Infinite lives + code:00b91d/ad + cheat + description:Worthiness item worth nothing on pick-up + code:06997a/ad + cheat + description:Schwing item worth nothing on pick-up + code:06994a/ad + cheat + description:Infinite Schwings if you have at least 1 + code:068552/ad + cheat + description:Invincibility lasts longer after getting hit + code:069ce5/ff + cheat + description:Invincibility does not last as long after getting hit + code:069ce5/10 + cheat + description:Invincibility lasts forever after getting hit (Wayne blinks) + code:069d94/bd + cheat + description:Invincibility (Wayne doesn't blink) + code:069c9b/80 + cheat + description:Amp power-up worth nothing on pick-up + code:06989a/00 + cheat + description:Amp power-up gives you Distortion-type chords + code:06989a/04 + cheat + description:Amp power-up gives you Mega-Amp-type chords + code:06989a/02 + cheat + description:Amp power-up gives you Chorus-type chords + code:06989a/03 + cheat + description:Amp power-up gives you Homer-type chords + code:06989a/05 + cheat + description:Distortion power-up worth nothing on pick-up + code:069900/00 + cheat + description:Distortion power-up gives you Amp-type chords + code:069900/01 + cheat + description:Distortion power-up gives you Mega-Amp-type chords + code:069900/02 + cheat + description:Distortion power-up gives you Chorus-type-chords + code:069900/03 + cheat + description:Distortion power-up gives you Homer-type-chords + code:069900/05 + cheat + description:Heart item worth nothing + code:06999d/ad + cheat + description:Start with 1 life + code:00cbce/01 + cheat + description:Start with 3 lives + code:00cbce/03 + cheat + description:Start with 7 lives + code:00cbce/07 + cheat + description:Start with 9 lives + code:00cbce/09 + cheat + description:Start with 1 Worthiness point + code:00b93e/01 + cheat + description:Start with 3 Worthiness points + code:00b93e/03 + cheat + description:Start with 7 Worthiness points + code:00b93e/07 + cheat + description:Start with 9 Worthiness points + code:00b93e/09 + +cartridge sha256:0b1ba31ae95b61d7d9a0f5509b5836fff84f60915802e3b3ba1170a5c50a4b71 + name:WeaponLord (USA) + cheat + description:Infinite health - P1 + code:ea64c7/7a + cheat + description:Infinite health - both players + code:ea64c6/ad + cheat + description:Infinite time + code:e94d22/ad + cheat + description:Hit anywhere - both players + code:e973c6/80+e97409/80+e973c2/00+e97403/00 + cheat + description:Play as Zarak in story mode + code:eae5a1/06 + +cartridge sha256:e931c3c08f20f78e3a43ad92d16eb472be619abaa17c2d8e2b0fcd5d05dbd74d + name:We're Back! - A Dinosaur's Story (USA) + cheat + description:Infinite health + code:9a96dc/ad + cheat + description:Infinite lives + code:9a847a/ad + cheat + description:Infinite Vorb on pick-up for the rest of the stage + code:9aae88/ad + cheat + description:Infinite Elsa on pick-up for the rest of the stage + code:9aa761/ad + cheat + description:Infinite Dweebs on pick-up for the rest of the stage + code:9aac73/ad + cheat + description:Infinite Woog on pick-up + code:9aa964/ad + cheat + description:Super-jump + code:9a9a68/1f + cheat + description:Mega-jump + code:9a9a68/2f + cheat + description:Less grain to get for tail swipe + code:9a8909/03 + cheat + description:Less grain to get for stomp + code:9a8903/09 + cheat + description:Start with less health + code:99b299/02+9a8886/02 + cheat + description:Start with 9 lives + code:99b293/09 + cheat + description:Start with 6 lives + code:99b293/06 + cheat + description:Start with 1 life + code:99b293/01 + cheat + description:Start on Manhattan - Zone 2 + code:99b17f/a9+99b180/02+99b181/00 + cheat + description:Start on the Subway + code:99b17f/a9+99b180/03+99b181/00 + cheat + description:Start on Crazy Crane + code:99b17f/a9+99b180/04+99b181/00 + cheat + description:Start on Construction in the City + code:99b17f/a9+99b180/06+99b181/00 + cheat + description:Start on Thanksgiving - Zone 1 + code:99b17f/a9+99b180/07+99b181/00 + cheat + description:Start on Thanksgiving - Zone 2 + code:99b17f/a9+99b180/08+99b181/00 + cheat + description:Start on Balloon Blow-out + code:99b17f/a9+99b180/09+99b181/00 + cheat + description:Start on Central Park - Zone 1 + code:99b17f/a9+99b180/0b+99b181/00 + cheat + description:Start on Central Park - Zone 2 + code:99b17f/a9+99b180/0c+99b181/00 + cheat + description:Start on the Zoo + code:99b17f/a9+99b180/0d+99b181/00 + cheat + description:Start on Prehistoric Panic + code:99b17f/a9+99b180/0e+99b181/00 + cheat + description:Start on Outside the Circus + code:99b17f/a9+99b180/10+99b181/00 + cheat + description:Start on Circus - Zone 1 + code:99b17f/a9+99b180/11+99b181/00 + cheat + description:Start on Circus - Zone 2 + code:99b17f/a9+99b180/12+99b181/00 + cheat + description:Start on Jack in the Box + code:99b17f/a9+99b180/13+99b181/00 + cheat + description:Start on Empire State Building + code:99b17f/a9+99b180/15+99b181/00 + cheat + description:Start on Spaceship - Zone 1 + code:99b17f/a9+99b180/16+99b181/00 + cheat + description:Start on Spaceship - Zone 2 + code:99b17f/a9+99b180/17+99b181/00 + 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 + name:Wheel of Fortune (USA) + cheat + description:Infinite time to choose + code:008425/ad + cheat + description:Don't lose money when landing on bankrupt + code:0094f4/ad + cheat + description:3/4 of normal time to choose + code:009866/1e + cheat + description:1/2 of normal time to choose + code:009866/14 + cheat + description:1/4 of normal time to choose + code:009866/0a + cheat + description:Vowels are free is you have at least $250 + code:008cd5/00 + cheat + description:Vowels cost $50 if you have at least $250 + code:008cd5/32 + cheat + description:Vowels cost $100 if you have at least $250 + code:008cd5/64 + cheat + description:Vowels cost $150 if you have at least $250 + code:008cd5/96 + cheat + description:Vowels cost $200 if you have at least $250 + code:008cd5/c8 + +cartridge sha256:0a52dc1e7820f5541f53ce0e1e96144fe079af0efe3dae5c2c89d86365feb8b1 + name:Whizz (USA) + cheat + description:Infinite health + code:80a1a4/a5 + cheat + description:Infinite time + code:80874f/ad + cheat + description:Infinite lives + code:80ab7c/ad + cheat + description:Infinite time (alt) + code:7e03a4/63 + +cartridge sha256:c8f159e2625ac8078535c06857ea28475706da45df494de8e46f50888272cf71 + name:Wild Guns (USA) + cheat + description:Invincibility + code:038067/24 + cheat + description:Hit anywhere + code:009520/24+00952d/24+009537/24+039301/24+009516/24+0094f0/80 + cheat + description:Infinite specials + code:7e1fa0/05 + cheat + description:Infinite lives + code:7e1fb2/04 + cheat + description:Enable stage select after select player screen (disable before you exit the menu) + code:7e05f0/ff+7e05f1/ff + +cartridge sha256:2167fc7c5447b2287668d2f3e4ef1a285361b2292ecc8a4cbd9f966a460ad7a2 + name:Wing Commander (USA) + cheat + description:Increase front shield on Hornet + code:8b9bad/3c + cheat + description:Increase rear shield on Hornet + code:8b9c21/3c + cheat + description:Increase front armor on Hornet + code:8b9c95/40 + cheat + description:Increase rear armor on Hornet + code:8b9d09/40 + cheat + description:Increase left side armor on Hornet + code:8b9df1/40 + cheat + description:Increase right side armor on Hornet + code:8b9d7d/40 + cheat + description:Increase front shield on Scimitar + code:8b9bb1/63 + cheat + description:Increase rear shield on Scimitar + code:8b9c25/63 + cheat + description:Increase front armor on Scimitar + code:8b9c99/63 + cheat + description:Increase rear armor on Scimitar + code:8b9d0d/63 + cheat + description:Increase left side armor on Scimitar + code:8b9df5/63 + cheat + description:Increase right side armor on Scimitar + code:8b9d81/63 + cheat + description:Mega front shields on Hornet + code:8b9bae/ff + cheat + description:Mega rear shields on Hornet + code:8b9c22/ff + cheat + description:Mega front shields on Scimitar + code:8b9bb2/55 + cheat + description:Mega rear shields on Scimitar + code:8b9c26/55 + +cartridge sha256:132ca0b6a4888edf7de785d48f4417fac28522646e6c7514f80c5e9ff1438d5f + name:Wing Commander - The Secret Missions (USA) + cheat + description:Infinite blaster power + code:80c081/ad + cheat + description:Infinite fuel + code:80a1bb/ad + cheat + description:Infinite missiles + code:818a8f/ea + cheat + description:Start on mission 4 + code:8386b9/04 + cheat + description:Start on mission 8 + code:8386b9/08 + +cartridge sha256:c3bcd5c716f96e6359ebcfd85c3e9b07b46c5124bf4010d89ceef5b6f2f868f6 + name:Wings 2 - Aces High (USA) + cheat + description:Infinite lives - all pilots (you can still get fired) + code:02b5c9/bd + cheat + description:Infinite power-ups + code:02ac80/ad + +cartridge sha256:025dd3047c474d879e69b91a3918add9cdabedf4182e1c1e10e5f0c13a124bf9 + name:Wizard of Oz, The (USA) + cheat + description:Invincibility + code:01bd0f/d0 + cheat + description:Infinite health + code:02e3a2/bd + cheat + description:Infinite lives + code:00e4f3/dd + 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 + name: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:05bbb9/bd + cheat + description:Create a character and he has a lot of gold + code:049c13/20 + +cartridge sha256:e0165bafeb8d65be08a5a4079f8651104471f450c60794b761b1255853ca2d98 + name:Wolfchild (USA) + cheat + description:Infinite health + code:00c4e7/ea + cheat + description:Infinite health (alt) + code:7e0636/14 + cheat + description:Infinite continues + code:00f2a7/ad + cheat + description:Infinite lives + code:00c38b/a5 + cheat + description:Infinite lives (alt) + code:7e029a/99 + cheat + description:Infinite Bombs + code:00c4e1/a5 + cheat + description:Infinite Bombs (alt) + code:7e0298/99 + cheat + description:Infinite Projectiles + code:7e0296/99 + cheat + description:Stay in wolf form until next continue + code:00c3f8/ad+00c3fb/ad + cheat + description:Start with 254 lives and 255 Bombs + code:00888f/fe + cheat + description:Start at final boss + code:008887/0b + +cartridge sha256:9c2b458e8fda5cb437a4c6d28fb430e45c4cfef98420c40546b8e08563a4fc7d + name:Wolfenstein 3-D (USA) + cheat + description:Infinite health + code:c0a9a2/ad + cheat + description:Infinite ammo + code:c0b401/ad + cheat + description:Infinite lives + code:c0dbbc/ad + cheat + description:Infinite ammo for special weapon 1 after first life + code:c0b45c/ad + cheat + description:Infinite ammo for special weapon 2 after first life + code:c0b618/ad + cheat + description:Start with 1 life + code:c0da78/01 + cheat + description:Start with 6 lives + code:c0da78/06 + cheat + description:Start with 9 lives + code:c0da78/09 + cheat + description:Start with more ammo + code:c0da5d/63+c0d8b8/63 + cheat + description:Start with chain gun + code:c0d8ae/8d + cheat + description:Start with machine gun + code:c0d8ab/8d + cheat + description:Start with special weapon 1 (super machine gun) and ammo after first life + code:c0d8c0/8d+c0d8a3/04 + cheat + description:Start with special weapon 2 (rocket launcher) and ammo after first life + code:c0d8bd/8d+c0d4a3/05 + +cartridge sha256:44428a3d1c796fbd41da7620e321c45f11cd80a0e5f4ab8c48177106cb960d77 + name:Wolverine - Adamantium Rage (USA) + cheat + description:Infinite health + code:80f707/a5 + cheat + description:Infinite time + code:b1cfb3/d0 + cheat + description:No enemies + code:b8f751/85 + cheat + description:Hit anywhere + one hit kills + code:808349/24+808342/24+80836c/24+808360/24+808322/24+80832e/24+80837f/24+808359/24+808352/24 + cheat + description:One hit kills + code:80837f/24 + cheat + description:Invincibility + code:7e00b8/ff + cheat + description:Infinite health (alt) + code:7e1027/64 + +cartridge sha256:ea76cfdbb2a555a7b6eff8b466a879f9a9189639416e8c2fb45bf074e695105f + name:World Heroes (USA) + cheat + description:Infinite health - P1 + code:c046b7/24 + cheat + description:Hit anywhere - P1 + code:c010fe/30+c010fa/c0+c010fb/00+c010fc/10 + cheat + description:Always win - P1 + code:c0ba8b/39 + cheat + description:Win a draw - P1 + code:c04a55/02 + cheat + description:Win a draw - P2 + code:c04a55/07 + cheat + description:Slow timer down by half + code:c0463b/a0 + cheat + description:3 hits to win round - either player + code:c048a2/19+c0489f/00 + cheat + description:2 hits to win round - either player + code:c048a2/31+c0489f/00 + cheat + description:1 hit to win (sudden death) - either player + code:c048a2/61+c0489f/00 + cheat + description:Start with more health - P1 + code:c02a5c/7e + cheat + description:Start with 1/2 health - P1 + code:c02a5c/30 + cheat + description:Start with very little health - P1 + code:c02a5c/01 + cheat + description:Start with more health - P2/CPU + code:c02ac6/7e + cheat + description:Start with half health - P2/CPU + code:c02ac6/30 + cheat + description:Start with very little health - P2/CPU + code:c02ac6/01 + +cartridge sha256:159d5341d13d6801324e8271f7191c0223617c9d30984676319b2df7937c78c0 + name:World Heroes 2 (USA) + cheat + description:Invincibility - P1 + code:00b3d6/60+00b9e6/60 + cheat + description:Invincibility - P2 + code:00b1d1/60+00b821/60 + cheat + description:Hit anywhere - P1 + code:00b1cc/80+00b81c/80 + cheat + description:Hit anywhere - P2 + code:00b3d1/80+00b9e1/80 + 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 + name:World League Soccer (USA) + cheat + description:Score from anywhere (hold X and kick to the goal line and out of bounds) + code:038d65/a5+038d67/0a+038d69/44+038d68/30+038d66/33 + cheat + description:Each goal worth 2 - P1 + code:03cba3/02 + cheat + description:Each goal worth 3 - P1 + code:03cba3/03 + cheat + description:Each goal worth 4 - P1 + code:03cba3/04 + cheat + description:Each goal worth 5 - P1 + code:03cba3/05 + cheat + description:Each goal worth 6 - P1 + code:03cba3/06 + cheat + description:Each goal worth 7 - P1 + code:03cba3/07 + cheat + description:Each goal worth 8 - P1 + code:03cba3/08 + cheat + description:Each goal worth 9 - P1 + code:03cba3/09 + cheat + description:Each goal worth 2 - P2 + code:03cc0c/02 + cheat + description:Each goal worth 3 - P2 + code:03cc0c/03 + cheat + description:Each goal worth 4 - P2 + code:03cc0c/04 + cheat + description:Each goal worth 5 - P2 + code:03cc0c/05 + cheat + description:Each goal worth 6 - P2 + code:03cc0c/06 + cheat + description:Each goal worth 7 - P2 + code:03cc0c/07 + cheat + description:Each goal worth 8 - P2 + code:03cc0c/08 + cheat + description:Each goal worth 9 - P2 + code:03cc0c/09 + +cartridge sha256:2143bbd87ea1c5cfe5eaf46ae39e3ebb11a2e929d05cbb929904037f4d72acfe + name:World Soccer 94 - Road to Glory (USA) + cheat + description:Score from anywhere (press and hold A, kick to the goal line and out of bounds) + code:80f20f/ad+80f210/a5+80f211/0d+80f213/55 + +cartridge sha256:0af7b0d3022acd24a1fb15865a076519f7f56e7a4b33f12b6d851b3a91e5388c + name:WWF Raw (USA) + cheat + description:Start with half health + code:acf108/03 + cheat + description:Nobody gets hurt + code:afeb63/ad + cheat + description:No out of ring timer + code:affae1/ad + 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 + name: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 + name:WWF Super WrestleMania (USA) + cheat + description:Punches and kicks (except flying drop kick) do no damage + code:009c65/00 + cheat + description:Punches and kicks (except flying drop kick) do more damage + code:009c65/03 + cheat + description:Punches and kicks (except flying drop kick) do a lot more damage + code:009c65/06 + cheat + description:Stomps do no damage + code:009d47/00 + cheat + description:Stomps do more damage + code:009d47/03 + cheat + description:Stomps do a lot more damage + code:009d47/06 + cheat + description:Elbow drops do no damage + code:05f8f5/00 + cheat + description:Elbow drops do more damage + code:05f8f5/05 + cheat + description:Elbow drops do a lot more damage + code:05f8f5/08 + cheat + description:Flying elbow drops do no damage + code:05f8f7/00 + cheat + description:Flying elbow drops do more damage + code:05f8f7/07 + cheat + description:Flying elbow drops do a lot more damage + code:05f8f7/0a + cheat + description:Headbutts do no damage + code:009d99/00 + cheat + description:Headbutts do more damage + code:009d99/06 + cheat + description:Headbutts do a lot more damage + code:009d99/09 + cheat + description:Start with 1/4 health - both players + code:00a284/0c + cheat + description:Start with 1/2 health - both players + code:00a284/18 + cheat + description:Start with 3/4 health - both players + code:00a284/24 + +cartridge sha256:67faa6ed3406a5ab0d7224b811c0960bb36560040ee959bb3304c9293ceaa093 + name:WWF WrestleMania - The Arcade Game (USA) + cheat + description:Infinite time + code:e51845/ea + cheat + description:Do mega damage and don't die + code:c302d4/a5 + cheat + description:Max combo meter + code:c31e48/a9+c31e4b/80 + cheat + description:Start with 1/4 health + code:c30041/20+c300d9/20 + cheat + description:Start with 1/2 health + code:7e0000/00+c300d9/4f + cheat + description:Start with 3/4 health + code:c30041/78+c300d9/78 + cheat + description:Start with 1/4 health - opponent + code:c30012/20 + cheat + description:Start with 1/2 health - opponent + code:c30012/4f + cheat + description:Start with 3/4 health - opponent + code:c30012/78 + +cartridge sha256:71b69490c78d0bbaf47da25217c5dae295190311aa5df75653c3fac0a1b45358 + name:Xardion (USA) + cheat + description:Immune to most collisions + code:04d976/2c + cheat + description:Immune to most bullets + code:04e260/2c + cheat + description:Start characters at level 12 + code:08f1de/00 + +cartridge sha256:dc3792e9fe7ef7aaea4ac675a48ad06129dd3ebdd4b96a513bc8241549cbd579 + name:X-Kaliber 2097 (USA) + cheat + description:Infinite time + code:008c4e/ad + cheat + description:Infinite lives + code:0083ae/ea + cheat + description:Soda Cans give 50% life back + code:1080ee/5a + 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 + name:X-Men - Mutant Apocalypse (USA) + cheat + description:Infinite health + code:c00f99/ee + cheat + description:Infinite health (alt) + code:7e008b/41+7e0c35/41 + cheat + description:Infinite lives - training mode + code:c00e66/ad + cheat + description:Infinite lives - mission mode + code:c00936/ad + cheat + description:Hit anywhere + code:c2f1ee/24+c2f218/80 + cheat + description:Easy specials (press X) + code:c12b2d/ee + cheat + description:Walk through walls + code:c02e38/ad+c106df/b5+c02e45/ad + 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 + name: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 + name: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 + name:Yoshi's Cookie (USA) + cheat + description:In action mode, passing a stage advances to the next round + code:0ab417/80 + cheat + description:Immediately complete current Action level whenever effects switch is turned on (keep switch off to play) + code:0ab303/02 + cheat + description:All 99 Action rounds available without the secret code + code:0aa18b/62 + cheat + description:In VS mode, only 1 win is required instead of 3. P2 always wins the set (2P only) + code:0abb8d/01 + cheat + description:In VS mode, the fuses don't count down + code:0acc44/ad + cheat + description:In VS mode, play against tougher opponents without the secret code + code:02b37e/08+02b386/00 + cheat + description:In Puzzle mode, passing a stage advances to the next round + code:0aeeaf/00 + cheat + description:Unlimited moves in puzzle mode (turn effects switch off to use up moves if the level becomes impossible) + code:0af6cd/ad + +cartridge sha256:12fba2aff04c8e39968e828629ebd16caa314bca397a9418d35fdaffe8188e20 + name:Yoshi's Safari (USA) + cheat + description:Almost infinite health + code:90d16a/ad+83bce7/ad + cheat + description:Infinite power + code:818191/00+90d58b/00 + cheat + description:Infinite time + code:83fc5c/ad + cheat + description:Infinite lives + code:80d3be/ad + cheat + description:Don't lose coins when you miss a jump + code:83b711/ad + cheat + description:1 minute for stage 1 instead of 4 + code:8fa456/01 + cheat + description:9 minutes for stage 1 + code:8fa456/09 + cheat + description:1 minute for stage 2 instead of 4 + code:8fa458/01 + cheat + description:9 minutes for stage 2 + code:8fa458/09 + cheat + description:Lose power more quickly + code:818192/01+90d58c/01 + cheat + description:Lose power more slowly + code:818191/05+90d58b/05 + cheat + description:Gain power more quickly + code:8181aa/01+90d59e/01 + cheat + description:Gain power more slowly + code:8181a9/20+90d59d/20 + cheat + description:1-up with every coin after you get 10 + code:83fd12/09 + cheat + description:1-up with every coin after you get 30 + code:83fd12/1e + cheat + description:1-up with every coin after you get 99 + code:83fd12/62 + cheat + description:Start with 1 life + code:8d8131/00 + cheat + description:Start with 5 lives + code:8d8131/04 + cheat + description:Start with 10 lives + code:8d8131/09 + +cartridge sha256:fbe8926fc0149d3e8e2aec20f15640ea6814f4f4b01c3960f3c477f5f17e890f + name:Young Merlin (USA) + cheat + description:Faster Merlin + code:859538/05 + cheat + description:Slower mine cart + code:998193/02 + cheat + description:2 hearts from rainbow water bottle + code:80a642/02 + cheat + description:3 hearts from rainbow water bottle + code:80a642/03 + cheat + description:Start with 6 heart containers (new game) + code:91ba88/06 + cheat + description:Start with 8 heart containers (new game) + code:91ba88/08 + cheat + description:Infinite health + code:7eedde/02 + cheat + description:Have Air Bubble 1D + code:7e4d00/02 + cheat + description:Have Air Bubble on button Y + code:7e4d29/21 + cheat + description:Have Balloon + code:7e4d07/02 + cheat + description:Have Balloon on button Y + code:7e4d1c/28 + cheat + description:Have Blue Spark 6C + code:7e4cf5/02 + cheat + description:Have Blue Sparkly on button Y + code:7e4d26/16 + cheat + description:Have Bubble Wand + code:7e4d0c/02 + cheat + description:Have Bubble Wand on button Y + code:7e4d1d/2d + cheat + description:Have Daffodil + code:7e4ce2/02 + cheat + description:Have Daffodil on button Y + code:7e4d1a/03 + cheat + description:Have Daisy + code:7e4ce1/02 + cheat + description:Have Daisy on button Y + code:7e4d17/02 + cheat + description:Have Dwarf Teleport + code:7e4d11/02 + cheat + description:Have Dwarf Teleport on button Y + code:7e4d1f/32 + cheat + description:Have FishBowl E 4C + code:7e4d0d/02 + cheat + description:Have FishBowl E on button Y + code:7e4d24/2e + cheat + description:Have Key - Gold 4C + code:7e4d03/02 + cheat + description:Have Key - Gold on button Y + code:7e4d22/24 + cheat + description:Have Key - Silver + code:7e4d04/02 + cheat + description:Have Key - Silver on button Y + code:7e4d25/25 + cheat + description:Have Golden Comb + code:7e4cf7/02 + cheat + description:Have Golden Comb on button Y + code:7e4d20/18 + cheat + description:Have Gold Spark 6C + code:7e4d15/02 + cheat + description:Have Gold Spark on button Y + code:7e4d28/36 + cheat + description:Have Golden Foxglove + code:7e4ce4/02 + cheat + description:Have Golden Foxglove on button Y + code:7e4d19/05 + cheat + description:Have Hour Glass + code:7e4cf6/02 + cheat + description:Have Hour Glass on button Y + code:7e4d21/17 + cheat + description:Have Mirror + code:7e4d08/02 + cheat + description:Have Mirror on button Y + code:7e4d1e/29 + cheat + description:Have Reflec Cry 6C + code:7e4d0a/02 + cheat + description:Have Reflec Cry 6C on button Y + code:7e4d27/2b + cheat + description:Have Rose + code:7e4ce3/02 + cheat + description:Have Rose on button Y + code:7e4d18/04 + cheat + description:Have Spring 4C + code:7e4d0b/02 + cheat + description:Have Spring on button Y + code:7e4d23/2c + cheat + description:Have Stun Dust + code:7e4d01/02 + cheat + description:Have Stun Dust on button Y + code:7e4d1b/22 + cheat + description:Have Tulip + code:7e4ce0/02 + cheat + description:Have Tulip on button Y + code:7e4d16/01 + cheat + description:Have Wheel 1D + code:7e4d05/02 + cheat + description:Have Wheel on button Y + code:7e4d2b/26 + cheat + description:Have Wrench 1D + code:7e4d02/04 + cheat + description:Have Wrench on button Y + code:7e4d2a/23 + +cartridge sha256:b0e74f0fe8d1e7fe2fe404341fea7c68e28f3a0ab78552d5092d413f2ecec417 + name:Ys III - Wanderers from Ys (USA) + cheat + description:Invincibility + code:7e1afc/08 + cheat + description:Infinite health + code:1794e1/ad + cheat + description:Infinite Amulet shots + code:7e1fe9/03 + cheat + description:Items are free if you have enough money + code:00f49a/80+00f49b/0a + cheat + description:One hit kills on bosses (except final boss) + code:7e17e1/00 + cheat + description:Gain experience quicker + code:179799/a9 + cheat + description:Gain experience much quicker + code:179799/a9+17979a/35 + cheat + description:Start with 100 hit points instead of 20 + code:17bddb/64 + cheat + description:Start with 200 hit points + code:17bddb/c8 + cheat + description:Start with 488 Gold instead of 1,000 + code:17bdf2/01 + cheat + description:Start with 2,024 Gold + code:17bdf2/07 + cheat + description:Start with 9,704 Gold + code:17bdf2/25 + cheat + description:Start with 20,200 Gold + code:17bdf2/4e + cheat + description:Start with 40,168 Gold + code:17bdf2/9c + cheat + description:Start with 65,512 Gold + code:17bdf2/ff + cheat + description:Invincibility (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:7e12a9/ff+7e12aa/ff+7e12ab/ff+7e12b3/ff+7e12ac/ff+7e12ad/ff+7e12ae/ff+7e12af/ff+7e12b0/ff+7e12b1/ff+7e12b2/ff+7e12a0/ff+7e12a1/ff+7e12a2/ff+7e12a3/ff+7e12a4/ff+7e12a5/ff+7e12a6/ff+7e12a7/ff+7e12a8/ff + cheat + description:Have all inventory items + code:7e12c2/ff+7e12c3/ff+7e12c4/ff+7e12b9/ff+7e12ba/ff+7e12bb/ff+7e12bc/ff+7e12bd/ff+7e12be/ff+7e12bf/ff+7e12c0/ff+7e12c1/ff + cheat + description:Have all statues + code:7e12c5/ff+7e12c6/ff+7e12c7/ff+7e12c8/ff + +cartridge sha256:10d94f1acd8108552eaefe9e26069e5d83e8fc3e847df7af318c2e25b53d39c3 + name: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 + name:Yu Yu 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:9b2cb155b270a78d122c46c44287f4973064dc96f75b0471c0843ca6a54bf41d + name:Zen-Nihon GT Senshuken (Japan) + cheat + description:Disable timer + code:7e16dc/00 + cheat + description:Always 1st + code:7e0cdc/00 + cheat + description:Lap modifier + code:7e149c/00 + +cartridge sha256:7d414b7f5941f1eddc35259a22accbbbd7b47c517dfcf8bad86c4dcfa9e50b1e + name:Zero the Kamikaze Squirrel (USA) + cheat + description:Jump higher + code:838542/f4+838a45/f4 + 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 + name: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 + cheat + description:Hit anywhere + code:009de0/80+009de1/1a + cheat + description:Multi-jump + code:00e031/80 + +cartridge sha256:b27e2e957fa760f4f483e2af30e03062034a6c0066984f2e284cc2cb430b2059 + name:Zombies Ate My Neighbors (USA) + cheat + description:Invincibility, hit anywhere, get items from anywhere (do not use martian gun) - both players + code:80f9a8/80+80d01e/00+80bf0c/00+80befe/00 + cheat + description:Invincibility - both players + code:80d01e/00 + cheat + description:Infinite health - both players + code:80d041/ea + cheat + description:Infinite weapons - both players + code:80ed47/00 + cheat + description:Infinite Keys on pick-up + code:80e910/00 + cheat + description:Infinite special items (except Keys and random Potions) + code:80eb58/00 + cheat + description:Infinite lives - both players + code:80cec5/bd + cheat + description:Victims are invincible + code:83a3ac/6b + cheat + description:Package of 99 Squirtgun shots worth 999 + code:80f8ad/09 + cheat + description:Package of 20 Soda Pop Cans worth 99 + code:80f8b8/99 + cheat + description:Package of 20 Tomatoes worth 99 + code:80f8ba/99 + cheat + description:Package of 5 Bazookas worth 999 + code:80f8b7/99 + cheat + description:Each First Aid Kit worth 9 on pick-up + code:80f915/09 + cheat + description:Each Key worth 9 on pick-up + code:80f907/09 + cheat + description:Only 1 victim to rescue per level (no bonus for rescuing all victims, game is over if Zombie eats a victim) + code:8085e8/01 + 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:80c86b/9c + cheat + description:Walk through walls + code:80e4cc/80+80e50b/80 + cheat + description:Continue with 1/2 health + code:80d960/05 + cheat + description:Start with 1/2 health + code:80887a/05 + cheat + description:Start with 10 lives + code:808880/09 + cheat + description:Start with 7 lives + code:808880/06 + cheat + description:Start with 1 life + code:808880/00 + cheat + description:Start with 50 shots in Squirtgun + code:808893/00 + cheat + description:Start with 100 shots in Squirtgun + code:808892/00 + cheat + description:Start with 550 shots in Squirtgun + code:808893/05 + cheat + description:Start with 950 shots in Squirtgun + code:808893/09 + cheat + description:Start with Soda Pop Cans instead of Squirtguns (Press B or Y to get item) + code:80889d/d8 + cheat + description:Start with Bazookas (Press B or Y to get item) + code:80889d/d6 + cheat + description:Start with Tomatoes (Press B or Y to get item) + code:80889d/da + cheat + description:Start with Fire Extinguishers (Press B or Y to get item) + code:80889d/ce + cheat + description:Start with Ice Pops (Press B or Y to get item) + code:80889d/dc + cheat + description:Start with Peppers (Press B or Y to get item) + code:80889d/de + cheat + description:Start with Martian Bubble Guns (Press B or Y to get item) + code:80889d/d0 + cheat + description:Start with Weed-eaters (Press B or Y to get item) + code:80889d/d2 + cheat + description:Start with Ancient Artifacts (Press B or Y to get item) + code:80889d/d4 + cheat + description:Start with Plates (Press B or Y to get item) + code:80889d/e0 + cheat + description:Start with Silverware (Press B or Y to get item) + code:80889d/e2 + cheat + description:Start with Footballs (Press B or Y to get item) + code:80889d/e4 + cheat + description:Start with 9 First Aid Kits instead of 1 + code:808895/09 + cheat + description:Start with Speed Shoes instead of First Aid Kit (Press B or Y to get item) + code:8088a0/0e + cheat + description:Start with a Monster Potion (Press B or Y to get item) + code:8088a0/10 + cheat + description:Start with a Ghost Potion (Press B or Y to get item) + code:8088a0/12 + cheat + description:Start with a Random Potion (Press B or Y to get item) + code:8088a0/14 + cheat + description:Start with a Pandora's box (Press B or Y to get item) + code:8088a0/1c + cheat + description:Start with a Skeleton key (Press B or Y to get item) + code:8088a0/1e + cheat + description:Start with a Decoy (Press B or Y to get item) + code:8088a0/20 + cheat + description:Start on level 2 + code:8085f1/02 + cheat + description:Start on level 3 + code:8085f1/03 + cheat + description:Start on level 4 + code:8085f1/04 + cheat + description:Start on level 5 + code:8085f1/05 + cheat + description:Start on level 6 + code:8085f1/06 + cheat + description:Start on level 7 + code:8085f1/07 + cheat + description:Start on level 8 + code:8085f1/08 + cheat + description:Start on level 9 + code:8085f1/09 + cheat + description:Start on level 10 + code:8085f1/0a + cheat + description:Start on level 11 + code:8085f1/0b + cheat + description:Start on level 12 + code:8085f1/0c + cheat + description:Start on level 13 + code:8085f1/0d + cheat + description:Start on level 14 + code:8085f1/0e + cheat + description:Start on level 15 + code:8085f1/0f + cheat + description:Start on level 16 + code:8085f1/10 + cheat + description:Start on level 17 + code:8085f1/11 + cheat + description:Start on level 18 + code:8085f1/12 + cheat + description:Start on level 19 + code:8085f1/13 + cheat + description:Start on level 20 + code:8085f1/14 + cheat + description:Start on level 21 + code:8085f1/15 + cheat + description:Start on level 22 + code:8085f1/16 + cheat + description:Start on level 23 + code:8085f1/17 + cheat + description:Start on level 24 + code:8085f1/18 + cheat + description:Start on level 25 + code:8085f1/19 + cheat + description:Start on level 26 + code:8085f1/1a + cheat + description:Start on level 27 + code:8085f1/1b + cheat + description:Start on level 28 + code:8085f1/1c + cheat + description:Start on level 29 + code:8085f1/1d + cheat + description:Start on level 30 + code:8085f1/1e + cheat + description:Start on level 31 + code:8085f1/1f + cheat + description:Start on level 32 + code:8085f1/20 + cheat + description:Start on level 33 + code:8085f1/21 + cheat + description:Start on level 34 + code:8085f1/22 + cheat + description:Start on level 35 + code:8085f1/23 + cheat + description:Start on level 36 + code:8085f1/24 + cheat + description:Start on level 37 + code:8085f1/25 + cheat + description:Start on level 38 + code:8085f1/26 + cheat + description:Start on level 39 + code:8085f1/27 + cheat + description:Start on level 40 + code:8085f1/28 + cheat + description:Start on level 41 + code:8085f1/29 + cheat + description:Start on level 42 + code:8085f1/2a + cheat + description:Start on level 43 + code:8085f1/2b + cheat + description:Start on level 44 + code:8085f1/2c + cheat + description:Start on level 45 + code:8085f1/2d + cheat + description:Start on level 46 + code:8085f1/2e + cheat + description:Start on level 47 + code:8085f1/2f + cheat + description:Start on level 48 + code:8085f1/30 + cheat + description:Start on bonus level Son of Dr. Tongue + code:8085f1/32 + cheat + description:Start on bonus level Day of the Tentacle + code:8085f1/33 + cheat + description:Start on bonus level Someplace Very Warm + code:8085f1/34 + cheat + description:Start on bonus level Curse of the Pharaohs + code:8085f1/35 + cheat + description:Start on bonus level Mushroom Men + code:8085f1/36 + cheat + description:Start on bonus level Cheerleaders vs. the Monsters + code:8085f1/37 + cheat + description:Start on credit level Monsters Among Us + code:8085f1/31 + 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:c8497ee7a25d1eb7cf4ef1604b2fd7836a64c5c30e8334f7a48f1ed2a27b5cc1 + name:1942 (USA, Europe) + cheat + description:Invincibility + code:2c8b/28/18+18c5/28/18 + cheat + description:Hit anywhere + code:19ec/26/00+19f5/1b/c9 + +cartridge sha256:da5eb5a56ab97f7b6779fa70b894cb94abf351aaf0c9430bd775156528a334a0 + name:4-in-1 Fun Pak (USA, Europe) + cheat + description:Chess - move anywhere + code:5ed0/be/77+5ed1/28/18 + cheat + description:Checkers - move anywhere + code:54bc/28/18+54cd/20/18+539c/28/18 + +cartridge sha256:d16375478a455270b758eb61f9c9fb380fbf5187e32a8fe3fc93ba4f4a330959 + name:4-in-1 Fun Pak Volume II (USA, Europe) + cheat + description:Solitaire - move cards anywhere + code:48e3/16/00+4559/7d/00 + +cartridge sha256:f66a6c521c706bf3bf4536731becacf1336a711bd40658d853646cd6b20fdb2b + name:720 Degrees (USA, Europe) + cheat + description:Jump to get 1000 points + code:7da4/0c/00 + +cartridge sha256:52ee7edb02d42bfc7a9a5a52df082424cd8d9b3cbd2aa47fc84bd32f79cd059a + name:A-mazing Tater (USA) + cheat + description:Walk anywhere + code:0f68/1d/00 + +cartridge sha256:fa9fe020c07a5194dcd61ab33be44779ce5c9de4074fac3eb68bae9311d7c2f6 + name:Action Man - Search for Base X (USA, Europe) + cheat + description:Invincibility + code:66d8/ea/fa + cheat + description:Hit anywhere + code:673a/24/00 + +cartridge sha256:18746d4607424feca05aee056c3ed5f840195c792409881e9145d4bd96800dbd + name:Addams Family, The - Pugsley's Scavenger Hunt (USA, Europe) + cheat + description:Invincibility + code:3915/35/c9 + cheat + description:Infinite health + code:3915/35/be + cheat + description:Infinite hearts + code:3911/c1/00 + cheat + description:Infinite lives + code:0428/ea/fa + cheat + description:Infinite lives (alt) + code:0427/3d/be + cheat + description:When game begins, go through any door, enter secret bonus room, disable to exit room + code:13de/e6/af+13df/1f/3c+13e1/7f/7d + cheat + description:Lose 1 heart to become invincible + code:0adc/ea/fa + cheat + description:Start each life with 1 heart + code:7fe9/03/01 + cheat + description:Start each life with 5 hearts + code:7fe9/03/05 + cheat + description:Start with 1 life + code:0217/05/01 + cheat + description:Start with 10 lives + code:0217/05/0a + +cartridge sha256:f267738e785f43a09c92511bcbb7f16d2e8acbe43b36f75bee35ff3fb0c21621 + name:Addams Family, The (USA) + cheat + description:Invincibility + code:4ada/ea/be+09d7/ea/c9 + cheat + description:Infinite health + code:1f35/35/be + cheat + description:Infinite lives + code:5dce/35/be + cheat + description:Infinite weapon + code:7868/35/be + cheat + description:Hit anywhere + code:49fd/08/00 + +cartridge sha256:7771919d5f5a114fb8685345eab290be22e99c59d8798ed9c5f29e3079c11c56 + name:Adventure Island (USA, Europe) + cheat + description:Invincibility + code:1653/ea/be + cheat + description:Infinite time + code:1690/35/be + cheat + description:Infinite lives + code:7ac8/35/be + cheat + description:Hit anywhere + code:20e1/f6/00+2102/28/18 + +cartridge sha256:bbb38ee1e9877404dd999ef7067aa238a1039ca603b987f8adeff4488e318331 + name:Adventure Island II - Aliens in Paradise (USA, Europe) + cheat + description:Invincibility + code:1ad8/ea/c9 + cheat + description:Infinite time + code:0e2c/ea/c9 + cheat + description:Infinite lives + code:46dd/01/00 + cheat + description:Infinite lives (alt) + code:46dc/d6/be + cheat + description:Hit anywhere + code:1ca1/c8/c9+1922/d2/c3 + cheat + description:No gradual loss of energy, but can still be drained by obstacles and enemies + code:0e28/01/00 + cheat + description:Once you collect any non-throwable object, you can't lose it from menu + code:5d51/01/00 + cheat + description:Start with 1 of each power-up + code:4037/af/3c + cheat + description:Start with 1 life + code:406d/03/00 + cheat + description:Start with 6 lives + code:406d/03/05 + cheat + description:Start with 9 lives + code:406d/03/08 + cheat + description:Start on level 1-4 + code:4057/01/08 + +cartridge sha256:4c156c4d826b9cba5741feb621de60c6294adb36553fc43971794bd2a4ffb34a + name:Adventures of Lolo (Europe) (SGB Enhanced) + cheat + description:Walk anywhere + code:4928/06/00 + +cartridge sha256:50c3a2193005c9134699ab00de16510fb946db10cdbc33bfacd8a3132926b72e + name:Adventures of Pinocchio, The (Unknown) (Proto) + cheat + description:Invincibility + code:14c0/e0/c9 + +cartridge sha256:ee582fc5f302c430556703c553c3a49db8e05847ba9b13d0f6bc018657ac8593 + name:Adventures of Rocky and Bullwinkle and Friends, The (USA) + cheat + description:Invincibility + code:144c/c0/c9 + cheat + description:Invincibility after first hit + code:1428/ea/fa + cheat + description:Infinite energy + code:1496/ea/fa + cheat + description:Die in one hit + code:1453/78/01 + cheat + description:Start with 1 life + code:515c/02/00 + cheat + description:Start with 10 lives + code:515c/02/09 + cheat + description:Start with 15 lives + code:515c/02/0e + cheat + description:Start with 1 mooseberry - 1st life + code:5161/03/00 + cheat + description:Start with 5 mooseberries - 1st life + code:5161/03/04 + cheat + description:Start with 10 mooseberries - 1st life + code:5161/03/09 + cheat + description:Start with 1 mooseberry - 2nd life + code:14bc/03/00 + cheat + description:Start with 5 mooseberries - 2nd life + code:14bc/03/04 + cheat + description:Start with 10 mooseberries - 2nd life + code:14bc/03/09 + +cartridge sha256:e946c9e9c819cb9ba37eb1718903aa3cd5ea101d5890e27681b370a44fe0f1d8 + name:Adventures of Star Saver, The (USA, Europe) + cheat + description:Invincibility (blinking) + code:1bd9/ea/c9 + cheat + description:Infinite lives + code:11a7/35/be + cheat + description:Infinite life ropes + code:2389/c6/00 + cheat + description:Infinite shields on pick-up + code:2163/c6/00+1bb7/c6/00+1bdb/c6/00 + cheat + description:Hit anywhere + code:1dc4/38/18+1db7/38/18 + cheat + description:49 life ropes on pick-up + code:1c94/34/75 + cheat + description:Start with all power-ups (except shields) - 1st life only + code:117f/af/3c + cheat + description:Start with 2 lives + code:1199/03/02 + cheat + description:Start with 4 lives + code:1199/03/04 + cheat + description:Start with 6 lives + code:1199/03/06 + +cartridge sha256:29a39e0ccf66a1eb5d456e027b2c1abcd9d2ea8bbf6b6d19d86fff61a493e008 + name:Adventures of the Smurfs, The (Europe) (En,Fr,De,Es,It,Nl) + cheat + description:Infinite health + code:1b9f/09/00 + +cartridge sha256:cb1d45fca310ef4b7013d094663bddcd209362f272bb3e54ce10540828c8c212 + name:Aerostar (USA, Europe) + cheat + description:Invincibility + code:2aad/d2/03+2aae/30/17+1707/3e/f0 + cheat + description:Infinite lives + code:16f1/e0/f0 + cheat + description:Infinite jump + code:1870/e0/be + cheat + description:Hit anywhere + code:2e93/c0/c9+2fe0/2f/3e+2fdf/30/18 + +cartridge sha256:efee40857f6310f5437732198d998779711f86d80673e72cfc93a3378ca26303 + name:AirForce Delta (USA) + cheat + description:Invincibility + code:7568/38/18 + +cartridge sha256:8e45c7d6b5498d4048653e92b2a792bb2eea00b2897a7711fb7be1b6bed0534f + name:Akumajou Dracula - Shikkoku Taru Zensoukyoku - Dark Night Prelude (Japan) (SGB Enhanced) + cheat + description:Fast walk left + code:4df3/c5/11 + cheat + description:Fast walk right + code:4dcc/c5/11 + cheat + description:Fast jump left + code:542c/c5/11 + cheat + description:Fast jump right + code:540b/c5/11 + +cartridge sha256:4940bf228fb2095daa6b382d84ebd0cf05cd81fc2e6e5244a03ab458593e53f5 + name:Aladdin (USA) (SGB Enhanced) + cheat + description:Infinite health + code:0dca/90/be + cheat + description:Infinite lives + code:1ce5/3d/be + cheat + description:Infinite Apples + code:216d/3d/be + cheat + description:Hit anywhere - Sword + code:5c54/c0/00+5c4a/d8/00 + +cartridge sha256:944df9d20c715099ef6bf0e418d928684b284d4a4562391a661a7978fa7f5417 + name:Alfred Chicken (USA) + cheat + description:Invincibility + code:1546/e0/be + cheat + description:Infinite time + code:1bc2/ce/be + cheat + description:Infinite lives + code:1be9/93/be + +cartridge sha256:4790f55d0917f4418c63d29c5c528362b1c7ae39546f6fc3ae94e867d1e9f270 + name:Alien 3 (USA, Europe) + cheat + description:Almost infinite health + code:1768/ea/fa + cheat + description:Infinite tries + code:1692/ea/fa + cheat + description:Infinite shots per clip on pick-up + code:2f9c/c3/00 + cheat + description:Infinite magazine clips on pick-up + code:2b45/ea/fa + cheat + description:50 shots per magazine clip + code:5a3c/3c/32 + cheat + description:75 shots per magazine clip + code:5a3c/3c/4b + cheat + description:100 shots per magazine clip + code:5a3c/3c/64 + cheat + description:Start with 1/2 health + code:2442/ff/8e + cheat + description:Start with 4 tries + code:1b27/03/04 + cheat + description:Start with 6 tries + code:1b27/03/06 + cheat + description:Start with 10 tries + code:1b27/03/0a + +cartridge sha256:073f82f8bf4ab9d15569b5a7a4aa152351c177b9072a9481563b26562215f55b + name:Alien Olympics (Europe) + cheat + description:Meter never decreases + code:4d7d/9a/c9 + cheat + description:Hyper velocity + code:4d7a/93/be + cheat + description:Freeze time + code:5c6d/3c/be + +cartridge sha256:e1a71b44a1c5dcacfe90e76907766fd48518482950531bee34208114d4a03e53 + name:Alien vs Predator - The Last of His Clan (USA) + cheat + description:Infinite lives + code:2fd4/35/be + cheat + description:Infinite energy + code:04ef/3d/be + cheat + description:Infinite HP + code:3bba/ea/be + +cartridge sha256:ed8070e011713527bdc03e2b9cec9f9c4a7e3aaa00e57e8786a186b265da1bb2 + name:Alleyway (World) + cheat + description:Infinite lives + code:07ee/3d/be + cheat + description:Hit anywhere - Paddle + code:0cd1/0f/00 + +cartridge sha256:04c5507efe0beb40ea1a887538bd8a04acc70622bf9ef800951a71f4804c9cbc + name:All-Star Baseball 99 (USA) + cheat + description:Infinite time + code:665e/01/00 + cheat + description:Computer's 3-pt. shots worth 25 points + code:211f/03/19 + cheat + description:Computer's 3-pt. shots worth 17 points + code:211f/03/11+2118/c1/11 + cheat + description:Computer makes almost all shots + code:2ef7/fe/36+26f8/04/09 + cheat + description:Computer can't score against you + code:2115/36/34+2116/c1/00 + cheat + description:Shot clock for human player is 9 seconds - 1-on-1 game + code:65fb/24/09+233d/24/09+65c4/24/09 + +cartridge sha256:21d507b3ee6acbde8427d8e5cc5de1083eec03df8bd55745e4384ee0be14460e + name:All-Star Baseball 2000 (USA, Europe) + cheat + description:Balls are considered strikes + code:53f8/0c/00+53ea/1a/00+53dc/28/00 + +cartridge sha256:c0bd16cfe156f36a0bcbf70c537a172ad4780641da6e23eacf47cc5f155d2640 + name:All-Star Baseball 2001 (USA) + cheat + description:Balls are considered strikes + code:53f7/30/3e+53ea/1a/00+53dc/28/00 + +cartridge sha256:995dc210efdf7c12ae7d4c731e2ea0ae758554fc7f545dae72aa97a99dd10ed7 + name:Alone in the Dark - The New Nightmare (USA) (En,Fr,Es) + cheat + description:Invincibility + code:43d5/38/18 + +cartridge sha256:4f6450321ee163d5fd8a942816b10af1ce41bbcad62185a550c97b16cac125a1 + name:Altered Space - A 3-D Alien Adventure (USA) + cheat + description:Infinite energy (air) + code:14f1/d6/3a + +cartridge sha256:db4e590899aab75bceb31e84a2ec77c34b561838a61fd9dc9fda004a0507a01c + name:Amazing Penguin (USA, Europe) + cheat + description:Invincibility + code:119f/c0/c9 + cheat + description:Infinite lives + code:2228/3d/be + cheat + description:Infinite time + code:16c4/35/be + +cartridge sha256:a52b036d637b59950749de679208785480b8ad2d5e95c0ea2a6f638750cc645e + name:Amazing Spider-Man, The (USA, Europe) + cheat + description:Hit anywhere + code:28ea/d8/00+288c/65/00 + +cartridge sha256:c4eb652e47d458b8faba7fd753a3eff8e875658f2b4cee0ae6194dc8cb0783e7 + name:Amida (Japan) + cheat + description:Invincibility + code:03eb/06/00+05e2/20/18 + +cartridge sha256:4d2cca30eb8804ed6fffa07da2dea1992ff1ce12bded2195d05cf912b879b951 + name:Animaniacs (USA) (SGB Enhanced) + cheat + description:Multi-jump + code:4a0e/c0/00+4a0b/c0/00 + cheat + description:Get Stars from anywhere + code:4060/40/00 + +cartridge sha256:23b432a52aefcca6731fccace793f58ee5cac030b27ad18ac8d354430a388f01 + name:Arcade Classics - Battlezone & Super Breakout (USA, Europe) (SGB Enhanced) + cheat + description:Paddle hits ball anywhere + code:0f6d/79/00+0f70/38/18 + +cartridge sha256:7cebe1e446c56061f71e94b99cf6dfb7267cac0e21cb37b0f9a8118d5a127eb0 + name:Arcade Classic No. 2 - Centipede & Millipede (USA, Europe) (SGB Enhanced) + cheat + description:Centipede - Invincibility + code:5628/d2/c3 + cheat + description:Millipede - Invincibility + code:7543/ea/fa+7573/b8/37 + +cartridge sha256:b9bb5b4d3274a7f4c443bd8fb2bf5f1018358d76a54c01e3a53f7ff610fa4fa6 + name:Aretha (Japan) + cheat + description:Walk anywhere + code:562e/01/00 + +cartridge sha256:afaf5380f970c2f07ff585a84bab50295fd17888591511cc1d71e8d7ddad7599 + name:Aretha II (Japan) + cheat + description:Walk anywhere + code:4cce/01/00 + +cartridge sha256:c504be420e7bfdcf9905fc4d6674fd4b7466e832976a7a48660b901086536d1f + name:Army Men (USA, Europe) (En,Fr,De) + cheat + description:Invincibility + code:7d00/38/18 + cheat + description:Infinite health + code:0c33/c0/c9 + cheat + description:Infinite ammo - all weapons + code:0cd1/35/00 + cheat + description:Get items from anywhere + code:3345/d2/fa+332c/d2/fa + +cartridge sha256:6da0357c4b00a1b8393f4e9fb5dbbe620e9b1680a7c4032303a058178fa245b7 + name:Army Men 2 (USA, Europe) (En,Fr,De) + cheat + description:Invincibility + code:796a/20/18 + cheat + description:Infinite health + code:772a/c0/c9 + cheat + description:Infinite ammo - all weapons + code:0cda/35/00 + +cartridge sha256:801660458dc65c29701f21985943ba84c1f55cf57c9be3527b17548c33be260d + name:Asterix - Search for Dogmatix (Europe) (En,Fr,De,Es,It,Nl) + cheat + description:Invincibility + code:1043/28/3e+47b2/c8/c9 + cheat + description:Hit anywhere + code:1d14/d2/fa + +cartridge sha256:b34d96392f38b6b7c5462ce166f26e5c42f356dff6cff74ef9ac3e940ad7c6de + name:Asteroids (USA, Europe) + cheat + description:Infinite lives + code:0383/35/00 + cheat + description:No extra rocks as you go up levels + code:2a7e/34/00 + cheat + description:Invincible against rocks (from starting/center position only) + code:2cb4/07/01+039c/35/00 + cheat + description:Start with 1 life + code:0315/03/01 + cheat + description:Start with 5 lives + code:0315/03/05 + cheat + description:Start with 9 lives + code:0315/03/09 + +cartridge sha256:3f0688ed9219c44ce133647f0668cde50fdcba7ed8f04c34c3a0fc5ce596bfe5 + name:Asteroids (USA, Europe) + cheat + description:Invincibility + code:5549/d0/c9 + +cartridge sha256:d5306853c8dc7d402808cc340064fdf48d930bbc5a531c8ece3661bfa7f7ff55 + name:Atlantis - The Lost Empire (USA, Europe) + cheat + description:Infinite energy + code:52ac/ea/fa + cheat + description:Infinite lives + code:1c3a/ea/fa + cheat + description:Start with 9 lives + code:343e/03/09 + +cartridge sha256:2df8eb5d48a204d9609e0c12fed81304cc0b23421c5015ab2296d51ffc8b36ad + name:Atomic Punk (USA) + cheat + description:Invincibility and infinite time + code:025e/47/09+025d/94/75+0976/ff/91 + cheat + description:Hit anywhere - Mode A + code:1672/38/20+1671/10/3d+1670/fe/8b+166f/1a/f0 + cheat + description:Hit anywhere - Mode B + code:57ee/d8/c8+57ed/10/00+57ea/4a/c3+57e9/48/00+57e8/cd/21 + +cartridge sha256:ac3656cb5b86c13ad67a486d11d21643fdec306500d989fbd770b5939bab22f0 + name:Attack of the Killer Tomatoes (USA, Europe) + cheat + description:Infinite health + code:0adb/35/00 + cheat + description:Infinite lives + code:3945/ea/fa + +cartridge sha256:0d80b2ad776053f50c3eb0e0e32c675f24acf94923bf3ac4c156c7c28bc76a6e + name:Avenging Spirit (USA, Europe) + cheat + description:Invincibility except against spikes + code:3592/fa/c9+2e82/c0/c9 + cheat + description:Invincibility against spikes + code:554d/c0/c9 + cheat + description:Infinite health except if weapon is used against you + code:35af/ea/fa+2ec2/ea/fa + cheat + description:Infinite L health except against spikes + code:2eb5/ea/fa + cheat + description:Hit anywhere + code:2d4d/ea/fa+2d30/33/00 + cheat + description:Get items from anywhere + code:6550/ca/fa + cheat + description:Multi-jump + code:4fa6/d8/00 + cheat + description:Start with 1/2 health + code:332b/14/0a + cheat + description:Start with 1/4 health + code:332b/14/05 + cheat + description:Start with 3/4 health + code:332b/14/0f + cheat + description:Start on level 2 (brings you back to level 2) + code:39b9/01/02 + cheat + description:Start on level 4 (brings you back to level 2) + code:39b9/01/04 + cheat + description:Start on level 6 (brings you back to level 2) + code:39b9/01/06 + +cartridge sha256:6340ba86bf9500ece66d8acbcca90c4ab8c42de26804fde393311d62eaab3b61 + name:B.C. Kid 2 (Europe) (SGB Enhanced) + cheat + description:Invincibility + code:5aab/12/00+4f26/20/18 + cheat + description:Hit anywhere + code:5dce/28/18+5c08/cd/fa + +cartridge sha256:1b48b454bb421836c33c2d572c61f69145a077ebcecbf8194dfb05fc6581ff82 + name:Balloon Kid (USA, Europe) + cheat + description:Invincibility against fire + code:5604/09/00 + +cartridge sha256:c71663c9172c69b3daded65aaaa3735d1f50379a471af345e8421a6a6c9aaa98 + name:Barbie - Game Girl (USA, Europe) + cheat + description:Infinite HP + code:3aa5/ea/fa + cheat + description:Infinite continues + code:6b95/ea/fa + cheat + description:1 continue + code:27ad/03/01 + cheat + description:4 continues + code:27ad/03/04 + cheat + description:8 continues + code:27ad/03/08 + cheat + description:Start with 2 HP + code:277a/05/02 + cheat + description:Start with 4 HP + code:277a/05/04 + cheat + description:Start with 8 HP + code:277a/05/08 + +cartridge sha256:86e5b7037d7c61248adfdc316d61b5c58fe46c5d3fe376bcdfeda9d6538b197d + name:Bart Simpson's Escape from Camp Deadly (USA, Europe) + cheat + description:Infinite health + code:07fa/ea/fa + +cartridge sha256:debc4ac9d7587166f4754d99955c8ed8c5ae014bb10e91764fe9e632cdbcb3fc + name:Baseball (World) + cheat + description:Balls are counted as strikes + code:6047/d8/00 + +cartridge sha256:0eedbdd6530f30adcc8ee88b32e852b7983de8bba8122ddd2c1adaf2805a454c + name:Bases Loaded for Game Boy (USA) + cheat + description:No walks + code:4c63/3c/00 + cheat + description:1 ball and you walk + code:4c66/04/00 + cheat + description:2 balls and you walk + code:4c66/04/02 + cheat + description:3 balls and you walk + code:4c66/04/03 + cheat + description:5 balls and you walk + code:4c66/04/04 + cheat + description:Outs aren't counted (base runners will still be taken out) + code:4c77/3c/00 + cheat + description:Number of outs to retire the side varies + code:738f/03/00 + cheat + description:Strikes aren't counted + code:4c43/34/00 + cheat + description:1 strike and you're out + code:4c46/03/01 + cheat + description:2 strikes and you're out + code:4c46/03/02 + cheat + description:5 strikes and you're out + code:4c46/03/05 + cheat + description:No scoring - disable to score + code:081f/01/00+0811/01/00 + +cartridge sha256:2eb0708771791f2e126bd97e672a365c70c3d7064ecc391433545352133dad60 + name:Battle Crusher (Japan) (SGB Enhanced) + cheat + description:Hit anywhere - P1 + code:53de/05/00 + cheat + description:Invincibility (except throws) - P1 + code:53cc/28/18 + cheat + description:Blocking disabled - both players + code:23cb/01/00 + +cartridge sha256:ea30dd015164e6895547d518a96cee60a17767f985b68c50d07ca560c80956ae + name:Battle of Olympus, The (Europe) (En,Fr,De,Es,It) + cheat + description:Hit anywhere + code:2a7b/b7/37 + cheat + description:Get items from anywhere (press down) + code:61a6/11/00 + +cartridge sha256:c38fc7e54ed27bd82c9829a6535f5be0d2ff81822863ab9c088bf345ab01b734 + name:BattleCity (Japan) + cheat + description:Invincibility + code:3668/da/c3 + cheat + description:Invincibility - Base + code:3e99/01/00 + +cartridge sha256:9ac1f4a299d32ba21cf65f67ab210afeb4c629adbd8e5779f76b6667ca3a0a4a + name:Batman - The Animated Series (USA, Europe) + cheat + description:Almost invincible - disable if you get stuck + code:2592/cd/21 + cheat + description:Infinite energy + code:25ef/77/00 + cheat + description:Infinite batarangs + code:2ba3/35/00 + cheat + description:One hit kills on most enemies + code:1615/91/af + cheat + description:Each batarang pick-up is worth 9 + code:4a70/05/09 + cheat + description:Most enemies don't die + code:1616/77/00 + cheat + description:Most enemies are harder to kill + code:4fcd/02/0a + cheat + description:Start with 7 batarangs + code:2496/af/00+249a/ea/fa + cheat + description:Start with very little energy + code:248e/07/01 + cheat + description:Start with about half energy + code:248e/07/04 + cheat + description:Start with about 2x energy + code:248e/07/0e + +cartridge sha256:d0e4ff010ab013e519abd9950ab465f3369c76e23d82927c0f39b5e259d4febf + name:Batman - The Video Game (World) + cheat + description:Invincibility + code:018d/ff/a1 + cheat + description:Infinite health + code:4ec1/ea/fa + cheat + description:Infinite health (alt) + code:0104/c0/c8 + cheat + description:Infinite lives + code:095d/ea/fa + cheat + description:Infinite lives (alt) + code:0103/c0/c7 + cheat + description:Hit anywhere + code:4275/54/00+2e16/30/18+2e17/12/23 + cheat + description:Hit anywhere - Bosses + code:2eca/25/28+2ec9/38/18 + cheat + description:Multi-jump + code:375b/28/18 + +cartridge sha256:152fc252bba7130e786d408eed310b3009b8e05834f8003dfbf514ec804cbaea + name:Batman - Return of the Joker (USA, Europe) + cheat + description:Invincibile against enemies + code:54ad/11/00+54b2/e6/c6 + cheat + description:Infinite batarangs on pick-up + code:1996/3d/00 + cheat + description:Infinite continues + code:2ab5/c7/00 + cheat + description:Select any weapon from menu + code:56bc/e6/00 + cheat + description:Hit anywhere + code:26b5/6c/00+26ac/75/00 + cheat + description:Multi-jump + code:1f4b/28/18+2003/ca/c3+1a34/22/00 + cheat + description:5 Batarangs on pick-up + code:4da0/0a/05 + cheat + description:20 Batarangs on pick-up + code:4da0/0a/14 + cheat + description:40 Batarangs on pick-up + code:4da0/0a/28 + cheat + description:1 continue + code:0207/05/02 + cheat + description:9 continues + code:0207/05/0a + cheat + description:Start with max of 3 HP + code:f000/ba/00 + cheat + description:Start with max of 8 HP + code:0201/0a/10 + +cartridge sha256:bfb324176949811c6e116cb8e3d434b4937634d95b4f9bdfb54e0157c612dea0 + name:Batman Beyond - Return of the Joker (USA) + cheat + description:Hit anywhere + code:4e67/d0/00 + +cartridge sha256:519ca6523e54b67a4b4dcc7f525d56df986e0d77c84699dcf9e022f0ae6fbd0e + name:Battle Arena Toshinden (USA) (SGB Enhanced) + cheat + description:Hit anywhere - both players + code:4e01/ca/fa + cheat + description:Blocking disabled - both players + code:6a8f/02/00 + +cartridge sha256:b9909506f566ea7998d6170e9610bad62dbda7d38e42830cd187592e262acfed + name:Battle Unit Zeoth (USA, Europe) + cheat + description:Infinite health + code:1233/e0/f0 + +cartridge sha256:dfa8ec0354c2c364398686cac91545dd2729ab4e0784e6f0b3a23cfe2f7d253b + name:Battletoads (USA, Europe) + cheat + description:Invincibility + code:277d/01/04+277c/28/36 + cheat + description:Infinite lives and energy + code:0cca/ea/fa+17b0/c6/00 + cheat + description:Infinite continues + code:17c2/35/00 + cheat + description:One hit kills + code:2e9a/15/00 + cheat + description:Keep axe after dying + code:7d91/ea/fa + cheat + description:Big arms that hack at you from caves in level 1 do not move + code:1542/01/00 + cheat + description:1 continue + code:77f2/03/01 + cheat + description:5 continues + code:77f2/03/05 + cheat + description:10 continues + code:77f2/03/0a + cheat + description:Start with 1 life + code:77ed/03/00 + cheat + description:Start with 6 lives + code:f000/ba/00 + cheat + description:Start with 10 lives + code:77ed/03/09 + cheat + description:Start with 2 extra HP - after 1st life + code:7e38/0c/0e + cheat + description:Start 1st life with 2 extra HP + code:0326/0c/0e + cheat + description:Start 1st life with 1/2 energy + code:0326/0c/06 + cheat + description:Start with only 1/2 energy - after 1st life + code:7e38/0c/06 + +cartridge sha256:e10716e26a1b4edddc8c8fbf24cdad4decd054e555c77a6c0cd64fe283fa2287 + name:Battletoads in Ragnarok's World (USA) + cheat + description:Invincibility - beat'em up levels + code:2cfd/fa/ea + cheat + description:Infinite health + code:0871/ea/fa + cheat + description:Infinite lives + code:1a31/35/7e + +cartridge sha256:ffb240c74aac4527af2c268e1d7cf4f1b44229ff624d22966b5679e301617465 + name:Beast Fighter (Asia) (Unl) + cheat + description:Invincibility + code:57f6/c8/00+5800/c0/00+57ff/00/01+57fe/fe/3e + cheat + description:Infinite time + code:2db6/c8/c9 + cheat + description:One hit kills on bosses + code:46fa/02/00 + +cartridge sha256:1cbdbf760d84d62933f1b66410a80dda4185b138d964e6ec51780d391d09143d + name:Beauty and the Beast - A Board Game Adventure (USA) (SGB Enhanced) + cheat + description:Access credits in options menu + code:6915/03/04 + +cartridge sha256:436918dc75ffe606f458206caad6c063369ecbf650afcf96499eb98b2b85a72f + name:Beetlejuice (USA) + cheat + description:Infinite health + code:37e4/ea/fa + cheat + description:Infinite lives + code:37ef/ea/fa + +cartridge sha256:0e825ec2c23a16fac1f33cdfd7402f218e3813961e95ddb4ca9fed19bfd79d04 + name:Bill & Ted's Excellent Game Boy Adventure (USA, Europe) + cheat + description:Invincibility + code:2eb7/28/18 + +cartridge sha256:378435aa66290a4d8a930e000eddf08dcb7b00fd36341991b0abedc488bb8c5d + name:Bill Elliott's NASCAR Fast Tracks (USA) + cheat + description:Start with burst of speed + code:f000/ba/00 + cheat + description:Infinite fuel + code:5465/35/00 + cheat + description:Collisons with cars don't affect speed + code:4d46/35/00 + cheat + description:Collisions barely affect speed + code:43c5/77/00+523f/77/00+50bd/3d/00 + cheat + description:Start with 1 lap - ignore lap timer and counter + code:4731/57/1e+4732/13/02 + cheat + description:Start with 3 laps - ignore lap timer and counter + code:4731/57/1e+4732/13/04 + cheat + description:Start with 9 laps - ignore lap timer and counter + code:4731/57/1e+4732/13/0a + +cartridge sha256:692e62d9e0048350256ee124d55c6ef225dc2bb54e0808fd882312d4dcaf0f28 + name:Bionic Commando (USA) + cheat + description:Infinite energy + code:4e6e/ea/fa + cheat + description:Infinite lives + code:160a/df/00 + cheat + description:Infinite continues + code:1404/df/00 + cheat + description:2 continues + code:7481/03/02 + cheat + description:4 continues + code:7481/03/04 + cheat + description:6 continues + code:7481/03/06 + cheat + description:Start with 8 energy + code:15e0/af/84 + cheat + description:Start with 2 lives + code:140e/03/02 + cheat + description:Start with 4 lives + code:140e/03/04 + cheat + description:Start with 6 lives + code:140e/03/06 + +cartridge sha256:9338af642104f7f286687b2e6e55759917c0db35bc89ef398a92c18570bff681 + name:Blades of Steel (USA) + cheat + description:Set length of game to 1:00 + code:4165/20/01 + cheat + description:Set length of game to 3:00 + code:4165/20/03 + cheat + description:Set length of game to 9:00 + code:4165/20/09 + cheat + description:Opponent's energy doesn't go up again and yours does + code:7793/3c/00 + cheat + description:Invincible in fights + code:779f/ea/fa + cheat + description:3 penalty shots in shoot-out + code:55b6/05/03 + cheat + description:5 penalty shots in shoot-out + code:55b6/05/05 + cheat + description:9 penalty shots in shoot-out + code:55b6/05/09 + +cartridge sha256:e0258871c84d18cb0b4cf9a41e1be2ad010c04fad45d97b23baca7746edcfa76 + name:Blaster Master - Enemy Below (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:0ef3/c0/c9+1681/c0/c9 + cheat + description:Invincibility when falling from very high (on foot) + code:1682/21/c9 + cheat + description:Hit anywhere + code:6dd5/cd/fa+6dbe/28/18 + cheat + description:Get items from anywhere + code:6c3b/28/18 + cheat + description:Multi-jump (vehical) + code:4605/28/18+45ff/28/3e + cheat + description:Multi-jump (on foot) + code:4d05/c0/00 + cheat + description:Infinite POW meter - Vehicle + code:0140/c1/24 + cheat + description:Infinite POW meter - Jason + code:0140/c1/25 + cheat + description:Infinite HOV meter - Vehicle + code:0140/c1/26 + cheat + description:Infinite Gun meter - Jason + code:0140/c1/27 + cheat + description:Infinite Homing Missiles + code:0163/c1/28 + cheat + description:Infinite Thunderbolts + code:0163/c1/29 + cheat + description:Infinite 3-Way Missiles + code:0163/c1/2a + cheat + description:All vehicle upgrades + code:01ff/c1/06+01ff/c1/07 + +cartridge sha256:01bb3527ea235380895b8df07a864829b2ad9e399f8cd90bb816110e2bfb1693 + name:Blaster Master Boy (USA) + cheat + description:Invincibility + code:2d06/24/10+2d05/28/18 + cheat + description:Hit anywhere + code:159b/af/7b + cheat + description:One hit kills - normal enemies + code:37cb/3d/af + cheat + description:One hit kills - bosses + code:3849/30/3e + +cartridge sha256:04aeb80ff35bd863c3922ad9b8cac7ee379e78feac4ce3cef2d58ccca142fc03 + name:Blues Brothers, The (USA, Europe) + cheat + description:Infinite energy + code:6af2/77/00 + cheat + description:Infinite encores + code:0805/ea/fa + cheat + description:Start with 3 encores (continues) + code:037c/02/03 + cheat + description:Start with 7 encores + code:037c/02/07 + cheat + description:Start with 9 encores + code:039c/02/09 + cheat + description:Start with 5 lives + code:4015/02/05 + cheat + description:Start with 7 lives + code:4015/02/07 + cheat + description:Start with 9 lives + code:4015/02/09 + +cartridge sha256:9053443a6c786a54bebc2fa9c10acd3875887134c953e5bdf0a07dc554721fb6 + name:Bo Jackson - Two Games in One (USA) + cheat + description:Baseball - 1 ball and you walk + code:3f13/04/01 + cheat + description:Baseball - 2 balls and you walk + code:3f13/04/02 + cheat + description:Baseball - 5 balls and you walk + code:3f13/04/05 + cheat + description:Baseball - Strikes aren't counted - ignore message, you need 4 balls to walk + code:3ec5/34/00 + cheat + description:Baseball - Outs aren't counted + code:73e8/34/00 + cheat + description:Baseball - 1 strike and you're out + code:3e87/03/01 + cheat + description:Baseball - 2 strikes and you're out + code:3e87/03/02 + cheat + description:Baseball - No scoring - disable to score + code:783c/34/00+7826/34/00 + cheat + description:Football - Infinite time + code:356e/e0/f0 + cheat + description:Football - Infinite timeouts + code:5012/35/00 + cheat + description:Football - Always 1st down + code:47d0/e0/f0 + cheat + description:Football - Start with 1 timeout + code:4068/03/01 + cheat + description:Football - Start with 2 timeouts + code:4068/03/02 + cheat + description:Football - Start with 10 timeouts + code:4068/03/0a + +cartridge sha256:195f5a9e97bfec6f071bfd6b82a39ffa25185b687a26a1f2937f9718c4d4d16e + name:Boggle Plus (USA) + cheat + description:Infinite time + code:25af/01/00 + cheat + description:1-minute game + code:26bc/03/01 + cheat + description:5-minute game + code:26bc/03/05 + cheat + description:9-minute game + code:26bc/03/09 + cheat + description:Can re-use shaded letters + code:5882/c2/d4 + cheat + description:Can select any letter on the board - letters don't have to be next to each other + code:5ea9/28/30 + cheat + description:Boggle - 1 and 2 letter words allowed + code:5b4c/03/01 + cheat + description:Boggle - Minimum word length 4 letters + code:5b4c/03/04 + cheat + description:Big Boggle - 1 to 3 letter words allowed + code:5b8f/04/01 + cheat + description:Big Boggle - Minimum word length 5 letters + code:5b8f/04/05 + +cartridge sha256:beca58b71a27884d2c2820da0c7eb806fa945b2fab66da271588281e03153900 + name:Bomb Jack (Europe) + cheat + description:Infinite lives + code:0479/e0/f0 + +cartridge sha256:604db636c45af3cd1fec52e206701a8969a8a3e610df281f7461769bd86729ea + name:Bomber Man GB 3 (Japan) (SGB Enhanced) + cheat + description:Invincibility + code:4cae/01/02 + cheat + description:Infinite lives + code:1517/3d/00 + cheat + description:Freeze timer + code:29e0/3d/00 + cheat + description:Maximum Bombs placable + code:7515/20/18 + cheat + description:Maximum blast range + code:7523/20/18 + +cartridge sha256:16d6a4650566ede0ec9e3e23a85544737faab4154d6381668e8547047340eee6 + name:Bomberman GB (USA, Europe) (SGB Enhanced) + cheat + description:Hit anywhere (press B) + code:73c0/00/3d+73c1/cd/3d+73bf/00/a1+73c2/03/c9+73be/01/f0 + cheat + description:Bombs can break any block + code:76c2/05/00 + +cartridge sha256:27d2eb237362b5647b020d0b22a08b079b40e50347dacc43b732830b9519a852 + name:Bomberman Max - Blue Champion (USA) + cheat + description:Invincibility + code:51b9/ff/00+52eb/ca/c3 + cheat + description:Hit anywhere + code:35e2/22/f2+35e3/c6/c2 + cheat + description:Walk anywhere + code:4b16/ea/fa + cheat + description:Infinite health + code:0102/c3/04 + cheat + description:Infinite lives + code:010a/c2/f7 + cheat + description:Infinite time + code:01ff/c3/01 + cheat + description:Max Bombs + code:0109/c2/f3 + cheat + description:Max Explosion + code:0109/c2/f4 + cheat + description:All enemies frozen + code:0100/c2/ff + +cartridge sha256:5f7c1cdf6adbe6d6dcef488bd37d0da82fa356b79fd579b2022a149e983abc39 + name:Bomberman Max - Red Challenger (USA) + cheat + description:Invincibility + code:52ea/a7/af+519d/38/18 + cheat + description:Hit anywhere + code:35f1/c6/c2+35f0/22/f2 + cheat + description:Walk anywhere + code:4b15/01/00 + cheat + description:Infinite health + code:0102/c3/04 + cheat + description:Infinite lives + code:010a/c2/f7 + cheat + description:Infinite time + code:01ff/c3/01 + cheat + description:Max Bombs + code:0109/c2/f3 + cheat + description:Max Explosion + code:0109/c2/f4 + cheat + description:All enemies frozen + code:0100/c2/ff + +cartridge sha256:0e885739f2b4ce4a6a196e4db9f317d3346ce270276e44adce078927231096df + name:Bomberman Quest (USA) (SGB Enhanced) + cheat + description:Walk through walls + code:4a46/28/18 + +cartridge sha256:6081309e7f5b63e4f6694965060c68baf82a775eb18e667c2c89898096e6e3d8 + name:Bonk's Adventure (USA) + cheat + description:Infinite energy + code:4513/c5/00 + cheat + description:Infinite lives + code:2799/cd/00 + cheat + description:Start with 3 lives, 1st life as Mad Bonk + code:01af/03/02+01b3/af/00 + cheat + description:Start 1st life as Turtle Bonk + code:01af/03/02+01b3/af/00 + cheat + description:Start with 8 lives + code:01af/03/07 + cheat + description:Start with 10 lives + code:01af/03/09 + +cartridge sha256:6ac93cc5186a2e92e13260fd61951c1b28f0df2278b9003b2bcb1ddcbf51543c + name:Boomer's Adventure in ASMIK World (USA) + cheat + description:Always have key + code:23c7/c8/00 + +cartridge sha256:c2fdb7f5887132d1d5ba4081f1332d347089dd73bf1e30a47af21bacc314e601 + name:Brain Drain (USA) (SGB Enhanced) + cheat + description:Clear level automatically + code:22a5/28/18 + cheat + description:Clear level automatically - Race Mode + code:2bf3/28/18 + +cartridge sha256:b164bafab4da7f92a33a2cdfce706b35407f3aa0ac379cd770fe2f78447bdf7a + name:Bram Stoker's Dracula (USA, Europe) + cheat + description:Invincibility + code:0672/19/00 + cheat + description:Infinite time + code:2d50/ea/fa + cheat + description:Infinite ammo + code:1121/ea/fa + +cartridge sha256:5ffda4ca9e2712e2ecc44e75bfd8c7307f4ed5fbcbb82a0f5cd9ad19e3bac6c2 + name:Brave Saga - Shinshou Astaria (Japan) + cheat + description:No random battles + code:42cf/c8/c9 + +cartridge sha256:c5ddbb08e8509633853346c5f35850cc3abe5afaabb0d0ee294b40e804253b7f + name:Bubble Bobble (USA, Europe) + cheat + description:Hit anywhere + code:1d22/08/00+1d29/38/18 + cheat + description:Hit anywhere - Bosses (except final boss) + code:4c05/d0/00+4bfc/d0/00 + cheat + description:Get items from anywhere + code:2c02/d0/00+2c0b/d0/00+2d56/d0/00+458f/21/37+2d5f/d0/37+4590/1d/c9 + cheat + description:One hit kill - final boss + code:48b7/3d/af + +cartridge sha256:29f17b604be580c0132a6d0bd7a966c82930069ca82f83798c955d532c6b4694 + name:Bubble Bobble Part 2 (USA, Europe) + cheat + description:Infinite hearts + code:1bce/ea/fa + cheat + description:Defeat one enemy to go to next level + code:5e33/3d/af + cheat + description:Hit anywhere + code:25d5/04/11+24d8/d2/fa+24c7/da/fa + cheat + description:One hit kills - bosses + code:24fb/38/18 + cheat + description:No big bubbles appear + code:178a/03/c9 + cheat + description:Run into 1 enemy and you remain invincible for the rest of the game + code:1558/ea/fa+1b46/ea/fa+1b63/ea/fa + cheat + description:Start with 1 heart + code:155c/03/01 + cheat + description:Start with 6 hearts + code:155c/03/06 + cheat + description:Start with 9 hearts + code:155c/03/09 + cheat + description:Start on round 20 + code:0839/fa/3e+083a/0d/13+083b/c1/00 + cheat + description:Start on round 40 + code:0839/fa/3e+083a/0d/27+083b/c1/00 + cheat + description:Start on round 60 + code:0839/fa/3e+083a/0d/3b+083b/c1/00 + +cartridge sha256:106d5443e092df3dc53035930766061f1ae4eae670470a93d648dc1adcda01c0 + name:Bubble Ghost (USA, Europe) + cheat + description:Bubble is invincible + code:24aa/3e/c9+2ddf/3e/c9+3653/3e/c9 + +cartridge sha256:6c8a53796be79a934f1393c668057cad38e857922cd552bc52fdf8f3ebdd2cc6 + name:Bugs Bunny & Lola Bunny - Operation Carrots (Europe) (En,Fr,De,Es,It,Nl) + cheat + description:Stage skip (pause, press Select to skip to the next stage) + code:7af5/13/00 + +cartridge sha256:a0bd5d25545de941e719437f7829f4edf32b3a140a399387f96dda2f8059fe4e + name:Bugs Bunny Crazy Castle, The (USA, Europe) + cheat + description:Invincibility + code:36cc/38/18 + cheat + description:Get carrots from anywhere (entire level) + code:2ce2/09/00+2cdd/0e/00 + cheat + description:Get carrots from anywhere (horizontal position) + code:2cdd/0e/00 + +cartridge sha256:cf1a8d9c9d4fc9e58740f6e008e5280ff2831c099aecab642e64e5195c0ad0bc + name:Bugs Bunny Crazy Castle 2, The (USA) + cheat + description:Invincibility + code:6289/ea/c9 + cheat + description:Infinite lives + code:1600/3d/be + cheat + description:Get keys from anywhere (except from the ones inside of doors) + code:5fd5/01/16+5fd4/28/18 + +cartridge sha256:89e43fdc94ec1d2a67aaab39d72afa50dd01df4323df7bf3d0909247cc490c24 + name:Bugs Bunny - Crazy Castle 3 (USA, Europe) + cheat + description:Invincibility + code:6197/c0/c9 + cheat + description:Get Keys from anywhere + code:6069/33/00+606e/2e/00 + cheat + description:Open locked doors without having 8 Keys + code:4c65/28/18 + cheat + description:Enter any door to clear level + code:1ab6/07/05 + +cartridge sha256:e5abce2a219fe38e53d1a572d371008f3b6d70be4607c1722139a9ea95fa7422 + name:Bug's Life, A (USA) (SGB Enhanced) + cheat + description:Invincibility (can still drown) + code:10ee/fa/00 + cheat + description:Infinite lives + code:262f/35/00 + +cartridge sha256:2f4254faaa4bda89486c4820c601917cd034c7965eae075ba81acef4295fa8bd + name:BurgerTime Deluxe (World) + cheat + description:Invincibility + code:2e98/36/c9 + cheat + description:Infinite lives + code:15ca/d6/fe + cheat + description:Infinite weapon + code:2b76/d6/fe + cheat + description:Touch Burgers from anywhere + code:20c0/3a/00 + +cartridge sha256:2fbf14a5bffb070e183537c3ff4cd8e05626a94b3949785ed240b28642d0a259 + name:Bust-A-Move Millennium (USA, Europe) + cheat + description:Hit one bubble to clear level - Challenge Mode + code:433a/3d/af+42ee/ba/c2 + cheat + description:Hit one bubble to clear level - Puzzle Mode + code:5469/28/18 + cheat + description:Win automatically - Story Mode + code:45ab/0a/07+45aa/28/18+4593/04/06 + +cartridge sha256:2223993b7a91a5f2ccca1f43652df0062528e3fb37128f61a0ec8a779bcf65a1 + name:Buster Bros. (USA) + cheat + description:Hit anywhere - main weapon + code:2559/d1/5b+2531/d2/fa + +cartridge sha256:ce892641c500ddd0ccb804208556113ad4b9736f89cc94c6822f863508eb81f0 + name:Buzz Lightyear of Star Command (USA, Europe) + cheat + description:Infinite health + code:0164/cc/da + cheat + description:Always have five coins + code:0105/cc/c8 + +cartridge sha256:f0b147eb3429b1b480424a31eb2d800b5676d01a701b494b2c9e9d2de63d31c5 + name:Captain America and the Avengers (USA) + cheat + description:Infinite energy + code:15cc/77/00 + cheat + description:Enemy bullets do very little damage + code:7774/0c/01 + cheat + description:Enemy bullets do more damage + code:7774/0c/19 + cheat + description:Enemy bullets do much more damage + code:7774/0c/33 + cheat + description:Start with energy at 153 + code:0a29/64/99 + cheat + description:Start with energy at 255 + code:0a29/64/ff + cheat + description:Start with energy at 34 + code:0a29/64/22 + cheat + description:Start with 1 lives + code:01dd/03/01 + cheat + description:Start with 10 lives + code:01dd/03/0a + cheat + description:Start on stage 1-2 + code:03a8/1e/3e+03a9/00/01+03aa/f0/e0 + cheat + description:Start on stage 1-3 + code:03a8/1e/3e+03a9/00/02+03aa/f0/e0 + cheat + description:Start on stage 1-4 + code:03a8/1e/3e+03a9/00/03+03aa/f0/e0 + cheat + description:Start on stage 1-5 + code:03a8/1e/3e+03a9/00/04+03aa/f0/e0 + cheat + description:Start on stage 1-6 + code:03a8/1e/3e+03a9/00/05+03aa/f0/e0 + cheat + description:Start on stage 2-1 + code:03a8/1e/3e+03a9/00/06+03aa/f0/e0 + cheat + description:Start on stage 2-2 + code:03a8/1e/3e+03a9/00/07+03aa/f0/e0 + cheat + description:Start on stage 2-3 + code:03a8/1e/3e+03a9/00/08+03aa/f0/e0 + cheat + description:Start on stage 2-4 + code:03a8/1e/3e+03a9/00/09+03aa/f0/e0 + cheat + description:Start on stage 2-5 + code:03a8/1e/3e+03a9/00/0a+03aa/f0/e0 + cheat + description:Start on stage 2-6 + code:03a8/1e/3e+03a9/00/0b+03aa/f0/e0 + cheat + description:Start on stage 3-1 + code:03a8/1e/3e+03a9/00/0c+03aa/f0/e0 + cheat + description:Start on stage 3-2 + code:03a8/1e/3e+03a9/00/0d+03aa/f0/e0 + cheat + description:Start on stage 3-3 + code:03a8/1e/3e+03a9/00/0e+03aa/f0/e0 + cheat + description:Start on stage 3-4 + code:03a8/1e/3e+03a9/00/0f+03aa/f0/e0 + cheat + description:Start on stage 3-5 + code:03a8/1e/3e+03a9/00/10+03aa/f0/e0 + cheat + description:Start on stage 4-1 + code:03a8/1e/3e+03a9/00/11+03aa/f0/e0 + cheat + description:Start on stage 4-2 + code:03a8/1e/3e+03a9/00/12+03aa/f0/e0 + cheat + description:Start on stage 4-3 + code:03a8/1e/3e+03a9/00/13+03aa/f0/e0 + cheat + description:Start on stage 4-4 + code:03a8/1e/3e+03a9/00/14+03aa/f0/e0 + cheat + description:Start on stage 4-5 + code:03a8/1e/3e+03a9/00/15+03aa/f0/e0 + cheat + description:Start on stage 4-6 + code:03a8/1e/3e+03a9/00/16+03aa/f0/e0 + cheat + description:Start on stage 5-1 + code:03a8/1e/3e+03a9/00/17+03aa/f0/e0 + cheat + description:Start on stage 5-2 + code:03a8/1e/3e+03a9/00/18+03aa/f0/e0 + cheat + description:Start on stage 5-3 + code:03a8/1e/3e+03a9/00/19+03aa/f0/e0 + cheat + description:Start on stage 5-4 + code:03a8/1e/3e+03a9/00/1a+03aa/f0/e0 + cheat + description:Start on stage 5-5 + code:03a8/1e/3e+03a9/00/1b+03aa/f0/e0 + cheat + description:Start on stage 5-6 + code:03a8/1e/3e+03a9/00/1c+03aa/f0/e0 + +cartridge sha256:1ff537c010391d6b865b5113d03a9c6601e43659f341f5db2bfc5cc501b6aa04 + name:Casper (USA) + cheat + description:Infinite Brass Keys + code:0163/c1/a9 + cheat + description:Infinite Iron Keys + code:0163/c1/a8 + cheat + description:Infinite Weights + code:0163/c1/ab + +cartridge sha256:1bedb523a9612d48adafe8d70c88408f35e1fc84d0e70031649f3d113d5d9d09 + name:Casper (USA) + cheat + description:Return Books from anywhere + code:66b2/c0/00 + cheat + description:Invincibility - Platform mini-game + code:5d5f/30/18 + cheat + description:Hit anywhere - Shooting mini-game + code:5701/dc/cd + +cartridge sha256:17570ceec1b22153604622c4412d048dd8f7ccb4626daf9ddea96de8a062dbf2 + name:Castlevania II - Belmont's Revenge (USA, Europe) + cheat + description:Invincibility + code:4586/fa/ea + cheat + description:Hit anywhere + code:3936/09/00 + cheat + description:Multi-jump + code:4294/02/87+4295/c0/c8+4296/3d/e6+4297/ca/10+4298/d4/20+4299/43/15+0d47/d8/c9 + +cartridge sha256:edb101e924f22149bdcbcfe6603801fdb4ec0139a40493d700fa0205f6dab30c + name:Castlevania - The Adventure (USA) + cheat + description:Infinite energy + code:7af2/77/00 + cheat + description:Infinite time - disable at end of stages + code:0407/77/00 + cheat + description:Infinite lives + code:0694/77/00 + cheat + description:Hit anywhere + code:2261/12/00+2271/02/00 + cheat + description:Multi-jump + code:17e3/18/00+00eb/ff/18+00e8/ff/1a+00ea/ff/23+00e7/ff/32+00ec/ff/c9+00e6/ff/cd+00e9/ff/cd+17e2/23/e6 + cheat + description:Slightly improves speed - new games only + code:173c/c0/ff + cheat + description:Don't lose weapon after being hit + code:7acf/77/00 + cheat + description:Start with 5 lives + code:085e/02/04 + cheat + description:Start with 7 lives + code:085e/02/06 + cheat + description:Start with 2 energy bars + code:055c/0a/02 + cheat + description:Start with 4 energy bars + code:055c/0a/04 + cheat + description:Start with 6 energy bars + code:055c/0a/06 + cheat + description:Start with timer at 2:15 for first stage + code:09b3/13/02 + cheat + description:Start with timer at 4:15 for first stage + code:09b3/13/04 + cheat + description:Start with timer at 7:15 for first stage + code:09b3/13/07 + +cartridge sha256:56d3dee063b8801704a284bd1bc229b94f15a3a448f485d347f04283d9bd16d7 + name:Castlevania Legends (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:573b/cb/c9 + cheat + description:Infinite lives + code:4345/ea/da + cheat + description:Infinite time + code:2d85/22/c9 + cheat + description:Disable death traps + code:545c/cd/c9 + cheat + description:Fast walk left + code:4c9d/c5/11 + cheat + description:Fast walk right + code:4c76/c5/11 + cheat + description:Fast jump left + code:52d6/c5/11 + cheat + description:Fast jump right + code:52b5/c5/11 + cheat + description:Hit anywhere + code:2349/5a/4b+545c/cd/c9 + cheat + description:Multi-jump + code:5733/37/03+5732/fa/28+5736/02/51+572e/18/55+5735/fe/59+5731/c0/67+5737/c8/c9+1fe4/d0/c9+5730/b7/cb+5734/c7/cd+5170/ea/fa + +cartridge sha256:2f83ab433323f4d08f111ace559a7e29d37ff33fe1ca9d726edd5bb98a854ec2 + name:Centipede (USA) + cheat + description:Kill one enemy to complete level + code:4586/01/05 + +cartridge sha256:7e483524aa104928149e4e56f01b7e98c6eed70dcd30ac5d65cd9d2387cde5ff + name:Chessmaster, The (DMG-N5) (USA) + cheat + description:Move pieces anywhere + code:19d8/28/18+1a12/28/18+1a00/d9/00 + +cartridge sha256:0a44d1f127436d73fc2f64201da0e0fd40793a414e533bba0a08e02dfb51cb10 + name:Chessmaster, The (DMG-N5) (USA) (Rev A) + cheat + description:Move pieces anywhere + code:1ab6/28/18+1af8/28/18+1ae6/d1/00 + +cartridge sha256:781b31deb923c544b42b2116d973a103fd5c21b3cf25e920968ef392a5df917b + name:Chessmaster (USA, Europe) + cheat + description:Move pieces anywhere + code:2783/d1/00+2795/28/18+2753/28/18 + +cartridge sha256:50a6ddd98a515f530ca031f86e5491c8d77d16b0694c0d1054bcc964991eba41 + name:Chicken Run (USA, Europe) (En,Fr,De,Es,It) + cheat + description:Invisibility + code:16cd/c0/c9 + cheat + description:Infinite Feed + code:1bfb/20/18 + cheat + description:Infinite Time + code:4495/c0/c9 + cheat + description:Walk through walls + code:1b02/02/00 + cheat + description:Stage skip (pause, press Select to skip to the next stage) + code:60f7/20/18 + +cartridge sha256:2eb1ab19a19e688ebc047497922b17218da3cb673084846999bd81a4dd73eba4 + name:Chiki Chiki Tengoku (Japan) + cheat + description:Clear level automatically + code:3afe/30/3e+3b17/03/00+3b0a/20/3e + +cartridge sha256:53199f624a81f566104c143b835ca648ee9bbccc2c10efa21a3f4b3f5b5e7ea7 + name:College Slam (USA) + cheat + description:Dunk and layup from anywhere + code:6c09/13/00 + +cartridge sha256:d8e44a2c2aa67f9afa49365f62802160842aef48d2003a69daeb109813f6f20c + name:Contra - The Alien Wars (USA) (SGB Enhanced) + cheat + description:Invincibility + code:4b81/28/3e + cheat + description:Infinite smart bombs + code:37e2/3d/00 + cheat + description:Hit anywhere + code:1377/55/00+137c/50/00+1382/4a/00+1387/45/00+13c3/36/00 + cheat + description:Get 5 smart bombs after you die + code:42b1/01/05 + cheat + description:Get 9 smart bombs after you die + code:42b1/01/09 + cheat + description:Don't flash after getting hit + code:406f/64/01 + cheat + description:Longer invincibility after getting hit + code:406f/64/ff + cheat + description:Start with Flame Thrower + code:4797/00/01 + cheat + description:Start with Crush Gun + code:4797/00/07 + cheat + description:Start with Homing shot + code:4797/00/08 + cheat + description:Start with Spread shot + code:4797/00/09 + +cartridge sha256:8e765a4e381462a29632b7a3c5421080be3e8445e5913d7e904a8e80d688ca81 + name:Contra (Japan) + cheat + description:Invincibility + code:3b3a/fe/be+3aa3/fe/be+1a0f/fe/be + cheat + description:Hit anywhere + code:3ad0/1c/00+3aea/dc/c3+3afb/fe/c6 + cheat + description:Multi-jump + code:558c/55/00+00e6/ff/26+00e9/ff/46+00e7/ff/52+00ea/ff/55+00eb/ff/c9+00e5/ff/cd+00e8/ff/cd+558b/46/e5 + +cartridge sha256:830e46d203dee9775b76849a3aa259b530e6bf5ea17cf8c79cc19549d61bce37 + name:Cool Ball (USA) + cheat + description:All items worth 99 + code:0c66/fe/3e+0c67/64/63 + cheat + description:Complete levels automatically + code:1393/38/18+13ad/20/3e + +cartridge sha256:aa993ef6fd692435f869c63add9d49bf08db6fc8d6ee7baa9b406982d7b38c7c + name:Cool Bricks (Europe) (En,Fr,De,Es,It) + cheat + description:Paddle hits ball anywhere + code:1858/2b/00+1855/2e/00 + +cartridge sha256:805c18920e01f4b5746827c201e9a88554f085a8c297ed45f119700fe54da52e + name:Cool Spot (USA) + cheat + description:Hit anywhere + code:1bd8/49/00+1867/d2/fa + +cartridge sha256:e0dafd8b66cc6c19c3b64471d198e1dc87f3e5e1000c4fd8d71122a004fea5ae + name:Cosmo Tank (USA) + cheat + description:Invincibility + code:599f/38/18 + cheat + description:Hit anywhere + code:4d4f/12/00 + +cartridge sha256:5437ce255372eca79a5e33cfca4158e70c7a9d46fd93c6a38ed1e1a13cab4b73 + name:Croc (USA, Europe) + cheat + description:Invincibility + code:6114/c0/c9 + cheat + description:Enemies die on contact + code:5bd9/28/18 + +cartridge sha256:002ad8e22b4d846d3185c2e42af284dcb5f9b040bb174c9b5e9670de4df79278 + name:Croc 2 (USA, Europe) + cheat + description:Invincibility + code:55c9/c0/c9+5595/c0/c9 + cheat + description:Enemies die on contact + code:5580/20/18 + cheat + description:Walk over pits + code:4731/fa/c9 + +cartridge sha256:3c86f30b11442c93b011287310dfea0a9c23a182527d8447769226e52ef29d5e + name:Crystal Quest (USA) + cheat + description:Invincibility (allows you to exit the level at anytime) + code:1000/c8/c9+0d79/30/18 + cheat + description:Hit anywhere + code:08b9/77/00+0863/30/3e + +cartridge sha256:3ab8bcd08f0aa01c16ccc2bc286fc6c50cf2d140fd3ed411ef0e16e586410110 + name:Crystalis (USA) + cheat + description:Hit anywhere + code:2a5b/28/3e + cheat + description:Walk anywhere + code:46b8/c0/00 + +cartridge sha256:d5a1c0e7af970859449c47fcc80a5f4dfa4f456b20fdfcd49e753ce46f2dc3da + name:Cyraid (USA) + cheat + description:Infinite lives + code:4d8c/01/00 + cheat + description:1st nasty on bottom level of stage 1 is removed from the game + code:6072/01/00 + cheat + description:Collect only 1 energy capsule and all enemy robots are destroyed-can proceed to next room + code:1a4e/3d/af + cheat + description:Skip to 3rd room after completing 1st + code:0e8a/28/3e+0e8b/05/03 + cheat + description:Skip to 5rd room after completing 1st + code:0e8a/28/3e+0e8b/05/05 + cheat + description:Skip to 8rd room after completing 1st + code:0e8a/28/3e+0e8b/05/08 + cheat + description:Start with 4 lives + code:1e7c/05/04 + cheat + description:Start with 6 lives + code:1e7c/05/06 + cheat + description:Start with 9 lives + code:1e7c/05/09 + +cartridge sha256:06d2f49483cf16f00580ba227d86174fdb9f72e555d9a9afea6aebcbfff012e4 + name:Daedalian Opus (USA) + cheat + description:Infinite time + code:2d62/34/00 + cheat + description:Place any piece to clear level + code:1115/d0/1b + cheat + description:Get password to select any level after completing level 1 + code:019a/fe/3e+019b/24/0a + cheat + description:Start on level 5 or 6 after completing level 1 + code:019c/30/3e+019d/05/05 + +cartridge sha256:30faf530573519d690d066093e9fae3b461d79df37c025a9ec9115f5fc5786e4 + name:Daffy Duck (Europe) + cheat + description:Infinite jet pack + code:3401/3c/af + cheat + description:Infinite jet pack + hit anywhere + code:3401/3c/af+3df2/c2/c3+3dd5/20/18+3deb/da/fa+3eb2/da/fa + +cartridge sha256:e4a40a4c961f937950a69da5a9de654a121ebffe307d3ad9e834731b68d4e347 + name:Daikatana (Europe) (En,Fr,It) + cheat + description:Invincibilities against enemies + code:522b/da/c3 + cheat + description:Infinite ammo - sub-weapons + code:6a3b/ea/fa + cheat + description:Hit anywhere + code:52d5/da/18+52d6/72/1e + cheat + description:Hit anywhere - sub-weapons + code:4f04/c5/29+4f03/da/18 + cheat + description:Get items from anywhere + code:6f18/da/18+6f19/b3/20 + cheat + description:Multi-jump + code:6b7c/51/00 + +cartridge sha256:b482f9a96a292dea1fcc94bdeae24b664a3222c9eb820795388aab274eebdaf0 + name:Darkman (USA, Europe) + cheat + description:Infinite energy + code:050f/fa/ba + cheat + description:Infinite lives + code:04dd/c0/01 + cheat + description:Infinite time + code:0597/01/00 + cheat + description:Start 1st life with mega-energy + code:3f91/1c/63 + cheat + description:Start 1st life with 1/2 energy + code:3f91/1c/0a + cheat + description:Start rest of lives with mega-energy + code:2640/1c/63 + cheat + description:Start with 9 minutes + code:59ac/40/90 + cheat + description:Start with 1 life + code:024d/03/00 + cheat + description:Start with 8 lives + code:024d/03/07 + +cartridge sha256:122a1d3bd99c87a337f770fbdef2b7cf8538673df1595585af6684d4d4807614 + name:Darkwing Duck (USA) + cheat + description:Infinite lives + code:0a0b/c9/01 + cheat + description:Infinite ammo on pick-up + code:7d39/ea/fa + cheat + description:Hit anywhere + code:40ce/30/3e + cheat + description:One hit kills + code:4102/28/18 + cheat + description:Invincibility time lasts 4 seconds + code:4064/50/aa + cheat + description:Invincibility time lasts 6 seconds + code:4064/50/ff + cheat + description:1 touch by an enemy kills you + code:406f/50/01 + cheat + description:Start with 1 pt. of energy and 1 life - 1st game + code:0184/04/01 + cheat + description:Start with 5 pts. of energy on 1st life and 5 lives - 1st game + code:0184/04/05 + cheat + description:Start with 9 pts. of energy on 1st life and 9 lives - 1st game + code:0184/04/09 + cheat + description:Start with 1 pt. of energy after 1st life + code:09f0/04/01 + cheat + description:Start with 5 pts. of energy after 1st life + code:09f0/04/05 + cheat + description:Start with 9 pts. of energy after 1st life + code:09f0/04/09 + +cartridge sha256:61d632a2e17526cc55cc8e107abaf9aa11830cd4dd94c0b0f94d10a12a0c9f71 + name:David Crane's The Rescue of Princess Blobette Starring A Boy and His Blob (USA) + cheat + description:Infinite jellybeans + code:2056/01/00 + cheat + description:Infinite lives + code:2d4f/35/00 + cheat + description:Start with 2 honeys + code:7c0e/03/02 + cheat + description:Start with 4 honeys + code:7c0e/03/04 + cheat + description:Start with 8 honeys + code:7c0e/03/08 + cheat + description:Start with 2 root beers + code:7c0c/00/02 + cheat + description:Start with 4 root beers + code:7c0c/00/04 + cheat + description:Start with 2 tangerines + code:7c0a/06/02 + cheat + description:Start with 4 tangerines + code:7c0a/06/04 + cheat + description:Start with 2 vanillas + code:7c08/05/02 + cheat + description:Start with 4 vanillas + code:7c08/05/04 + cheat + description:Start with 2 limes + code:7c06/00/02 + cheat + description:Start with 4 limes + code:7c06/00/04 + cheat + description:Start with 2 apples + code:7c04/01/02 + cheat + description:Start with 4 apples + code:7c04/01/04 + cheat + description:Start with 2 bananas + code:7c02/00/02 + cheat + description:Start with 4 bananas + code:7c02/00/04 + cheat + description:Start with 2 colas + code:7c00/00/02 + cheat + description:Start with 4 colas + code:7c00/00/04 + cheat + description:Start with 2 coconuts + code:7bfe/03/02 + cheat + description:Start with 4 coconuts + code:7bfe/03/04 + cheat + description:Start with 2 strawberries + code:7bfc/00/02 + cheat + description:Start with 4 strawberries + code:7bfc/00/04 + cheat + description:Start with 2 licorices + code:7bfa/02/02 + cheat + description:Start with 4 licorices + code:7bfa/02/04 + cheat + description:Start with 2 ketchups + code:7c10/01/02 + cheat + description:Start with 4 ketchups + code:7c10/01/04 + cheat + description:Start with 2 punches + code:7c12/00/02 + cheat + description:Start with 4 punches + code:7c12/00/04 + cheat + description:Start with 2 mints + code:7c14/00/02 + cheat + description:Start with 4 mints + code:7c14/00/04 + cheat + description:Start with 2 lives + code:7bca/05/02 + cheat + description:Start with 4 lives + code:7bca/05/04 + cheat + description:Start with 8 lives + code:7bca/05/08 + +cartridge sha256:1a62bbcaff8d12b752826472beac346e5fce9d8640f7ae23c6e390b79e55346d + name:Days of Thunder (USA, Europe) + cheat + description:Infinite time in pits + code:6e7b/ea/fa + cheat + description:Infinite fuel + code:7294/72/00 + cheat + description:Car takes no damage + code:169c/77/00 + cheat + description:Tires take no damage + code:272f/34/c9 + +cartridge sha256:d534102be843dc15a465709164e09e82c6bdf6df2ac440930af2e34c2f0e01ce + name:Dead Heat Scramble (USA) + cheat + description:Infinite time + code:0405/3d/00 + cheat + description:Start on stage 2 + code:7b0c/01/02 + cheat + description:Start on stage 3 + code:7b0c/01/03 + cheat + description:Start on stage 4 + code:7b0c/01/04 + cheat + description:Start on stage 5 + code:7b0c/01/05 + cheat + description:Start on stage 6 + code:7b0c/01/06 + cheat + description:Start on stage 7 + code:7b0c/01/07 + cheat + description:Start on stage 8 + code:7b0c/01/08 + cheat + description:Start on stage 9 + code:7b0c/01/09 + cheat + description:Start on stage 10 + code:7b0c/01/0a + +cartridge sha256:a089bea1d6eec0e99f03276744aea293fe3fe3a2889791ab8f3a00b83e2cf58b + name:Deer Hunter (USA) + cheat + description:Infinite time + code:041f/3c/00 + +cartridge sha256:2d8fb80ece07198260fb47b6a2e8d0097e2d6ca27fb21bc3c439f90d7880317d + name:Dig Dug (USA) + cheat + description:Invincibility + code:23c1/ea/fa + cheat + description:Infinite lives + code:481b/3d/00 + cheat + description:When Pookas are partially inflated, they don't shrink + code:3450/35/00 + cheat + description:1 pump kills monster instantly + code:36d9/01/04+239e/01/04+478e/01/04 + cheat + description:Start with 6 lives + code:5bac/03/06 + cheat + description:Start with 9 lives + code:5bac/03/09 + cheat + description:Start with 2 lives + code:5bac/03/02 + cheat + description:Start on level 4 (display still says level 1) + code:5cd9/38/3e+5cda/02/04 + cheat + description:Start on level 2 (display still says level 1) + code:5cd9/38/3e+5cda/02/02 + cheat + description:Start on level 9 (display still says level 1) + code:23ec/1c/00+5cda/02/09 + +cartridge sha256:0ee26b1a12c91560ab852510a792b13d7391c2fcebf4c0c0a1d8323194eb473a + name:Donald Duck - Goin' Quackers (USA) (En,Fr,De,Es,It) + cheat + description:Get blue items from anywhere + code:74a2/28/3e + +cartridge sha256:2781f6b1014336e3318073f162cadd970329c8148fc62b5e795441cd6fd57051 + name:Donkey Kong (Japan) (En) (SGB Enhanced) + cheat + description:Infinite lives + code:094d/35/00 + cheat + description:Infinite time + code:0c34/01/00 + cheat + description:Can open doors without a key + code:407b/d2/fa + cheat + description:Timer is 2x faster + code:0c34/01/02 + cheat + description:Practice stage XX - level indicator doesn't work, can't go on to next level + code:24f3/fa/3e+f000/ba/00+24f5/c8/00 + cheat + description:Start with 36 lives + code:0264/04/88 + +cartridge sha256:b490c89efe718633b07381def66ce0ed58a5075aabe40c6e644baf2b408a76f4 + name:Donkey Kong (World) (Rev A) (SGB Enhanced) + cheat + description:Invincibility + code:53b4/36/c9+544d/72/c9+5546/36/c9 + cheat + description:Invincibility (alt) + code:51f5/c2/fa + +cartridge sha256:eaf831ddd75e7cbc9990e478a139ac162034c03377670fdb79615a9aa2cc570d + name:Donkey Kong Land (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:4081/28/3e + cheat + description:Kill enemies on contact + code:2599/20/3e+25a5/7c/6d + cheat + description:Infinite lives + code:4d9d/35/00+4da0/c2/21 + cheat + description:Multi-jump + code:54b4/38/3e + cheat + description:Always save game at end of level, regardless if you have KONG letters or not + code:40cb/ca/c3 + cheat + description:Lose all your lives when you die + code:4da0/c2/c3 + cheat + description:If you get hit you don't change characters until you are back at the map screen + code:4dfd/ea/c9 + cheat + description:Each banana gives you mega lives (disable when you have enough lives) + code:44c6/35/00+44c0/36/3e + cheat + description:Change soundtrack + code:421f/35/00 + cheat + description:Start with 1 life + code:6e89/05/00+7e95/05/00 + cheat + description:Start with 9 lives + code:6e89/05/08+7e95/05/08 + cheat + description:Start with 15 lives + code:6e89/05/0e+7e95/05/0e + cheat + description:Start with 99 lives + code:6e89/05/63+7e95/05/63 + +cartridge sha256:7722555df42413c6fd5434b717e82ba4a842cc0df3ef02fd0cd9b45b1bb5f2ca + name:Donkey Kong Land 2 (USA, Europe) (SGB Enhanced) + cheat + description:Multi-jump (disables hanging on horizontal ropes) + code:083b/22/00+0b33/20/18+085a/3a/36+0852/a4/a5+085b/5f/af + cheat + description:Glimmer's Galleon always lit + code:46ad/df/00 + cheat + description:Can exit unbeaten levels + code:4a26/28/3e + +cartridge sha256:75f902ab8674c3cd379438fbd54cfe7e87ca3ddf9727679547261d1b77db720b + name:Double Dragon (USA, Europe) + cheat + description:Infinite health + code:012f/c4/98 + cheat + description:Infinite lives + code:0104/c4/99 + cheat + description:Hit anywhere + code:6e97/21/18+6e98/84/4c + cheat + description:One hit kills (bosses die after three hits) + code:6ada/28/00+6b62/04/00 + cheat + description:Start on Mission 1 (slum) (disable code to advance to next stage) + code:0100/c6/50 + cheat + description:Start on Mission 1 (area with boxes) (disable code to advance to next stage) + code:0101/c6/50 + cheat + description:Start on Mission 1 (boss) (disable code to advance to next stage) + code:0102/c6/50 + cheat + description:Start on Mission 2 (disable code to advance to next stage) + code:0103/c6/50 + cheat + description:Start on Mission 3 (woods) (disable code to advance to next stage) + code:0104/c6/50 + cheat + description:Start on Mission 3 (cave) (disable code to advance to next stage) + code:0105/c6/50 + cheat + description:Start on Mission 4 (outside enemy's base) (disable code to advance to next stage) + code:0106/c6/50 + cheat + description:Start on Mission 4 (enemy's base) (disable code to advance to next stage) + code:0107/c6/50 + cheat + description:Start on Ending (disable code to advance to next stage) + code:0108/c6/50 + +cartridge sha256:21639689078496d4c2d000b120d493b69e7df603e5c2b5cd337974665e597878 + name:Double Dragon II (USA, Europe) + cheat + description:Invincibility + code:34e6/21/c9 + cheat + description:Hit anywhere + code:339f/fa/18+33a0/50/23 + cheat + description:One hit kills + code:56f2/0d/00+5772/0c/00+57a3/04/00+56f4/04/01 + +cartridge sha256:ba60449b8e57d1288e78a2cb69c6df46e1443cc611d139d27f4c5d5fad307fd3 + name:Double Dragon 3 - The Arcade Game (USA, Europe) + cheat + description:Infinite lives + code:700e/3d/00 + cheat + description:Infinite coins + code:0f1b/01/00 + cheat + description:Start with 4 lives + code:009f/06/03 + cheat + description:Start with 10 lives + code:009f/06/09 + cheat + description:Start with 13 lives + code:009f/06/0c + cheat + description:Start with 5 coins + code:7949/01/04 + cheat + description:Start with 10 coins + code:7949/01/09 + cheat + description:Start with 20 coins + code:7949/01/19 + cheat + description:Start 1st life with 5 energy points + code:0097/bf/50 + cheat + description:Start 1st life with 15 energy points + code:0097/bf/f0 + cheat + description:Start with 5 points of energy - after 1st life + code:7013/bf/50 + cheat + description:Start with 15 points of energy - after 1st life + code:7013/bf/f0 + +cartridge sha256:936df4d0f74620c784129259a22fc3216eea04f70c10cab6005457a0f681e313 + name:Double Dribble - 5 on 5 (USA) + cheat + description:Infinite time + code:0b8c/01/00 + cheat + description:No computer scoring + code:0d64/22/00 + cheat + description:Game lasts only 1 quarter, goes straight to 4th quarter + code:0ce2/01/04 + cheat + description:When selecting skill level, keep pressing down. Bleeping will continue, and computer will become more and more skillful. + code:1a0b/03/ff + +cartridge sha256:3296ce126e2ebf61f99e39d82e20e0f7d7ade84539ddd48f7c0e21fef5f46932 + name:Dr. Mario (World) + cheat + description:Drop capsules anywhere to clear level + code:2a3a/20/18+2be2/20/3e + +cartridge sha256:15fecc6e3d9f72e9cf3f5af7c1f034cc94a2007d29ea0a204976adcc0ff9a52e + name:Dragon's Lair - The Legend (USA) + cheat + description:Have all Life Stones + code:0101/c3/43+0109/c3/44+0104/c3/45 + +cartridge sha256:8dab48cc81d14bcee7c73274df09cf5c4dd44c3b93d10a5a3175e04fead25dee + name:Dragon Ball Z - Legendary Super Warriors (USA) + cheat + description:Opponent doesn't attack + code:68fc/fa/c9 + +cartridge sha256:3996cbfb2f133a48f58a0d81420362caceaa3e348704d496ba6cbff0eb47139f + name:Dragon Warrior I & II (USA) (SGB Enhanced) + cheat + description:No random battles + code:40b1/38/3e + cheat + description:Walk anywhere + code:62f5/20/3e + +cartridge sha256:34f11935cb3c23102462aab9d96c09e25b81b35eef91f5e5456b2c3665734f0e + name:Dragon Warrior III (USA) + cheat + description:Enemies only attack themselves + code:5add/14/04+5adc/28/f6 + cheat + description:Quick level gain + code:457f/2a/01+4580/46/ff+4581/4f/ff + cheat + description:HP set to approx 198 every move + code:5f5e/79/7c + +cartridge sha256:64d791cadae2500ddd7dfd3ebedc48a182fdc0e027f9bfd74c8ff65b56371dbf + name:Druaga no Tou (Japan) + cheat + description:Reset to see ending + code:016f/08 + +cartridge sha256:4d754abe2502f79396790f04963468f5c614eb4768e2b3f9b5c79c8e28b55dcb + name:Elevator Action EX (Europe) (En,Fr,De,Es,It) + cheat + description:Invincibility + code:5ee8/38/18+59fa/c2/c3 + cheat + description:Hit anywhere + code:4c83/28/3e+4bc7/28/3e + cheat + description:Don't get crushed by elevators + code:5eaf/28/18+472d/28/18 + +cartridge sha256:9eee3454a1198c01c7adb9562507f2eb5791888c63885bea2e933948f66f6321 + name:Extra Bases! (USA) + cheat + description:Outs aren't counted + code:100b/34/00 + cheat + description:Strikes aren't counted + code:407a/34/00 + cheat + description:Balls aren't counted + code:408b/34/00 + cheat + description:Opponents can't score (disable when you're batting so you can score) + code:5b91/3c/00 + cheat + description:One strike and you're out + code:0fd6/03/01 + cheat + description:2 strikes and you're out + code:0fd6/03/02 + cheat + description:1 out and side is retired + code:0ff0/03/01 + cheat + description:2 outs and side is retired + code:0ff0/03/02 + cheat + description:1 ball and you walk + code:0fc0/04/01 + cheat + description:2 balls and you walk + code:0fc0/04/02 + +cartridge sha256:571e45610cae528b3c50304c42c946f307d71797fc2029e9ca1978045dd5186d + name:F-15 Strike Eagle (USA, Europe) + cheat + description:Infinite bullets + code:2a52/ea/fa + cheat + description:Infinite sidewinders + code:08ee/ea/fa + cheat + description:Infinite mavericks + code:08ab/ea/fa + cheat + description:Infinite E.C.M. + code:085b/ea/fa + cheat + description:Fly very slowly + code:33bc/02/01 + cheat + description:Fly at supersonic speed + code:33bc/02/09 + cheat + description:Start with 10 sidewinders + code:3388/1e/0a + cheat + description:Start with 50 sidewinders + code:3388/1e/32 + cheat + description:Start with 90 sidewinders + code:3388/1e/5a + cheat + description:Start with 10 mavericks + code:338d/0f/0a + cheat + description:Start with 50 mavericks + code:338d/0f/32 + cheat + description:Start with 90 mavericks + code:338d/0f/5a + cheat + description:Start with 10 E.C.M. + code:3392/18/0a + cheat + description:Start with 50 E.C.M. + code:3392/18/32 + cheat + description:Start with 90 E.C.M. + code:3392/18/5a + cheat + description:Start with 513 bullets + code:339b/03/02+339a/20/01 + cheat + description:Start with 2049 bullets + code:339b/03/08+339a/20/01 + cheat + description:Start with 4097 bullets + code:339b/03/10+339a/20/01 + +cartridge sha256:ece080d17963acfb7f9b2c28272881edd2a17bc93fcd65bb649810b5e8ed513a + name:Fastest Lap (Japan, USA) + cheat + description:Quick laps + code:1fd8/da/fa+1fd1/d2/fa + +cartridge sha256:db506cb639b6336bf17c993c597da3990398ec01e235e0d9236e9df87ab0439e + name: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:3458/3d/00 + cheat + description:When you crash with another car, your speed won't drop to 0 + code:3022/c8/00 + cheat + description:No qualifying timer + code:4a39/01/00+4a1a/01/00 + +cartridge sha256:9b72e7d44d1cb31a06cf4e630c83abc61fb7218e3d55d7dc6aa1ecbf9e490cf0 + name:Fighting Simulator 2 in 1 (USA, Europe) + cheat + description:Infinite energy + code:173c/3c/3d + cheat + description:Infinite lives + code:18d7/3d/00 + cheat + description:Start with 5 lives + code:1724/03/05 + cheat + description:Start with 9 lives + code:1724/03/09 + cheat + description:Start with 15 lives + code:1724/03/0f + +cartridge sha256:5a462f1bbb4e75823c04c7a0b2a7497cbe7e709a425854c71c1fc4d60f16f445 + name:Final Fantasy Adventure (USA) + cheat + description:Most items are free + code:5606/01/40 + cheat + description:Start with 255 of each ability + code:6e6b/02/ff + cheat + description:Start with 65,330 GP + code:6ecc/ff + +cartridge sha256:e5b1d116a8fb01b7a7213f906b3ef1bcc91a18f6826b01ee1bccd89429a0d906 + name:Final Fantasy Legend, The (USA) + cheat + description:Infinite items + code:4395/35/00+28cf/35/00 + cheat + description:Enemies have 0 HP + code:5758/7b/af+575a/7a/af + cheat + description:Enemies have 0 in all abilities + code:5760/0a/af+5763/0a/af+5766/0a/af+5769/0a/af + cheat + description:No random battles + code:229a/c0/c9 + cheat + description:Walk faster + code:245a/01/02 + cheat + description:Human male - Start with 1 strength point + code:7123/08/01 + cheat + description:Human male - 5 strength points + code:7123/08/05 + cheat + description:Human male - 2 defense points + code:7124/01/02 + cheat + description:Human male - 6 defense points + code:7124/01/06 + cheat + description:Human male - 3 agility points + code:7125/04/03 + cheat + description:Human male - 7 agility points + code:7125/04/07 + cheat + description:Human male - 4 mana points + code:7126/00/04 + cheat + description:Human male - 8 mana points + code:7126/00/08 + cheat + description:Human male - 1 HP + code:7258/3c/01 + cheat + description:Human male - Start with 5 HP + code:7258/3c/05 + +cartridge sha256:2d89231f9e264a024d634bcf7d00de5a66d8a45f6f4ca33e1fc1602a35b9840b + name:Final Fantasy Legend II (USA) + cheat + description:Infinite HP (don't heal or stay and Inn) + code:4064/11/b9 + cheat + description:0 HP - enemies + code:448c/7c/af+4489/7d/af + cheat + description:Infinite item usage + code:5d28/35/00+41f0/12/00 + cheat + description:Items are free + code:655b/30/00+655c/cd/fa + cheat + description:Get extra GP and Meat + code:4d23/30/c9 + cheat + description:Get tons of GP after every battle + code:4d23/30/00 + cheat + description:Engage in a fight every second + code:2fc5/35/37 + cheat + description:Start with 15,163 HP (shows only 999) - All characters + code:0596/78/00+059c/78/00 + cheat + description:Start with 9 HP + code:78e2/3b/09 + cheat + description:Start with 9 defense points + code:78e6/03/09 + cheat + description:Start with 9 mana points + code:78e7/03/09 + cheat + description:Start with 9 agility points + code:78e5/05/09 + cheat + description:Start with 9 strength points + code:78e4/06/09 + cheat + description:Start with 9 swords (if your character can start with swords) + code:7e81/32/09 + +cartridge sha256:5ed87f65225b72a74c3c04a4e5d67683fb5cc33e5f1266157350828ab973fc1d + name:Final Fantasy Legend III (USA) + cheat + description:Set initial power to mega-power + code:7a92/00/ff+7891/32/ff+7893/32/ff + cheat + description:Always strike first + code:6aa0/76/ff + cheat + description:Able to run from every battle, even bosses + code:4ab4/52/ff + cheat + description:Gain extra EXP and GP + code:57ca/37/d7 + cheat + description:Defeating leftmost or upper-left enemy defeats all enemies on screen + code:54ca/37/02 + cheat + description:Gain a level after every battle on a new game - Character 1 (Hero - Arthur) + code:7a87/01/ff + cheat + description:Gain a level after every battle on a new game - Character 2 (Boy - Curtis) + code:7ae7/01/ff + cheat + description:Gain a level after every battle on a new game - Character 3 (Girl - Gloria) + code:7b47/00/ff + cheat + description:Gain a level after every battle on a new game - Character 4 (Heroine - Sharon) + code:7ba7/00/ff + +cartridge sha256:8327ed0d686d223995f86c267eeaf5f450c0d16a9bf9b6925dcb52cd1481f0e1 + name:Fish Dude (USA) + cheat + description:Infinite lives + code:02a8/35/00 + cheat + description:No timer + code:0525/fa/21 + cheat + description:Start with 1 life + code:023d/02/00 + cheat + description:Start with 5 lives + code:023d/02/04 + cheat + description:Start with 9 lives + code:023d/02/08 + cheat + description:Start with 15 lives (ignore counter for first 5 lives) + code:023d/02/0e + +cartridge sha256:da62ce2133b788e88605fad8f8d15582457d2a08de88124f231ef943ffba8805 + name:Fist of the North Star (USA) + cheat + description:Almost invincible + code:0e9f/ea/21 + cheat + description:No energy loss from weapons thrown + code:0fa5/ea/21 + cheat + description:Hit anywhere - both players + code:10d0/06/00+10d5/30/18 + cheat + description:One hit kills + code:0e10/09/00 + cheat + description:Start on level 5 + code:1bcc/01/05 + cheat + description:Start on level 9 + code:1bcc/01/09 + cheat + description:Start with 25% energy + code:1ff7/ff/40 + cheat + description:Start with 50% energy + code:14f7/ff/7f + cheat + description:Start with 75% energy + code:14f7/ff/c4 + +cartridge sha256:eededd0318cc5b80a2aa019a9a7eb3dfb9cb9ac11d974d24d704d7d4cf771a94 + name:Flash, The (USA, Europe) + cheat + description:Infinite energy (except against exploding bombs) + code:0a85/c1/00 + cheat + description:Infinite lives + code:03a8/c0/00 + cheat + description:Infinite time (disable at end of each stage) + code:3db6/35/00 + cheat + description:Start with 1 life + code:059c/03/01 + cheat + description:Start with 6 lives + code:059c/03/06 + cheat + description:Start with 1/2 surge power + code:05a1/8f/4c + cheat + description:Start with 1/2 energy + code:05a6/48/24 + +cartridge sha256:23fe1e88229645354f665908eb0dcd39cd8f3fbbeebec4bd93d11f7740a478e4 + name:Flipull (USA) + cheat + description:Any block can clear an entire row or column + code:22df/20/3e+2177/20/3e + +cartridge sha256:44bd5dd98b6ca3730435197d5af7f4fb6fa0f86fecf9b74005d5a76c28870f88 + name:Foreman for Real (USA, Europe) + cheat + description:Enable everyone for tournament mode + code:0c9b/01/00+0ca0/0f/13 + +cartridge sha256:06643cffc888b1c0c80ccae3cef66babb9b878ee594c29de8c9216bddd48287f + name:Fortified Zone (USA, Europe) + cheat + description:Hit anywhere + code:6317/fe/18+6318/ff/14 + +cartridge sha256:f07e6f63023d997a83066b422024242d6a7b61cee1af0c1fc41e6fbf4b54b65b + name:Frogger (USA) + cheat + description:Invincibility + code:0d14/ea/fa+0a7f/ea/fa + cheat + description:Infinite lives + code:0b6d/ea/fa + cheat + description:Infinite time + code:0e84/77/00 + +cartridge sha256:1f60f516020ef685d353dcbff810e4d93d09a4bcf6f6e87803768ea776c85929 + name:Frogger (USA) + cheat + description:Invincibility + code:0d12/3e/c9+0a7b/20/18 + cheat + description:Infinite time + code:0e71/c0/c9 + +cartridge sha256:8c144ddebdc63631949ba0f946ae4a745be4aaf1082736676cb1af61887ab7a2 + name:Frogger 2 (USA) + cheat + description:Invincibility + code:0e5f/3e/c9+0e3d/3e/c9 + cheat + description:Infinite time + code:036d/34/00 + +cartridge sha256:d96da0c0c17a164c398b2d5b02cbe92e7eafbfa755fee649d159b46e61814dc6 + name:Galaga - Destination Earth (USA) + cheat + description:Invincibility + code:51b2/28/18+764c/30/18 + cheat + description:Hit anywhere + code:5a5a/d2/fa+5a8b/d2/fa+5a71/da/fa + +cartridge sha256:af4fda51b28e426f6cab8b48037cf2cbc18ad6c1f02311ad901365aa52c918b7 + name:Ganso!! Yancha Maru (Japan) + cheat + description:Invincibility (the second code kills enemies on contact) + code:4776/07/00+477b/01/00 + cheat + description:Infinite Shurikens on pick-up + code:0b8d/03/01 + cheat + description:999 coins on pick-up + code:0c5f/d0/00 + cheat + description:Infinite time + code:0bb9/77/00 + +cartridge sha256:ad6f9fe97a40418279d3b834a64d9c6c52c0da209f430718f2bd02611892326f + name:Gargoyle's Quest (USA, Europe) + cheat + description:Invincibility + code:6e17/c8/c9 + cheat + description:Hit anywhere + code:7bb0/30/3e+7ba6/30/3e + +cartridge sha256:b7774eb039d335d8870b28e05ff7bc0869c46d0accc0d7f467affd71bbae8871 + name:Gauntlet II (USA, Europe) + cheat + description:Invincibility + code:432d/d2/c3 + +cartridge sha256:4bbf52ae46599bed5e08c6ea97f05220a4a5244f35519003d9b66e9d77328fe1 + name:Gekitou Power Modeller (Japan) (SGB Enhanced) + cheat + description:Invincibility against normal attacks - P1 + code:790e/28/18 + cheat + description:Hit anywhere + code:7878/7e/0b+7874/ae/84 + +cartridge sha256:78d35816612a521315e0b0618886e4b9e1005c58e459248c7e7585d8c04e71ac + name:George Foreman's KO Boxing (USA, Europe) + cheat + description:Infinite health (display still decreases) + code:19cb/28/3e + cheat + description:Infinite time + code:1189/01/00 + cheat + description:Infinite super punch + code:17ee/38/3e + +cartridge sha256:ca9d168e068492644cf054a2e35f0bccc31af5899e54c05a2cbc740247014a51 + name:Gex - Enter the Gecko (USA, Europe) + cheat + description:Invincibility + code:06bf/cd/c9 + cheat + description:Hit anywhere + code:51bf/d0/00+51c9/d0/00 + cheat + description:Get Skulls from anywhere (the ones that are not dropped by enemies) + code:6516/0d/00+650c/17/00 + cheat + description:Moon jump + code:4279/20/02+4277/d2/d5+4276/09/9f + +cartridge sha256:af1c1c11d7039fbf03932b17629b8ad17c275d1cb638fdb2e00dab5084919cb9 + name:Gex 3 - Deep Pocket Gecko (USA) + cheat + description:Invincibility + code:4f94/35/77+4f92/28/3e + cheat + description:Hit anywhere + code:5566/fd/94+5565/c2/c3 + cheat + description:Get Butterflies from anywhere (the ones that are not dropped by enemies) + code:61c9/0a/00+61bf/14/00 + cheat + description:Moon jump + code:48c0/66/4e+48be/d8/da+48bd/05/d7 + +cartridge sha256:895524c63a57b94718e63cd8f71db21617e1692788659cd7cec8e3470b7921f2 + name:Ghosts'n Goblins (USA, Europe) + cheat + description:Invincibility + code:3335/f0/c9 + cheat + description:Hit anywhere + code:21d8/3b/00 + +cartridge sha256:1d47b7e1d6654747e41bd38bf2f6064c23537e9bcea280634f263cdccc6ec5e4 + name:Ghostbusters II (USA, Europe) + cheat + description:Get visible ghosts from anywhere (press B) + code:4795/28/3e+4772/29/00 + +cartridge sha256:dc898d66af6c2ada73946f1cb68f1539c16240060f72e31da5bee2ba2655fcbc + name:Goal! (USA) + cheat + description:Infinite time + code:19ef/01/00 + cheat + description:Select time of up to 99 minutes per half + code:43ec/2d/63 + cheat + description:No goals scored against you by computer + code:4ada/3c/00 + cheat + description:Some teammates have a mega-kick + code:555b/0b/22 + cheat + description:Player 2 is fastest on the pitch + code:555a/09/ff+555b/0b/ff+555c/09/ff + +cartridge sha256:185f092bbebd5fa29a82ffb7d18c8242f75d6f8fee968cf6dee00b32a879febb + name:God Medicine - Hukkoku Ban (Japan) (SGB Enhanced) + cheat + description:Sell an item to get maximum cash + code:5f60/03/00 + cheat + description:Gain maximum EXP after each battle + code:460c/d8/00 + cheat + description:No random battles + code:3294/c8/c9 + cheat + description:Enemies have no HP + code:404a/1a/af+4052/1a/af + cheat + description:Final boss has no HP + code:75d6/03/00 + +cartridge sha256:0f129d30e71c578d737cc9ca6be57abe68d8ba12a934da7d90a3949e192b0dfb + name:Gold and Glory - The Road to El Dorado (USA) + cheat + description:Invincibility + code:5603/1b/00+55f9/d6/3e + cheat + description:Hit anywhere + code:6dd9/f0/c9+6dd8/47/37 + cheat + description:Multi-jump + code:53e3/ec/e0+53e1/20/00+53b5/20/18+53a2/5f/00 + +cartridge sha256:896d9ffbdfe35c802cdcb66b5a6ce84a4ad6bc356c85067904883944a621cbb4 + name:Golf (World) + cheat + description:Wind power is 10 mph + code:1d87/38/3e+1d88/09/5e + +cartridge sha256:4c4397870b96a88e3232f7437945ba122ab2e951b3fe2bb7775d99843d1d6aa5 + name:Grandia - Parallel Trippers (Japan) + cheat + description:Walk anywhere + code:4c57/ea/fa+4c65/ea/fa + cheat + description:Skip battles + code:69c8/ea/fa+6a34/30/18 + +cartridge sha256:2ed249eb86d4fd01e10efd1787a545f4921c19dc0e00b5c516b8bbdfe4c4aedc + name:Gradius - The Interstellar Assault (USA) + cheat + description:Invincibility + code:5118/fa/c9 + cheat + description:Hit anywhere + code:4a57/64/59+5a95/01/05+4a4a/d0/00+4a39/d0/00 + +cartridge sha256:77e9ab506b0995d958fa4b320b9076ee3408de063f76140663c01ae6c32ae3aa + name:Grand Theft Auto (USA) + cheat + description:Infinite ammo + code:46fb/35/00 + cheat + description:Jesus mode + code:1b4d/28/c9 + +cartridge sha256:da9bbcdbd8baba652599419c3d828697c206fb9290b9e008c2ed9ca6103561e8 + name:Great Greed (USA) + cheat + description:No random battles + code:4934/46/00 + cheat + description:One hit kills + code:4c1f/9f/7c + cheat + description:Enemies don't attack + code:466f/28/18 + cheat + description:Walk through walls + code:4e60/55/00 + +cartridge sha256:c1b7a9c2c3df31292b70824159e8c102045f23ac38b263b23ef17a96d8b60c44 + name:HAL Wrestling (USA) + cheat + description:CPU loses all health with one hit + code:2eaa/30/3e + cheat + description:CPU can't recover health + code:58a4/ea/fa + +cartridge sha256:6281ee9af82cbd882250de4802465876a630239b1bc27c1c58b2b3c4ac6fa5d3 + name:Hatris (Japan, USA) + cheat + description:Eliminate a stack with two hats + code:31e6/20/3e+320b/d2/c3 + +cartridge sha256:bfbed25beef74dec194a7330e3f4864a4b82f28927121cf03d9b871965553420 + name:Heavyweight Championship Boxing (USA) + cheat + description:No ring timer + code:1ba4/01/00 + cheat + description:No round increase + code:46e1/3d/af + cheat + description:Juggle your power - can alter power settings and give full power in all categories + code:18b2/3d/00 + cheat + description:Start with punch, life and speed at 1 + code:0478/03/01 + cheat + description:Start with punch, life and speed at 2 + code:0478/03/02 + cheat + description:Start with punch, life and speed at 3 + code:0478/03/03 + cheat + description:Start with punch, life and speed at 4 + code:0478/03/04 + cheat + description:Start with punch, life and speed at 5 + code:0478/03/05 + cheat + description:Start with punch, life and speed at 6 + code:0478/03/06 + cheat + description:Start with punch, life and speed at 7 + code:0478/03/07 + cheat + description:Start with punch, life and speed at 8 + code:0478/03/08 + cheat + description:Start with punch, life and speed at 9 + code:0478/03/09 + cheat + description:Start with super power + code:0478/03/99 + +cartridge sha256:6bf16580b0047f7b0dbaf2bf9a2d34095e057efe70414feeda48de8dcf8952fd + name:High Stakes (USA) + cheat + description:Once you've collected an item from Shady, you can't lose it - blackjack mission 1 only + code:4cad/35/00+566b/35/00 + cheat + description:Betting and cheat tokens cost 0 + code:1bb1/12/00 + cheat + description:No limit to how much you can buy of each item from Shady + code:1003/78/00+40b2/c2/00 + cheat + description:Start with 1/2 money (display will show $50,000) + code:08d8/c3/62 + cheat + description:Start with over $65,000 (display will show $50,000) + code:08d8/c3/ff + +cartridge sha256:f6bdf9f2c4148ce7da23986524781ee844729f360ff9ef27d695ecf0886ff9e0 + name:Hit the Ice - VHL - The Official Video Hockey League (USA, Europe) + cheat + description:Infinite timer + code:1a54/01/00 + cheat + description:Faster timer + code:1a54/01/02 + cheat + description:Infinite super shots + code:2297/34/00 + cheat + description:Only 1 super shot allowed + code:2299/0a/01 + cheat + description:5 super shots allowed + code:2299/0a/05 + cheat + description:10 super shots allowed + code:2299/0a/0a + cheat + description:1-minute periods - vs. mode + code:41f6/05/01 + cheat + description:2-minute periods - vs. mode + code:41f6/05/02 + cheat + description:10-minute periods - vs. mode + code:41f6/05/0a + cheat + description:Neither team can score + code:4439/01/00 + cheat + description:10 seconds in short race after the first shot of 20 seconds + code:1197/20/0a + cheat + description:15 seconds in short race after the first shot of 20 seconds + code:1197/20/0f + cheat + description:5 seconds in short race after the first shot of 20 seconds + code:1197/20/05 + +cartridge sha256:2449307e540566135734977b01ca488a3feb2ce9d887f69a275a308b5a78cc3f + name:Home Alone (USA, Europe) + cheat + description:Invincibility + code:2abd/d0/c9 + cheat + description:Infinite hit points + code:2b5a/3d/00 + cheat + description:Hit anywhere + code:2cb6/d2/fa+2cc7/d2/fa + cheat + description:No enemies + code:0434/fa/21 + cheat + description:Multi-jump + code:1933/3e/00 + cheat + description:Need 1 treasure to finish level 1 + code:23e5/24/01 + cheat + description:Start with 1 hit point + code:23ad/03/01 + cheat + description:Start with 6 hit points + code:23ad/03/06 + cheat + description:Start with 9 hit points + code:23ad/03/09 + +cartridge sha256:f1506c97b36e776a8839187b278efacdfacaa6bb5cf0b3f18e04ced31d0d4a01 + name:Home Alone 2 - Lost In New York (USA, Europe) + cheat + description:Infinite lives + code:1782/3d/00 + cheat + description:Infinite hits unless picked up by shoulders + code:17e9/3d/00 + cheat + description:Get 111,111 points instantly + code:1675/78/00 + cheat + description:Start with 5 lives + code:166f/03/05 + cheat + description:Start with 6 lives + code:166f/03/06 + +cartridge sha256:0dc2278500feb3844ba0ceabee289be011da1084903ab1c3fd681c83e7191118 + name:Hook (USA) + cheat + description:Infinite lives + code:2cfd/35/3d + cheat + description:Multi-jump + code:5f23/30/00 + cheat + description:Skip intro screen + code:3637/06/18+3638/00/23 + +cartridge sha256:a04db245f19a55cd3ff43e2b3fc51cc747fc048a551c4e18639fef4af77553e1 + name:Humans, The (USA) + cheat + description:Infinite humans + code:03e9/ea/fa + cheat + description:Infinite time + code:39b7/ea/fa + cheat + description:Start with 6 humans + code:6d60/0c/06 + cheat + description:Start with 9 humans + code:6d60/0c/09 + cheat + description:Start with 15 humans + code:6d60/0c/0f + +cartridge sha256:690f7b634282d9e8d0ba74f32164f08be45eab1f213bd2c4f02f2b75e22b1773 + name:Ikari no Yousai 2 (Japan) + cheat + description:Invincibility + code:14bb/28/3e + cheat + description:Hit anywhere + code:0caf/d8/00+0cb1/d0/00+0ccc/d8/00+0ad3/ea/fa+0cce/d0/00 + +cartridge sha256:ef563c4a4b063ea045d71b435dd078c19d0738f85079928803167cee8f34a4ec + name:Incredible Crash Dummies, The (USA, Europe) + cheat + description:Infinite time + code:313e/01/00 + cheat + description:Faster timer + code:913e/01/02 + cheat + description:Don't lose money when you go through fire + code:5b00/ff/00 + cheat + description:More cash for each hit + code:3149/83/85 + cheat + description:Start with 2 lives + code:02a9/05/02 + cheat + description:Start with 4 lives + code:02a9/05/04 + cheat + description:Start with 8 lives + code:02a9/05/08 + +cartridge sha256:a900ffcc69fa1fa94dc99584b94914de46d2fa9f1a38c8c303c493a5ee008fec + name:In Your Face (USA) + cheat + description:Computer can't score - when it scores, you get the points + code:14e9/23/00 + cheat + description:Opponents are frozen - 2-on-2 game + code:08aa/c2/c3 + cheat + description:5-second game + code:1a08/59/05 + cheat + description:10-second game + code:1a08/59/0a + cheat + description:20-second game + code:1a08/59/20 + +cartridge sha256:616202e0c2bea4898268c9b3a4eb22e198f1b559e29406057e039dded3db9637 + name:Jeep Jamboree (USA) + cheat + description:Always finish in 1st place + code:1c62/80/3e+1c63/3c/01 + cheat + description:Mega speed - stay at constant high speed even when off course and hitting rocks + code:69d4/7d/79+69d7/7c/79 + cheat + description:Race 1 lap shorter + code:5bf0/01/02 + cheat + description:Race 2 laps shorter + code:5bf0/01/03 + cheat + description:Race 3 laps shorter + code:5bf0/01/04 + +cartridge sha256:7459baee09bf535b8a5402c4c9f9ffc91642a473b7a0ef6085f1df47a35354a0 + name:Jeopardy! (USA) + cheat + description:Always correct (even if you enter nothing) + code:124c/c8/00+1252/28/18 + +cartridge sha256:5eaa028521fbff19dd87cd65a89a1a964ab098e343f4df6a94acae0d24b65e7d + name:Jeopardy! - Sports Edition (USA) + cheat + description:Always correct (even if you enter nothing) + code:1263/28/18+125d/c8/00 + +cartridge sha256:9f8a2dec7c3faa1ca2c12dd819cb36dc331a0ff7c2bb1b49786568e9df016357 + name:Jeopardy! - Teen Tournament (USA) (SGB Enhanced) + cheat + description:Always correct (even if you enter nothing) + code:1289/28/18+1283/c8/00 + +cartridge sha256:873d813fc51b735571c721c12922e85f200ee66f0cb742a60e4a9a63aea74944 + name:Jetsons, The - Robot Panic (USA, Europe) + cheat + description:Infinite lives + code:0fc7/01/00 + cheat + description:Infinite health - some robots can't be killed (disable to fight them) + code:7908/77/00 + cheat + description:Max collectible health + code:3f1e/05/09 + cheat + description:Capped robots on first Elroy stage take 1 hit to kill + code:42a7/02/01 + cheat + description:Capped robots on first Elroy stage take 8 hits to kill + code:42a7/02/08 + cheat + description:Start with 4 lives + code:3f16/03/04 + cheat + description:Start with 7 lives + code:3f16/03/07 + cheat + description:Start with 9 lives + code:3f16/03/09 + +cartridge sha256:bbc006dcf175f1fec822c533bed6abc136a98bcb3b6f8d726cc87c8e17c62e1f + name:Joe & Mac (USA) + cheat + description:Infinite lives + code:2237/01/00 + cheat + description:Infinite health + code:3be9/ea/fa + cheat + description:Take one hit and lose life + code:3be8/91/af + cheat + description:No extra energy from pick-ups + code:3bd8/77/00 + cheat + description:Start with 1 life + code:0a81/03/01 + cheat + description:Start with 6 lives + code:0a81/03/06 + cheat + description:Start with 9 lives + code:0a81/03/09 + cheat + description:Start on level 3 + code:0a89/e0/3e+0a8a/e5/02+0a8b/f0/e0 + cheat + description:Start on level 6 + code:0a89/e0/3e+0a8a/e5/05+0a8b/f0/e0 + cheat + description:Start on level 9 + code:0a89/e0/3e+0a8a/e5/08+0a8b/f0/e0 + +cartridge sha256:63a7bfef616b1f9c19c90fdbbea1a096fd1ab6aad16f67d619b07842b0ad04c1 + name:Jordan vs Bird - One on One (USA, Europe) + cheat + description:Infinite time of possession-1-on-1 game + code:2706/01/00 + cheat + description:8 seconds of possession-1-on-1 game + code:8dd6/24/08 + cheat + description:10 seconds of possession-1-on-1 game + code:8de6/24/0a + cheat + description:15 seconds of possession-1-on-1 game + code:8dd6/24/0f + cheat + description:No timer + code:2748/01/00 + cheat + description:5 points on 3-point shots + code:2672/02/05+2681/02/05 + cheat + description:8 points on 3-point shots + code:2672/02/08+2681/02/08 + cheat + description:12 points on 3-point shots + code:2672/02/0c+2681/02/0c + cheat + description:5 points on 2-point shots + code:26a1/01/05+26ad/02/05 + cheat + description:8 points on 2-point shots + code:26a1/01/08+26ad/02/08 + cheat + description:12 points on 2-point shots + code:26a1/01/0c+26ad/02/0c + +cartridge sha256:6b13a664a3c74e6e61b019f4024f65b3fb301ee5518a9cf9e2a27dc41bbdd561 + name:Jurassic Park (USA) + cheat + description:Infinite hearts + code:1c46/3d/00 + cheat + description:Infinite lives + code:1c11/01/00 + cheat + description:Remove All Objects (Disable this code to collect eggs, enable it to avoid the dinosaurs) + code:4c55/3c/9b+3075/49/f8+4642/8e/00 + cheat + description:Only need 1 card to open the gate + code:43c9/27/af + cheat + description:Canメt collect any energy + code:43dc/3c/00 + cheat + description:First Aid gives you mega energy + code:43dc/3c/af + cheat + description:Get max energy from collecting energy + code:43da/28/3e+43db/05/03 + cheat + description:Die after one hit + code:1c46/3d/af + cheat + description:Start with 1 lives + code:039e/03/01 + cheat + description:Start with 5 lives + code:039e/03/05 + cheat + description:Start with 7 lives + code:039e/03/07 + cheat + description:Start with 9 lives + code:039e/03/09 + cheat + description:Start with 1 heart - after 1st life + code:1c06/04/01 + cheat + description:Start with 9 hearts - after 1st life + code:1c06/04/09 + cheat + description:Start with 1 heart - 1st life + code:039b/04/01 + cheat + description:Start with 9 hearts - 1st life + code:039b/04/09 + +cartridge sha256:5b3e8b6b22662607933bac74e03059ceb7274b6ed3dc2c8752cab45472584a3a + name:Karate Joe (Europe) (Unl) + cheat + description:Invincibility + code:1e82/35/77+1e80/28/3e + cheat + description:Hit anywhere + code:0fc1/d2/fa+0fbb/da/fa+0fa2/d2/fa+0f9c/da/fa + cheat + description:Hit anywhere - Boss + code:10e6/d2/fa+10e0/da/fa+10c7/d2/fa+10c1/da/fa + +cartridge sha256:5759871de43dd530b6e54bbd8025018576c0e5f97a2aa7128c091df33554ea91 + name:Ken Griffey Jr.'s Slugfest (USA) + cheat + description:Balls are considered strikes + code:6802/20/18 + +cartridge sha256:b0a1019b6199c923a6a764c15e7bf6d1bb0bef8a042c383f3e3ead74ab171ede + name:Kid Dracula (USA, Europe) + cheat + description:Invincibility + code:0813/77/00 + cheat + description:Infinite lives + code:5bf5/ea/fa + cheat + description:Hit anywhere + code:3a9d/d0/00+3aae/d0/00 + cheat + description:One hit kills + code:3bac/28/18 + cheat + description:Start with 1 energy heart + code:0543/03/01 + cheat + description:Start with 5 energy hearts + code:0543/03/05 + cheat + description:Start with 1 life + code:054b/02/00 + cheat + description:Start with 5 lives + code:054b/02/04 + cheat + description:Start with 10 lives + code:054b/02/09 + cheat + description:Start on level 3 + code:70cd/01/03 + cheat + description:Start on level 5 + code:70cd/01/05 + +cartridge sha256:92c1fbf422abb8f09ca7fdbb563d1284108cc042e60e1222422986d9a59f9d97 + name:Kid Icarus - Of Myths and Monsters (USA, Europe) + cheat + description:Hit anywhere + code:48b8/af/00 + cheat + description:Run into enemies to get Hearts + code:4567/28/18 + cheat + description:Collected hammers seem to count towards your enemy kill number + code:7ad1/79/c9+7ab4/c0/7a + cheat + description:Maximum kills after killing first enemy + code:0cca/d0/00 + +cartridge sha256:4a091956a579de541aa2eef831e6d0c07d8324255cff7cc889c8ed9b70847769 + name:Killer Instinct (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility - P1 + code:50d1/c0/c9+4b4c/d2/c3 + cheat + description:Hit anywhere - P1 + code:4b01/27/22+4b00/d2/c3 + cheat + description:Disable blocking - P2 + code:4518/ca/c3+501c/ca/c3 + cheat + description:Infinite health + code:47b0/ea/fa + cheat + description:Infinite time + code:6219/3d/00 + cheat + description:Round starts with 10 seconds + code:231c/99/10 + cheat + description:Round starts with 30 seconds + code:231c/99/30 + cheat + description:Round starts with 50 seconds + code:231c/99/50 + cheat + description:Round starts with 75 seconds + code:231c/99/75 + cheat + description:Fierce tiger fury does no damage + code:7b42/22/00 + cheat + description:Fierce tiger fury does more damage + code:7b42/22/88 + cheat + description:Fierce tiger fury kills + code:7b42/22/ff + cheat + description:Fierce wind kick does no damage + code:7b69/1f/00 + cheat + description:Fierce wind kick does more damage + code:7b69/1f/88 + cheat + description:Fierce wind kick kills + code:7b69/1f/ff + cheat + description:Fierce laser blade does no damage + code:7b83/1d/00 + cheat + description:Fierce laser blade does more damage + code:7b83/1d/88 + cheat + description:Fierce laser blade kills + code:7b83/1d/ff + cheat + description:Freeze everything except timer + code:2038/14/d9 + cheat + description:Start with very little energy + code:22ea/dc/01 + cheat + description:Start with 1/4 energy + code:22ea/dc/4b + cheat + description:Start with 1/2 energy + code:22ea/dc/88 + cheat + description:Start with 3/4 energy + code:22ea/dc/b4 + +cartridge sha256:0eac0600e7d9b243c5c648fc3d9f8b5d9962e3634d6ff0d6f1873281d31e8ff7 + name:King of Fighters '95, The (USA) (SGB Enhanced) + cheat + description:Hit anywhere - P1 + code:482d/13/00+4778/0e/00 + cheat + description:Blocking disabled - both players + code:2c57/de/9e + +cartridge sha256:0b5f1ddb0b40b34735c1adf42b46651526d1e55c14c13969659cf04fc2173e16 + name:Kirby's Block Ball (USA, Europe) (SGB Enhanced) + cheat + description:Paddle hits Kirby from anywhere + code:54a6/6d/01+54a5/d2/18 + +cartridge sha256:0f6dba94fae248d419083001c42c02a78be6bd3dff679c895517559e72c98d58 + name:Kirby's Dream Land (USA, Europe) + cheat + description:Infinite lives + code:46db/ea/fa + cheat + description:Infinite lives and gain points when hit + code:500c/fd/00+2ff1/e0/b1 + cheat + description:Infinite vitality bars except against end of stage boss + code:4463/ea/fa + cheat + description:Hit anywhere + code:43e1/05/00 + cheat + description:Inhale from anywhere + code:4853/39/00+4867/25/00 + cheat + description:Start with 2 lives + code:01bb/05/02 + cheat + description:Start with 5 lives + code:01bb/05/05 + cheat + description:Start with 9 lives + code:01bb/05/09 + cheat + description:Start with 2 vitality bars + code:01c0/06/02 + cheat + description:Start with 5 vitality bars + code:01c0/06/05 + cheat + description:Start with 9 vitality bars + code:01c0/06/09 + +cartridge sha256:08ddc36709d551b6c2b768e8280e0213ebe89a5088b34e1cc6c0e14977b8e312 + name:Kirby's Dream Land 2 (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility after one hit + code:7383/3d/00 + cheat + description:Don't flash at all after getting hit + code:52bf/60/01 + cheat + description:Don't flash as long after getting hit + code:52bf/60/20 + cheat + description:Infinite energy + code:27cb/ea/fa + cheat + description:Infinite lives + code:41c4/ea/fa + cheat + description:Hit anywhere + code:26e5/20/00+2704/30/18 + cheat + description:Inhale from anywhere + code:25be/3d/00+25df/1c/00 + cheat + description:Get items from anywhere + code:7b89/38/18 + cheat + description:One hit and you die + code:3a9e/90/af + cheat + description:Each star worth an extra life + code:7cde/07/01 + cheat + description:Can't get extra lives from stars + code:7cdc/3c/00 + cheat + description:Each star takes away a life + code:7cde/07/01+7c87/3c/3d + cheat + description:Start with 1 life + code:6d58/02/00 + cheat + description:Start with 5 lives + code:6d58/02/04 + cheat + description:Start with 7 lives + code:6d58/02/06 + cheat + description:Start with 10 lives + code:6d58/02/09 + +cartridge sha256:43bbc3111fe66b5d87940da810a1a0839ab7d48b50c327807538026241b40295 + name:Kirby's Pinball Land (USA, Europe) + cheat + description:Infinite bonus room time - disable to exit + code:5f1a/ea/fa + cheat + description:Infinite balls + code:4534/c0/00 + cheat + description:Infinite M-Tomato + code:43f6/c8/74 + cheat + description:30 seconds allowed in Wispy-Woods bonus room + code:60b9/60/30 + cheat + description:99 seconds allowed in Wispy-Woods bonus room + code:60b9/60/99 + cheat + description:Go straight to end of level bosses + code:6ecf/f0/3e+6ed0/d2/01 + cheat + description:Go straight to bonus games + code:6ecf/f0/3e+6ed0/d2/02 + cheat + description:DeDeDe takes 1 hit + code:4d1d/17/01 + cheat + description:Start with 5 balls + code:047c/03/05 + cheat + description:Start with 1 ball + code:047c/03/01 + cheat + description:Start with 9 balls + code:047c/03/09 + +cartridge sha256:e497ee2ed48507c32bb3a0c89f449d6f3e3e6b3850534f6af814aaa6d5dcefbd + name:Kirby's Star Stacker (USA, Europe) (SGB Enhanced) + cheat + description:Clear most blocks with any pair + code:6f75/0b/00+6f6d/13/00+6fa6/cc/cd+6f77/28/18 + +cartridge sha256:841bb9ea4b253145b2ed2225e6e81d396ddc4260a7ef6b42d54f0a7e25fef90d + name:Kizuchida Quiz da Gen-san da! (Japan) + cheat + description:Infinite time to answer + code:352d/34/00 + cheat + description:Always correct + code:3751/5d/53 + +cartridge sha256:214710311150029f87ab0c8d67713ac446f3b75057cbebdc8960455acb1824eb + name:Knockout Kings (USA, Europe) + cheat + description:Invincibility + code:5794/c2/c3 + cheat + description:Hit anywhere + code:582e/c2/fa+580c/c2/fa+581a/ca/fa+4f6d/ca/fa+57ff/c2/fa + +cartridge sha256:7c7fb68ae4693ee68fa67e6ac0aef20554b697411d859c30da778290be7b9280 + name:Koushien Pocket (Japan) (SGB Enhanced) + cheat + description:Balls are considered strikes + code:6657/13/00 + +cartridge sha256:cca2e1e06b50869a16b0b7bcef0095ff7d53af926419808da2b82fbab3762750 + name:Krusty's Fun House (USA, Europe) + cheat + description:Infinite lives + code:03ac/ea/fa + cheat + description:Infinite pies + code:46eb/ea/fa + cheat + description:Start with 2 pies + code:025d/0a/02 + cheat + description:Start with 7 pies + code:025d/0a/07 + cheat + description:Start with 15 pies (only shows 10) + code:025d/0a/0f + cheat + description:Start with 2 lives + code:0243/03/02+0258/03/02 + cheat + description:Start with 6 lives + code:0243/03/06+0258/03/06 + cheat + description:Start with 9 lives + code:0243/03/09+0258/03/09 + +cartridge sha256:dff23b973c6c5e85da109dfb346ee396625fa7f934bc7c4b853ce4f237dfa42a + name:Kung-Fu Master (USA, Europe) + cheat + description:Mostly invincible + code:09ff/35/00+0a42/90/00 + cheat + description:Infinite time (disable to complete level) + code:5c8e/35/00 + cheat + description:Hit anywhere + code:138d/02/00 + cheat + description:Touch weak enemies to defeat them + code:09e6/06/00 + +cartridge sha256:e1340810c6dd12f55ab5928f08fbec92975f2303bda68e2a4b94cd8bc5ddec33 + name:Kwirk - He's A-maze-ing! (USA, Europe) + cheat + description:Walk through walls + code:11d6/28/18+11d7/6f/1e + +cartridge sha256:4804741a60591a637103a54a6e3a5611bd775097c457fdf85775d74da93ab600 + name:Kyoro-chan Land (Japan) + cheat + description:Invincibility + code:29ee/38/3e + +cartridge sha256:dbcecd9ed9ee70e8f3a231eb0bda95c882ff0e9697d52fe919a02f076962de91 + name:Lamborghini American Challenge (USA, Europe) + cheat + description:Infinite money + code:328a/9e/00 + cheat + description:Infinite turbos + code:7931/35/00 + cheat + description:Increased money + code:1d1a/00/99 + cheat + description:No Loss Of Speed On Collisions + code:61c3/60/00 + cheat + description:No Loss Of Speed When Off Track + code:6a18/04/00 + cheat + description:Start With 2 Turbos + code:1d27/01/01 + cheat + description:Start With 6 Turbos + code:1d27/01/05 + cheat + description:Start With 10 Turbos + code:1d27/01/09 + +cartridge sha256:2451d61085652f25d36e35f1fa50dc7e6b51c6e20a50120decc33efcf1c91109 + name:Last Action Hero (USA, Europe) + cheat + description:Level select (# = level 1-9 or A for ending credits) + code:f000/ba/00 + +cartridge sha256:26c7fd748c4f34b6c091870ebaa0d4798216df6389642493681deb644752508c + name:Lawnmower Man, The (Europe) + cheat + description:Invincibility - Sidescrolling levels + code:4037/c4/fa+4030/c4/fa + cheat + description:Invincibility - Cyber Tube + code:429e/da/c3 + cheat + description:Invincibility - Virtual World + code:5f1f/30/18+6409/30/18 + cheat + description:Infinite lives + code:46fd/ea/fa+5a6d/ea/fa+4315/35/00+0faf/ea/fa+4554/ea/fa + +cartridge sha256:96db9c11cff58dd637efbdc11416580d1a05bb6cc119d9efa0b17bfb0d0f80ad + name:Lazlos' Leap (USA) + cheat + description:Move one piece to clear level (move a piece over another) + code:1fa0/06/07 + +cartridge sha256:7fcf3eec2ce487e804115b814b8ddc3f833bdae8d7e01df8975a1af029edefcd + name:Legend (Japan) + cheat + description:No random battles + code:3eef/d0/c9 + +cartridge sha256:21f712e213f43f9efb93ca039a5190fc09325d5d932af1fb2f8e90b4f9fd169f + name:Legend of Zelda, The - Link's Awakening (USA, Europe) + cheat + description:Infinite health + code:f000/04/00 + cheat + description:Infinite rupees (rupees aren't deducted for purchases you can afford) + code:5fbd/ea/fa+5fb2/ea/fa + 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:4c56/01/09+5c74/01/09 + cheat + description:Get 5 rupees for each single rupee + code:64ee/01/05 + cheat + description:Get 50 rupees for each single rupee + code:64ee/01/32 + cheat + description:Get 255 rupees for each single rupee + code:64ee/01/ff + cheat + description:Hookshot attaches to anything + code:7c9e/a0/9f+7ca3/77/ea+7ca4/a7/9f+7ca5/c9/c2 + 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:7716/b6/af + +cartridge sha256:5373296324b1ad40716f707239d42cfec8a1ee44ba6f0aa3e1809463747bf767 + name:Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev A) + cheat + description:Hookshot attaches to anything + code:7c9c/a0/9f+7ca0/77/ea+7ca1/a7/9f+7ca2/c9/c2 + +cartridge sha256:c95dd3d9cb798e86c28e3269554e458d434bf3277b96cadf5bc81cfacfb5ee60 + name:Legend of Zelda, The - Link's Awakening DX (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:6d73/fa/c9 + 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 free yourself. Allows you to go through walls starting from locations in the water. Doesn't work for underground passages. + code:745b/b6/af + +cartridge sha256:6285ba6201f17bc8595c600ebc2477d52561f0aff29b11f7fc3343bacb2e230b + name:Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev A) (SGB Enhanced) + cheat + description:Invincibility + code:6d68/fa/c9 + cheat + description:Hit anywhere + code:6e8d/d2/fa+6e6d/d2/fa+5a03/d0/90+6323/d0/90 + cheat + description:One hit kills + code:72ad/7e/00 + cheat + description:Shop items are free + code:7a2c/30/18 + cheat + description:Revive infinite times + code:63c9/55/04+63c8/28/18 + cheat + description:Throw more than one Boomerang at a time + code:4462/01/00 + cheat + description:Multi-jump + code:14d4/c0/00 + cheat + description:Walk over water, holes, etc + code:762f/ea/c9 + cheat + description:Can place up to 14 bombs at once + code:66a9/34/00 + cheat + description:Cut down almost anything with your sword + code:1633/c0/00+1616/ca/fa+1621/28/18 + cheat + description:Horse pieces always land standing + code:7691/04/00+7690/01/00 + cheat + description:Easier Wing Egg puzzle + code:7a90/07/0d+7a8e/be/02+7a8c/19/79+7a8d/79/fe + +cartridge sha256:5dee5816ed9b46cfc4a2d94f275e555dd3c5080eca00ded975a41a881a6d4c06 + name:Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev B) (SGB Enhanced) + cheat + description:Invincibility + code:6d68/fa/c9 + cheat + description:Hit anywhere + code:6e8d/d2/fa+6e6d/d2/fa+5a03/d0/90+6323/d0/90 + cheat + description:Shop items are free + code:7a2c/30/18 + cheat + description:Revive infinite times + code:63c9/55/04+63c8/28/18 + cheat + description:Cut down almost anything with your sword + code:1633/c0/00+1616/ca/fa+1621/28/18 + cheat + description:Horse pieces always land standing + code:7691/04/00+7690/01/00 + cheat + description:Easier Wing Egg puzzle + code:7a90/07/0d+7a8e/be/02+7a8c/19/79+7a8d/79/fe + +cartridge sha256:0b56b78a9e45452e98c33edd111234931f1e034dc097f6f23082eb8db6055474 + name:Legend of Zelda, The - Oracle of Ages (USA) + cheat + description:Invincibility + code:47df/7b/c9 + cheat + description:Infinite Seed/Bomb use on pick-up + code:17d3/01/00 + cheat + description:Hit anywhere + code:44e4/be/fe+533c/fd/fc+42b5/da/c3+6ec7/af/00 + cheat + description:Get items from anywhere + code:4214/d0/00+4b7b/d0/00 + cheat + description:Moon-jump + code:5328/20/18+5329/28/06 + cheat + description:Defeat 1 enemy for fully grown Gashas/Maple meeting + code:0246/c0/00 + cheat + description:Each Seed/Gasha/Bomb worth 99 + code:4592/02/00 + cheat + description:Cut down almost anything with your sword + code:78e1/3a/01+7936/1c/3a+4751/d0/00+4762/c8/00 + cheat + description:Walk through walls. It's not hard to get stuck, so save where it's safe. + code:5da5/1a/af + cheat + description:Always win shooting gallery mini-game + code:5085/20/18 + cheat + description:Never miss in Goron Dance + code:7908/28/18+7909/1d/1a + cheat + description:Mermaid Suite - hold down button instead of continuously pressing + code:5910/2a/29 + +cartridge sha256:862a51368fb30539279d336b3fe193b43876d2cb15c87a36f5da517804ab3971 + name:Legend of Zelda, The - Oracle of Seasons (USA) + cheat + description:Invincibility + code:47c7/7b/c9 + cheat + description:Infinite Seed/Bomb use on pick-up + code:17ac/01/00 + cheat + description:Hit anywhere + code:5a32/eb/00+448e/34/30+7780/d0/00+44cc/be/fe+429d/da/c3+6749/3d/00+6e3f/d0/00+463f/62/c9 + cheat + description:Get items from anywhere + code:420d/d0/00+4221/d0/00 + cheat + description:Moon-jump + code:515d/20/18+515e/31/06+5182/02/00 + cheat + description:Defeat 1 enemy for fully grown Gashas/Maple meeting + code:0246/c0/00 + cheat + description:Each Seed/Gasha/Bomb worth 99 + code:4598/02/00 + cheat + description:Cut down almost anything with your sword + code:4437/3d/56+774c/e1/01+4741/c8/00+4730/d0/00 + cheat + description:Walk through walls. It's not hard to get stuck, so save where it's safe. + code:5c96/1a/af + cheat + description:Touch any button to enter desert with pirate ship + code:6014/07/00 + cheat + description:Lost woods - no need to change seasons to move on (Noble Sword direction - L, L, L, L. Level 6 direction - L, D, R, U.) + code:5e0c/03/00 + +cartridge sha256:68e708010f14daa6013370d43b9ee00a2305b1a95285e7daafa6642a0677b8c2 + name:Lethal Weapon (USA, Europe) + cheat + description:Infinite weapon energy + code:1601/ea/fa + cheat + description:Infinite life energy (except falling down holes) + code:2a1d/ea/fa+2aa5/ea/fa + cheat + description:No enemies + code:445b/ff/00 + cheat + description:Start with weapon energy on 1/2 + code:19ce/40/1e + cheat + description:Start with life energy on 1/2 + code:19c3/40/23 + +cartridge sha256:c24d7fdc7706cf0e01cbdb8c67ce4fb8079015e2b533a731a520844126073d77 + name:Little Magic (Japan) + cheat + description:Invincibility + code:44cb/fa/ea + cheat + description:Stairs always open + code:5b4d/c2/fa + cheat + description:Walk anywhere + code:4721/08/00+4704/08/00+475b/08/00+473e/08/00 + +cartridge sha256:f15722ebebdae93e08bd6642d642614114f2d128778d6a131748c9855603e052 + name:Little Mermaid, The (USA) + cheat + description:Infinite energy + code:1822/35/c9 + cheat + description:Infinite lives + code:0c79/35/00 + cheat + description:Start with 2 lives + code:07f1/03/01 + cheat + description:Start with 6 lives + code:07f1/03/05 + cheat + description:Start with 10 lives + code:07f1/03/09 + cheat + description:Start with 1 energy pt + code:0896/03/01 + cheat + description:Start with 5 energy pts + code:0896/03/05 + cheat + description:Start with 8 energy pts + code:0896/03/08 + cheat + description:Start on level 2 + code:0807/ff/01 + cheat + description:Start on level 3 + code:0807/ff/02 + cheat + description:Start on level 4 + code:0807/ff/03 + cheat + description:Start on level 5 + code:0807/ff/04 + cheat + description:Start on level 6 + code:0807/ff/05 + cheat + description:See end of game credits + code:0807/ff/06 + +cartridge sha256:0d6c56da2fdb6b27d388912604ad97c2f71729604a075d76c1fcd923f29e6915 + name:Lock n' Chase ~ Lock 'n' Chase (World) + cheat + description:Invincibility + code:1764/28/3e + cheat + description:Press A to clear level (except final level) + code:255e/ae/b6+2560/a7/3d + +cartridge sha256:17b55c1a46af87f5dae066b0fdbe2b7cac05c29c3d86800e0717ed4c6325af3e + name:Looney Tunes (USA) + cheat + description:Infinite time + code:0890/3c/00 + cheat + description:Hit anywhere + code:7845/d2/fa+780a/d2/fa+7800/d2/fa + cheat + description:Multi-jump + code:4480/03/00 + cheat + description:Start with 99 lives + code:01ec/02/99 + +cartridge sha256:a62f8d94d9eb0633c03d6a67100b354ffee92bee2fff26c0de8c35796a544a53 + name:Looney Tunes (USA, Europe) + cheat + description:Infinite time + code:0890/3c/00 + cheat + description:Hit anywhere + code:7845/d2/fa+7809/bd/37+77ff/bc/37 + cheat + description:Multi-jump + code:4481/c2/fa + +cartridge sha256:53c29bbf5a96a600e4879374215c3bc840df0343bce7ef37a2b7f043b383cb1c + name:Looney Tunes - Carrot Crazy (USA) (En,Fr,Es) + cheat + description:Invincibility + code:17e0/e0/f0 + cheat + description:Invincible from high falls + code:28bb/20/18 + cheat + description:Hit anywhere + code:78cc/30/3e+78f6/20/3e+790e/38/3e+7908/20/3e + +cartridge sha256:59971b1b4a49e14b4870dd500682ece31f1654ce2f34a3799e5dcdeda5f5e73e + name:Looney Tunes Collector - Martian Revenge! (Europe) (En,Fr,De,Es,It,Nl) + cheat + description:Invincibility + code:3eee/c0/c9 + cheat + description:Hit anywhere + code:0ab7/0c/9b + cheat + description:Infinite ammo + code:5db3/77/00 + cheat + description:Get items from anywhere + code:569e/c8/00+5a80/c8/00 + cheat + description:Walk over space + code:519b/c8/c9 + +cartridge sha256:ff9b75f13d25595ebf286d284f6bb951648f3d67f0fd043947d3c48132441c7f + name:Lucky Luke (USA) (En,Fr,De,Es) + cheat + description:Invincibility + code:7647/e0/f0+32c7/e0/f0 + cheat + description:Infinite ammo + code:1916/77/00 + +cartridge sha256:4231fd9f25a5729208475d2d6aa6c2a6e53b1e918e7731a1eee3ce532993301b + name:Lufia - The Legend Returns (USA) + cheat + description:0 HP - Enemies + code:674b/2a/af+674c/46/47 + cheat + description:No random battles + code:4034/3c/af + cheat + description:Enemies always miss + code:7295/f5/c9 + cheat + description:Walk anywhere + code:55e6/ca/c3+55dd/01/00 + +cartridge sha256:2e102efe39e0825933f1fbf4b0b8cc2dbef42f3df809311a5c8a8c1d84899bf7 + name:M&M's Minis Madness (USA) + cheat + description:Multi-jump + code:65d0/ca/fa + +cartridge sha256:bf4cae27bd0dfdede3838d50f92d03cb7cd183a15091bd2a76c7b3fc7b3e718b + name:Madden '95 (USA, Europe) (SGB Enhanced) + cheat + description:Infinite play clock + code:1c3b/3d/00 + cheat + description:Infinite game time + code:1c62/3d/00+3933/e0/f0 + cheat + description:Start on second down + code:288e/01/02 + cheat + description:Start on third down + code:288e/01/03 + cheat + description:Start on fourth down + code:288e/01/04 + cheat + description:Down never increases + code:25de/3c/00+3ef0/ea/fa + +cartridge sha256:eabe2a1c9116871837ddb1d39d643621dc144c18490b5673bd8eedc88b8ceff9 + name:Malibu Beach Volleyball (USA) + cheat + description:Easier to score + code:4daa/04/03 + cheat + description:Computer can't score a point. If score is 0-0, makes you change court a lot. + code:5f0c/c1/00 + cheat + description:You always serve + code:5d0e/01/00+5de0/01/00 + +cartridge sha256:0d479d68a4ac800ab9fde8b3db016af718c13a979163b3eb34b00af96550cd3e + name:Mario's Picross (USA, Europe) (SGB Enhanced) + cheat + description:Infinite time + code:7b11/3d/00 + cheat + description:Mistakes don't decrease time + code:7c8f/91/00 + +cartridge sha256:2c45623446cf82896830712223079e9be5e79b3e5faf550c07f92f082bef419e + name:Maru's Mission (USA) + cheat + description:Infinite health + code:397c/91/00+3980/98/00 + +cartridge sha256:3fe6e53d0a44081f90a91004aa2ea4253a5a5933fff940c22e30e84029e4b2ef + name:Max (Europe) + cheat + description:Infinite Rockets + code:08dd/ea/fa + cheat + description:Hit anywhere + code:551a/38/18+550d/38/18+54b5/38/18+54a8/38/18 + +cartridge sha256:550995df4740397fccdc70d480c9a595260afb59bfcea0b0ec50cb5d55cfe9b0 + name:McDonaldland (Europe) + cheat + description:Invincibility + code:2639/28/3e + cheat + description:Hit anywhere - Throwing and pickup up blocks + code:3aaa/d2/fa + cheat + description:Multi-jump + code:3fa6/28/3e + +cartridge sha256:33d16365318411f063edd9100c79458aabb7ea71bb1873e30f38b93814f0ec6e + name:Mega Man - Dr. Wily's Revenge (USA) + cheat + description:Invincibility + code:55fa/01/00+683f/be/41 + cheat + description:Infinite weapons except Flash + code:4209/12/00+515a/ea/fa+4964/ea/fa + cheat + description:Hit anywhere + code:5861/fe/01+2a3d/13/15+2b47/7d/52+281a/af/00+2b5a/21/00+10d2/38/18+10d3/0c/11 + cheat + description:Multi-jump + code:6b24/21/fa+6b25/4a/3f+6b27/7e/e6+6b28/b7/01+6b2b/35/00+6cce/34/1c+6ccf/28/18 + cheat + description:One hit kills + code:2b62/01/00+4c87/01/00 + cheat + description:Moon jump + code:6b2a/4d/00+6b49/12/18+6b4a/af/18+6b4b/ea/2c + +cartridge sha256:be3fc7ab2d7eb79a9e2538b090bdecc2694740f3beda933f34cb1e4059b10a11 + name:Mega Man II (USA) + cheat + description:Invincibility + code:35ce/c0/c9 + cheat + description:Infinite weapons + code:3a14/90/00 + cheat + description:Multi-jump + code:00f0/ff/cd+00f1/ff/d4+00f2/ff/0f+00f3/ff/c9+1226/fa/cd+1227/6f/f0+1228/cf/00+122a/28/18+1244/20/00+1245/00/01 + +cartridge sha256:7344a36fcfc8151098238529218762e44c5a1546fab7e7fd5d32927e06cbf5a8 + name:Mega Man III (USA) + cheat + description:Infinite energy + code:6c09/77/00 + cheat + description:Infinite weapons + code:4235/12/00+5488/ea/fa+58a9/ea/fa + cheat + description:One hit kills + code:296e/01/00+0f25/01/00 + cheat + description:Laser barriers appear and explode immediately on Sparkman stage + code:3977/01/00 + cheat + description:Takes 1 hit to kill Merciless Matt + code:3953/07/01 + cheat + description:Takes 15 hits to kill Merciless Matt + code:3953/07/0f + cheat + description:Multi-jump + code:6e3f/21/fa+6e40/4a/3f+6e42/7e/e6+6e43/b7/01+6e46/35/00+7002/34/1c+7003/28/18 + cheat + description:Start with 2 lives + code:0b17/03/02 + cheat + description:Start with 6 lives + code:0b17/03/06 + cheat + description:Start with 9 lives + code:0b17/03/09 + +cartridge sha256:4d980ca46a83cd127312dbc445ed1a83e97ed7a8026dce6fdd22a01b1895781b + name:Mega Man IV (USA) + cheat + description:Invincibility + code:5fea/c2/21 + cheat + description:Infinite energy + code:61ce/77/00 + cheat + description:Infinite lives + code:0c45/df/01 + cheat + description:Shoot more than 3 shots at a time + code:4567/d0/00 + cheat + description:Start with 1/4 energy + code:09f6/98/26 + cheat + description:Start with 1/2 energy + code:09f6/98/4b + cheat + description:Start with 3/4 energy + code:09f6/98/70 + cheat + description:Start with 1 lives + code:0cae/03/01 + cheat + description:Start with 5 lives + code:0cae/03/05 + cheat + description:Start with 9 lives + code:0cae/03/09 + +cartridge sha256:7a108770a7c1ad592b52d0c46d7ead422d0a20961abaafca3d40086e3f2f588f + name:Mega Man V (USA) (SGB Enhanced) + cheat + description:Invincibility + code:6226/c2/21 + cheat + description:Infinite lives + code:0b75/df/01 + cheat + description:Infinite energy + code:641d/77/00 + cheat + description:Walk through enemies (can still take damage from projectiles) + code:12cd/00 + cheat + description:Hit anywhere + code:11fa/0c/11+11f9/38/18+7a0e/0c/11+7a0d/38/18 + cheat + description:Multi-jump + code:6682/21/fa+6683/52/40+6685/7e/e6+6686/b7/01+6689/35/00+6871/08/1c+6879/34/1c + cheat + description:One hit kills + code:1185/01/00+290e/01/00+7a4e/01/00 + cheat + description:Start with 1 lives + code:0bea/03/01 + cheat + description:Start with 5 lives + code:0bea/03/05 + cheat + description:Start with 9 lives + code:0bea/03/09 + cheat + description:Start with about 1/4 energy + code:0944/98/26 + cheat + description:Start with about 1/2 energy + code:0944/98/4b + cheat + description:Start with about 3/4 energy + code:0944/98/70 + +cartridge sha256:638225d961484c8749ff8ceba1c865d267a5401b0d37a3a84cac7a6fb6bd8b9a + name:Mega Man Xtreme (USA, Europe) + cheat + description:Invincibility + code:2d0e/28/18 + cheat + description:Infinite secondary weapons + code:6844/35/00 + cheat + description:Hit anywhere + code:2d62/77/0b+2d63/2d/2f + cheat + description:Get items from anywhere + code:7bd4/77/0b+7bd5/2d/2f + +cartridge sha256:e37a14a8e61bd64f2226dacc26a7ee75dd90abfcf88c5016eb97b76ecda0ddca + name:Mega Man Xtreme 2 (USA, Europe) + cheat + description:Invincibility + code:285e/28/18 + cheat + description:Infinite secondary weapons + code:66a9/77/00 + cheat + description:Hit anywhere + code:28b5/28/2a+28b4/cb/9d + cheat + description:get items from anywhere + code:75f3/09/00 + +cartridge sha256:bed7986ba7428470bf946a174810db1a49494f05a0985270a7c6d1ab6fe86f2b + name:Megalit (USA, Europe) + cheat + description:Infinite lives + code:026a/ea/fa + cheat + description:Infinite time - Quest mode + code:2d31/ea/fa + cheat + description:Blocks don't break + code:2f7f/34/00 + +cartridge sha256:0430cbbcdd56b693d40ab7b424603c639d98d5ec97e91e17ce1ede766104e765 + name:Merlin (Europe) (En,Fr,De,Es,It,Nl) + cheat + description:Level select (below Options at title screen) + code:6285/03/04 + +cartridge sha256:56a69d19ba26941a25adad8bdf17c7baba12245097e901999f4c897eec877ddb + name:Metal Gear Solid (USA) + cheat + description:Infinite ammo for all weapons + code:6318/3d/00 + cheat + description:Enemies don't see you + code:74a8/b7/c9+64e8/fa/c9 + cheat + description:Cameras don't see you (normal game and VR training) + code:7369/c8/c9 + +cartridge sha256:58130b462d7760624fa150938f5e3958f9185ef827644855acdef38ff6d55749 + name:Metal Walker (USA) + cheat + description:1 HP - enemies + code:4e2b/79/3c+4e24/78/af + cheat + description:No random battles + code:523e/c0/c9 + +cartridge sha256:3080bcc2eb9965de463f5f4e02f0dabbb13b060e1654a18da8b50948c10af4a6 + name:Metroid II - Return of Samus (World) + cheat + description:Invincibility against enemies + code:2ee8/c0/c9 + cheat + description:Infinite energy + code:2f6d/27/80 + cheat + description:Infinite missiles + code:4f36/01/00 + cheat + description:Hit anywhere + code:3270/36/0d+326f/30/18+52e3/30/18 + cheat + description:Multi-jump + code:0d46/13/14+0d45/9d/98+0d44/c2/cd+1430/ea/fa+1461/ea/fa + +cartridge sha256:7c96841877908473f7873c91373b06bfd3749b341b4c4180c8fd2cc8b8308b68 + name:Mickey Mouse (Europe) + cheat + description:Invincibility + code:625e/20/18 + cheat + description:Can open locked doors without 8 Keys + code:48ab/c2/fa + +cartridge sha256:bc14dac53de625535cc2825efa3d2399bf0c8c661f8a9417c4b97414a630cd0e + name:Mickey Mouse - Magic Wands (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:0e92/c8/3e + +cartridge sha256:fedb0c8100987cb466c116a3ac3a6572675b6aa721a7a8930cec1ae39f677bc6 + name:Mickey's Dangerous Chase (USA) + cheat + description:Invincibility after first hit + code:11a8/01/00 + cheat + description:Infinite health + code:1da0/ea/fa + cheat + description:Infinite lives + code:05e2/ea/fa + cheat + description:Start with 99 lives + code:04b6/03/63 + +cartridge sha256:573798e5dfa80c13f2c7f77795fa3460c0c41ffbc49ab3b830fb4bf30c89f179 + name:Mighty Morphin Power Rangers (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:2cb9/e0/c9+2d1e/21/c9+2c9f/f0/c9 + cheat + description:Hit anywhere + code:2e1e/30/3e+2e2a/38/18 + cheat + description:One hit kills - bosses + code:2e4a/28/18 + cheat + description:Multi-jump + code:26c9/38/00+2535/20/3e + +cartridge sha256:67f16ea0f0afdb20fa75cc988466c0726203412a57a36e0f866eb341ede5d311 + name:Mighty Morphin Power Rangers - The Movie (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:4c7b/d0/c9 + cheat + description:Hit anywhere + code:4041/03/00 + cheat + description:Can always use power + code:486d/c0/00 + +cartridge sha256:70124937963d44c034d73e3e3c7ecf9c3440cdb934cd1a8b6fd4629381343d02 + name:Milon's Secret Castle (USA, Europe) + cheat + description:Protection against most hazards + code:7d36/ea/fa + cheat + description:Infinite money on pick-up + code:678f/ea/fa + cheat + description:Each $ box is worth 99 + code:7713/fa/3e+7714/cf/62+7715/df/00 + cheat + description:Start with and keep double shot and shield + code:7cfd/ea/fa+5ca8/af/3c + cheat + description:Start with 3 energy bars + code:76ea/05/03 + cheat + description:Start with 6 energy bars + code:76ea/05/06 + cheat + description:Start with 9 energy bars + code:76ea/05/09 + +cartridge sha256:b136c40a4ca52d6567e7f71790690b1e71ddad3b9df8d1ee98135ac46a2e7637 + name:Minesweeper - Soukaitei (Japan) + cheat + description:Never miss + code:306b/28/18+3140/28/18 + +cartridge sha256:d74962fe1750b3918c6b5e34dd30851df50e33eaeb27659097d52090c9803705 + name:Miner 2049er Starring Bounty Bob (USA) + cheat + description:Invincibility + code:5239/d2/c3+52dd/d2/c3+4ca4/ea/fa + cheat + description:Infinite time + code:6223/01/00 + cheat + description:Infinite lives + code:423d/01/00 + cheat + description:Take 1 step to complete level + code:3f26/d2/fa + cheat + description:Nasties are invincible + code:09ca/00/03 + cheat + description:Start with 2 lives + code:269e/03/02 + cheat + description:Start with 4 lives + code:269e/03/04 + cheat + description:Start with 8 lives + code:269e/03/08 + +cartridge sha256:f6d779c4882e032919903b4874dec1b6f06716911f77eb9f8acd1727215eb791 + name:Missile Command (USA, Europe) + cheat + description:Infinite missiles + code:129a/3d/00+124b/3d/00+1ffd/0f/20 + cheat + description:Invincible bases + code:26bb/fe/ff + cheat + description:Hit anywhere + code:1f4d/da/c3+1fa8/af/37 + cheat + description:New York + code:1f28/00/02 + cheat + description:London + code:1f28/00/04 + cheat + description:Sydney + code:1f28/00/06 + cheat + description:Paris + code:1f28/00/08 + cheat + description:Moscow + code:1f28/00/0a + cheat + description:San Francisco + code:1f28/00/18 + +cartridge sha256:0b3e5a9611551cc135cebfa67fe3f9aa1a54ef9855c0888b715351035908e126 + name:Missile Command (USA) + cheat + description:Hit anywhere + code:1f4d/da/c3+1fa8/af/37 + cheat + description:Infinite Missiles + code:124c/ea/fa+129b/ea/fa + +cartridge sha256:3b0aaea526447c2d682139c9494eec82045b36e5e684cc56132391ba9a2ef689 + name:Momotarou Dengeki (Japan) + cheat + description:Hit anywhere + code:5184/c2/fa+51d8/c2/fa+51b1/c2/fa+5157/c2/fa + cheat + description:Multi-jump + code:2112/23/29+20a1/c2/fa + +cartridge sha256:f1bf118bd383a91ecf81f7ee759ce702b85cfee9f8cf11d8365cb243d555c607 + name:Momotarou Dengeki 2 (Japan) (SGB Enhanced) + cheat + description:Hit anywhere + code:5333/38/18+5382/38/18+5341/38/18+538f/38/18 + cheat + description:Multi-jump + code:4113/c2/fa+419e/2b/1d + +cartridge sha256:5bc4ca50f5cbbc2cf5e2fc98f4a4df661faab495369ab41d9a63c0f8d49c0fa3 + name:Monopoly (USA) + cheat + description:Infinite money - P1 + code:c47c/99+c47d/99+c47e/09 + cheat + description:Infinite money - P2 + code:c480/99+c481/99+c482/09 + cheat + description:Infinite money - P3 + code:c484/99+c485/99+c486/09 + cheat + description:Infinite money - P4 + code:c488/99+c489/99+c48a/09 + +cartridge sha256:003097c7a363da268fa2853262c1924ee72fe23fc546834b247c359f69a684aa + name:Montezuma's Return! (USA) (En,Es) + cheat + description:Invincibility against enemies + code:5580/c0/c9+490d/30/18 + cheat + description:Invincibility against fire + code:49e0/28/18 + cheat + description:Invincibility against high falls + code:4a2f/28/18 + +cartridge sha256:84686cd3c77c533926fc2c56783613ecc5781de1bff7065e00112a69d17a5e69 + name:Mortal Kombat (USA, Europe) + cheat + description:Infinite health - P1 + code:3594/d6/00 + cheat + description:Infinite time + code:1cb5/35/00 + cheat + description:Infinite continues + code:2296/d6/00 + cheat + description:Infinite fatality time + code:0a11/c2/c3 + cheat + description:One button fatality - Sonya (Press back, close but not close to opponent) + code:38c9/00/ff + cheat + description:One button fatality - Rayden (Press back) + code:3879/00/ff + cheat + description:One button fatality - Kano (Press down) + code:3889/00/ff + cheat + description:One button fatality - Liu Kang (Press foward) + code:3899/00/ff + cheat + description:One button fatality - Scorpion (Press forward, Halfway distance) + code:38aa/01/ff + cheat + description:One button fatality - Sub Zero (Press forward) + code:38b9/00/ff + cheat + description:Foot sweep does less damage + code:39c7/41/10 + cheat + description:Foot sweep does more damage + code:39c7/41/ff + cheat + description:Punches do less damage + code:39af/21/10 + cheat + description:Punches do more damage + code:39af/21/ff + cheat + description:Knees do less damage + code:39bf/41/10 + cheat + description:Knees do more damage + code:39bf/41/ff + cheat + description:Uppercuts do less damage + code:39a7/82/10 + cheat + description:Uppercuts do more damage + code:39a7/82/ff + cheat + description:Kicks to stomach do less damage + code:39cf/41/10 + cheat + description:Kicks to stomach do more damage + code:39cf/41/ff + cheat + description:Kicks to face do less damage + code:39b7/62/10 + cheat + description:Kicks to face do more damage + code:39b7/62/ff + cheat + description:Shoulder throws do less damage + code:3a17/41/10 + cheat + description:Shoulder throws do more damage + code:3a17/41/ff + cheat + description:Sub-Zero's slide does less damage + code:3a07/51/10 + cheat + description:Sub-Zero's slide does more damage + code:3a07/51/ff + cheat + description:Sonya's leg grab does less damage + code:3a27/61/10 + cheat + description:Sonya's leg grab does more damage + code:3a27/61/ff + cheat + description:Kano's cannonball does less damage + code:3a1f/61/10 + cheat + description:Kano's cannonball does more damage + code:3a1f/61/ff + cheat + description:Rayden's lightning does less damage + code:3a5f/e7/10 + cheat + description:Rayden's lightning does more damage + code:3a5f/e7/ff + cheat + description:1 continue + code:4014/06/01 + cheat + description:5 continues + code:4014/06/05 + cheat + description:10 continues + code:4014/06/0a + +cartridge sha256:29d69e0f71b692f348a0954cc3aaa86dcd9a32d8a7268ce6b76ba26b0c0e4629 + name:Mortal Kombat II (USA, Europe) + cheat + description:Infinite health + code:4948/dd/00 + cheat + description:Infinite continues + code:0dab/35/00 + cheat + description:Infinite time + code:4c55/01/00 + cheat + description:No continues + code:0157/06/00 + cheat + description:1 continue + code:0157/06/01 + cheat + description:3 continues + code:0157/06/03 + cheat + description:9 continues + code:0157/06/09 + cheat + description:15 continues + code:0157/06/0f + cheat + description:Much faster timer + code:4c55/01/02 + cheat + description:Timer starts at 30 + code:2339/9a/2c + cheat + description:Timer starts at 40 + code:2339/9a/3c + cheat + description:Timer starts at 50 + code:2339/9a/4c + cheat + description:Timer starts at 60 + code:2339/9a/5c + cheat + description:Player can't move from floor + code:462e/77/00+501f/77/00 + cheat + description:Complete round 1 and go to round 3 (disable after end of round) + code:1179/28/3e+117a/10/03+117b/f0/e0 + cheat + description:Complete round 1 and go to round 4 (disable after end of round) + code:1179/28/3e+117a/10/04+117b/f0/e0 + cheat + description:Computer can't move from floor + code:6327/3d/00+6324/3d/00 + cheat + description:Normal punches do more damage + code:60e8/31/f4 + cheat + description:Uppercuts do less damage + code:6100/f4/31 + cheat + description:Back throws do less damage + code:613a/c0/31 + cheat + description:Special moves (projectiles) do more damage + code:615a/82/f4 + +cartridge sha256:6c2733c0a57bbfe5075bec42e0735c685c934780db45b33f899f62dfea549f69 + name:Mortal Kombat 3 (USA) + cheat + description:Invincibility except for throws and projectiles + code:1a25/fa/00+1a26/e7/00+1a27/c0/7d+1a29/0f/14+1a2a/c0/c8+1d57/c8/c9 + cheat + description:Hit anywhere - P1 + code:1d30/04/00 + cheat + description:Enable Smoke + code:3dda/20/18 + cheat + description:Infinite Fatality time + code:0e16/35/00 + cheat + description:Cyrax one button Fatality (press Down) + code:44d5/80/16+44d4/00/ff+44d3/02/80 + cheat + description:Cyrax one button Babality (press Punch) + code:44ca/20/22+44c9/00/ff + cheat + description:Kabal one button Fatality (press Kick) + code:462a/00/ff+462b/08/16 + cheat + description:Kabal one button Babality (press Down) + code:4641/11/80+4643/10/22+4642/00/ff + cheat + description:Kano one button Fatality (press Down) + code:435b/11/80+435d/10/16+435c/00/ff + cheat + description:Kano one button Babality (press Kick) + code:436e/80/22+436d/00/ff + cheat + description:Sektor one button Fatality (press Block) + code:4468/20/16+4467/00/ff + cheat + description:Sektor one button Babality (press Kick) + code:4451/80/22+4450/00/ff + cheat + description:Sheeva one button Fatality (press Punch) + code:45d2/00/ff+45d3/10/16 + cheat + description:Sheeva one button Babality (press Kick) + code:4601/00/ff+4602/20/22 + cheat + description:Sindel one button Fatality (press Punch) + code:4573/10/16+4572/00/ff + cheat + description:Sindel one button Babality (press Up) + code:4559/10/22+4558/00/ff + cheat + description:Smoke one button Fatality (press Down) + code:451b/00/ff+451c/10/16 + cheat + description:Smoke one button Babality (press Kick) + code:4525/00/ff+4526/20/22 + cheat + description:Sonya one button Fatality (press Down) + code:4382/11/80+4383/10/ff+4384/00/16 + cheat + description:Sonya one button Fatality (press Kick) + code:43d1/00/ff+43d2/10/22 + cheat + description:Sub-Zero one button Fatality (press Forward) + code:46a2/00/ff+46a3/20/16 + cheat + description:Sub-Zero one button Babality (press Kick) + code:46d2/00/ff+46d3/20/22 + +cartridge sha256:cd999acce90fb40bb1231fda253fa8a0db9e26517ed4723353429aedf4ddf5db + name:Mortal Kombat 4 (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility - normal attacks + code:1ce0/c8/c9 + cheat + description:Hit anywhere - normal attacks + code:1ccb/0f/00 + cheat + description:Infinite Fatality Time + code:0e43/35/00 + cheat + description:Fujin one button Fatality (press Back) + code:43e5/10/16+43e4/00/ff + cheat + description:Liu Kang one button Fatality (press Down) + code:43cb/10/16+43ca/00/ff + cheat + description:Quanchi one button Fatality (press Forward) + code:4363/80/16+4362/00/ff + cheat + description:Raiden one button Fatality (press Up) + code:43a9/40/16+43a8/00/ff + cheat + description:Reiko and Shinnok one button Fatality (press Back) + code:4331/80/16+4330/00/ff + cheat + description:Reptile one button Fatality (press Punch) + code:438e/10/16+438d/00/ff + cheat + description:Scorpion one button Fatality (press Back) + code:437b/10/16+437a/00/ff + cheat + description:Sub Zero one button Fatality (press Down) + code:43f9/10/16+43f8/00/ff + cheat + description:Tanya one button Fatality (press Down) + code:4349/40/16+4348/00/ff + +cartridge sha256:abc725f10251ae954a23c46b7e33b101bc52203fed4ffad49018858d82361964 + name:Motocross Maniacs (USA) + cheat + description:Infinite tires on pick-up + code:1dcd/ea/fa + cheat + description:Infinite jet on pick-up + code:1dc7/ea/fa + cheat + description:Infinite time + code:2d22/01/00 + cheat + description:Faster timer + code:2d22/01/02 + cheat + description:Start with 7 nitros + code:09e4/04/07 + cheat + description:Super fast bike + code:201e/ea/fa+1988/96/00 + +cartridge sha256:e493b87e119d61268af2f97c9e16e65daab3c8223c15261214656667108cc817 + name:Mouse Trap Hotel (USA) + cheat + description:Infinite lives + code:220c/ea/fa + cheat + description:Collect cookie for invincibility against balls, etc. + code:06e9/ea/fa+06da/ea/fa + cheat + description:Start with 4 lives + code:0338/02/04 + cheat + description:Start with 6 lives + code:0338/02/06 + cheat + description:Start with 8 lives + code:0338/02/08 + +cartridge sha256:6e4876c4e6516d8f3325a7341bea05a275d91de178af080e174d697a4e3d5921 + name:Mr. Chin's Gourmet Paradise (USA) + cheat + description:Can eat momos without zapping them + code:1c51/ca/fa+1d4d/ca/fa+1cf9/ca/fa+1ca5/ca/fa + +cartridge sha256:c19f7ec9ff29fa438d7ef189f81711dcaedaa55c86b192d6d9020f5f7dc22702 + name:Mr. Do! (USA) + cheat + description:Invincibility + code:1c39/30/18 + cheat + description:Infinite lives + code:3728/ea/fa + cheat + description:Only 1 Cherry needed to complete level + code:3e35/3d/af + cheat + description:Keep 1 map layout thru game (still will progress from map to map, but layout stays the same) + code:182c/fe/3e+182d/0a/09+182e/20/18 + cheat + description:Start new game from level you died on + code:356a/22/23+2478/ea/21 + cheat + description:Start with 1 life + code:15b2/03/01 + cheat + description:Start with 6 lives + code:15b2/03/06 + cheat + description:Start with 9 lives + code:15b2/03/09 + +cartridge sha256:ccf89ab34bbea5c54cf8da205bd5db9364c1e81136a8ffd009fa0f822d0373a8 + name:Mr. Driller (USA) + cheat + description:Invincibility + code:2504/28/18 + cheat + description:Infinite air + code:264e/ea/fa + cheat + description:Break brown blocks faster + code:7e03/20/3e+273e/c5/c9 + cheat + description:Dig faster (hold A) + code:2489/1b/1a + +cartridge sha256:46c4a36696d1594ffa3441db352d80c8e4927794373d9d2712dcd425664936fe + name:Mr Nutz (Europe) (En,Fr,De,Es,It,Nl) + cheat + description:Invincibility + code:4cee/cb/3e + cheat + description:Hit anywhere - Nuts + code:4e01/01/44+4e00/30/18 + cheat + description:Hit anywhere - Tail + code:4d3b/93/61+4d3a/c2/18 + cheat + description:One hit kills - Bosses + code:4963/38/18 + cheat + description:Always have Nuts + code:1ee5/06/11+1ee4/28/18 + cheat + description:Moon jump + code:1f54/20/00+1f4c/20/3e + +cartridge sha256:d3148649d39fc4f5a8ca3624e022a6c92afbb82b335a3b568b514c60894bfd6b + name:Mr Nutz (USA) (En,Fr,Es) + cheat + description:Press Select to refill your health, nutz and lives. Hold Select and press Start to skip to the next stage. + code:397a/25/00 + +cartridge sha256:21db857936d7eff3d57d576f0a01a52e012d0dcf5dc8f2a6cdb0e92a131a72b6 + name:Ms. Pac-Man (USA) + cheat + description:Invincibility + code:1906/02/00 + cheat + description:Get fruit from anywhere + code:1b21/0f/00 + +cartridge sha256:8e556307f484b3451429f695391820e896202b1046312473911abb72222acee3 + name:Ms. Pac-Man - Special Color Edition (USA) (SGB Enhanced) + cheat + description:Ms. Pac-Man - Invincibility + code:521e/30/18 + cheat + description:Ms. Pac-Man - Infinite lives + code:67d1/ea/fa + cheat + description:Ms. Pac-Man - Get fruits from anywhere + code:36cd/30/3e + cheat + description:Super Pac - Invincibility + code:69c0/ca/c3 + cheat + description:Super Pac - Infinite lives + code:6a23/ea/fa + cheat + description:Super Pac - After eating a power pellet, ghosts stay vulnerable until eaten + code:559f/0b/00 + +cartridge sha256:ba1afcea3239c1acc9af228cebe6872f5547ad04480e71652e2e56dcd4e2f08e + name:Mysterium (USA) + cheat + description:Invincibility + code:37f8/c0/c9 + cheat + description:Infinite lives + code:3398/ea/fa + cheat + description:Max energy in battle. Works for enemies, disable to defeat them. + code:3878/80/af + cheat + description:Start with 1/2 energy + code:7db3/00/3a + cheat + description:Start with 1 life + code:7d00/03/01 + cheat + description:Start with 5 lives + code:7d00/03/05 + cheat + description:Start with 9 lives + code:7d00/03/09 + +cartridge sha256:220915c980318a194273d11d7a22836734ae6365ea2d8658956c3be374fc89f0 + name:Mystical Ninja Starring Goemon (USA) (SGB Enhanced) + cheat + description:Invincibility + code:41cf/c0/c9 + cheat + description:Hit anywhere - main weapon + code:422b/7f/da+4219/c8/00 + cheat + description:Hit anywhere - ninja stars + code:4255/c8/3c+4241/c8/00 + cheat + description:Walk over water and pits + code:45e9/20/18 + +cartridge sha256:424ca9fc4d842444a01c4dbf7375558035f4cb04a7d7056a4c1a1a18b769643d + name:Nail'n Scale (USA, Europe) + cheat + description:Infinite lives + code:0b7e/c3/00 + cheat + description:Can always use power-ups (press select) + code:214c/77/00+136e/20/18 + cheat + description:Can use power-ups in boss levels + code:132f/c3/00 + cheat + description:Start with 1 life + code:04b5/04/00 + cheat + description:Start with 9 lives + code:04b5/04/08 + +cartridge sha256:24797d8f8f74f56fd619f346db92b1829b2262c979a0dca58875ae86d93abe66 + name:NBA Jam (USA, Europe) + cheat + description:Dunk and layup from anywhere + code:3642/da/c3+3623/22/00+4466/cd/fa+361b/c8/00 + +cartridge sha256:e807eef2018cb12c73a5395a47936ce0b24b1e8876c10e3dff6b2d30873e52f3 + name:Nemesis (Europe) + cheat + description:Hit anywhere - Default weapon + code:28a7/d0/00+28b8/d0/00 + cheat + description:Hit anywhere - Laser + code:295f/d0/00+2970/d0/00 + cheat + description:Hit anywhere - Missiles + code:29cb/d0/00+29dc/d0/00 + cheat + description:Get items from anywhere + code:2768/d0/00 + +cartridge sha256:58c4da647070388c9e77ddf1a0fce6777c63ff96efcd804d0917f555c3e02369 + name:Nemesis (USA) + cheat + description:Hit anywhere - normal weapon + code:28a5/d0/00+2894/d0/00 + cheat + description:Hit anywhere - Laser + code:295d/d0/00+294c/d0/00 + cheat + description:Hit anywhere - Missiles + code:29c9/d0/00+29b8/d0/00 + cheat + description:Get items from anywhere + code:2755/d0/00 + +cartridge sha256:9ee539f631e964cb0fbf3564de53f8261b55ad61ca4b022ee423bfc8367f5002 + name:Nettou Garou Densetsu 2 (Japan) (SGB Enhanced) + cheat + description:Invincibility - P1 + code:4054/28/18+40b5/28/18 + cheat + description:Hit anywhere (except projectiles) + code:40a5/05/00 + +cartridge sha256:e8b4326469231ba798657cfa8032bc6c2000c0a61e11fbad8406711642a184eb + name:NFL Football (USA) + cheat + description:No game timer + code:5934/01/00 + cheat + description:Computer can't score on its possessions + code:11ed/83/af + cheat + description:Touchdown worth 1 point + code:0f59/06/01 + cheat + description:Touchdown worth 5 points + code:0f59/06/05 + cheat + description:Touchdown worth 8 points + code:0f59/06/08 + +cartridge sha256:d50625512f089c7a8c6ce3a44de7357466d61a2ef91ae0a0b87afce2a2e9621c + name:NFL Quarterback Club (USA, Europe) + cheat + description:Final time is always under one second(speed and mobility) + code:2588/7c/af + +cartridge sha256:f513d07ace08618cb2d8a39471b617982f23e0b4f7814a62809b9969ff41635b + name:Ninja Boy (USA, Europe) + cheat + description:Hit anywhere (can get items from anywhere by punching) + code:6e27/4a/00 + +cartridge sha256:efc3b14064153fd16b690034c078188d7d1f424ad210b585aaa4e7b0f7f171ee + name:Ninja Gaiden Shadow (USA) + cheat + description:Invincibility + code:669c/c0/c9 + cheat + description:Invincibility (alt) + code:22c1/fa/c9 + cheat + description:Infinite health + code:231d/3d/00 + cheat + description:Infinite lives + code:131c/3d/00 + cheat + description:Hit anywhere + code:2730/1b/00+271d/dc/cd + cheat + description:One hit kills - bosses + code:0100/c4/11 + cheat + description:Start each new life with 5 firewheel markers + code:0b01/01/05+0b29/01/05 + cheat + description:Start at stage 1 boss (Spider) + code:0ae6/00/02 + cheat + description:Start at beginning of stage 2 + code:0ae6/00/04 + cheat + description:Start at stage 2 boss (Jack & Gregory) + code:0ae6/00/07 + cheat + description:Start at beginning of stage 3 + code:0ae6/00/08 + cheat + description:Start at stage 3 boss (Colonel Allen) + code:0ae6/00/0b + cheat + description:Start at beginning of stage 4 + code:0ae6/00/0c + cheat + description:Start at stage 4 boss (Evil Nobleman Who-kisai) + code:0ae6/00/0f + cheat + description:Start at beginning of stage 5 + code:0ae6/00/10 + +cartridge sha256:58ce4e32820b1313d86c96555abcc53220c9c221ae785338b0ebcf360eb5aaa7 + name:Ninja Taro (USA) + cheat + description:Infinite health + code:0109/ff/97 + +cartridge sha256:ea284fad45e612ab2fcd721152ab815fe8e58062155ab6e182195f637d7b6da4 + name:Nintendo World Cup (USA, Europe) + cheat + description:Computer can't score + code:7e2d/3c/00 + cheat + description:No timer + code:7d2c/01/00 + cheat + description:1:59 each half + code:7cdd/03/01 + cheat + description:4:59 each half + code:7cdd/03/04 + cheat + description:6:59 each half + code:7cdd/03/06 + cheat + description:9:59 each half + code:7cdd/03/09 + +cartridge sha256:79b35e46b8258cccf8a858b6d66caf16855399fdc54bb1c0a5342e409908363f + name:Nobunaga's Ambition (USA) + cheat + description:Train samurais once and they have 100% skill level (must be Oda Nobunaga) + code:4f9f/fe/3e + cheat + description:Start with 75 loyalty pts (must be Oda Nobunaga) + code:515a/32/4b + cheat + description:Start with 100 loyalty pts (must be Oda Nobunaga) + code:515a/32/64 + cheat + description:Start with 50 town value pts (must be Oda Nobunaga) + code:5156/19/32 + cheat + description:Start with 75 town value pts (must be Oda Nobunaga) + code:5156/19/4b + cheat + description:Start with 100 town value pts (must be Oda Nobunaga) + code:5156/19/64 + cheat + description:Start with 50 castle defense pts (must be Oda Nobunaga) + code:515c/0f/32 + cheat + description:Start with 75 castle defense pts (must be Oda Nobunaga) + code:515c/0f/4b + cheat + description:Start with 100 castle defense pts (must be Oda Nobunaga) + code:515c/0f/64 + cheat + description:Start with flood control level at 75 (must be Oda Nobunaga) + code:515b/32/4b + cheat + description:Start with flood control level at 100 (must be Oda Nobunaga) + code:515b/32/64 + cheat + description:Start with 2580 rice pts (must be Oda Nobunaga) + code:4eb6/14/0a+4eb9/00/0a + cheat + description:Start with 788 rice pts (must be Oda Nobunaga) + code:4eb6/14/03+4eb9/00/03 + cheat + description:Start with 276 rice pts (must be Oda Nobunaga) + code:4eb6/14/01+4eb9/00/01 + cheat + description:Start with 999 gold (must be Oda Nobunaga) + code:4eb6/0f/0a+4eb7/00/0a + 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:557e/fe/3e + +cartridge sha256:52ad82cb79d557d37c4fd92a9782c594f49340d493f007900b901b3aa232bb9e + name:Oddworld Adventures (USA, Europe) + cheat + description:Invincibility + code:7afa/ca/c3 + +cartridge sha256:0b6670e44cc2edc6fbf32fc78f499e774cf0802019480f2bf7bdb836ee15c433 + name:Operation C (USA) + cheat + description:Invincibility + code:5abf/cb/af+5ac0/4e/77 + cheat + description:Hit anywhere + code:3aca/1c/00+3ae4/dc/c3+3af5/fe/c6 + cheat + description:Multi-jump + code:55c0/55/00+00e6/ff/5a+00e7/ff/52+00ea/ff/55+00e9/ff/7a+00e5/ff/cd+00e8/ff/cd+00eb/ff/c9+55bf/7a/e5 + +cartridge sha256:efcce0d4264fbfff4b1b3a0843a681194b2d7a597e842d2895c2eadcfc6998c3 + name:Out of Gas (USA) + cheat + description:Infinite lives + code:05dd/ea/fa + cheat + description:Collect only 1 canister to complete each stage + code:18ec/fe/af + cheat + description:Start with 2 lives + code:01ac/03/02 + cheat + description:Start with 4 lives + code:01ac/03/04 + cheat + description:Start with 8 lives + code:01ac/03/08 + +cartridge sha256:d07986785d76db33e96ccbbe840ac962542f1c359e5b896e6478afd5cf9586b3 + name:Pac-Man (USA) + cheat + description:Invincibility + code:177d/d0/c9 + cheat + description:Get fruit from anywhere + code:1922/c0/00+1928/c0/00 + +cartridge sha256:dcbbc8f8128940a35c9b09624a9987a80cecb2edc8db8e48605de30b4887a3a9 + name:Pac-Man - Special Color Edition (USA) (SGB Enhanced) + cheat + description:Invincibility + code:5627/d0/c9 + cheat + description:Infinite lives + code:4c89/35/00 + cheat + description:Get fruits from anywhere + code:57d2/c0/00+57cc/c0/00 + +cartridge sha256:8b81c75dd11e24ba5e1d2f439a6fabf7313024829df397409a20dd37995122cb + name:Pagemaster, The (USA) (SGB Enhanced) + cheat + description:Invincibility + code:4836/3d/00 + cheat + description:Infinite Help Books + code:7f34/3d/00 + cheat + description:Don't flash at all when you start a new stage + code:4095/3c/00 + cheat + description:Flash longer when you start a new stage + code:4095/3c/ff + cheat + description:Get a Help Book for every Gold Token + code:1fd1/1e/01 + cheat + description:Get a Help Book for every 2 Gold Tokens + code:1fd1/1e/02 + cheat + description:Get a Help Book for every 10 Gold Tokens + code:1fd1/1e/0a + cheat + description:Get a Help Book for every 50 Gold Tokens + code:1fd1/1e/32 + cheat + description:Get a Help Book for every 99 Gold Tokens + code:1fd1/1e/63 + cheat + description:Start in the Adventure World with 1 life + code:01bf/05/01+01c3/af/00 + cheat + description:Start in the Fantasy World with 2 lives + code:01bf/05/02+01c3/af/00 + cheat + description:Start with 1 life + code:01bf/05/01 + cheat + description:Start with 3 lives + code:01bf/05/03 + cheat + description:Start with 7 lives + code:01bf/05/07 + cheat + description:Start with 10 lives + code:01bf/05/0a + cheat + description:Start with 15 lives + code:01bf/05/0f + cheat + description:Start with 11,111,111 points + code:01cd/af/3c + +cartridge sha256:b36e2bb2642a385ce67c059e8fb2a1cc4f63ccff56c023a3f211d81ebd4a8a77 + name:Paperboy (USA, Europe) + cheat + description:Invincibility (except for training courses) + code:618c/cd/c9+62dc/d5/c9 + +cartridge sha256:5c357df199e755eae719588a3424d49bc5212289922f11968e47954276941d6a + name:Paperboy 2 (USA, Europe) + cheat + description:Infinite papers + code:64c0/35/00 + cheat + description:Infinite lives + code:4691/35/00 + cheat + description:Go on to next day after completing Monday + code:470c/06/00 + cheat + description:Start with 15 papers - 1st life only + code:3cc6/0a/0f + cheat + description:Start with 20 papers - 1st life only + code:3cc6/0a/14 + cheat + description:Start with 10 lives - Paperboy + code:3ae6/05/0a + cheat + description:Start with 20 lives - Paperboy + code:3ae6/05/14 + +cartridge sha256:3bcf1b2fe43907d96e58b9aca893a9124bfb3c35774926279f9368a975665086 + name:Parodius (Europe) + cheat + description:Invincibility + code:7a20/c0/c9 + cheat + description:Infinite lives + code:33c6/ea/fa + cheat + description:Infinite super shields once collected + code:7b5d/ea/fa + cheat + description:Start with super shields and triple firing + code:2bd3/00/ff+2bd6/00/ff + cheat + description:Start with 5 lives + code:2a93/03/05 + cheat + description:Start with 8 lives + code:2a93/03/08 + cheat + description:Start with 11 lives + code:2a93/03/0b + +cartridge sha256:b5c0c1e3bc4ee2f1ca3cba1bed9483707f4ab72b87e517ca80f1bbb612fd86cd + name:Penguin Land (Japan) + cheat + description:Infinite time + code:200a/ea/fa + +cartridge sha256:d84a2382b358d83a0891d40b2de65494f060d8be1a048d5aa8721282218b04b6 + name:Pinball - Revenge of the 'Gator (USA, Europe) + cheat + description:Infinite supply of balls + code:07e1/35/00 + cheat + description:Disable left flipper + code:2f24/cd/21 + cheat + description:Disable right flipper + code:2f2a/e6/c9 + cheat + description:Start with 1 ball + code:06ed/03/01 + cheat + description:Start with 9 balls + code:06ed/03/09 + +cartridge sha256:ec2420a8d1b129379435e9a217ef8e6be7fcece10a17d72affa8b1b2449888cb + name:Pinball Dreams (USA, Europe) + cheat + description:Infinite balls + code:0818/34/00 + cheat + description:Start with 5x bonus, lose it if you collect any other bonus + code:0bed/ea/3e+0bee/6b/04+0bef/d1/00 + cheat + description:No tilt - shake the table as much as you want + code:34ba/28/00+34bb/16/00 + cheat + description:Collect 2x bonus and get 6x bonus + code:24c7/02/05 + cheat + description:Start with 1 ball + code:081b/03/01 + cheat + description:Start with 4 balls + code:081b/03/04 + cheat + description:Start with 7 balls + code:081b/03/07 + cheat + description:Start with 9 balls + code:081b/03/09 + +cartridge sha256:fddf9b0ebdc5294554339b59dd9b949286e5281bf81f05bc4c1759844effc0a9 + name:Pinocchio (USA) + cheat + description:Infinite health + code:0b59/35/36 + +cartridge sha256:11347375400080c6e2bfac1ae908d571b91bd4a5406b823c912eb9df1bd3d014 + name:Pitfall - Beyond the Jungle (USA, Europe) + cheat + description:Invincibility + code:719d/c0/c9 + cheat + description:Hit anywhere + code:6733/c2/fa+67ab/c2/fa+6764/c2/fa+67ed/c2/fa + cheat + description:Walk on air + code:1f6e/3e/c9 + +cartridge sha256:634c932dafbc56bdf9b88c02cd69540b327523c2b1d21edcb672884c9a06ef68 + name:Planet of the Apes (USA) (En,Fr,De,Es,It,Nl) + cheat + description:Infinite health + code:6563/c0/c9 + cheat + description:Start with all weapons + code:5e4b/1c/00 + +cartridge sha256:027a8bb2843c3f96373ca60830f58fbc2fcf15d51756649e002b87a97f438a41 + name:Play Action Football (USA) + cheat + description:Always kick at full power + code:35df/20/3e+35e0/e8/40+35e5/3d/00 + cheat + description:Infinite time + code:2a6b/3d/00 + cheat + description:Infinite downs + code:632a/c0/01 + cheat + description:Only get 2 downs + code:1b84/04/02 + cheat + description:Only need 5 yards for 1st down + code:6341/0a/05 + +cartridge sha256:d6702e353dcbe2d2c69183046c878ef13a0dae4006e8cdff521cca83dd1582fe + name:Pokemon - Crystal Version (USA, Europe) + cheat + description:One hit kills + code:5d49/30/3e + cheat + description:Opponent doesn't attack + code:46de/cd/c9 + cheat + description:No random battles + code:60ea/30/18 + cheat + description:Skip trainer battles + code:682c/1b/00 + +cartridge sha256:fdcc3c8c43813cf8731fc037d2a6d191bac75439c34b24ba1c27526e6acdc8a2 + name:Pokemon - Crystal Version (USA, Europe) (Rev A) + cheat + description:One hit kills + code:5d49/30/3e + cheat + description:Opponent doesn't attack + code:46de/cd/c9 + cheat + description:No random battles + code:60ea/30/18 + cheat + description:Skip trainer battles + code:682c/1b/00 + +cartridge sha256:fb0016d27b1e5374e1ec9fcad60e6628d8646103b5313ca683417f52b97e7e4e + name:Pokemon - Gold Version (USA, Europe) (SGB Enhanced) + cheat + description:One hit kills + code:5e86/0e/00 + cheat + description:Opponent doesn't attack + code:4686/cd/c9 + cheat + description:No random battles + code:6646/30/18 + cheat + description:Skip trainer battles + code:676b/1b/00 + +cartridge sha256:72b190859a59623cbef6c49d601f8de52c1d2331b4f08a8d2acc17274fc19a8c + name:Pokemon - Silver Version (USA, Europe) (SGB Enhanced) + cheat + description:One hit kills + code:5e85/30/3e + cheat + description:Opponent doesn't attack + code:4686/cd/c9 + cheat + description:No random battles + code:6646/30/18 + cheat + description:Skip trainer battles (the only way to fight them is to talk to them) + code:676b/1b/00 + +cartridge sha256:a54515bb6b3e364964d3c0226f5a6b0c8c0f7318c9296ef2e321df0bbb8541ce + name:Pokemon Trading Card Game (USA) (SGB Enhanced) + cheat + description:Always your turn + code:67be/e0/c9 + cheat + description:Attack without energy cards + code:474f/30/18 + +cartridge sha256:952660d14941a2ab77810c3fe36658c8e8dd490e2c4e744fb3d41ce2eb31e703 + name:Pocket Bomberman (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:458a/01/00+2c54/05/00 + cheat + description:Bomb hits anywhere when placed on the ground + code:40c2/07/00 + +cartridge sha256:2f74f1a512d862372e0bccf09260ffb91a676cdb2391fd91f2f6bc8487d75974 + name:Pong - The Next Level (USA, Europe) + cheat + description:Right side player cannot hit ball + code:48fc/20/28+48fd/20/df+48fb/02/03 + +cartridge sha256:cfff247d91c3c448d3588a5c5fc3ee4c19b0031e45679022bdbdadae6d545802 + name:Pop'n TwinBee (Europe) + cheat + description:Invincibility + code:3a52/30/18+3e8d/d2/c3 + cheat + description:Hit anywhere - normal enemies + code:32dd/30/3e+32ce/30/3e + cheat + description:Hit anywhere - bosses + code:60d0/30/3e+60c3/30/3e + +cartridge sha256:4a1c9750f77deffb8e003b8938d2ffe5f520fb43143aedd309909b8a9907856d + name:Popeye 2 (USA) + cheat + description:Invincibility after first hit until end of level + code:4e83/3d/00 + cheat + description:Infinite Pows + code:63c5/ea/fa + cheat + description:Infinite lives + code:03af/ea/fa + cheat + description:Infinite time - disable to advance in some areas + code:4202/12/2a + cheat + description:Infinite continues + code:5a1a/3d/00 + cheat + description:Super code - more lives and power + code:4b68/03/88 + cheat + description:Start with 1 Pow after 1st life + code:03a7/03/01 + cheat + description:Start with 7 Pows after 1st life + code:03a7/03/07 + cheat + description:Start with no continues + code:53f7/05/00 + cheat + description:Start with 2 continues + code:53f7/05/02 + cheat + description:Start with 9 continues + code:53f7/05/09 + +cartridge sha256:584f8fcfde1ae9f262747be425df0ed4d1a7421d24b8d62af05b075875b1cb35 + name:Project S-11 (USA) + cheat + description:Invincibility + code:46bb/c2/c3 + cheat + description:Hit anywhere - normal enemies + code:45b0/30/3e+45a4/38/3e+45b5/38/3e+459f/30/3e + cheat + description:Hit anywhere - bosses + code:465d/38/3e+466e/38/3e+4669/30/3e+4658/30/3e + cheat + description:One hit kills - normal enemies + code:45e2/38/18 + cheat + description:One hit kills - bosses + code:4687/30/3e + +cartridge sha256:e1b69e85caebf764bfa6cece5c1d33b67b370cf055480f309644b937e4a7ebdb + name:Prophecy - The Viking Child (USA) + cheat + description:Infinite lives + code:3e04/ea/fa + cheat + description:Infinite energy + code:3df5/ea/fa + cheat + description:Each coin gives lots of money + code:2d9b/7c/00 + cheat + description:Start with 25 energy - 1st life + code:04a5/63/19 + cheat + description:Start with 50 energy - 1st life + code:04a5/63/32 + cheat + description:Start with 4 lives + code:04a0/01/03 + cheat + description:Start with 7 lives + code:04a0/01/06 + cheat + description:Start with 10 lives + code:04a0/01/09 + +cartridge sha256:459ccbbab8580bd93a2a0d5d66ca4ae42c8f664f3106687ffc31c7aef7dd677b + name:Puzzle Boy II (Japan) + cheat + description:Walk anywhere + code:0f67/20/3e + +cartridge sha256:cfc6560d1385808cfd5c242a9f3aa38892c6ab2cb242d0767115144c633708b6 + name:Puzzled (USA) + cheat + description:Clear level automatically + code:424a/ca/c3+4296/c2/fa + +cartridge sha256:567aef8ea27486a4fa38ef4a4ae6ebae2a9138dc8a6a675d155895936e1318d8 + name:Pyramids of Ra (USA) + cheat + description:Energy bar doesn't go down when you make a move + code:458e/ea/fa + cheat + description:Only 1 pt. of energy per move on first attempt at each level (instead of 3) + code:7ac4/a1/a2+7ac6/7c/3c+7ac3/ea/fa + cheat + description:Start on level 100 + code:b1ab/01/64+01ac/00/00 + cheat + description:Start on level 300 + code:01ab/01/2c+01ac/00/01 + cheat + description:Start on level 500 + code:01ab/01/f4+01ac/00/01 + +cartridge sha256:4e624ad741077f574c1d0b57cbc45171ed4ca9f23fa89dfd8f282897aa53ab9a + name:Q Billion (USA) + cheat + description:Pressing Select in Game B once gives you 246 seconds + code:1b9f/0a/00 + cheat + description:Infinite timer + code:1755/3d/00 + cheat + description:Level select - Game A + code:0b61/38/3e+0b62/15/0d+0b63/79/00 + +cartridge sha256:878a21de57986965bf2c68774119180d21dbd5111eef4a9a70ffd0f9f6bdbf7b + name:Q-bert (USA) + cheat + description:Invincibility + code:3e61/da/fa + cheat + description:Step on one cube to clear level + code:482c/ca/c3 + +cartridge sha256:ed110933b5a41ed89d2b980e6e984733833fa6b2c15e5235eff1f5df54175df4 + name:QIX (World) + cheat + description:Invincibility + code:3edb/b7/af + cheat + description:Create any shape to clear level + code:409a/04/00 + +cartridge sha256:0ccfd1166f7e6158c8d4189e5dc9a11724fce01f375f2a78f54ed4a41d7beb0c + name:QIX Adventure (Europe) + cheat + description:Invincibility + code:49bd/ea/fa+738d/c2/c3 + cheat + description:Create any shape to clear level + code:5533/20/3e+5538/38/3e + +cartridge sha256:7d8e122f6f70f6ca49521f2c24fd987e91f621977da2912702285735438be901 + name:Quarth (USA, Europe) + cheat + description:Select up to level 5 + code:549e/03/05 + cheat + description:Super turbo ship + code:2b31/79/00 + cheat + description:Blocks don't drop (push Up to bring blocks down) + code:1632/90/af + cheat + description:Blocks drop faster + code:162b/fa/3e+162c/70/50+162d/c4/00 + cheat + description:Blocks drop super fast + code:162b/fa/3e+162c/70/80+162d/c4/00 + +cartridge sha256:3f6cdd669637c8a3aaaf02c9ae833e820a3e7f9e882e5cbb246bda5aa616ff87 + name:Quest - Fantasy Challenge (USA) (SGB Enhanced) + cheat + description:Invincibility + code:627d/d2/c3+5e92/3e/c9 + cheat + description:Hit anywhere + code:53ba/28/18+53a7/30/18+539a/30/18 + +cartridge sha256:6242b49e85e9652c278ceae22fd5c888495222b4ba78c0a82bb925f2acf66ac1 + name:Quest RPG - Brian's Journey (USA) + cheat + description:Invincibility + code:46f6/cd/fa+4616/c0/c9 + cheat + description:One hit kills + code:518f/da/c3+519c/da/c3 + +cartridge sha256:b3f2838cb64dfa12f93ab4767c3b0786cba0993015fefe1f592146f9d8f47d40 + name:Radar Mission (USA, Europe) + cheat + description:Game B - Infinite money + code:2333/35/00 + cheat + description:Game B - Move in 1 direction only + code:53cc/35/00 + cheat + description:Game B - Destroyed fleet disappears from radar screen but game doesn't end + code:5cc6/35/00 + cheat + description:Game B - Start with 1 money bag + code:21e0/03/01 + cheat + description:Game B - Start with 1 extra money bag + code:21e0/03/04 + +cartridge sha256:9e30f9c36cfa1bc1fd6f111fa38a43f3c5907c26d81a65309279eec54a3d05d6 + name:Raging Fighter (USA, Europe) + cheat + description:Infinite energy + code:44e0/c1/00+171a/77/00 + cheat + description:Infinite time + code:491f/12/00 + cheat + description:4th difficulty level - go to options, set difficulty, press Left 3 times (won't show anything), then exit + code:51f2/28/3e+51f3/02/04+51f4/34/77 + cheat + description:Start on level 4 - 1P tournament only + code:2e5b/ea/3e+2e5c/68/03+2e5d/c2/00 + cheat + description:Start on final level - 1P tournament only + code:2e5b/ea/3e+2e5c/68/07+2e5d/c2/00 + cheat + description:Start each fight with 10 seconds + code:5a9a/99/10 + cheat + description:Start with 1/2 time + code:5a9a/99/50 + cheat + description:Start with 3/4 time + code:5a9a/99/75 + +cartridge sha256:1a8bfa0e55e89241a9843e440e8e2a93dae906c654378e8b27df27e360de826c + name:Rampage - World Tour (USA, Europe) + cheat + description:Invincibility + code:7a06/01/00 + cheat + description:Knock down buildings with one punch + code:5abc/30/3e+5aba/28/3e + +cartridge sha256:ff3915dab21e648cc8f30b28702db6d6784c8e01792d9a5c17a50a9f5994e48c + name:Rampage 2 - Universal Tour (USA, Europe) + cheat + description:Invincibility + code:478a/38/18+7c7d/01/00+7c28/01/00 + cheat + description:Knock down buildings with one punch + code:6127/30/3e + +cartridge sha256:ad5d681fa599b6cf9dae135c304317ac41f33bee0a5a583d7fa2a178ca66506f + name: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:039c/35/00 + cheat + description:Infinite lives + code:470e/c4/01 + cheat + description:Infinite cannons + code:4eb3/c4/01 + cheat + description:Have 6 seconds to rebuild castle walls + code:4029/fa/3e+402a/e7/09+402b/c5/00 + cheat + description:Have 66 seconds to rebuild castle walls + code:4029/fa/3e+402a/e7/44+402b/c5/00 + cheat + description:Have 118 seconds to rebuild castle walls + code:4029/fa/3e+402a/e7/77+402b/c5/00 + cheat + description:Levels last 10 seconds + code:4040/fa/3e+4041/16/1a+4042/c6/00 + cheat + description:Levels last 25 seconds + code:4040/fa/3e+4041/16/2a+4042/c6/00 + cheat + description:Levels last 50 seconds + code:4040/fa/3e+4041/16/43+4042/c6/00 + +cartridge sha256:9ca5b01d04985e0c83c68d5b434f322d2e7ee494fffed08cd747e8ade1569b0a + name:Rayman (USA) (En,Fr,De,Es,It,Nl) + cheat + description:Get items from anywhere + code:4aad/07/00+6fa0/20/18 + +cartridge sha256:46cfbba977f7d4cb8df51d5cb51f00dc0a4d9c129868a1ed88f2b0fa97454905 + name:Ren & Stimpy Show, The - Space Cadet Adventures (USA) + cheat + description:Infinite lives + code:1754/e0/f0 + cheat + description:Infinite energy except when you fall into pits + code:1733/e0/f0 + cheat + description:Start with 2 life + code:5d2e/02/01 + cheat + description:Start with 6 lives + code:5d2e/02/05 + cheat + description:Start with 9 lives + code:5d2e/02/08 + cheat + description:Start with 5 energy - 1st life only + code:5d32/03/04 + cheat + description:Start with 6 energy - 1st life only + code:5d32/03/05 + cheat + description:Start with 7 energy - 1st life only + code:5d32/03/06 + cheat + description:Start with 4 energy - after 1st life + code:175c/03/04 + cheat + description:Start with 5 energy - after 1st life + code:175c/03/05 + cheat + description:Start with 6 energy - after 1st life + code:175c/03/06 + +cartridge sha256:9a97678cbd8da02c8763e977674e17f460c06ea8b73bad35c52fe6817f506d44 + name:Resident Evil Gaiden (USA) + cheat + description:Invincibility + code:4b18/04/00+4b12/26/00 + cheat + description:Infinite ammo on pick-up + code:4426/c3/00 + cheat + description:Infinite Herbs + code:74e8/35/00 + cheat + description:All Herbs cure poison + code:7490/c8/00 + cheat + description:Rapid fire + code:456b/02/00+41d0/cc/cb + +cartridge sha256:ebe140f2c6dcd4e99192d5676b4cfe443a071daa9ff243a23a26ae98a53fead8 + name:Return of the Ninja (USA) + cheat + description:Invincibility + code:284d/f5/c9 + cheat + description:Hit anywhere + code:48a1/d2/fa+4891/d2/fa + cheat + description:Hit anywhere on bosses + code:1c29/30/3e+1c19/30/3e + cheat + description:Cannot be detected by enemies + code:47ed/30/18 + cheat + description:Can always use special attack + code:1d4f/3c/04 + +cartridge sha256:5d7efe8f937eda0f42836482b728db9be2a5caf95d95b7985387e95b5448e3d3 + name:Rhino Rumble (USA, Europe) + cheat + description:Infinite lives + code:4942/1d/00 + +cartridge sha256:c6d02170734d6b533d4599b6fca10ac83141e5ffe4902c4a98001aa61c00dffc + name:RoboCop 2 (USA, Europe) + cheat + description:Infinite health on scrolling levels + code:159c/c8/c9 + cheat + description:Infinite health on ED-209 (tm) levels + code:54d9/77/af + cheat + description:Infinite lives + code:20c2/35/b6 + cheat + description:Infinite time - except stages 3 and 8 + code:1548/c8/c9 + cheat + description:Start with 2 lives + code:1ae8/04/02 + cheat + description:Start with 5 lives + code:1ae8/04/05 + +cartridge sha256:9fb0e41e4c8afe737a688dbdc1b6f7019874f7e9ef4c0a27cba2b8be329ce45b + name:RoboCop vs. The Terminator (USA) + cheat + description:Infinite energy + code:4e67/ea/fa + cheat + description:Start on level 2 + code:2d7d/00/01 + cheat + description:Start on level 3 + code:2d7d/00/02 + cheat + description:Start on level 4 + code:2d7d/00/03 + cheat + description:Start on level 5 + code:2d7d/00/04 + cheat + description:Start on level 6 + code:2d7d/00/05 + cheat + description:Start with 01010101 points + code:2d5d/2c/01 + cheat + description:Start with very little energy - 1st life + code:2d58/07/01 + cheat + description:Start with more energy - 1st life + code:2d58/07/15 + cheat + description:Start with very little energy - 2nd life + code:4ee0/07/01 + cheat + description:Start with more energy - 2nd life + code:4ee0/07/15 + +cartridge sha256:211362382e3637edece46d5ccd470061466a37cd7794777f140ec3f228166e5a + name:Robopon - Sun Version (USA) (SGB Enhanced) + cheat + description:Walk anywhere + code:61b0/ff/00+546e/20/18 + +cartridge sha256:92e8d1acd4d2d3297a961409d4bb0ed49c784be4a6e91cfceabd05ab11894f3d + name:Roger Clemens' MVP Baseball (USA) + cheat + description:Balls are counted as strikes + code:4fe2/90/00+5113/d0/00+5110/d8/00 + cheat + description:No walks + code:5468/c5/01 + cheat + description:No strikeouts + code:5487/c5/01 + cheat + description:Infinite outs (except strikeouts, base runners will still be taken out) + code:36b4/c5/01 + cheat + description:No outs are called, except strikeouts + code:36af/03/01+3b87/03/01 + cheat + description:No scoring - disable to score runs + code:4946/77/00+4961/77/00 + +cartridge sha256:e3d0b1ddea8b4ada14c3bb5e990171e6b2e26935d9dbc15e5de90fb5f7f9595d + name:Rolan's Curse (USA) + cheat + description:Infinite energy + code:3c96/e0/f0 + cheat + description:Start with 2 energy pts + code:15f5/04/02 + cheat + description:Start with 6 energy pts + code:15f5/04/06 + +cartridge sha256:cf3f8f41498cdd32f5b3ee0cdccde1901b073798f3edac1a7d9ccc0141cb16be + name:Rolan's Curse II (USA) + cheat + description:Infinite HP + code:f000/79/00 + cheat + description:Infinite magic + code:0e01/e0/f0 + cheat + description:Takes 9 MP to use Electric ball + code:5459/01/09 + cheat + description:Takes 2 MP to use Electric ball + code:5459/01/02 + cheat + description:Starts you from a new place with power-ups + code:1372/af/3c + +cartridge sha256:8cebc4b128b79dd1b53a5b5a99450bb2783b86840ec61b22e70245dd6df8c39b + name:R-Type (USA, Europe) + cheat + description:Invincibility + code:1e07/fa/c9 + cheat + description:Hit anywhere + code:2b40/6b/01+2ada/30/18+2adb/2b/29+2b49/79/af + cheat + description:One hit kills + code:079f/38/18+48c1/c2/fa + +cartridge sha256:3d20b3fef48771f0d3ea2cdcf80812b02122a0a04dee0e8c8ae8e3e027f36741 + name:R-Type DX (USA, Europe) + cheat + description:De Souza mode accessible (press left on the game selection screen) + code:413c/04/05 + +cartridge sha256:2b059983d79efc5a4f77b41a4efbad68c65ae259715dc008f20a3c11226a943b + name:R-Type II (Europe) + cheat + description:Invincibility + code:1f3f/fa/c9 + +cartridge sha256:e0a07f84198e062c9ba8d617ef15679ba044f96510e5c62309ea1f743499a2c9 + name:Samurai Shodown (USA, Europe) (SGB Enhanced) + cheat + description:Computer takes all damage, even when you get hit + code:2b60/e6/3e + cheat + description:Infinite time + code:2246/ea/fa + cheat + description:Hit anywhere - both players + code:16c3/20/18 + cheat + description:Blocking disabled - both players + code:4045/c2/fa + cheat + description:Start timer at 30 seconds + code:1f80/4f/3e+1f81/79/1e + cheat + description:Start timer at 46 seconds + code:1f80/4f/3e+1f81/79/2e + cheat + description:Start timer at 62 seconds + code:1f80/4f/3e+1f81/79/3e + cheat + description:Start timer at 78 seconds + code:1f80/4f/3e+1f81/79/4e + cheat + description:Start timer at 94 seconds + code:1f80/4f/3e+1f81/79/5e + cheat + description:Start timer at 110 seconds + code:1f80/4f/3e+1f81/79/6e + cheat + description:Start timer at 126 seconds + code:1f80/4f/3e+1f81/79/7e + cheat + description:Start timer at 142 seconds + code:1f80/4f/3e+1f81/79/8e + cheat + description:Start timer at 158 seconds + code:1f80/4f/3e+1f81/79/9e + cheat + description:Both players start with 1/3 energy + code:1f86/37/11 + cheat + description:Both players start with 2/3 energy + code:1f86/37/21 + cheat + description:Both players start with more energy + code:1f86/37/ff + cheat + description:Always fight Genan Shiranui + code:689a/30/3e+689b/0d/00+689c/f0/e0 + cheat + description:Always fight Galford + code:689a/30/3e+689b/0d/01+689c/f0/e0 + cheat + description:Always fight Haohmaru + code:689a/30/3e+689b/0d/02+689c/f0/e0 + cheat + description:Always fight Ukyo Tachibana + code:689a/30/3e+689b/0d/03+689c/f0/e0 + cheat + description:Always fight Charlotte + code:689a/30/3e+689b/0d/04+689c/f0/e0 + cheat + description:Always fight Tam Tam + code:689a/30/3e+689b/0d/05+689c/f0/e0 + cheat + description:Always fight Earthquake + code:689a/30/3e+689b/0d/06+689c/f0/e0 + cheat + description:Always fight Nakoruru + code:689a/30/3e+689b/0d/07+689c/f0/e0 + cheat + description:Always fight Wan Fan + code:689a/30/3e+689b/0d/08+689c/f0/e0 + cheat + description:Always fight Jubei Yagyo + code:689a/30/3e+689b/0d/09+689c/f0/e0 + cheat + description:Always fight Hanzo Hattori + code:689a/30/3e+689b/0d/0a+689c/f0/e0 + cheat + description:Always fight Kyoshiro Senryo + code:689a/30/3e+689b/0d/0b+689c/f0/e0 + +cartridge sha256:384885e8eb8c7396a8c7df08729f61022cc740b3234a8d35bebe17cc7aef3c71 + name:SeaQuest DSV (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:4e04/3d/00 + cheat + description:Infinite lives + code:71eb/01/00 + cheat + description:Lose most energy after first hit + code:4e04/3d/af + cheat + description:Start with super score + code:2b37/00/03 + cheat + description:Start with very little hull energy + code:31fc/0a/01 + cheat + description:Start with 1/2 hull energy + code:31fc/0a/05 + cheat + description:Start with 3/4 hull energy + code:31fc/0a/07 + cheat + description:Start with 2 lives + code:2b2d/04/01 + cheat + description:Start with 5 lives + code:2b2d/04/04 + cheat + description:Start with 10 lives + code:2b2d/04/09 + cheat + description:Start with 15 lives + code:2b2d/04/0e + +cartridge sha256:52924262f2c60fc1c387a92bfdb43835c84968daf4ba465e7cc6627774e7b8a5 + name:Serpent (USA) + cheat + description:Infinite missiles on pick-up + code:1fb0/c0/00 + cheat + description:Win immediately + code:03b9/c2/c3+050d/d2/fa + cheat + description:Start with 5 missiles + code:27c9/00/05 + cheat + description:Start with 8 missiles + code:27c9/00/08 + cheat + description:Start with 15 missiles + code:27c9/00/0f + cheat + description:Start with smaller tail + code:27c6/28/15 + cheat + description:Start with longer tail + code:27c6/28/40 + +cartridge sha256:c8979ad731912452dabedff2c9fb23b19aa68cfdedbf5e99fec902547ce1bb76 + name:Simpsons, The - Bart & the Beanstalk (USA, Europe) + cheat + description:Invincibility + code:372c/c0/c9 + cheat + description:Infinite energy + code:3742/ea/fa + cheat + description:Infinite lives + code:1283/01/00 + cheat + description:Infinite fire crackers + code:7a60/3d/00 + cheat + description:Start with 1 life + code:01ad/03/00 + cheat + description:Start with 5 lives + code:01ad/03/04 + cheat + description:Start with 10 lives + code:01ad/03/09 + cheat + description:Start with 1/4 energy + code:1637/5f/10 + cheat + description:Start with 1/2 energy + code:1637/5f/30 + cheat + description:Start with 3/4 energy + code:1637/5f/45 + +cartridge sha256:6ecab90879e06226ed6b2f6bdeb2d3ffa0736ee77c2132891083671465dd6934 + name:Simpsons, The - Bart vs. the Juggernauts (USA, Europe) + cheat + description:Infinite time on all games + code:08a6/77/00 + cheat + description:Always qualify with enough money + code:66eb/2a/0a + cheat + description:See end sequence + code:635b/07/04 + cheat + description:Start on week 2 + code:635b/07/02 + cheat + description:Start on week 3 + code:635b/07/03 + cheat + description:Capt. Lance Murdock's Skateboard Bash & Crash - Infinite lives + code:6f82/ea/fa + cheat + description:Capt. Lance Murdock's Skateboard Bash & Crash - Start with 1 life + code:6ea8/07/01 + cheat + description:Capt. Lance Murdock's Skateboard Bash & Crash - Start with 2 lives + code:6ea8/07/02 + cheat + description:Springfield Nuclear Power Plant Bop 'till You Drop - No hits against you + code:78f3/ea/fa + cheat + description:Herman's Military Minefield Mayhem - Infinite hits + code:7bf2/ea/fa + cheat + description:Herman's Military Minefield Mayhem - Infinite runs + code:7284/ea/fa + cheat + description:Kwik-E-Mart Doggie Dodge - Infinite chances + code:6227/ea/fa + cheat + description:Kwik-E-Mart Doggie Dodge - Start with 3 lives + code:5d89/1f/03 + cheat + description:Kwik-E-Mart Doggie Dodge - Start with 6 lives + code:5d89/1f/06 + cheat + description:Kwik-E-Mart Doggie Dodge - Start with 9 lives + code:5d89/1f/09 + +cartridge sha256:534478ebd2558ab6a871540062fadbb0ea27808d7f6860942b2e6805fd15e87b + name:Simpsons Itchy & Scratchy, The - Miniature Golf Madness (USA, Europe) + cheat + description:Invincibility + code:5a07/c8/00 + cheat + description:Invincible after getting hit + code:5a24/35/00 + cheat + description:Infinite lives + code:2a24/01/00 + cheat + description:Always get a hole in one + code:690e/01/00 + cheat + description:Start with 1 life + code:607d/09/00 + cheat + description:Start with 5 lives + code:607d/09/04 + cheat + description:Start with 15 lives + code:607d/09/0e + +cartridge sha256:28b2b87a43285afb3e55a96136f71c6a858b0bbe25caaa59f4ef3a6e6d5f64e8 + name:Smurfs, The (Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:56b1/20/18 + cheat + description:Multi-jump (don't jump off screen) + code:6067/20/18+6068/26/0a+605e/8a/8b + +cartridge sha256:5d9c9ce079923b92034c7c2d172b5abfad9ec37332102cb247ea849393db9a99 + name:Smurfs, The (USA, Europe) (En,Fr,De) (Rev A) (SGB Enhanced) + cheat + description:Invincibility + code:57c3/20/18 + cheat + description:Multi-jump (don't jump off screen) + code:6146/26/0a+6145/20/18+613c/8a/8b + +cartridge sha256:a1e0c6d8385ab8c39569217f28cb335ccac8c85d31e01c9a2343c79494164478 + name:Snoopy - Magic Show (USA, Europe) + cheat + description:Invincibility + code:43d6/20/18 + cheat + description:Start on level 2 + code:273f/ea/3e+2740/7b/02+2741/c3/00 + cheat + description:Start on level 5 + code:273f/ea/3e+2740/7b/05+2741/c3/00 + cheat + description:Start on level 9 + code:273f/ea/3e+2740/7b/09+2741/c3/00 + cheat + description:Start with 22 seconds + code:5849/40/10 + cheat + description:Start with 63 seconds + code:5849/40/3f + cheat + description:Start with 100 seconds + code:5849/40/64 + +cartridge sha256:fece5b09e599c1f8116602fcabd558cc8dbbfe1c6c253853c5e871b0d732c11c + name:SolarStriker (World) + cheat + description:Infinite lives + code:0cd6/35/00 + cheat + description:When you pick up a power-up, go straight to max power + code:1f65/fe/3e+1f66/05/04 + cheat + description:Bullets are mega-powerful, almost invisible, when you pick up a power-up + code:1f65/fe/3e+1f66/05/0b + cheat + description:No loss of power-ups on dying + code:1645/ca/00 + cheat + description:Stay on same level + code:0dee/34/00 + cheat + description:Start with 2 lives + code:05d0/02/01 + cheat + description:Start with 6 lives + code:05d0/02/05 + cheat + description:Start with 10 lives + code:05d0/02/09 + cheat + description:Start on stage 2 + code:050a/01/02 + cheat + description:Start on stage 3 + code:050a/01/03 + cheat + description:Start on stage 4 + code:050a/01/04 + cheat + description:Start on stage 5 + code:050a/01/05 + cheat + description:Start on stage 6 + code:050a/01/06 + +cartridge sha256:b876faa05d3fa8c9e6d2812a7e17cbc8be83463e1d1536f13e9719ba0e7108b5 + name:Solomon's Club (USA) + cheat + description:Invincibility + code:072a/20/18 + cheat + description:Hit anywhere - fireball + code:0663/38/14+0662/30/18 + cheat + description:Always have fireball + code:422a/de/08+4229/20/18 + cheat + description:Items are free + code:1f70/fa/09+1f6f/da/18 + +cartridge sha256:3d6fd2f730d66266215b06c7d40ebd060aca9a48f8117d25a4411fa5d644ff57 + name:Solitaire FunPak (USA, Europe) + cheat + description:Klondike - Move cards to any stack + code:4cd2/20/18+4bb3/20/18+4bb4/09/34+4cf2/cd/fa+4cf1/1d/00 + cheat + description:Freecell - Move cards to any stack + code:4b35/70/6d+4b34/ca/c3+49fe/25/00 + +cartridge sha256:b9b4ee32ab8b74ffd90d7606715893f4b6bd2a3b97c14b2ac2fc6683cfbe1986 + name:Soukoban (Japan) + cheat + description:Walk through walls + code:071a/ca/fa + +cartridge sha256:ed0ab3bfcbc6ac96cc1c8eebb9cdabf0c52e1a562d115eefe47b2078746bc691 + name:Soukoban 2 (Japan) + cheat + description:Walk through walls + code:0827/c2/fa+0803/01/ff + +cartridge sha256:c84accad1cc05913a034ff54bc936a908438c84b0dddce5138d79c11006c9cf2 + name:Space Marauder (USA) + cheat + description:Infinite lives + code:17be/01/00 + cheat + description:Start with 99 lives + code:0ec2/02/99 + +cartridge sha256:6ffe31b21d429801b8e5a460e58bd857e41aef888d19297fc558cf25def0d10d + name:Spanky's Quest (USA) + cheat + description:Infinite lives + code:1060/3d/00 + cheat + description:Mega ball power-ups - hit it with your head once for full power + code:241e/00/07 + cheat + description:Start with 1 life + code:2b96/02/00 + cheat + description:Start with 6 lives + code:2b96/02/05 + cheat + description:Start with 9 lives + code:2b96/02/08 + cheat + description:Start on tower 1, stage 5 (disable after starting stage) + code:2d68/cb/3e+2d69/37/04 + cheat + description:Start on tower 1, stage 10 (disable after starting stage) + code:2d68/cb/3e+2d69/37/09 + cheat + description:Start on tower 1, last stage (disable after starting stage) + code:2d68/cb/3e+2d69/37/0f + +cartridge sha256:7b96653450c5fb4522a77d46ecfa50d479b3dac28bafb1a13e416e43c42caae3 + name:Speedball 2 - Brutal Deluxe (USA, Europe) + cheat + description:Get lots of money + code:4dcd/04/99 + cheat + description:Infinite money + code:3ae4/ea/fa + cheat + description:No timer + code:6ed9/35/00 + cheat + description:Opponents can't score any points except from bounced stones + code:0c30/78/00 + +cartridge sha256:5bfae99484fe74c42b55a0dd8835861cfeb7d05590882aab8f4253e4e7138b92 + name:Speedy Gonzales (USA, Europe) + cheat + description:Infinite lives + code:4ca9/ea/fa + cheat + description:Infinite time + code:4940/ea/fa + cheat + description:Start 1st game with 1 life + code:7a8a/03/00 + cheat + description:Start 1st game with 7 lives + code:7a8a/03/06 + cheat + description:Start 1st game with 10 lives + code:7a8a/03/09 + cheat + description:Start in Forest Zone after entering password 500999 + code:645a/06/02+645b/90/00 + cheat + description:Start in Desert Zone after entering password 500999 + code:645a/06/03+645b/90/00 + cheat + description:Start in County Zone after entering password 500999 + code:645a/06/04+645b/90/00 + cheat + description:Start in Cheese Island Zone after entering password 500999 + code:645a/06/05+645b/90/00 + cheat + description:Start continued games with 1 life + code:4d87/03/00 + cheat + description:Start continued games with 7 lives + code:4d87/03/06 + cheat + description:Start continued games with 10 lives + code:4d87/03/09 + cheat + description:Start with 1/2 time + code:3ef6/09/05 + cheat + description:Start with 3/4 time + code:3ef6/09/07 + +cartridge sha256:290f9d2ebd3221142873aa9650dc3276b577f1cfaf4ea2bc407f66a1ae110139 + name:Speedy Gonzales - Aztec Adventure (USA, Europe) + cheat + description:Invincibility + code:06cd/c0/c9 + cheat + description:Walk on air + code:1ecf/28/3e + +cartridge sha256:89c4151a31f00dc0f20133ee5ec8f71f3023331de93e017e97d66dc497eb2aa9 + name:Spider-Man 2 (USA, Europe) + cheat + description:Infinite lives + code:16fb/ea/fa + cheat + description:Infinite energy + code:16c4/ea/fa + cheat + description:Infinite web power + code:1df6/ea/fa + cheat + description:1 energy point after life lost + code:16ee/ff/01 + cheat + description:Start with 1 life + code:1f78/03/00 + cheat + description:Start with 5 lives + code:1f78/03/04 + cheat + description:Start with 10 lives + code:1f78/03/09 + cheat + description:Start with 1 energy point + code:1f5b/ff/01 + cheat + description:Start with 4 web points - 1st life only + code:1f73/14/04 + cheat + description:Start with 5 web points - 1st life only + code:1f73/14/05 + cheat + description:Start with 9 web points - 1st life only + code:1f73/14/09 + +cartridge sha256:664dae41e2d08070ead51e76c2d6865e52a122566cf79203b7c6c496968ded6e + name:Spider-Man 3 - Invasion of the Spider-Slayers (USA, Europe) + cheat + description:Infinite energy + code:17ec/ea/fa + cheat + description:Infinite lives + code:1825/ea/fa + cheat + description:Need to shoot 1 enemy to clear level 1-1 + code:2e3a/14/01 + cheat + description:Start 1st life with 1/2 energy + code:23ab/ff/72 + cheat + description:Start lives after 1st with 1/2 energy + code:1818/ff/72 + cheat + description:Start 1st level with 1/2 time + code:476f/ea/fa + cheat + description:Start 1st level with 255 seconds on timer + code:2e2d/96/ff + +cartridge sha256:31b92ae1c10e59372e14fe78cda20556d6ceba86930c60cc2a6bab8100f3a4b5 + name:Splitz (Europe) + cheat + description:Infinite time + code:11f5/ea/fa + +cartridge sha256:7275c3af129971c53ce901321f6ca85b414ebd84574c420d66c38aa87c219fe3 + name:Spot - The Cool Adventure (USA) + cheat + description:Infinite energy (hearts) except when you fall off screen + code:390a/ea/fa + cheat + description:Start with 4 lives + code:2576/04/04 + cheat + description:Start with 6 lives + code:2576/04/06 + cheat + description:Start with 9 lives + code:2576/04/09 + cheat + description:Start with 15 lives + code:2576/04/0f + cheat + description:Start with 25 bonus discs + code:2580/00/25 + cheat + description:Start with 59 bonus discs + code:2580/00/50 + cheat + description:Start with 5 energy (easy level) + code:42f7/05/05 + cheat + description:Start with 8 energy (easy level) + code:42f7/05/08 + cheat + description:Start with 10 energy (easy level) + code:42f7/05/08 + cheat + description:Start with 5 energy (hard level) + code:257b/03/05 + cheat + description:Start with 8 energy (hard level) + code:257b/03/08 + cheat + description:Start with 10 energy (hard level) + code:227b/03/08 + +cartridge sha256:966883149824ad2542a03a6402278d1397cdf0cbc0a7ba8410265410426ebfb9 + name:Spud's Adventure (USA) + cheat + description:Infinite lives + code:1267/3d/00 + cheat + description:Begin each new screen with a key-except 1st screen + code:175f/af/00 + cheat + description:1 EXP pt. for killing a bad guy + code:11d1/f0/3e+11d2/df/01 + cheat + description:5 EXP pts. for killing a bad guy + code:11d1/f0/3e+11d2/df/05 + cheat + description:9 EXP pts. for killing a bad guy + code:11d1/f0/3e+11d2/df/09 + cheat + description:Start with 2 life + code:13c8/02/01 + cheat + description:Start with 6 lives + code:13c8/02/05 + cheat + description:Start with 10 lives + code:13c8/02/09 + +cartridge sha256:f0f1f547332965963ae2f8b3f3b5fd62203e0690cc0299d38e1a3aa56f6a263b + name:Spy vs Spy - Operation Boobytrap (USA) + cheat + description:Infinite time + code:52d2/35/00 + cheat + description:Both spies start with 4 energy + code:169e/0a/04 + cheat + description:Both spies start with 6 energy + code:169e/0a/06 + cheat + description:Both spies start with 8 energy + code:169e/0a/08 + cheat + description:After death, start with 4 energy - white spy + code:4d84/0a/04 + cheat + description:After death, start with full energy - white spy + code:4d84/16/08 + cheat + description:No loss of energy during fight - both spies + code:4514/35/00 + cheat + description:Other spy's punches do not affect your energy + code:4503/18/00 + cheat + description:Walking over floor flowers doesn't affect your energy + code:505c/ea/fa + cheat + description:Traps do not affect energy - white spy + code:4a76/02/00 + +cartridge sha256:5b6bdf85e9083f328449b1316f5dd9c2789f4a57bdac5b16d74fe10bbea1b03c + name:Square Deal - The Game of Two-Dimensional Poker (USA) + cheat + description:Infinite time on pause counter + code:1da0/c4/01 + cheat + description:Timer starts at 30 + code:1c83/3c/1e + cheat + description:No time on pause counter + code:1c83/3c/00 + cheat + description:Select up to level 10 in level select + code:24d8/05/0a + cheat + description:Start with 1 replay + code:23af/09/3e+23b0/7e/01 + cheat + description:Start with 3 replays + code:23af/09/3e+23b0/7e/03 + cheat + description:Start with 9 replays + code:23af/09/3e+23b0/7e/09 + +cartridge sha256:2cdf2edac4e6230e063c867c60f92d5bb5f37969a19a32fb65c33fe9fafaa378 + name:Stargate (USA, Europe) + cheat + description:Tile counter doesn't work + code:4822/01/00 + cheat + description:Tiles all look blank but aren't + code:2274/c8/c9 + cheat + description:The bottom of the tiles are always tile one + code:497d/19/0e+497e/4e/01 + cheat + description:The bottom of the tiles are always tile two + code:497d/19/0e+497e/4e/02 + cheat + description:The bottom of the tiles are always tile three + code:497d/19/0e+497e/4e/03 + cheat + description:The bottom of the tiles are always tile four + code:497d/19/0e+497e/4e/04 + cheat + description:The bottom of the tiles are always tile five + code:497d/19/0e+497e/4e/05 + cheat + description:The bottom of the tiles are always tile six + code:497d/19/0e+497e/4e/06 + cheat + description:The bottom of the tiles are always tile seven + code:497d/19/0e+497e/4e/07 + cheat + description:The bottom of the tiles are always tile eight + code:497d/19/0e+497e/4e/08 + cheat + description:The bottom of the tiles are always tile nine + code:497d/19/0e+497e/4e/09 + cheat + description:The bottom of the tiles are always tile ten + code:497d/19/0e+497e/4e/0a + cheat + description:The bottom of the tiles are always tile eleven + code:497d/19/0e+497e/4e/0b + cheat + description:The bottom of the tiles are always tile twelve + code:497d/19/0e+497e/4e/0c + cheat + description:The bottom of the tiles are always smart bomb tiles + code:497d/19/0e+497e/4e/0d + cheat + description:The bottom of the tiles are always digger tiles + code:497d/19/0e+497e/4e/0e + cheat + description:The bottom of the tiles are always tile wildcard tiles + code:497d/19/0e+497e/4e/0f + +cartridge sha256:3123e4bcd304d84819c589775db3bf4a2b4fa6d23209b3da691ea7eda6045037 + name:Star Hawk (Europe) + cheat + description:Infinite lives + code:0a2c/ea/fa + cheat + description:Impenetrable shield + code:08c0/3d/00 + cheat + description:Infinite continues + code:0692/c5/00 + cheat + description:Keep power-ups when you die + code:0f15/ea/fa + cheat + description:Start with 8 lives + code:01c1/03/08 + cheat + description:Start with 10 lives + code:01c1/03/0a + cheat + description:Start with 12 lives + code:01c1/03/0c + +cartridge sha256:2085a11062131fd64c2bc836200a6e203c0bd45909d193c8ad82c0f79f2c025b + name:Star Trek Generations - Beyond the Nexus (USA) (SGB Enhanced) + cheat + description:Almost infinite phasers and shields + code:2256/30/18 + cheat + description:Infinite attempts in sub game + code:73d4/db/01 + cheat + description:Start with very little phasers and shields + code:73f7/64/01 + cheat + description:Start with 1/4 phasers and shields + code:73f7/64/22 + cheat + description:Start with 1/2 phasers and shields + code:73f7/64/3f + cheat + description:Start with 3/4 phasers and shields + code:73f7/64/4f + +cartridge sha256:9c08d6bdf045668d64934c7cc773bb2353ec15e9dc3e3f5d8ea2e02f2a22be40 + name:Star Trek - The Next Generation (USA, Europe) + cheat + description:Infinite shields + code:2427/ea/fa + cheat + description:Damage isn't repaired + code:2113/34/00 + cheat + description:Damage repaired immediately + code:2115/63/00 + cheat + description:Life support starts at 25% power + code:6e16/64/19 + cheat + description:Life support starts at 50% power + code:6e16/64/32 + cheat + description:Life support starts at 75% power + code:6e16/64/4b + cheat + description:Warp drive starts at 25% power + code:6e1a/64/19 + cheat + description:Warp drive starts at 50% power + code:6e1a/64/32 + cheat + description:Warp drive starts at 75% power + code:6e1a/64/4b + cheat + description:Impulse drive starts at 25% power + code:6e1e/64/19 + cheat + description:Impulse drive starts at 50% power + code:6e1e/64/32 + cheat + description:Impulse drive starts at 75% power + code:6e1e/64/4b + cheat + description:Shields start at 25% power + code:6e22/64/19 + cheat + description:Shields start at 50% power + code:6e22/64/32 + cheat + description:Shields start at 75% power + code:6e22/64/4b + cheat + description:Phasers start at 25% power + code:6e26/64/19 + cheat + description:Phasers start at 50% power + code:6e26/64/32 + cheat + description:Phasers start at 75% power + code:6e26/64/4b + cheat + description:Photon Torpedoes start at 25% power + code:6e2a/64/19 + cheat + description:Photon Torpedoes start at 50% power + code:6e2a/64/32 + cheat + description:Photon Torpedoes start at 75% power + code:6e2a/64/4b + cheat + description:Sensors start at 25% power + code:6e2e/64/19 + cheat + description:Sensors start at 50% power + code:6e2e/64/32 + cheat + description:Sensors start at 75% power + code:6e2e/64/4b + cheat + description:Transporter starts at 25% power + code:6e32/64/19 + cheat + description:Transporter starts at 50% power + code:6e32/64/32 + cheat + description:Transporter starts at 75% power + code:6e32/64/4b + +cartridge sha256:9cf6aa2b4d6a4bb877d33bb6131562c9f41deb369d08c5b60266941bb276561f + name:Star Wars (USA) + cheat + description:Infinite energy + code:3b5c/35/c9 + cheat + description:Infinite lives + code:3b6a/ff/00 + cheat + description:Infinite continues + code:12f6/ea/fa + cheat + description:No continues + code:03a2/0a/00 + cheat + description:20 continues + code:03a2/0a/14 + cheat + description:More energy - 1st life only + code:10b7/08/99 + cheat + description:Start with 1/2 energy on all lives except 1st + code:3c12/08/04 + cheat + description:Start with 1 life + code:03b7/03/01 + cheat + description:Start with 6 lives + code:03b7/03/06 + cheat + description:Start with 9 lives + code:03b7/03/09 + +cartridge sha256:a62719fa767547a11ac20e0ad5d1fd43b68f92908a5c81dd3aba95f921458c51 + name:Star Wars - The Empire Strikes Back (USA) + cheat + description:Infinite continues + code:0ea1/3d/00 + cheat + description:Start with all force abilities in inventory - still need to get force power to activate + code:01d7/00/01+01cf/af/00 + +cartridge sha256:5393db89f3763c973438d8a6abd4ff83c404fe6cd58a8041adf2cd6d85535835 + name:Street Fighter Alpha - Warriors' Dreams (USA) + cheat + description:Hit anywhere - both players + code:6f26/c8/00+67e1/c8/00 + +cartridge sha256:8730c69cb2aa82260ac07257e0e29d61f598de2f8fa3e65da1d694790fa5db16 + name:Street Fighter II (USA, Europe) (Rev A) (SGB Enhanced) + cheat + description:Invincibility + code:2a8e/28/18+2a9f/28/18+2ad2/28/18 + cheat + description:Hit anywhere - P1 + code:2ab1/05/00 + cheat + description:Hit anywhere - P2 + code:2a8f/05/00 + cheat + description:Fireball kills + code:7583/15/88 + cheat + description:Nobody takes damage from anything but throws/grabs + code:6924/77/00 + cheat + description:Opponent can't win any normal rounds + code:7b93/c1/00 + cheat + description:Allows you to select a higher skill level + code:5385/06/09 + cheat + description:Fireball doesn't do any damage + code:7583/15/00 + cheat + description:Fireball does more damage + code:7583/15/40 + cheat + description:Player one starts with very little energy + code:63f8/70/01 + cheat + description:Player one starts with 1/4 energy + code:63f8/70/1f + cheat + description:Player one starts with 1/2 energy + code:63f8/70/3a + cheat + description:Player one starts with 3/4 energy + code:63f8/70/52 + cheat + description:Player one starts with more energy + code:63f8/70/ff + cheat + description:Player two starts with very little energy + code:63ff/70/01 + cheat + description:Player two starts with 1/4 energy + code:63ff/70/1f + cheat + description:Player two starts with 1/2 energy + code:63ff/70/3a + cheat + description:Player two starts with 3/4 energy + code:63ff/70/52 + cheat + description:Player two starts with more energy + code:63ff/70/ff + cheat + description:Start with seconds on the timer + code:6461/63/88 + cheat + description:Ryu - Foot sweep doesn't do any damage + code:750b/10/00 + cheat + description:Ryu - Foot sweep does more damage + code:750b/10/40 + cheat + description:Ryu - Foot sweep kills + code:750b/10/88 + cheat + description:Ryu - Crouch punch doesn't do any damage + code:74f7/10/00 + cheat + description:Ryu - Crouch punch does more damage + code:74f7/10/40 + cheat + description:Ryu - Crouch punch kills + code:74f7/10/88 + cheat + description:Ryu - Normal upper cut doesn't do any damage + code:74a7/10/00 + cheat + description:Ryu - Normal upper cut does more damage + code:74a7/10/40 + cheat + description:Ryu - Normal upper cut kills + code:74a7/10/88 + cheat + description:Ryu - Straight punch doesn't do any damage + code:74cf/10/00 + cheat + description:Ryu - Straight punch does more damage + code:74cf/10/40 + cheat + description:Ryu - Straight punch kills + code:74cf/10/88 + cheat + description:Ryu - Standong hack kick doesn't do any damage + code:74bb/0a/00 + cheat + description:Ryu - Standong hack kick does more damage + code:74bb/0a/40 + cheat + description:Ryu - Standong hack kick kills + code:74bb/0a/88 + cheat + description:Ryu - Rolling throw doesn't do any damage + code:75b5/12/00 + cheat + description:Ryu - Rolling throw does more damage + code:75b5/12/40 + cheat + description:Ryu - Rolling throw kills + code:75b5/12/88 + cheat + description:Ryu - Jumping straight up and kicking doesn't do any damage + code:7533/11/00 + cheat + description:Ryu - Jumping straight up and kicking does more damage + code:7533/11/40 + cheat + description:Ryu - Jumping straight up and kicking kills + code:7533/11/88 + cheat + description:Ryu - Standing short kick doesn't do any damage + code:74d9/08/00 + cheat + description:Ryu - Standing short kick does more damage + code:74d9/08/40 + cheat + description:Ryu - Standing short kick kills + code:74d9/08/88 + +cartridge sha256:201aec9eb615f1434100e0db39d6039e3f80670a680b8af9df15915315c170b1 + name:Sumo Fighter (USA) + cheat + description:Infinite energy + code:5ec8/ea/fa + cheat + description:At easy or hard level screen, press down three times then A for super hard mode (makes display look weird) + code:0206/05/09 + cheat + description:Start with 2 energy bars + code:5baf/03/02 + cheat + description:Start with 5 energy bars + code:5baf/03/05 + cheat + description:Start with 8 energy bars + code:5baf/03/08 + cheat + description:Start with 2 lives + code:020b/02/01 + cheat + description:Start with 5 lives + code:020b/02/04 + cheat + description:Start with 8 lives + code:020b/02/07 + +cartridge sha256:79da9658fdd3b92910f0a63ba6c7a45fb680b0e0ebe03ad1ed982d3dc92edae1 + name:Super Battletank - War in the Gulf (USA) + cheat + description:Infinite damage + code:3b00/f0/e0 + cheat + description:Infinite ammo + code:3595/35/00 + cheat + description:Infinite fuel + code:2de1/f0/c9 + cheat + description:Start with 5 shells + code:2e42/32/05 + cheat + description:Start with 99 shells + code:2e42/32/63 + cheat + description:Start with 5 laser shots + code:2e4d/01/05 + cheat + description:Start with 99 laser shots + code:2e4d/01/63 + cheat + description:Start with 5 smoke shots + code:2e58/01/05 + cheat + description:Start with 99 smoke shots + code:2e58/01/63 + cheat + description:Start with 5 bullets + code:2e63/96/05 + cheat + description:Start with 99 bullets + code:2e63/96/63 + cheat + description:Start with very little fuel + code:2e72/ff/15 + +cartridge sha256:fbd32fe43df00f5821f290e0b2010b9944e46fd687eabf34cf78451e4a62be68 + name:Super Bombliss (Japan) (SGB Enhanced) + cheat + description:Drop one piece to clear level + code:4b69/20/3e+4aa2/00/01 + +cartridge sha256:f607ad68fdfd8cbaabe554fea2075050a7055f0fafef9a0fd2825a67b2fd038a + name:Super Breakout (USA) + cheat + description:Paddle hits ball from anywhere (ball goes down the screen at times) + code:0736/d5/3c+0735/da/c3 + +cartridge sha256:be805b8c607bbf1fdaade6345f244da20ba6ca8ac587402445b8f272a0d708d7 + name:Super Breakout! (USA) + cheat + description:Paddle hits ball from anywhere (ball goes down the screen at times) + code:0736/d5/3c+0735/da/c3 + +cartridge sha256:dab87fd694aa1358278b4850371ff1303dea2295b7b7cc14842c969014a73fb1 + name:Super Chase H.Q. (USA, Europe) + cheat + description:Infinite time + code:1678/01/00 + cheat + description:Infinite turbos + code:1767/3d/00 + cheat + description:Turbo boosts last half as long + code:1747/fa/77 + cheat + description:Turbo boosts lasts very short + code:1747/fa/15 + cheat + description:Turbo boosts lasts forever. Disable to fire a turbo boost then enable while turbo boost is going. + code:1714/c4/00 + cheat + description:Start with lots of points + code:4990/f2/f5 + cheat + description:Start with 1 turbo boost + code:50e5/03/01+4908/03/01 + cheat + description:Start with 2 turbo boosts + code:50e5/03/02+4908/03/02 + cheat + description:Start with 5 turbo boosts + code:50e5/03/05+4908/03/05 + cheat + description:Start with 9 turbo boosts + code:50e5/03/09+4908/03/09 + +cartridge sha256:1a3841dfc6ccf87167d7b1f0ce17f3bbf9fd64445611e249f5902e8824e17483 + name:Super Chinese Land (Japan) + cheat + description:Invincibility (blinking) + code:14be/c9/00 + cheat + description:Infinite health + code:450a/1a/7c+450b/77/12 + cheat + description:Infinite lives + code:555a/c9/47 + +cartridge sha256:af5a78f29f7e5e70bfe4d0122bdb99d5d0e38a3e8912ff49c2630c7d6be7db67 + name:Super Mario Bros. Deluxe (USA, Europe) + cheat + description:Invincibility - Star effect + code:01ff/c1/da+01ff/c1/db + cheat + description:Fireballs hit anywhere + code:40bb/28/18+40cb/28/18+2301/da/fa+230f/da/fa + cheat + description:Fireballs go through all enemies and obstacles + code:40bb/28/18+40cb/28/18 + cheat + description:Blocks that contain coins also give a Starman + code:48a3/00/02+4752/40/48+4751/00/b5 + +cartridge sha256:db81dd4acbd0c7a3b9004f169ee278450c764c842ae777abd28073fbedf4078b + name:Super Mario Bros. Deluxe (USA, Europe) (Rev A) + cheat + description:Invincibility - Star effect + code:01ff/c1/da+01ff/c1/db + cheat + description:Fireballs hit anywhere + code:40bb/28/18+40cb/28/18+2301/da/fa+230f/da/fa + cheat + description:Fireballs go through all enemies and obstacles + code:40bb/28/18+40cb/28/18 + cheat + description:Blocks that contain coins also give a Starman + code:48a3/00/02+4752/40/48+4751/00/b5 + +cartridge sha256:c06af1a1c2a804e4169fd9bfd6eee7073545d88c97febc96c345dd10efd77547 + name:Super Mario Bros. Deluxe (USA, Europe) (Rev B) + cheat + description:Invincibility - Star effect + code:01FFDAC1+01FFDBC1 + cheat + description:Fireballs go through all enemies and obstacles + code:40bb/28/18+40cb/28/18 + cheat + description:Blocks that contain coins also give a Starman + code:48a3/00/02+4752/40/48+4751/00/b5 + +cartridge sha256:49fbd2f61f953d5ef28cab73e357e524c3009ad19fcf30f6a9ee0ae273be41dc + name:Super Mario Land (World) (Rev A) + cheat + description:Enable level select + code:04d3/45/00+04aa/d2/c3 + cheat + description:Infinite time (disable at end of stage) + code:5860/01/00 + cheat + description:Always have superballs + code:4a17/c8/00 + cheat + description:Multi-jump + code:49c2/f2/00+49c9/eb/00+49d8/19/00+49e4/08/00+49ae/20/18+4b75/d8/c9+49e7/ea/fa + cheat + description:Disable music + code:6cc3/c8/c9 + cheat + description:Clear level automatically + code:02a7/06/0c+02a6/27/40+02c0/76/40+02c1/23/0c + +cartridge sha256:470d6c45c9bcf7f0397d00c1ae6de727c63dd471049c8eedbefdc540ceea80b4 + name:Super Mario Land (World) + cheat + description:Enable level select + code:04d3/45/00+04aa/d2/c3 + cheat + description:Superballs hit anywhere + code:204b/2d/00+2048/d2/00+2049/2d/e1+204a/2d/e5 + cheat + description:Multi-jump + code:49c2/f2/00+49c9/eb/00+49d8/19/00+49e4/08/00+49ae/20/18+4b75/d8/c9+49e7/ea/fa + cheat + description:Disable music + code:6dbd/c8/c9 + +cartridge sha256:42045a1642f77b568534ab85b9db93c8a33d2b95c38ae84c987f497e8d52f97f + name:Super Mario Land 2 - 6 Golden Coins (USA, Europe) (Rev B) + cheat + description:Infinite time + code:5d8d/01/00 + cheat + description:Always have fireballs + code:32ce/c0/00 + cheat + description:Fireballs hit anywhere + code:304c/7f/4e+3062/7f/64 + +cartridge sha256:30d3316d06710cb94c529c477975cae3b051312b88aca9392888614b1c4b3894 + name:Super Mario Land 2 - 6 Golden Coins (USA, Europe) (Rev A) + cheat + description:Infinite lives + code:3140/01/00 + cheat + description:Infinite time + code:5d8d/01/00 + cheat + description:Timer counts down by 2 + code:5d8d/01/02 + cheat + description:Mushroom turns you into Bunny Mario + code:345b/01/02 + cheat + description:Mushroom turns you into Fire Mario + code:345b/01/03 + cheat + description:Stay as Super Mario when hit + code:31b9/ea/fa + cheat + description:Stay as Fire or Bunny Mario when hit + code:31c8/ea/fa + cheat + description:Hearts (extra life) worth nothing + code:34bb/3c/00 + cheat + description:Play 30 coin game of chance for free + code:745f/30/00 + cheat + description:Play 50 coin game of chance for free + code:7428/50/00 + cheat + description:Play 200 coin game of chance for free + code:73f2/02/00 + cheat + description:Play 999 coin game of chance for free + code:73bb/09/00+73ba/99/00 + cheat + description:Each coin worth 101 + code:1d92/00/01+592b/00/01 + cheat + description:Each coin worth 0 + code:5922/3c/00+1d89/3c/00 + cheat + description:Each defeated enemy worth 2 + code:7321/01/02 + cheat + description:Each defeated enemy worth 5 + code:7321/01/05 + cheat + description:Can re-enter boss levels + code:418d/28/18 + cheat + description:Always have fireballs + code:32cb/c0/00 + cheat + description:Start new game with 1 life instead of 6 + code:4241/05/00 + cheat + description:Start new game with 10 lives instead of 6 + code:4241/05/09 + cheat + description:Start new game with 25 lives instead of 6 + code:4241/05/24 + cheat + description:Start new game with 50 lives instead of 6 + code:4241/05/49 + cheat + description:Start new game with 75 lives instead of 6 + code:4241/05/74 + cheat + description:Start new game with 100 lives instead of 6 + code:4241/05/99 + +cartridge sha256:5450dce1bd0c073964c374b5b5b5729dce8d00f2e807892c34af32b8bce1392e + name:Super Mario Land 2 - 6 Golden Coins (USA, Europe) + cheat + description:Infinite lives + code:3140/01/00 + cheat + description:Infinite time + code:5d8d/01/00 + cheat + description:Fireballs hit anywhere + code:3049/7c/4b+305f/7c/61 + cheat + description:Always have fireballs + code:32cb/c0/00 + +cartridge sha256:91bd1f24827bde4dbb58ead76a8b4e5a507431ec9b6bbc7ef9473b852538a4d5 + name:Super Off Road (USA, Europe) + cheat + description:Infinite money + code:4da2/ea/fa + cheat + description:Infinite tires, nitros, etc. when you buy them + code:233a/35/00 + cheat + description:Start with 2 credits + code:0b87/03/02 + cheat + description:Start with 4 credits + code:0b87/03/04 + cheat + description:Start with 8 credits + code:0b87/03/08 + +cartridge sha256:1c93028e0882746e91721fedda27165281603744afa15f25fd7247d7c04071e8 + name:Survival Kids (USA) (SGB Enhanced) + cheat + description:Walk anywhere + code:276e/20/3e + +cartridge sha256:f522c83d9dc77825a8bd5933e0877173fcb260fe72c5b032ef38b109250a63e9 + name:Swamp Thing (USA, Europe) + cheat + description:Invincibility + code:1285/90/c9 + cheat + description:Infinite lives + code:038f/ea/fa + cheat + description:Infinite environmental meter + code:6fcf/ea/fa + cheat + description:Start with half energy + code:055a/40/20 + cheat + description:Start with 1/2 environmental meter + code:0555/20/10 + +cartridge sha256:3e7a15c930db627b82b83f1e2a499436b0419e4d05b85bdfeb2a475e6a07c9b1 + name:Sword of Hope, The (USA) + cheat + description:Infinite HP + code:4172/c7/00 + cheat + description:Start with 11 dexterity points + code:2abf/05/09 + cheat + description:12 stamina points + code:2ac4/05/09 + cheat + description:Shaman is free + code:34a0/e0/f0 + cheat + description:Forest shop is free + code:3a3c/e0/f0 + +cartridge sha256:f55e542cc82dc5fbefc0fc5f42e95e882fba7895e73a8ff084ce7aa8408bdd85 + name:T2 - The Arcade Game (USA, Europe) + cheat + description:Infinite energy + code:2c9d/e0/f0 + cheat + description:Infinite lives + code:2cab/e0/f0 + cheat + description:Infinite rockets + code:14b8/ea/fa + cheat + description:Infinite continues + code:1d5c/ea/fa + cheat + description:Start with 2 lives + code:0346/05/02 + cheat + description:Start with 4 lives + code:0346/05/04 + cheat + description:Start with 8 lives + code:0346/05/08 + +cartridge sha256:351a3b24efa68f60009bc7e05d554034c8dc3d360d51d7399c80e65370899679 + name:Tail 'Gator (USA, Europe) + cheat + description:Invincibility + code:1baf/28/3e+222d/c2/fa + cheat + description:Hit anywhere + code:51b0/34/00+5234/ca/fa + +cartridge sha256:731385527be39125a2044edbc46da9f5d9bc48cff7e320b213c45d77c5069067 + name:Tarzan (USA, Europe) + cheat + description:Infinite time + code:4086/ea/fa + cheat + description:One hit kills + code:43ed/38/18+4441/38/18 + cheat + description:Multi-jump + code:4784/20/3e + cheat + description:Only one special item needed + code:40bc/3d/af + +cartridge sha256:596787d9f1dfeef0151b20ce330ef78220e041d0a360b34dea75ce21c7cbb889 + name:Taz-Mania (USA, Europe) + cheat + description:Invincibility + code:7365/c0/00 + cheat + description:Infinite spins + code:6c51/ea/fa + cheat + description:Infinite hearts + code:373c/ea/fa + cheat + description:Infinite time + code:76aa/ea/fa + cheat + description:Infinite credits + code:2a48/ea/fa + cheat + description:Don't flash after getting hit + code:6a96/80/00 + cheat + description:Don't flash as long after getting hit + code:6a96/80/11 + cheat + description:Flash longer after getting hit + code:6a96/80/f1 + cheat + description:Start with 1 heart - 1st life + code:076e/03/01 + cheat + description:Start with 5 hearts - 1st life + code:076e/03/05 + cheat + description:Start with 10 hearts - 1st life + code:076e/03/0a + cheat + description:Start timer at 58 seconds + code:7840/19/3e+7841/2a/05 + cheat + description:Start timer at 1 minute 48 seconds + code:7840/19/3e+7841/2a/0a + +cartridge sha256:8b5f65da035664baedd19c55ddfe06682e2dd7d45970bcb10917078c855aa19c + name:Taz-Mania 2 (USA) + cheat + description:Invincibility + code:0108/dc/49 + cheat + description:Infinite health + code:0100/db/60 + cheat + description:Infinite attack + code:0128/d3/ba + cheat + description:Infinite time + code:0138/d3/7d + +cartridge sha256:1f3c9ff627b0445e57a7425bc433c0476a0eeafe25ea5c6522b102d1ef8f875e + name:Tecmo Bowl (USA) + cheat + description:Infinite time + code:5dc9/35/00 + cheat + description:Have 49 downs + code:44d6/04/49 + cheat + description:Have 5 downs + code:44d6/04/05 + cheat + description:8 minutes 30 seconds per quarter + code:44ef/01/08 + cheat + description:6 minutes 30 seconds per quarter + code:44ef/01/06 + cheat + description:1 minutes 30 seconds per quarter + code:44ef/01/01 + +cartridge sha256:f4ef2ca5506f493f48833c16dff5eaa2b18ba488c352ed5bc03059d150e46620 + name:Teenage Mutant Ninja Turtles - Fall of the Foot Clan (USA) + cheat + description:Infinite health + code:0109/c9/81 + cheat + description:Hit anywhere + code:3de2/a1/b8+3e26/a1/b8+3ddf/0e/3e+3e23/0e/3e + +cartridge sha256:b2588721a1a298cfbd1f2fca465ac70f0b2aa488fab8eed1b7f49cac592ac438 + name:Teenage Mutant Ninja Turtles II - Back from the Sewers (USA) + cheat + description:Invincibility + code:564c/30/18+56b4/d0/c9 + cheat + description:Hit anywhere + code:56f1/d0/00 + +cartridge sha256:95c804c1a851b502c15a3418eef75e491aec9371e2fb2a34e4aaa27b37e02023 + name:Teenage Mutant Ninja Turtles III - Radical Rescue (USA) + cheat + description:Invincibility + code:233b/d0/c9+4884/21/c9 + cheat + description:Hit anywhere + code:2247/d0/00+2264/d0/00+22de/d0/00+22fb/d0/00 + +cartridge sha256:cdcb6ba23ea2c32a2af47abb267d8bd065a8bc10777b435de6a9be421e5bf919 + name:Tennis (World) + cheat + description:Neither player scores points - disable to score + code:21da/34/00 + cheat + description:1 game needed to win set + code:209c/07/01 + cheat + description:2 games needed to win set + code:209c/07/02 + cheat + description:3 games needed to win set + code:209c/07/03 + cheat + description:4 games needed to win set + code:209c/07/04 + cheat + description:1st point takes you to 40 points + code:219a/03/01 + cheat + description:2nd point takes you to 40 points + code:219a/03/02 + cheat + description:Neither player can win game + code:2099/34/00+2074/e3/e0+207e/e3/e0 + +cartridge sha256:5fa11359e8147b295bebd1e5631c7b96908c649d9d33fdc45a2dd3de8d69ca73 + name:Terminator 2 - Judgment Day (USA, Europe) + cheat + description:Almost infinite energy + code:1500/ea/c9 + cheat + description:Infinite time in reprogramming stage + code:4103/3d/00 + cheat + description:20 shots kill end of level 1 boss + code:4854/28/14 + cheat + description:10 shots kill end of level 1 boss + code:4854/28/0a + cheat + description:5 shots kill end of level 1 boss + code:4854/28/05 + cheat + description:Start with 1/2 energy + code:2e59/e0/70 + +cartridge sha256:7fde11dd4e594a6905deccd57943d2909ecb37665a030741c42155aeb346323b + name:Tetris (Japan) (En) + cheat + description:Drop a piece on the far left side of the board to clear the section + code:21b9/f7/00 + +cartridge sha256:0d6535aef23969c7e5af2b077acaddb4a445b3d0df7bf34c8acef07b51b015c3 + name:Tetris (World) (Rev A) + cheat + description:Drop a piece on the far left side of the board to clear the section + code:215e/f7/00 + cheat + description:Keep stack displayed while paused + code:1c30/cb/ce + cheat + description:Keep current and next pieces displayed while paused + code:1c53/cd/d9 + cheat + description:Only piece 1 will appear + code:2063/e0/00+2064/ae/3e+2065/7b/00 + cheat + description:Only piece 2 will appear + code:2063/e0/00+2064/ae/3e+2065/7b/04 + cheat + description:Only piece 3 will appear + code:2063/e0/00+2064/ae/3e+2065/7b/08 + cheat + description:Only piece 4 will appear + code:2063/e0/00+2064/ae/3e+2065/7b/0c + cheat + description:Only piece 5 will appear + code:2063/e0/00+2064/ae/3e+2065/7b/10 + cheat + description:Only piece 6 will appear + code:2063/e0/00+2064/ae/3e+2065/7b/14 + cheat + description:Only piece 7 will appear + code:2063/e0/00+2064/ae/3e+2065/7b/18 + +cartridge sha256:d349dc93423c6abcd775d3b6a8797df715a44a42ec837afb21bf17ae43b40a9e + name:Tetris DX (World) (SGB Enhanced) + cheat + description:Drop pieces on the left side of the board to clear lines + code:5a8b/f7/00 + cheat + description:Score increases a lot + code:53c9/86/1f + cheat + description:Swap over next shape to current shape by pressing A + code:57c5/fa/c3+57c6/82/b6+57c7/af/58 + cheat + description:Swap over next shape to current shape by pressing B + code:581e/fa/c3+581f/82/b6+5820/af/58 + cheat + description:Swap over next shape to current shape by pressing select + code:5876/fa/18+5877/87/3e + +cartridge sha256:771d24adf7dd11ff166fc43d3f2be66dd7a24251b8920e813956c62514813051 + name:Tetris 2 (USA) + cheat + description:Drop one piece to clear level + code:5df6/06/00 + cheat + description:No next piece screen + code:58e9/fa/c9 + cheat + description:Blocks come down fast + code:6d64/c6/10+6d62/fa/00+6d63/96/3e + cheat + description:Blocks come down very fast + code:6d64/c6/70+6d62/fa/00+6d63/96/3e + cheat + description:Blocks come down super fast + code:6d64/c6/20+6d62/fa/00+6d63/96/3e + cheat + description:Can select round above 30 on options screen + code:5a4b/d0/00 + cheat + description:In versus mode, no blocks added to top of screen + code:78cb/ea/fa + +cartridge sha256:2c3bc48a4ec9b6c640b83ce6524570f472db329d4a96d0b527b34abd42b7d695 + name:Tetris 2 (USA, Europe) (SGB Enhanced) + cheat + description:Drop one piece to clear level + code:5f67/06/00 + +cartridge sha256:b8765e752153310f835e10d6ceaee80b0e0913cdadf832b9516af8bf974e9666 + name:Tetris Attack (USA) (SGB Enhanced) + cheat + description:Rows clear automatically (except in Puzzle Mode) + code:4734/d9/00 + +cartridge sha256:252e9981ba15054b5b8e2eeab22ccbae7ac3cbe9d7cd7a895c75fb35054717f9 + name:Tetris Attack (USA, Europe) (Rev A) (SGB Enhanced) + cheat + description:Rows clear automatically (except in Puzzle Mode) + code:4732/d9/00 + +cartridge sha256:379f9034b2702f06247e1dd4a6e21d51a76aff84d12ff851e4e962b105094d10 + name:Tiny Toon Adventures 2 - Montana's Movie Madness (USA, Europe) + cheat + description:Invincibility + code:2cda/c2/c3 + cheat + description:Infinite health + code:2d5c/3d/00 + cheat + description:Infinite time + code:4614/3d/00 + cheat + description:Infinite lives + code:2a5e/01/00 + cheat + description:One hit and you die + code:2d53/e0/00 + cheat + description:Don't flash as long after getting hit + code:2d53/e0/3f + cheat + description:Start with 1 heart + code:1966/04/02 + cheat + description:Start with 2 hearts + code:1966/04/03 + cheat + description:Start with 1 life + code:6e1e/02/00 + cheat + description:Start with 5 lives + code:6e1e/02/04 + cheat + description:Start with 10 lives + code:6e1e/02/09 + cheat + description:Start with mega points + code:6e22/af/00 + cheat + description:Start with 100 seconds on the clock + code:6e31/05/01 + cheat + description:Start with 300 seconds on the clock + code:6e31/05/03 + cheat + description:Start with 700 seconds on the clock + code:6e31/05/07 + cheat + description:Start with 900 seconds on the clock + code:6e31/05/09 + +cartridge sha256:fe2f3a9c8af3702b53398fea579951634effbeafaea10865aac8b07d7458e9b1 + name:Tiny Toon Adventures 2 (Japan) + cheat + description:Invincibility + code:2cda/c2/c3 + cheat + description:Infinite health + code:2d5c/3d/00 + cheat + description:Infinite time + code:4614/3d/00 + cheat + description:Infinite lives + code:2a5e/01/00 + cheat + description:One hit and you die + code:2d53/e0/00 + cheat + description:Don't flash as long after getting hit + code:2d53/e0/3f + cheat + description:Start with 1 heart + code:1966/04/02 + cheat + description:Start with 2 hearts + code:1966/04/03 + cheat + description:Start with 1 life + code:6e1e/02/00 + cheat + description:Start with 5 lives + code:6e1e/02/04 + cheat + description:Start with 10 lives + code:6e1e/02/09 + cheat + description:Start with mega points + code:6e22/af/00 + cheat + description:Start with 100 seconds on the clock + code:6e31/05/01 + cheat + description:Start with 300 seconds on the clock + code:6e31/05/03 + cheat + description:Start with 700 seconds on the clock + code:6e31/05/07 + cheat + description:Start with 900 seconds on the clock + code:6e31/05/09 + +cartridge sha256:4d078174031509ca7b63c237e176e9f5c0aed88b42352ad23aee98a777d3a0d7 + name:Titus the Fox to Marrakech and Back (USA, Europe) + cheat + description:Infinite energy until level 3 + code:6e7d/35/00 + cheat + description:Infinite energy from level 3 on + code:6273/35/00 + cheat + description:Infinite lives + code:696a/35/00 + cheat + description:Start 1st life with 1 energy unit + code:53d0/05/01 + cheat + description:Start 1st life with 9 energy units + code:53d0/05/09 + cheat + description:Start with 1 energy unit after 1st life + code:21cf/05/01 + cheat + description:Start with 9 energy units after 1st life + code:21cf/05/09 + cheat + description:Start 1st level with 100-pt. bonus + code:53dc/00/64 + cheat + description:Start 1st level with 250-pt. bonus + code:53dc/00/fa + cheat + description:Start with 1 life + code:53d5/03/01 + cheat + description:Start with 6 lives + code:53d5/03/06 + cheat + description:Start with 9 lives + code:53d5/03/09 + cheat + description:Start on level 1, part 2 + code:03ba/af/00 + +cartridge sha256:17e1629cd8a95ef8d09643d62f7336efa7c0983f03ceda5038632d2125885fa6 + name:Toki Tori (USA, Europe) (En,Ja,Fr,De,Es) + cheat + description:Get eggs from anywhere + code:40ce/27/33+40cd/38/18 + +cartridge sha256:597f70c8d600427fee6f3a3714115bad30b24402dd830c36dc010a7b3a92a7a3 + name:Tom & Jerry (USA, Europe) + cheat + description:Invincibility + code:455c/fa/ea+455a/20/3e + cheat + description:Infinite lives + code:2854/d5/00 + cheat + description:Infinite balls once collected + code:4684/ea/fa + cheat + description:Infinite energy (may have to die once first) + code:2d47/34/00 + cheat + description:Infinite time + code:1c3f/ea/fa+1c43/ea/fa + cheat + description:Moon jump + code:40da/28/3e + cheat + description:Every time you collect one cheese you get 11 (can't go over 100) + code:4067/01/11 + cheat + description:Start with 1 life + code:4f7b/03/01 + cheat + description:Start with 5 lives + code:4f7b/03/05 + +cartridge sha256:bcd52c83f3662165baaeff2527fd221c04b734214d5dacb8cdda6fbcb95fbc3b + name:Tom and Jerry - Frantic Antics! (USA, Europe) + cheat + description:Infinite lives + code:1e39/d3/01 + cheat + description:Infinite lives + code:4ce4/35/00 + cheat + description:Infinite time + code:3143/01/00+3151/01/00 + cheat + description:Don't flash after getting hit + code:7333/78/01 + cheat + description:Flash longer after getting hit + code:7333/78/fa + cheat + description:Start with 1 life + code:390c/03/01 + cheat + description:Start with 5 lives + code:390c/03/05 + cheat + description:Start with 10 lives + code:390c/03/0a + cheat + description:Start with 1 minutes on the timer + code:30de/05/01 + cheat + description:Start with 10 minutes on the timer + code:30de/05/0a + cheat + description:Start with 15 minutes on the timer - ignore counter + code:30de/05/0f + +cartridge sha256:ebcba74ab890e56676a4c1720f89719a489b73c7c688d1fd0c6a98074dc7afeb + name:Tomb Raider (USA, Europe) (En,Fr,De,Es,It) + cheat + description:Invincibility against enemies + code:40f3/28/3e+40f5/35/77 + cheat + description:Hit anywhere + code:5927/65/00 + +cartridge sha256:a75109b2730df5bef628f05660d670f07a1be6c6249d73f7f88375061c3f3bbb + name:Tomb Raider - Curse of the Sword (USA, Europe) + cheat + description:Invincibility + code:41bc/35/77+41ba/28/3e + cheat + description:Hit anywhere (only when standing and not against a wall) + code:5de8/6b/00 + cheat + description:One hit kills + code:5615/77/fe+5614/90/cb + +cartridge sha256:1878a9fa68e052362b0fbb13421db1ae822ffd74b69db34217455f9e43ce61dd + name:Top Gear Pocket (USA) + cheat + description:No slowdown (except for drifting) + code:1f7c/21/c9+1ef2/da/c3 + +cartridge sha256:976b837a48218903e55ae86b943db2a3bf49c1aba0e5d6e135cb2e775416382e + name:Top Gear Pocket 2 (USA) + cheat + description:All cars unlocked + code:4092/c2/c3 + cheat + description:All tracks unlocked + code:11a7/c2/c3 + +cartridge sha256:bb2f56c5035b47183c55b197bc380ea02df00dd733ce732d062f7c7695bd330f + name:Top Gun - Guts & Glory (USA, Europe) + cheat + description:Infinite missiles + code:6424/ea/fa + cheat + description:Infinite lives + code:6859/c4/00 + cheat + description:Start with 1 life (do not alter mission on the first menu screen) + code:2be4/03/01 + cheat + description:Start with 5 lives (do not alter mission on the first menu screen) + code:2be4/03/05 + cheat + description:Start with 10 lives (do not alter mission on the first menu screen) + code:2be4/03/0a + cheat + description:Start on mission 10 (do not alter mission on the first menu screen) + code:6485/ea/00+6486/99/3e+6487/c5/0a + +cartridge sha256:13a6106b5548261764b0f0d676b07265e6ed37b4cf2f85fc763b05dde749eb64 + name:Total Carnage (USA, Europe) + cheat + description:Infinite grenades + code:2228/ea/fa + cheat + description:Infinite lives + code:21ad/3d/00 + cheat + description:Start with very little energy after 1st life + code:21b1/06/02 + cheat + description:Start with mega energy after 1st life + code:21b1/06/99 + cheat + description:Don't take damage from some enemies after getting hit + code:1355/3d/00 + cheat + description:Start with very little energy-1st life + code:4054/06/02 + cheat + description:Start with mega energy-1st life + code:4054/06/99 + cheat + description:Start with 1 life + code:404f/03/00 + cheat + description:Start with 9 lives + code:404f/03/08 + cheat + description:Start with 15 lives + code:404f/03/0f + cheat + description:Start with 33 grenades + code:405f/00/03 + +cartridge sha256:eae3b192006eff607dffdae3d7720af579f85335be81e6cacb55276bfc32424c + name:Track & Field (USA, Europe) + cheat + description:Always have 100% power + code:277f/28/3e+2780/01/00 + cheat + description:Max angle on long jump + code:6d99/80/45 + cheat + description:Max angle on javelin + code:5a1e/80/45 + cheat + description:Max angle on triple jump + code:54d1/80/45 + +cartridge sha256:9047447e6ff5b0b510732befa3f48a464aebfa9ba06274b3cf6120b25e8dd033 + name:Triple Play 2001 (USA, Europe) + cheat + description:Balls are considered strikes + code:73f2/32/00 + +cartridge sha256:3990c42543e74387c30ac935eb45067e291b4a5e93702d5520acd0e91d14f34f + name:Tumble Pop (USA, Europe) + cheat + description:Infinite lives + code:25bc/ea/fa + cheat + description:Only have 2 minutes to complete each screen + code:188a/03/02 + cheat + description:Only have 5 minutes to complete each screen + code:188a/03/05 + cheat + description:Only have 10 minutes to complete each screen + code:188a/03/0a + cheat + description:Start across river from original position + code:1817/00/05 + cheat + description:Start at island castle + code:1817/00/ff + cheat + description:Hold enemies inside gun as long as you want + code:2e68/35/00 + cheat + description:Start with 1 life + code:181c/03/00 + cheat + description:Start with 6 lives + code:181c/03/05 + cheat + description:Start with 9 lives + code:181c/03/08 + +cartridge sha256:954ed263a5133c608636af442c4c0ade7f9b7dfdc768e7bfbf31d2528a8d7796 + name:Turn and Burn (USA) + cheat + description:Infinite missiles + code:2e1c/35/00 + cheat + description:Gun doesn't overheat + code:3151/04/00 + cheat + description:Start with more Aim-54 missiles + code:1299/79/7c + cheat + description:Start with more Aim-9 missiles + code:128b/79/7c + +cartridge sha256:0ca41e5faef09acc0f440ddb57624fb66cfb5f945145b7acc9390dd6ab07803c + name:Turok - Battle of the Bionosaurs (USA, Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:6a9c/c0/c9 + cheat + description:Hit anywhere + code:6494/11/3a+6493/28/18 + cheat + description:Multi-jump + code:5f16/a7/3d+5f15/cb/8b + +cartridge sha256:0e82076895f9aa7f8b787d5c76a33d72394f611bd0ac93ecd550873b7ce21b60 + name:Turok - Rage Wars (USA, Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:0b78/fa/c9 + cheat + description:Infinite ammo + code:509f/77/00 + cheat + description:Hit anywhere + code:4198/20/18+4199/2d/22 + +cartridge sha256:21f2b0f417dd94f8aaa75adf09b849c97780ab9140b1d7d53ed4516f33233037 + name:Turok 2 - Seeds of Evil (USA, Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:4934/28/3e+4d8e/d0/c9 + cheat + description:Hit anywhere (you have to be in line with them on the streets) + code:750c/11/3a+750b/28/18 + cheat + description:Multi-jump + code:4bc5/cb/8b+4bc6/a7/3d + +cartridge sha256:1710b81824ea2044e7c475c3a8befe52fb8ba92f5dfc8866d7362c1e11393859 + name:Turok 3 - Shadow of Oblivion (USA, Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:43f9/20/18 + cheat + description:Infinite ammo + code:4efd/77/00 + cheat + description:Hit anywhere + code:44a8/ff/6c+4452/59/50+4451/30/18 + +cartridge sha256:9008df8d950b4e6966b38218e43bc3baf9bad91ef44b271b558aee6f38c993d7 + name:Ultima - Runes of Virtue (USA) + cheat + description:Infinite energy + code:05f3/ea/fa+3400/ea/fa + cheat + description:Infinite money + code:0b5b/ea/fa + cheat + description:Walk anywhere + code:2a2b/05/00+2aec/20/18 + cheat + description:Start with dexterity of 10 - Shamino codes only - can't use with Journey Onward option + code:762b/15/10 + cheat + description:Start with dexterity of 30 - Shamino codes only - can't use with Journey Onward option + code:762b/15/30 + cheat + description:Start with dexterity of 50 - Shamino codes only - can't use with Journey Onward option + code:762b/15/50 + cheat + description:Start with strength of 10 - Shamino codes only - can't use with Journey Onward option + code:762c/15/10 + cheat + description:Start with strength of 30 - Shamino codes only - can't use with Journey Onward option + code:762c/15/30 + cheat + description:Start with strength of 50 - Shamino codes only - can't use with Journey Onward option + code:562c/15/50 + cheat + description:Start with IQ of 10 - Shamino codes only - can't use with Journey Onward option + code:762f/15/10 + cheat + description:Start with IQ of 30 - Shamino codes only - can't use with Journey Onward option + code:762f/15/30 + cheat + description:Start with IQ of 50 - Shamino codes only - can't use with Journey Onward option + code:762f/15/50 + cheat + description:Start with 15 coins - Shamino codes only - can't use with Journey Onward option + code:7565/30/15 + cheat + description:Start with 40 coins - Shamino codes only - can't use with Journey Onward option + code:7565/30/40 + cheat + description:Start with 60 coins - Shamino codes only - can't use with Journey Onward option + code:7565/30/60 + cheat + description:No energy replacement - Shamino codes only - can't use with Journey Onward option + code:0c0a/ea/fa + +cartridge sha256:60d23465ffb1a84cb8c72a51146fd3bf2fa2fc323424098d801622e6190af761 + name:Ultima - Runes of Virtue II (USA) + cheat + description:Walk anywhere (player and enemies) + code:19bc/b7/af+1866/ca/c3+19bd/c0/c8 + +cartridge sha256:850a429b64b7ebcb8034da2c25789dff631d64682b1ce65f8de346c9744ae31e + name:Universal Soldier (USA, Europe) + cheat + description:Infinite energy + code:387a/35/00 + cheat + description:Infinite time + code:0a5a/35/00 + cheat + description:Infinite lives + code:03ee/c0/c9 + cheat + description:Fewer enemies on each level + code:1c50/34/00+1c4b/35/00 + cheat + description:Start with 5 lives + code:15d1/03/05 + cheat + description:Start with 7 lives + code:15d1/03/07 + cheat + description:Start with 9 lives + code:15d1/03/09 + cheat + description:Start with 5 power lines + code:16ac/03/05 + cheat + description:Start with 7 power lines + code:16ac/03/07 + cheat + description:Start with 9 power lines + code:16ac/03/09 + +cartridge sha256:102dabffa56271534c651579445c13a375e7978f37bdcccc3271e9320c3710fa + name:Uno (USA) + cheat + description:Place any card on the stack regardless of color + code:5891/ca/fa + +cartridge sha256:56b00fb68b829dabe56e88f3074316ee2f3022a15c6f45bd70bda5e8f62c2e8f + name:Uno - Small World (Japan) + cheat + description:Can place any color card on the stack + code:589f/30/18 + +cartridge sha256:88773be9e71529b35ce03d39f417e866f48df97cdfb894943f729dab7beefb90 + name:Uno 2 - Small World (Japan) (SGB Enhanced) + cheat + description:Place any card on the stack + code:5701/30/18+57b7/30/18 + +cartridge sha256:19e8ccfe0df0647cbd6517a456fcffa39c3a9ecc1e40dd31bd193423b4779020 + name:Velious - Roland no Majuu (Japan) + cheat + description:Invincibility + code:3bb6/ff/00 + cheat + description:Hit anywhere + code:3d5a/af/b7 + cheat + description:Walk through walls + code:038b/28/18 + +cartridge sha256:2b3ed695acb2fcd3aa8159b12373a55b01a72ae3a9e0867ef8446fd8abddec51 + name:Velious II - Fukushuu no Jashin (Japan) + cheat + description:Invincibility + code:3e3c/b7/af + cheat + description:Infinite TP + code:0e01/e0/f0 + cheat + description:Hit anywhere - main weapon + code:3fa7/d0/00+3f98/d8/00+3fa2/d8/00+3f9d/d0/00 + cheat + description:Hit anywhere - sub-weapon + code:3f70/d0/00+3f6b/d8/00+3f66/d0/00+3f61/d8/00 + cheat + description:Walk through walls + code:031d/28/18 + +cartridge sha256:1709e340bc089dc179bbc0c24242c9bd5fab9aa7bd1e57b1328725b9b4787786 + name:Wacky Races (USA) (En,Fr,Es) + cheat + description:Press select during gameplay to skip to the end of race in your current position + code:07d9/0f/00 + cheat + description:View ending (enable before booting the game) + code:018e/ff/fe + +cartridge sha256:1af2d4b29552fb2cf141955e1d77f8dd99e856b1f04fbff5240d5a1c3c2c41bf + name:Wario Blast featuring Bomberman! (USA, Europe) (SGB Enhanced) + cheat + description:Infinite time + code:0a5b/77/00 + cheat + description:Collect up to 8 extra bomb power-ups + code:53f1/04/08 + cheat + description:Extra bomb power-ups don't do anything + code:53ef/77/00 + cheat + description:Explosion expanders don't do anything + code:53d7/77/00 + cheat + description:Start with 300 seconds + code:1f87/01/03 + cheat + description:Start with 4 extra bomb power-ups + code:26c7/01/04 + cheat + description:Start with 4 explosion expander + code:26cb/00/04 + cheat + description:Start on round 3-3 + code:403b/ea/21+4013/af/00 + cheat + description:Start on round 3-Boss + code:403b/ea/21+4013/af/3c + +cartridge sha256:ac1682f17abcf590311a233289ee325214c2d71ab3a5aa175004002d85075e56 + name: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:0d63/ea/fa + cheat + description:Most enemies and obstacles are invisible + code:43aa/02/00+36c0/ea/c9 + cheat + description:Multi-jump + code:518e/c2/c4+5193/c2/c4+5196/cb/18+5197/47/11 + cheat + description:Get 10 hearts for killing an enemy + code:03e4/01/10 + cheat + description:Get 25 hearts for killing an enemy + code:03e4/01/25 + cheat + description:Get 50 hearts for killing an enemy + code:03e4/01/50 + cheat + description:Get 99 hearts for killing an enemy + code:03e4/01/99 + cheat + description:Start as Small Wario + code:7b7e/01/00 + cheat + description:Start as Bull Wario + code:7b7e/01/02 + cheat + description:Start as Jet Wario + code:7b7e/01/03 + cheat + description:Start as Dragon Wario + code:7b7e/01/04 + cheat + description:Start with 10 hearts + code:7b7c/00/10 + cheat + description:Start with 25 hearts + code:7b7c/00/25 + cheat + description:Start with 50 hearts + code:7b7c/00/50 + cheat + description:Start with 99 hearts + code:7b7c/00/99 + cheat + description:Start with 10 coins + code:7b7b/00/10 + cheat + description:Start with 25 coins + code:7b7b/00/25 + cheat + description:Start with 50 coins + code:7b7b/00/50 + cheat + description:Start with 99 coins + code:7b7b/00/99 + cheat + description:Start with 10 lives + code:7b7d/05/10 + cheat + description:Start with 25 lives + code:7b7d/05/25 + cheat + description:Start with 50 lives + code:7b7d/05/50 + cheat + description:Start with 99 lives + code:7b7d/05/99 + cheat + description:Start on course 26 + code:7b7f/00/01 + cheat + description:No turbo boost + code:1240/3c/00 + cheat + description:Infinite turbo boost + code:12ca/3d/00 + cheat + description:No lap timer + code:53b7/22/00 + cheat + description:Start with 800cc bike + code:4965/20/3e+4966/03/02+4967/af/00 + cheat + description:Start with 650cc bike + code:4965/20/3e+4966/03/01+4967/af/00 + +cartridge sha256:5c11041f10b7ee96d433ef167dcb331acbf92deece796cdc10eb30ab7da1efee + name:Wave Race (USA, Europe) + cheat + description:Always have Dolphin Power + code:6ffa/20/3e+6fa9/46/00+6fa4/4b/00 + +cartridge sha256:a3bd35fb1d2466868b5308a45e8ad3844925bd5dfa819b27ff67d0391b8e3511 + name:WCW Main Event (USA, Europe) + cheat + description:Infinite time + code:233e/01/00 + cheat + description:One hit kills + code:1606/30/18+1605/90/af + cheat + description:Never regain energy + code:15d9/34/c9 + cheat + description:Computer does massive damage + code:163e/01/09 + cheat + description:Faster timer + code:233e/01/02 + +cartridge sha256:e424a9893faed6a486d66002ed606cf32d68dab71971ec461103396042800b63 + name:Wendy - Every Witch Way (USA, Europe) + cheat + description:Invincibility + code:4177/c0/c9 + cheat + description:Infinite Stars + code:4190/ea/fa + cheat + description:Infinite time + code:7fab/22/00 + cheat + description:Hit anywhere + code:6afa/20/af+6afb/5f/c9 + cheat + description:Shoot 3 projectiles from wand + code:5f9a/c2/c3 + +cartridge sha256:b915f6ffe0dd3ab9fe8972468013334a0c6d3f664982bc8ed8888e54d5bbbebf + name:Who Wants to Be a Millionaire - 2nd Edition (USA) + cheat + description:Always correct + code:18ff/28/18 + +cartridge sha256:db8029c84c99c1bff1724656d0887636497986fac02892f4d4334c60f646c84f + name:Wild Snake (USA) (SGB Enhanced) + cheat + description:Infinite time in King Cobra mode + code:0b1e/ea/fa + cheat + description:All snakes are shorter + code:227e/30/3e+227f/f5/03 + cheat + description:Only plain yellow snakes fall + code:2315/79/3e+2316/a7/01 + cheat + description:Only zig-zag snakes fall + code:2315/79/3e+2316/a7/02 + cheat + description:Only dark dotted snakes fall + code:2315/79/3e+2316/a7/03 + cheat + description:Only light dotted snakes fall + code:2315/79/3e+2316/a7/04 + cheat + description:Only dark striped snakes fall + code:2315/79/3e+2316/a7/05 + cheat + description:Only light striped snakes fall + code:2315/79/3e+2316/a7/06 + cheat + description:Only vertically striped snakes fall + code:2315/79/3e+2316/a7/07 + cheat + description:Only checkered snake snakes fall + code:2315/79/3e+2316/a7/08 + cheat + description:Only skeleton snakes fall + code:2315/79/3e+2316/a7/0a + cheat + description:Only temporarily invisible snakes fall + code:2315/79/3e+2316/a7/0b + cheat + description:Only dark snakes fall + code:2315/79/3e+2316/a7/0c + cheat + description:Only wild snakes fall + code:2315/79/3e+2316/a7/0d + cheat + description:Only king cobra snakes fall + code:2315/79/3e+2316/a7/0e + cheat + description:Collect 1 snake in King Cobra mode and finish level + code:26df/fa/3e+26e1/c8/3e+26e2/3c/30 + cheat + description:Snakes fall very fast + code:4553/fa/3e+4554/4b/01+4555/c6/00 + cheat + description:Snakes fall extremely fast + code:4553/fa/3e+4554/4b/00+4555/c6/00 + cheat + description:Snakes fall slower + code:4553/fa/3e+4554/4b/05+4555/c6/00 + cheat + description:Snakes fall very slow + code:4553/fa/3e+4554/4b/1f+4555/c6/00 + cheat + description:Snakes fall extremely slow + code:4553/fa/3e+4554/4b/af+4555/c6/00 + +cartridge sha256:b396d2a15563b6144630d5ec5f0a8a2928a4b289ca215e6cc581df7a5fe295ff + name:WordZap (USA) + cheat + description:Infinite hints + code:0870/35/00 + cheat + description:Any word is acceptable + code:137d/20/18 + cheat + description:Start with only 1 hint + code:1bc9/04/01 + cheat + description:Start with 5 hints + code:1bc9/04/05 + cheat + description:Start with 9 hints + code:1bc9/04/09 + cheat + description:Start with 1 chance + code:1bce/03/01 + cheat + description:Start with 9 chances + code:1bce/03/09 + +cartridge sha256:439854d8d2ec85bffb171efe3ec0d6ba98fed2443b26053340daaf8190611859 + name:World Bowling (USA) + cheat + description:Always bowl at full power + code:4694/c6/3e+4695/09/ff + cheat + description:Get a spare even if you miss + code:5344/79/3e+5345/90/0a + +cartridge sha256:246d48cb2a6ed53a7cf78d94fc219762aaaea0111467a5fcf415ca76f9170124 + name:World Circuit Series (USA) + cheat + description:No loss of speed on course you take your finger from acceleration button + code:1ca0/3d/00 + cheat + description:No loss of speed when you leave course-except hitting walls + code:1ae2/35/00 + cheat + description:No qualifying timer + code:0384/35/00+0385/c0/c9 + +cartridge sha256:03e6c6bcd5c9942a7fd30917c70524f961e152bdd3b4e70bf1fd9f012635c065 + name:World Heroes 2 Jet (USA, Europe) (SGB Enhanced) + cheat + description:Hit anywhere - both players + code:46a1/ca/fa+452c/20/18 + +cartridge sha256:0ba3d3b9be8c615bd29956887584aff9446a88fb2606bfb8ccc75907164c4cf9 + name:WWF King of the Ring (USA, Europe) + cheat + description:No out of ring timer + code:2c0f/01/00 + +cartridge sha256:770a3c6cd89d34af0d452eb4f52cd5a2f9d2651b9b54b247de349ff701f59a52 + name:WWF Raw (USA, Europe) + cheat + description:Infinite health - P1 + code:0154/cf/10 + cheat + description:No health - P2 + code:0100/cf/4f + +cartridge sha256:e5971b4a0c14a8dc06386844975ea76a65a9f81539e43bbe90a6bed198990b15 + name:WWF WrestleMania 2000 (USA, Europe) + cheat + description:Infinite health - P1 + code:0164/c0/b8 + cheat + description:Infinite health - P2 + code:0184/c0/f9 + cheat + description:No health - P1 + code:0100/c0/b8 + cheat + description:No health - P2 + code:0100/c0/f9 + cheat + description:Always fight in cage + code:0102/c6/94 + cheat + description:Always fight in ring + code:0101/c6/94 + +cartridge sha256:85c5368af171f9c47e02157222f140ad44ee9f9307f31838ffe9430793d80c65 + name:X-Men - Mutant Academy (USA, Europe) + cheat + description:Hit anywhere - both players + code:5465/28/18+5466/01/12+52e6/d0/c9 + +cartridge sha256:e8b42d935ea865f0b00f2a5447c8695799116e33dea30eaec5159ce7df225348 + name:X-Men - Mutant Wars (USA, Europe) + cheat + description:Invincibility + code:1699/30/18 + cheat + description:Hit anywhere + code:15fa/35/00 + cheat + description:One hit kills + code:7225/28/18 + cheat + description:One hit kills - bosses + code:40a4/38/18 + +cartridge sha256:3843f2cdb0746ff0cf7dc97e1aab4fc6a15219e7ac8e1970ead475a835c57aea + name:Xenon 2 - Megablast (USA, Europe) + cheat + description:Invincibility + code:1e50/ea/fa + cheat + description:Infinite energy + code:2416/ea/fa + cheat + description:Infinite lives + code:02eb/ea/fa + cheat + description:Purchases at shop are free + code:36db/21/c9 + cheat + description:When you die you get an awesome ship (for a while) + code:02f4/af/00 + cheat + description:Start with very little energy + code:0308/12/01 + cheat + description:Start with 1/3 energy + code:0308/12/05 + cheat + description:Start with 1/2 energy + code:0308/12/09 + cheat + description:Start with 2,222,222 points + code:0204/af/00 + cheat + description:Start with 1 life + code:3175/05/01 + cheat + description:Start with 5 lives + code:3175/05/05 + cheat + description:Start with 10 lives + code:3175/05/0a + +cartridge sha256:79847fc3769d81c17f95f7d4797b25129c5bf416e9da2a16ab2d09d71e9b9bbe + name:Yogi Bear - Great Balloon Blast (USA) + cheat + description:Power-up after almost every shot + code:77cb/28/00 + cheat + description:Power-up after almost every shot (alt) + code:0928/c9/26 + +cartridge sha256:98fb28e23fa2bdb969317544bf0fd5c24fb377134cac12897b29889bc67f6ca6 + name:Yogi Bear in Yogi Bear's Goldrush (USA) + cheat + description:Power-up after almost every shot + code:77cb/28/00 + +cartridge sha256:a41d3ab34e91fccdf6b4e3a203dbf606d1097b702039fdf2f252cb18c4c9f925 + name:Yoshi (USA) + cheat + description:Always get half egg pieces + code:1afc/11/1d+1afb/38/18+1af8/12/1e + cheat + description:At random intervals, 1 block comes down instead of 2 + code:13bb/7e/00 + cheat + description:When setup screen appears, go to level select, push right once to start on level 6 + code:2c70/fa/3e+2c71/b1/06+2c72/c6/22 + cheat + description:When setup screen appears, go to level select, push right once to start on level 8 + code:2c70/fa/3e+2c71/b1/08+2c72/c6/22 + cheat + description:No timer for game B + code:4c71/34/00 + +cartridge sha256:fb29a19cae1b04bf0f3e20e9f9853d62a5b3bf536c8aece32943442d5bb0a049 + name:Yoshi's Cookie (USA, Europe) + cheat + description:Move one column to clear level + code:13f8/f2/00 + +cartridge sha256:1f6a79c3a548718eea5cf530f30d67f8fd76ee9693cd2da164caef36d310a501 + name:Zen - Intergalactic Ninja (USA) + cheat + description:Infinite lives + code:196d/ea/fa + cheat + description:Infinite energy against bullets and most enemies + code:4336/ea/fa+42a4/ea/fa + cheat + description:Instant staff power-up (hold B) + code:2a3e/05/01 + cheat + description:No energy loss against fire + code:51b1/ea/fa + cheat + description:No energy loss against hang-on enemies + code:2fda/ea/fa + cheat + description:Start lives with 1/2 energy + code:7166/0a/05 + cheat + description:Start each life with 7 energy points + code:7166/0a/07 + cheat + description:Start with 1 life + code:0591/03/01 + cheat + description:Start with 5 lives + code:0591/03/05 + cheat + description:Start with 10 lives + code:0591/03/0a + diff --git a/Database/Sufami Turbo.bml b/Database/Sufami Turbo.bml new file mode 100644 index 0000000..dc5a6e6 --- /dev/null +++ b/Database/Sufami Turbo.bml @@ -0,0 +1,213 @@ +database + revision: 2020-01-01 + +//Sufami Turbo (JPN) + +database + revision: 2018-04-14 + +game + sha256: f73bda08743565e0bd101632ebbac2d363d703a3ab39d23f49d95217cab29269 + label: 美少女戦士セーラームーン セーラースターズ ふわふわパニック2 + name: Bishoujo Senshi Sailor Moon Sailor Stars - Fuwafuwa Panic 2 + region: SFT-0112-JPN + revision: SAILOR MOON + board: PT-911 + memory + type: ROM + size: 0x100000 + content: Program + note: Unlinkable + +game + sha256: afb3f2a83b5bfcb1b8829b6995f108cc4d64ca322d1ba4a50b83af6e1f2e89bd + label: クレヨンしんちゃん 長ぐつドボン!! + name: Crayon Shin-chan - Nagagutsu Dobon!! + region: SFT-0113-JPN + revision: SHINCYAN + board: PT-911 + memory + type: ROM + size: 0x80000 + content: Program + note: Unlinkable + +game + sha256: d93b3a570e7cf343f680ab0768a50b77e3577f9c555007e2de3decd6bc4765c8 + label: ゲゲゲの鬼太郎 妖怪ドンジャラ + name: Gegege no Kitarou - Youkai Donjara + region: SFT-0106-JPN + revision: KITARO DONJYAR + board: PT-911 + memory + type: ROM + size: 0x80000 + content: Program + note: Unlinkable + +game + sha256: 89aecd4e23d8219c8de3e71bb75db3dfe667d51c1eba4ea7239d2f772743d0cc + label: 激走戦隊カーレンジャ 全開!レーサー戦士 + name: Gekisou Sentai Carranger - Zenkai! Racer Senshi + region: SFT-0109-JPN + revision: CAR RANGER + board: PT-911 + memory + type: ROM + size: 0x80000 + content: Program + note: Unlinkable + +game + sha256: 602b20b788640f5743487108a10f3f77bca5ce2d24208b25b1ca498a96eb0d69 + label: ぽいぽい忍者ワールド + name: Poi Poi Ninja World + region: SFT-0103-JPN + revision: POI POI NINJYA + board: PT-911 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + note: Linkable: SFT-0103-JPN + +game + sha256: 2a9d7c9a61318861028a73ca03e32a48cff162d76cba36fbaab8690b212efe9b + label: SDガンダムジェネレーション アクシズ戦記 + name: SD Gundam Generation - Axis Senki + region: SFT-0107-JPN + revision: GUNDAM C + board: PT-912 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + note: Linkable: SFT-0104-JPN, SFT-0105-JPN, SFT-0107-JPN, SFT-0108-JPN, SFT-0110-JPN, SFT-0111-JPN + +game + sha256: 60ac017c18f534e8cf24ca7f38e22ce92db95ea6c30b2d59d76f13c4f1c8a6e4 + label: SDガンダムジェネレーション バビロニア建国戦記 + name: SD Gundam Generation - Babylonia Kenkoku Senki + region: SFT-0108-JPN + revision: GUNDAM D + board: PT-912 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + note: Linkable: SFT-0104-JPN, SFT-0105-JPN, SFT-0107-JPN, SFT-0108-JPN, SFT-0110-JPN, SFT-0111-JPN + +game + sha256: e639b5d5d722432b6809ccc6801dc584e1a3016379f34b335ed2dfa73b1ebf69 + label: SDガンダムジェネレーション コロニー格闘記 + name: SD Gundam Generation - Colony Kakutouki + region: SFT-0111-JPN + revision: GUNDAM F + board: PT-912 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + note: Linkable: SFT-0104-JPN, SFT-0105-JPN, SFT-0107-JPN, SFT-0108-JPN, SFT-0110-JPN, SFT-0111-JPN + +game + sha256: 8547a08ed11fe408eac282a90ac46654bd2e5f49bda3aec8e5edf166a0a4b9af + label: SDガンダムジェネレーション グリプス戦記 + name: SD Gundam Generation - Gryps Senki + region: SFT-0105-JPN + revision: GUNDAM B + board: PT-912 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + note: Linkable: SFT-0104-JPN, SFT-0105-JPN, SFT-0107-JPN, SFT-0108-JPN, SFT-0110-JPN, SFT-0111-JPN + +game + sha256: 3e82215bed08274874b30d461fc4a965c6bca932229da5d46d56e36f484d65eb + label: SDガンダムジェネレーション 一年戦争記 + name: SD Gundam Generation - Ichinen Sensouki + region: SFT-0104-JPN + revision: GUNDAM A + board: PT-912 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + note: Linkable: SFT-0104-JPN, SFT-0105-JPN, SFT-0107-JPN, SFT-0108-JPN, SFT-0110-JPN, SFT-0111-JPN + +game + sha256: 5951a58a91d8e397d0a237ccc2b1248e17c7312cb9cc11cbc350200a97b4e021 + label: SDガンダムジェネレーション ザンスカール戦記 + name: SD Gundam Generation - Zanscare Senki + region: SFT-0110-JPN + revision: GUNDAM E + board: PT-912 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + note: Linkable: SFT-0104-JPN, SFT-0105-JPN, SFT-0107-JPN, SFT-0108-JPN, SFT-0110-JPN, SFT-0111-JPN + +game + sha256: 2fec5f2bc7dee010af10569a3d2bc18715a79a126940800c3eade5abbd625e3f + label: SDウルトラバトル セブン伝説 + name: SD Ultra Battle - Seven Densetsu + region: SFT-0102-JPN + revision: ULTRA SEVEN 1 + board: PT-911 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + note: Linkable: SFT-0101-JPN, SFT-0102-JPN + +game + sha256: 2bb55214fb668ca603d7b944b14f105dfb10b987a8902d420fe4ae1cb69c1d4a + label: SDウルトラバトル ウルトラマン伝説 + name: SD Ultra Battle - Ultraman Densetsu + region: SFT-0101-JPN + revision: ULTRA MAN 1 + board: PT-911 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + note: Linkable: SFT-0101-JPN, SFT-0102-JPN + diff --git a/Database/Super Famicom.bml b/Database/Super Famicom.bml new file mode 100644 index 0000000..b5d5d2a --- /dev/null +++ b/Database/Super Famicom.bml @@ -0,0 +1,16069 @@ +database + revision: 2020-01-01 + +//Prototypes (JPN) + +database + revision: 2018-04-14 + +game + sha256: 182cd72c2ef57119b56bef1f7c18660498422a912f1bb652771d465cd183b04e + label: From TV Animation - Slam Dunk - 集英社Limited + name: From TV Animation - Slam Dunk - Shuueisha Limited + region: JPN + revision: 1.0 + board: SHVC-4PV5B-01 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: bcba4ca39f0279f7a52657bccbffa84564eaea455e2565597b93942ec245fdb1 + label: くにおくんのドッジボールだよ 全員集合! トーナメントスペシャル + name: Kunio-kun no Dodgeball da yo - Zen'in Shuugou! - Tournament Special + region: JPN + revision: 1.0 + board: SHVC-2P3B-01 + memory + type: ROM + size: 0x80000 + content: Program + +//Super Comboy (KOR) + +database + revision: 2018-04-14 + +game + sha256: b820ef79c16b3f43139cc9622c685020db3e87364c3a0f3946242bff93b787c8 + label: 드래곤볼Z 초무투전3 + name: Dragon Ball Z - Chomutujeon + region: SNSN-AZ4K-KOR + revision: SNS-AZ4K-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 9170aacd61bd2f936818db901451e44c18f3e88fd8d534553c2650ccad082466 + label: 한국프로야구 + name: Hanguk Pro Yagu + region: SNSN-3D-KOR + revision: SKOR-3D-0 + board: SHVC-2B3B-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + volatile + oscillator + frequency: 7600000 + +game + sha256: 1bb9ba72dfec638ed4cc7c721e31fde2f3e08d160b266a62b6e3997f711cf7cd + label: 태권도 + name: Taekwondo + region: SNSN-II-KOR + revision: SKOR-II-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +//Super Famicom (HKG) + +database + revision: 2018-04-14 + +game + sha256: bd763c1a56365c244be92e6cffefd318780a2a19eda7d5baf1c6d5bd6c1b3e06 + label: Super Mario World 2: Yoshi's Island + name: Super Mario World 2 - Yoshi's Island + region: SNSN-YI-HKG + revision: SNS-YI-1 + board: SHVC-1CB5B-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + oscillator + frequency: 21440000 + +//Super Famicom (JPN) + +database + revision: 2020-01-01 + +game + sha256: 5c4e283efc338958b8dd45ebd6daf133a9eb280420a98e2e1df358ae0242c366 + label: スパイダーマン リーサルフォーズ + name: Amazing Spider-Man, The - Lethal Foes + region: SHVC-ASPJ-JPN + revision: SHVC-ASPJ-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 6f6bacdd73aef29ff6a015c25db4a5cd8ba31142b2cc3fe56261d23bbf8329ea + label: アンジェリーク プレミアムBox + name: Angelique - Premium Box + region: SHVC-AAZJ-JPN + revision: SHVC-AAZJ-0 + board: SHVC-1J5M-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 1f7619ea0d02f16e2b2dcbb36013bb3405eb791885f23884b583eb63768614c4 + label: アンジェリーク ヴォイス・ファンタジー + name: Angelique - Voice Fantasy + region: SHVC-AQLJ-JPN + revision: SHVC-AQLJ-0 + board: SHVC-1J5M-01 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 47779500c43a0c2e75d7684078489a17baea31170a123063b8ece6ce77359413 + label: ボール・ブレット・ガン + name: Ball Bullet Gun + region: SHVC-AAGJ-JPN + revision: SHVC-AAGJ-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: a05f76cbceffc7b015491a1c4d4913758484d392471bca20af1dce6fd62d878b + label: バトルトードインバトルマニアック + name: Battletoads in Battlemaniacs + region: SHVC-8T + revision: SHVC-8T-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: af12d61733f120ef25cac2c095e0152345143025eb9d8ef820c7f857207d46ac + label: バイオメタル + name: Bio Metal + region: SHVC-BV + revision: SHVC-BV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ecd772c4a21101d079a795e47abbe00052bef69cc1c854a328f0077016c53311 + label: ボンバーマン ビーダマン + name: Bomberman B-Daman + region: SHVC-AH9J-JPN + revision: SHVC-AH9J-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 3ce321496edc5d77038de2034eb3fb354d7724afd0bc7fd0319f3eb5d57b984d + label: BS-X それは名前を盗まれた街の物語 + name: BS-X - Sore wa Namae o Nusumareta Machi no Monogatari + region: SHVC-ZBSJ-JPN + revision: SHVC-ZBSJ-1 + board: BSC-1A5B9P-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + memory + type: RAM + size: 0x80000 + content: Download + +game + sha256: 6e7dcbb4df32903d6ff5da1e308342c0a72f5af3f11479cf49391dc3a17d5d7b + label: キャプテンコマンドー + name: Captain Commando + region: SHVC-QM + revision: SHVC-QM-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 0938ff33f5bab359e383bb5499f4fcc2a488fe49747026db355c2d3d5c7c2fdb + label: クロノ・トリガー + name: Chrono Trigger + region: SHVC-ACTJ-JPN + revision: SHVC-ACTJ-0 + board: SHVC-BJ3M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0a8e5b78caf79f4710de3ccc41e2d1975cff3a6cb4146be9ed1c8767be1b0c5d + label: クロノ・トリガー 体験版サンプルROM + name: Chrono Trigger - Taikenban Sample ROM + region: SHVC-AC9J-JPN + revision: SHVC-AC9J-0 + board: SHVC-1J3M-11 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + volatile + note: No battery on PCB + +game + sha256: c195641a1b472590cb3d0be0c48d682b9fee94d7b700dd7bd3297bb995b49307 + label: Conveni Wars Barcode Battler 戦記 スーパー戦士 出撃せよ! + name: Conveni Wars - Barcode Battler Senki - Super Senshi Shutsugeki seyo! + region: SHVC-B5 + revision: SHVC-B5-0 + board: SHVC-1J3B-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 7fccf61a698b250f01b548fd20a7c133ef1c6dbb8172d3ee6c24657b60820a00 + label: であえ殿さま あっぱれ一番 + name: Deae Tonosama Appare Ichiban + region: SHVC-ADTJ-JPN + revision: SHVC-ADTJ-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 248217975279bbf9db8e74da11a906a6dd867a3ec88441b0b031ecf900466618 + label: デモンズ・ブレイゾン 魔界村紋章編 + name: Demon's Blazon - Makaimura Monshou Hen + region: SHVC-3Z + revision: SHVC-3Z-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 700e5d0a79a46d343216b822e28e6f3d0f33f68906f59b1c719735365c129553 + label: デア ラングリッサー + name: Der Langrisser + region: SHVC-ALGJ-JPN + revision: SHVC-ALGJ-1 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 38a855229eab468c3ede7573db73082c66b157adfc7af787ccac50559b747f5f + label: ダービースタリオン96 + name: Derby Stallion '96 + region: SHVC-ZDBJ-JPN + revision: SHVC-ZDBJ-0 + board: BSC-1A5M-02 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: b7209ec3a5a0d28724f5867343195aef7cb85aeb453aa84a6cbe201b61b0d083 + label: ドレミファンタジー ミロンのドキドキ大冒険 + name: DoReMi Fantasy - Milon no Dokidoki Daibouken + region: SHVC-AM4J-JPN + revision: SHVC-AM4J-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: dcb14c95f058a32f40cc329793f5d95fd6cf1755cffe02c0594d1c583a06d356 + label: エミット Vol. 1 時の迷子 + name: Emit Vol. 1 - Toki no Maigo + region: SHVC-AEMJ-JPN + revision: SHVC-AEMJ-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: dc1ecf27d9ce4fdf674c9405339016f5a812f7c4687e588cc6404e2b3b92541a + label: エミット Vol. 2 命がけの旅 + name: Emit Vol. 2 - Inochigake no Tabi + region: SHVC-AEIJ-JPN + revision: SHVC-AEIJ-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: f49417cb8759a30e12439e846f7d581afd1519c625e6a0522876666098521fcc + label: エミット Vol. 3 私にさよならを + name: Emit Vol. 3 - Watashi ni Sayonara o + region: SHVC-AETJ-JPN + revision: SHVC-AETJ-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 69d06a3f3a4f3ba769541fe94e92b42142e423e9f0924eab97865b2d826ec82d + label: Far East of Eden 天外魔境Zero 少年ジャンプの章 + name: Far East of Eden - Tengai Makyou Zero - Shounen Jump no Shou + region: SHVC-AZQJ-JPN + revision: SHVC-AZQJ-0 + board: SHVC-LDH3C-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: ROM + size: 0x400000 + content: Data + memory + type: RAM + size: 0x2000 + content: Save + memory + type: RTC + size: 0x10 + content: Time + manufacturer: Epson + identifier: RTC4513 + +game + sha256: 74aa3a26b66f34819fbbdcdb2475cf9161cc2590fb1ec89fb24940ef10e44332 + label: ファイナルファンタジーIV + name: Final Fantasy IV + region: SHVC-F4 + revision: SHVC-F4-0 + board: SHVC-1A3B-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 32125257a20c4a6495131f5df79128d189cf6dfb6d45e5314f8b0173ac6f6ebd + label: ファイナルファイト タフ + name: Final Fight Tough + region: SHVC-AFZJ-JPN + revision: SHVC-AFZJ-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 2d0e06e970ad7a1305db754a3a92b6e07e2eab848be196c8182b48dc416f1762 + label: ファイアーエムブレム トラキア776 + name: Fire Emblem - Thracia 776 + region: SHVC-BFRJ-JPN + revision: SHVC-BFRJ-0 + board: SHVC-1A5M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: db337a2e8cf6de653d092ba3489cabc658f91c63ec8a9db4e1866400aadf913f + label: ゲットインザホール + name: Get in the Hole + region: SHVC-AGHJ-JPN + revision: SHVC-AGHJ-0 + board: SHVC-2J3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: b248b2122a0caf99298ebd9a4f66ad8047dbfce1e4bbac8219ba3ea9fb7488b5 + label: ゴーストチェイサー電精 + name: Ghost Chaser Densei + region: SHVC-ET + revision: SHVC-ET-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 3a59d7d8df992e9e19c3944f1e17b8a3e9500b266412f51af306e14ff543ab45 + label: グール・パトロール + name: Ghoul Patrol + region: SHVC-AGJJ-JPN + revision: SHVC-AGJJ-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4e790991a1dc4a9df209f68895412597b4069b42971683c3a3092a160556f305 + label: ごきんじょ冒険隊 + name: Gokinjo Boukentai + region: SHVC-A3LJ-JPN + revision: SHVC-A3LJ-0 + board: SHVC-1J1M-20 + memory + type: ROM + size: 0x280000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 8d4e736e1876182a5cc6d9dcc3ca4eb36b16485bc35e2f40e750d023138ada43 + label: 美食戦隊 薔薇野郎 + name: Gourmet Sentai - Bara Yarou + region: SHVC-AV6J-JPN + revision: SHVC-AV6J-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 4a910531609abb6e0a8bab15c1c6269b608eb72cb2fbf227c0e706d0d6f6fe5b + label: ザ・グレイトバトルV + name: Great Battle V, The + region: SHVC-AG5J-JPN + revision: SHVC-AG5J-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 83a9d5c7732677838fd4812071aacf04e513e43b3a52e68bd7242db23b2ecc95 + label: 鋼 + name: Hagane + region: SHVC-AHGJ-JPN + revision: SHVC-AHGJ-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 8e0d620a307a225a757bbc9ef2a2a666792e5d533aa0279d3c0060a1b93ead82 + label: アイアンコマンドー 鋼鉄の戦士 + name: Iron Commando - Koutetsu no Senshi + region: SHVC-AICJ-JPN + revision: SHVC-AICJ-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: 4dfba33201de6b5dec952d0f327aeb44ed784c025a72c982356dd41b52efc219 + label: 糸井重里のバス釣りNo. 1 + name: Itoi Shigesato no Bass Tsuri No. 1 + region: SHVC-ZBPJ-JPN + revision: SHVC-ZBPJ-0 + board: BSC-1L3B-01 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + memory + type: RAM + size: 0x800 + content: Internal + volatile + +game + sha256: 23b320be74b9fc20de512080be3051575ba36c3246d5c4ee224f31a2fa7808f5 + label: 常勝麻雀天牌 + name: Joushou Mahjong Tenpai + region: SHVC-ZTMJ-JPN + revision: SHVC-ZTMJ-0 + board: BSC-1J3M-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: ff19a9c3f5a1ccb3ac6261886f54870ac910b0f25df9e46a436e4a621f8a0a59 + label: 化学者ハリーの波乱万丈 + name: Kagakusha Harley no Haran Banjou + region: SHVC-HV + revision: SHVC-HV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: f9ec39546e18b15b8f6a738204d0227c1542cd8157e3e0ea16934e76f39e288c + label: 迦楼羅王 + name: Karuraou + region: SHVC-OH + revision: SHVC-OH-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 1281841d3b9624e3b4cc3234f46350ce65473fba8d963b30a9f25b5385b8dd83 + label: 奇々怪界 謎の黒マント + name: Kiki Kaikai - Nazo no Kuro Manto + region: SHVC-KK + revision: SHVC-KK-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 374e411f64e4fd581a32296c90a5c74c0adf2936003077565e0672d0a91affdf + label: 奇々快界 月夜草子 + name: Kiki Kaikai - Tsukiyo Soushi + region: SHVC-3N + revision: SHVC-3N-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 1906b351d51fc0fc6d5a3cfa0fe7cb45b10d09aba256c411f5abad827bce95c6 + label: カービイのきらきらきっず + name: Kirby no Kirakira Kids + region: SHVC-BKKJ-JPN + revision: SHVC-BKKJ-0 + board: SHVC-1A1M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 0266520683f2df2179a2e6abf62754d0e8c7d82d12e59d3d3cbf7ae403a2625f + label: レナスII 封印の使徒 + name: Lennus II - Fuuin no Shito + region: SHVC-ALNJ-JPN + revision: SHVC-ALNJ-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: fe44f9d0db9f04f704764577b94e5bf2e18bc7a1c4ff1e6bdaca06d49ed6813c + label: リーサルエンフォーサーズ + name: Lethal Enforcers + region: SHVC-LK + revision: SHVC-LK-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 106c8158a10f493e0f57bd66ee3b3db36af01964bc44a48819498bf02cb1af7c + label: マジカルドロップ2 文化放送スペシャルバージョン + name: Magical Drop 2 - Bunka Housou Special Version + region: SHVC-AOQJ-JPN + revision: SHVC-AOQJ-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: ed617ad12c865fc9c9c5c75de840d3afeded57d13ca3a3062bf8e30095629414 + label: マジカルポップン + name: Magical Pop'n + region: SHVC-AIAJ-JPN + revision: SHVC-AIAJ-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 78d0f6dd9ce0813e0532c7b25c7fa0b6b945d12a4ace21aa940e98babf4dacb1 + label: 魔獣王 + name: Majuuou + region: SHVC-AOHJ-JPN + revision: SHVC-AOHJ-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: c51c5930b344f553415d54c3c964c050e1eb6355b10f5966deabb686e70e1750 + label: マリオとワリオ + name: Mario & Wario + region: SHVC-WE + revision: SHVC-WE-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e842cac1a4301be196f1e137fbd1a16866d5c913f24dbca313f4dd8bd7472f45 + label: マリオペイント + name: Mario Paint + region: SHVC-MP + revision: SHVC-MP-0 + board: SHVC-1A5B-04 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: dd314086a62e587bc6ad50c84a38a6ff9082b2d2d06dc50be5fa4c096bed5da3 + label: マイティ・モーフィン・パワーレンジャー + name: Mighty Morphin Power Rangers + region: SHVC-52 + revision: SHVC-52-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 2298d92acdfecc7270a6c9a57a6ddc55d7fa841fe9c0e7c0d64e33682fffa429 + label: ミニ四駆シャイニングスコーピオン レッツ&ゴー!! + name: Mini Yonku Shining Scorpion - Let's & Go!! + region: SHVC-A4WJ-JPN + revision: SHVC-A4WJ-0 + board: SHVC-1L5B-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + memory + type: RAM + size: 0x800 + content: Internal + volatile + +game + sha256: a5bfdaaf490d834917f7ac23ec115147b4c94bf4c18c62e18c64431d7cc79b01 + label: もと子ちゃんのワンダーキッチン + name: Motoko-chan no Wonder Kitchen + region: SHVC-WK + revision: SHVC-WK-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 97c5dcdc457fb29e6294ed93bc2a74117126c45eb399c7caf5920eca36fb63ec + label: 忍者龍剣伝巴 + name: Ninja Ryuukenden Tomoe + region: SHVC-ANRJ-JPN + revision: SHVC-ANRJ-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: c48a4ca22d001eb269fd85110fbe459034bf89f14b5b2733ee70b2d10c0687c0 + label: ザ・ニンジャウォリアーズアゲイン + name: Ninja Warriors, The - Again + region: SHVC-NI + revision: SHVC-NI-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: b41126e52ce1696da2efe524f7fd7467d76dcc3fbfa52ff6666671137587b089 + label: ノーマーク暴牌党 史上最強の雀士達 + name: Nomark Baku Haitou - Shijou Saikyou no Janshi-tachi + region: SHVC-AAPJ-JPN + revision: SHVC-AAPJ-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: d712adecbde70a74c4a580fe90a45d0d19f2641d1b4e091d507bddeec9601de1 + label: 音楽ツクールかなでーる + name: Ongaku Tsukuuru Kanadeeru + region: SHVC-ZMCJ-JPN + revision: SHVC-ZMCJ-0 + board: BSC-1J5M-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 18434c35fe5196bf699494bb5dbabda23019cfea099f4ca638437fda43133b39 + label: パチンコファン 勝利宣言 + name: Pachinko Fan - Shouri Sengen + region: SHVC-APSJ-JPN + revision: SHVC-APSJ-1 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 87e8e3f8b4fc83d2e56662c8b6844b104f6b562744c090d96cdacfcb9523af39 + label: パチンコ鉄人 七番勝負 + name: Pachinko Tetsujin - Nanaban Shoubu + region: SHVC-A77J-JPN + revision: SHVC-A77J-0 + board: SHVC-2A3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: e9a1f5cf088e060293b5566e7f518b0da89aeaebffb1c3f73fcc3f36fac036ae + label: ピットフォール マヤの大冒険 + name: Pitfall - Maya no Daibouken + region: SHVC-APAJ-JPN + revision: SHVC-APAJ-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 96af51216ee7d2978265a474e382835a88b78d12b456a57f39f944a048e95574 + label: プロック + name: Plok! + region: SHVC-P4 + revision: SHVC-P4-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e98821977389fe0ae16ec22e1f63d226698b5f869b2228885bd231a8a551c003 + label: ポコニャン! へんぽこりんアドベンチャー + name: Pokonyan! - Henpokorin Adventure + region: SHVC-APOJ-JPN + revision: SHVC-APOJ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 82a9ee11b5640409c67772363f1148517b26127cef13aa2a8ffc2480b487d81f + label: レンダリング・レンジャーR² + name: Rendering Ranger R2 + region: SHVC-AVCJ-JPN + revision: SHVC-AVCJ-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 4fc2832e7aa01d105ca67977b38840ec1188869b5e74d20e58613c1cd127d78f + label: ロックマン&フォルテ + name: Rockman & Forte + region: SHVC-AR6J-JPN + revision: SHVC-AR6J-0 + board: SHVC-1J1M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 2626625f29e451746c8762f9e313d1140457fe68b27d36ce0cbee9b5c5be9743 + label: ロックマンエックス + name: Rockman X + region: SHVC-RX + revision: SHVC-RX-0 + board: SHVC-2A0N-01#A + memory + type: ROM + size: 0x180000 + content: Program + note: Custom wiring on PCB + +game + sha256: 76f80cdf704a0e1daf1af5bbf564e427b425a5ee42329417de6f29219fe63e5f + label: ロックマンエックス + name: Rockman X + region: SHVC-RX + revision: SHVC-RX-1 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 6dfc016c571a16e5d42045060b1a88b6f3da5831e05b33c22035e1d990deccf3 + label: ロマンシング サ・ガ3 体験版サンプルROM + name: Romancing SaGa 3 - Taikenban Sample ROM + region: SHVC-AL9J-JPN + revision: SHVC-AL9J-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: d1e0d1c930011d22423cb7cde8feac445a00705da8067a4e53a735b08389a19d + label: RPGツクール2 + name: RPG Tsukuuru 2 + region: SHVC-ZR2J-JPN + revision: SHVC-ZR2J-0 + board: BSC-1A7M-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x10000 + content: Save + +game + sha256: 00e78318926e5cae79bce0535fddd3dccaa732f5c70e43acefc2769a9899eaed + label: ラッシング・ビート修羅 + name: Rushing Beat Shura + region: SHVC-R6 + revision: SHVC-R6-0 + board: SHVC-1J0N-01 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 3a709383208d8258dceb20a5e566903326515ba42931bf97fd389a415a13a72d + label: 鮫亀 + name: Same Game + region: SHVC-ZS5J-JPN + revision: SHVC-ZS5J-0 + board: BSC-1J3M-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 208f5ecb7a82b33629e67f39e96b7aa7a992cb2fcc3d1e4eb959abb0a8b7dd95 + label: SDガンダム ジーネクスト + name: SD Gundam G Next + region: SHVC-ZX3J-JPN + revision: SHVC-ZX3J-0 + board: BSC-1L5B-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + memory + type: RAM + size: 0x800 + content: Internal + volatile + +game + sha256: f1acb9fb0c73b4799b28c26d339823a8c6713106fdf1a15260e75ebb47b376f7 + label: 聖剣伝説3 体験版サンプルROM + name: Seiken Densetsu 3 - Taikenban Sample ROM + region: SHVC-A3EJ-JPN + revision: SHVC-A3EJ-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + volatile + note: No battery on PCB + +game + sha256: 601161a459e68824a24e635190e9e786dc93081803b4db66ac5a4744bb422841 + label: 少年忍者サスケ + name: Shounen Ninja Sasuke + region: SHVC-EO + revision: SHVC-EO-0 + board: SHVC-2A3M-11 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 302ba8a084081bbdd4f1f25bb473fe072b07d1514716c5a3ffd258595e9a176d + label: ソニックブラストマンII + name: Sonic Blast Man II + region: SHVC-2C + revision: SHVC-2C-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 7be858fc681df6728650f460d67fe6c80d816d5fbfc530c11153f652f8b1878e + label: サウンドノベルツクール + name: Sound Novel Tsukuuru + region: SHVC-ZSNJ-JPN + revision: SHVC-ZSNJ-0 + board: BSC-1A7M-10 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x10000 + content: Save + +game + sha256: efae37be832d0ea1490784d57bef00761a8bf0b5bcef9c23f558e063441c3876 + label: スターオーシャン + name: Star Ocean + region: SHVC-ARFJ-JPN + revision: SHVC-ARFJ-0 + board: SHVC-LN3B-01 + memory + type: ROM + size: 0x600000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: e722d20b9c264f81bbdb37d77338c5767f6b549af489486e75a648a0a65d5bfc + label: ストーンプロテクターズ + name: Stone Protectors + region: SHVC-ASOJ-JPN + revision: SHVC-ASOJ-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: f15731675e22dbf3882b777b2d8cd541a637dfdf5d8880c83903cf1e0b64590e + label: ストリートファイターZero 2 + name: Street Fighter Zero 2 + region: SHVC-AUZJ-JPN + revision: SHVC-AUZJ-0 + board: SHVC-1N0N-10 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: edacb453da14f825f05d1134d6035f4bf034e55f7cfb97c70c4ee107eabc7342 + label: スーファミターボ + name: Sufami Turbo + region: SHVC-A9PJ-JPN + revision: SHVC-A9PJ-0 + board: BANDAI-PT-923 + memory + type: ROM + size: 0x40000 + content: Program + +game + sha256: e57aa265b2fbfb7ee7f5488a3df06ae771db202d59ebbd13df8fc2db80a856f3 + label: スーパー・バック・トゥ・ザ・フューチャーII + name: Super Back to the Future - Part II + region: SHVC-B2 + revision: SHVC-B2-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 442397be57b3740ca236cfb37633b95f88a2c80dafc94b56a805229793563ce1 + label: スーパーボンバーマン2 体験版 + name: Super Bomberman 2 - Taikenban + region: SHVC-9B + revision: SHVC-9B-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5f8e6894f71c62bc5e70485715dbd2e2d8f3c0383ec54211dc5fe180098d0e3f + label: スーパーボンバーマン5 コロコロコミック + name: Super Bomberman 5 - CoroCoro Comic + region: SHVC-AK8J-JPN + revision: SHVC-AK8J-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: f73238b97807fc37911d9e94ad7b671be2746baf11200974e12aeb089b7f3c35 + label: スーパーフォーメーションサッカー95 デッラセリエA ザクア + name: Super Formation Soccer '95 - della Serie A - Xaqua + region: SHVC-ADEJ-JPN + revision: SHVC-ADEJ-0 + board: SHVC-2J3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 4d7fc331a811b8dc630b469262fd6f45e289243cef83101f32038158967d1b28 + label: スーパーゲームボーイ + name: Super Game Boy + region: SHVC-SGB + revision: SYS-SGB-2 + board: SGB-R-10 + memory + type: ROM + size: 0x40000 + content: Program + memory + type: ROM + size: 0x100 + content: Boot + manufacturer: Nintendo + architecture: SM83 + identifier: SGB1 + +game + sha256: e1db895a9da7ce992941c1238f711437a9110c2793083bb04e0b4d49b7915916 + label: スーパーゲームボーイ2 + name: Super Game Boy 2 + region: SHVC-SGB2-JPN + revision: SYS-SGB2-10 + board: SHVC-SGB2-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: ROM + size: 0x100 + content: Boot + manufacturer: Nintendo + architecture: SM83 + identifier: SGB2 + oscillator + frequency: 20971520 + +game + sha256: f56c083e54bc94efdc46c5224b3ceebc56c8ba7a0c38ee8620b0f73cd1317677 + label: スーパー麻雀大会 + name: Super Mahjong Taikai + region: SHVC-IQ + revision: SHVC-IQ-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 96c0cb3c670c36e068c36b38d1edae145f24f60159537da4988bf956eee58d59 + label: スーパー麻雀大会 + name: Super Mahjong Taikai + region: SHVC-IQ + revision: SHVC-IQ-1 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: b3204162def67b0dc40097344074e9b660ed296e5b5e22e778f373f0b985645b + label: スーパー麻雀大会 + name: Super Mahjong Taikai + region: SHVC-IQ + revision: SHVC-IQ-2 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 15d1187d17fa10c77152f691197d33674e64c33a1f8ceb37e8570588be507b89 + label: スーパー麻雀大会 + name: Super Mahjong Taikai + region: SHVC-IQ + revision: SHVC-IQ-3 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 68def3754ee32d6bce8f7e346e4d46dc2861c2c590835f8151c291c78f37b21b + label: スーパー桃太郎電鉄DX JR西日本Presents + name: Super Momotarou Dentetsu DX - JR Nishi Nihon Presents + region: SHVC-ANWJ-JPN + revision: SHVC-ANWJ-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 3972e52c1a6641842160ed70bac59c51d0d68a234deb8b2ad3b1e5daea38446e + label: す~ぱ~忍者くん + name: Super Ninja-kun + region: SHVC-8Q + revision: SHVC-8Q-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ecd462c64516169cc83dd266af354fe676fcf53811863a361d78cc918619da0d + label: スーパー三国志II 復刻版 + name: Super Sangokushi II + region: SHVC-XL + revision: SHVC-XL-1 + board: SHVC-1A5M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: fde83367c1caf6edfb41a0c609bacc90084e9808b32ba52b13d204eb59535ab5 + label: スーパースコープ6 + name: Super Scope 6 + region: SHVC-LR + revision: SHVC-LR-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8dda3b0888a32005041f2feb9be4e14807d40291f951a4612461cf41dac9cb78 + label: Super Tetris 2 + Bombliss + name: Super Tetris 2 + Bombliss + region: SHVC-T2 + revision: SHVC-T2-0 + board: SHVC-1A1B-06 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: a72b6f6722decc1c9e3f979f3d637794d3016b525822dd97f2aeba88696959aa + label: スーパータリカン + name: Super Turrican + region: SHVC-T9 + revision: SHVC-T9-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: db04fad1cfb1b8a58cb05ce62ae9e66532923699b54499344869cf8143f06098 + label: すってはっくん + name: Sutte Hakkun + region: SHVC-BSHJ-JPN + revision: SHVC-BSHJ-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x2e0000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: c9002e77bcc656e033c35e2574ee6067c4c0d070943359a850806c123a558949 + label: 戦え原始人3 主役はやっぱりジョーアンドマック + name: Tatakae Genshijin 3 - Shuyaku wa Yappari Joe & Mac + region: SHVC-J3 + revision: SHVC-J3-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b97f1bb3c7258d500660757a57c1c7e1d90a719dfcf7b3de5e8a0d06f7f8e814 + label: ティーンエージ ミュータント ニンジャ タートルズ/タートルズ イン タイム + name: Teenage Mutant Ninja Turtles - Turtles in Time + region: SHVC-TM + revision: SHVC-TM-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d844223275a9f8d428c73d5540c6e9ddd2781c53ba8a8d733bde5835ebfa4e25 + label: UFO仮面ヤキソバン ケトラーの黒い陰謀 景品版 + name: UFO Kamen Yakisoban - Kettler no Kuroi Inbou - Keihinban + region: SHVC-Y7 + revision: SHVC-Y7-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b66da2a23f249e525b1dd444596a3f10559cb3c30fa3c0bca83ed8f4405fcfcf + label: Undake 30 鮫亀大作戦 マリオバージョン + name: Undake 30 - Same Game Daisakusen - Mario Version + region: SHVC-ANZJ-JPN + revision: SHVC-ANZJ-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x60000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: cb8073cf95eace56ba4324a2106164fa540900c2de083aff490c4afe91ae95f7 + label: アンダーカバーコップス + name: Undercover Cops + region: SHVC-AUCJ-JPN + revision: SHVC-AUCJ-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 6b37c3bd79db2553bf71b79efbb131d96c40462cffac54c40dbc783f1ef44428 + label: ワイルドガンズ + name: Wild Guns + region: SHVC-4W + revision: SHVC-4W-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 491b5d20c0e00eaa7ae89e9f4cde044408258aa31042bb3ed16dff082e01a7a7 + label: レッキングクルー'98 + name: Wrecking Crew '98 + region: SHVC-BWCJ-JPN + revision: SHVC-BWCJ-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x1e0000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: c06e3c14a2f73180a7a6ff50ee76790c4542d58e8994bb3fae06412f7303d089 + label: やまねこバブジーの大冒険 + name: Yamaneko Bubsy no Daibouken + region: SHVC-UY + revision: SHVC-UY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 2b2fe61ac7a79c3cfaa0bc16f1b1f4da544fcc37cfdf3c18879d31b8b9f87941 + label: ヨッシーのクッキー クルッポンオーブンでクッキー + name: Yoshi no Cookie - Kuruppon Oven de Cookie + region: SHVC-YO + revision: SHVC-YO-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 64a124461cc12dd073191563729f559d0cf8911890ca7ede051e32024f6d9695 + label: 妖怪バスター ルカの大冒険 + name: Youkai Buster - Ruka no Daibouken + region: SHVC-AYOJ-JPN + revision: SHVC-AYOJ-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +//Super Famicom (ROC) + +database + revision: 2018-04-14 + +game + sha256: 1cf13dac329f83a7fe5347dcc20f92c3a09b3eab1511dd461f9cec90e9258403 + label: 三国志III + name: Sanguozhi III + region: SNSN-S3-ROC + revision: SCHN-S3-0 + board: SHVC-1J5M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +//Super Nintendo (AUS) + +database + revision: 2018-04-14 + +game + sha256: 7dbaebb1007984610623cb0b571f0e7167d73d89274598bfffc845cfb2de4aac + label: Lufia + name: Lufia + region: SNSP-ANIP-AUS + revision: SPAL-ANIP-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x280000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0483780080d10bae49f62c3e4bf6954f891a29c0b1356b3a073cc894784593b8 + label: Space Invaders + name: Space Invaders + region: SNSP-IC-AUS + revision: SPAL-IC-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x40000 + content: Program + +game + sha256: a1daaaaacf723ddfa4fcb406d0218a045d8f8a78674b6449a2322a0306e0af9f + label: Super Chase HQ + name: Super Chase HQ + region: SNSP-QT-AUS + revision: SPAL-QT-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +//Super Nintendo (BRA) + +database + revision: 2018-04-14 + +game + sha256: 1edcceab07d1544dcbd0fd681148b0fbefeea58b7077136fa0c3011973bf34df + label: FIFA: A Caminho da Copa '98 + name: FIFA - A Caminho da Copa '98 + region: SNS-A8FB-BRA + revision: SNS-A8FB-0 + board: EA-1A3M-30 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + note: Serial# is from ROM data; it is not present on cartridge or ROM chip + +//Super Nintendo (CAN) + +database + revision: 2018-04-14 + +game + sha256: dd499445275fca6692c0487a8bd70a23f6c8e78e766df0e3c58fbbe53f8adb06 + label: The Legend of Zelda: A Link to the Past + name: Legend of Zelda, The - A Link to the Past + region: SNS-ZF-CAN + revision: SNS-ZF-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +//Super Nintendo (ESP) + +database + revision: 2018-09-21 + +game + sha256: bd5e7a6bc08f64d39c54204b82c6c156f144c03e13c890128588c5faa560659c + label: The Addams Family: Pugsley's Scavenger Hunt + name: Addams Family, The - Pugsley's Scavenger Hunt + region: SNSP-AH-ESP + revision: SPAL-AH-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 7a75021fb390d04645b654a3dbd986c82cee1dbf34018e7ff7bf4b6ea125fa35 + label: Bram Stoker's Dracula + name: Bram Stoker's Dracula + region: SNSP-5D-ESP + revision: SPAL-5D-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6582c8f0ebec73d9dee61c1ff95b7b8e7c753a30c7bdd5dab560025dc531a43e + label: Cool World + name: Cool World + region: SNSP-CD-ESP + revision: SPAL-CD-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4a4803056afb251b06a2e9fa68d8062b6999156535bb66ff9fb069de180f32c1 + label: Jack Nicklaus Golf + name: Jack Nicklaus Golf + region: SNSP-JN-ESP + revision: SPAL-JN-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 929e15c8439b3beea249730e598e72cb192a3a70af0624ab7f91300f8f786a13 + label: Jurassic Park + name: Jurassic Park + region: SNSP-J8-ESP + revision: SESP-J8-0 + board: SHVC-2A0N-01 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: bd7e98db82d6b52307be1f3e1fd171e1e7204dc1f8810a95ee2cc64757087e4a + label: The Lost Vikings + name: Lost Vikings, The + region: SNSP-LV-ESP + revision: SESP-LV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6eecabd46305ac95d9cf3a17e1392c24a1b68a7a313173ef0c5b5a3a24cf3353 + label: Lufia + name: Lufia + region: SNSP-ANIS-ESP + revision: SPAL-ANIS-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: d70bc7916ed5132c3b0053f2adbb5004d78ccb986210c9440fedf642cac68554 + label: MechWarrior + name: MechWarrior + region: SNSP-WM-ESP + revision: SESP-WM-0 + board: SHVC-1A1M-10 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: d2233d6310522bbf183b6ca9bbe3e2afaf24de0cc4304bff6d0d547d678aed6f + label: Sonic Blast Man + name: Sonic Blast Man + region: SNSP-SK-ESP + revision: SPAL-SK-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a20d346da18ddabf70dc43f5095c4189c4a646ca8e6d4ed6c68c20e380f50332 + label: Super Battletank 2 + name: Super Battletank 2 + region: SNSP-2X-ESP + revision: SESP-2X-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 9eaf1c46d8a068c910d66f582e23b1155882ddfa4b9fd0813819fc5c008167e2 + label: Super James Pond + name: Super James Pond + region: SNSP-J5-ESP + revision: SPAL-J5-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: bd9cbb4c115716ec0f5d2d438bb812d02d496c41b7677a1d9520ff454254247b + label: Syvalion + name: Syvalion + region: SNSP-SY-ESP + revision: SPAL-SY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 7f731f4bb620e682132660da39641dda5762211dca4732f8192dd2411211b822 + label: Terranigma + name: Terranigma + region: SNSP-AQTS-ESP + revision: SPAL-AQTS-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 981128c93f0753dec7af29ec084f13e704cc5d02414be55bb477fc4b2fef5e58 + label: Tiny Toon Adventures: Buster Busts Loose! + name: Tiny Toon Adventures - Buster Busts Loose! + region: SNSP-TA-ESP + revision: SESP-TA-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ce2445ecd0a43f6025dc80857d91dae7c46d33f7821bf98232c2894ca1959da2 + label: Turn and Burn: No-Fly Zone + name: Turn and Burn - No-Fly Zone + region: SNSP-ZN-ESP + revision: SESP-ZN-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 9ed876a632aa699047e9efba8a64ab57abc55086a0aab6b5fa67d87ea4647f3f + label: Whirlo + name: Whirlo + region: SNSP-SH-ESP + revision: SPAL-SH-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ffcdce24171d9dc225a8a8b52e7d24a7832873f85135767359952537a8b9f8f1 + label: World Cup USA '94 + name: World Cup USA '94 + region: SNSP-U4-ESP + revision: SPAL-U4-0 + board: SHVC-2J3M-11 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: d897f80465d02a92f17e1eecb727b99211ec2fb9c58cbabfa76b35c554096ea6 + label: Young Merlin + name: Young Merlin + region: SNSP-Y6-ESP + revision: SPAL-Y6-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +//Super Nintendo (EUR) + +database + revision: 2018-09-21 + +game + sha256: ec3e81d628a293514e303b44e3b1ac03461ddd1da32764b10b7fab1e507602df + label: Aaahh!!! Real Monsters + name: Aaahh!!! Real Monsters + region: SNSP-ANNP-EUR + revision: SPAL-ANNP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a0baba78c9cad02957b80ed74fc8d09fac3c77e131e47333ef42ba471dc61228 + label: The Adventures of Batman & Robin + name: Adventures of Batman & Robin, The + region: SNSP-ABTP-EUR + revision: SPAL-ABTP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: e0c065aecfb6167cdb6dee8368b5f36d52fe55131ed4f6adbb3b2c62a39aafca + label: The Adventures of Mighty Max + name: Adventures of Mighty Max, The + region: SNSP-AMOP-EUR + revision: SPAL-AMOP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ffd634dbfa9ad88a81cfc59adcc889c15e03730536c171d358bf58b37c6bca6a + label: Air Cavalry + name: Air Cavalry + region: SNSP-ACCP-EUR + revision: SPAL-ACCP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 65feac0ff8bf834bdb3f1eade09102496e1bd021a261ca05fc3a75983c357c84 + label: Alien 3 + name: Alien 3 + region: SNSP-A3-EUR + revision: SPAL-A3-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 79ff74b758bb5df40d9fb6f830e9370de799c7a1423c482b2cc74eee78c55127 + label: Animaniacs + name: Animaniacs + region: SNSP-ANCP-EUR + revision: SPAL-ANCP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 41084f83e269d46b9d589f11c802a15e84fede57d604c7986053f2858f757adc + label: Archer Maclean's Super Dropzone + name: Archer Maclean's Super Dropzone + region: SNSP-ASDP-EUR + revision: SPAL-ASDP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ea4240989114fd2c6dbbf2bfcafb2047ab482ebc4aa276f30f3dc7b551197808 + label: Ardy Lightfoot + name: Ardy Lightfoot + region: SNSP-A9-EUR + revision: SPAL-A9-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f0cfaab9a4be5b2bac0cb3dafea14cea4cf8d7cbfa562323ab3026466985c9e1 + label: Bass Masters Classic: Pro Edition + name: Bass Masters Classic - Pro Edition + region: SNSP-A9BP-EUR + revision: SPAL-A9BP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a10f7406d76a85e27ae340ed2dd2379897321ed388b439e247b3437fa07806cb + label: Batman Forever + name: Batman Forever + region: SNSP-A3BP-EUR + revision: SPAL-A3BP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 4d347d60795008852ec11bc8e0256a3d1f159bf48c130b9798cb2961e560f319 + label: Beavis and Butt-Head + name: Beavis and Butt-Head + region: SNSP-ABUP-EUR + revision: SPAL-ABUP-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: a73c8864743dd64a61d756ebe001a1244d6ae387621a46f9da4421d061c6b7ac + label: Boogerman: A Pick and Flick Adventure + name: Boogerman - A Pick and Flick Adventure + region: SNSP-AB4P-EUR + revision: SPAL-AB4P-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 597894334926c326e332ecdea0d4ad61430ab6af03830a9beeb2c007c280c843 + label: Breath of Fire II + name: Breath of Fire II + region: SNSP-AF2P-EUR + revision: SPAL-AF2P-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: a057383e41bd5735b1c554c555b89fe0ff9b7eb7e9f9d46dbefbdd749c8d2181 + label: Brutal: Paws of Fury + name: Brutal - Paws of Fury + region: SNSP-ABLP-EUR + revision: SPAL-ABLP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: be86b8b9c390f1a85384117ce19170567e1234ddb08b538e1361af2feee63869 + label: Bubsy II + name: Bubsy II + region: SNSP-ABBP-EUR + revision: SPAL-ABBP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 3545306505c463c627bc4ced91ff4413481c945a658860ddc1f6e8e7b4cc6144 + label: Cannon Fodder + name: Cannon Fodder + region: SNSP-ACNP-EUR + revision: SPAL-ACNP-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 04a347e7d600c8aff435e769f72273ac1ae8160838905f325f03ef4c5aa93bbe + label: Captain Commando + name: Captain Commando + region: SNSP-QM-EUR + revision: SPAL-QM-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 0f37da5beb0beb5e8f8c34443bf0734575649f8222074e3394926c3b697589cc + label: Carrier Aces + name: Carrier Aces + region: SNSP-ACAP-EUR + revision: SPAL-ACAP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: ca99787148aac7053ae9d1a1b06c8a5f42f2bfdd70c2942282a9dd0c1c0fda4f + label: Castlevania: Vampire's Kiss + name: Castlevania - Vampire's Kiss + region: SNSP-ADZP-EUR + revision: SPAL-ADZP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: e1e2cc6b7ef58b512bb8aa6848dd67fce9e5d092ea67e6b4f31f156b060cc2b1 + label: Clay Fighter 2: Judgment Clay + name: Clay Fighter 2 - Judgment Clay + region: SNSP-ACZP-EUR + revision: SPAL-ACZP-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: b9d6cf21e7a280b83fadcf513029158be6f4dcdc51f73b699b7c215a5150be42 + label: CutThroat Island + name: CutThroat Island + region: SNSP-AC8P-EUR + revision: SPAL-AC8P-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 3a158e49478bd9a25b487a347c25f401cd0ed1cd1ccf72d8010752139a2143dc + label: Demolition Man + name: Demolition Man + region: SNSP-AD6P-EUR + revision: SPAL-AD6P-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: f6afe40ced7033c845df84b895230fd26ea0b48e6a58d6b6e18beee9b594ad6e + label: Demon's Crest + name: Demon's Crest + region: SNSP-3Z-EUR + revision: SPAL-3Z-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a2dc5ffc82e8d055d030c3f021d8df3ae8b08571c8301cdd1d7652248d6f9b55 + label: Dino Dini's Soccer + name: Dino Dini's Soccer + region: SNSP-ADSP-EUR + revision: SPAL-ADSP-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 574c61ab1a670a79b8dc69445b8f55aa5b4caa95ed0e1504fae8a1e3d336e7f1 + label: Donkey Kong Country 3: Dixie Kong's Double Trouble + name: Donkey Kong Country 3 - Dixie Kong's Double Trouble + region: SNSP-A3CP-EUR + revision: SPAL-A3CP-0 + board: SHVC-1J1M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 753467f4e343a563a1e4f5da43b731968a47cf3fc035f98575134e680a596f27 + label: Dragon: The Bruce Lee Story + name: Dragon - The Bruce Lee Story + region: SNSP-4N-EUR + revision: SPAL-4N-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 89dddd495d29db4542d45bf4a89d387bf2465eb8d2bd5b300c5397d8b24dc4af + label: Dragon Ball Z: Hyper Dimension + name: Dragon Ball Z - Hyper Dimension + region: SNSP-AZIF-EUR + revision: SPAL-AZIF-0 + board: SNSP-1L0N3S-01 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + volatile + memory + type: RAM + size: 0x800 + content: Internal + volatile + +game + sha256: 4a96f3c0a7694a1d8235e2bf03b583ed2e99488d1dc0e26691db003fd23191f7 + label: Earthworm Jim + name: Earthworm Jim + region: SNSP-AEJP-EUR + revision: SPAL-AEJP-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: df2b34467581f8ffdad24f59119d54a03875f355d33ab552459b60f8f0de3e78 + label: Earthworm Jim 2 + name: Earthworm Jim 2 + region: SNSP-A2EP-EUR + revision: SPAL-A2EP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: f4cabd80dd20b076ff90bf1f394b5dff5800900fa1fe178a42b6af967fd80c25 + label: Fatal Fury 2 + name: Fatal Fury 2 + region: SNSP-DJ-EUR + revision: SPAL-DJ-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: a12391775fa9770f85f383ffaec6441a686c33b2e1800de7c01a79a0b7c93154 + label: Fatal Fury Special + name: Fatal Fury Special + region: SNSP-3R-EUR + revision: SPAL-3R-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 20af141280d75c29a0981c6a4decfa1835c3613a47636a4ae0967948a7878f7c + label: Fever Pitch Soccer + name: Fever Pitch Soccer + region: SNSP-AVSP-EUR + revision: SPAL-AVSP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: ea769b616ad5d6f7b0a5e42951c31096191800347dc9fd6c8c9845f2afa95f5b + label: FIFA '97 + name: FIFA '97 + region: SNSP-A7IP-EUR + revision: SPAL-A7IP-0 + board: EA-1A3M-30 + memory + type: ROM + size: 0x1e0000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 14e8f7963bd71a3d8792952ae0c0def733178ac720417b954ea5cb12cc76dece + label: Final Fight 3 + name: Final Fight 3 + region: SNSP-AFZP-EUR + revision: SPAL-AFZP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: a0106f9cff7abbf25e081e2531f6d4b4aedf6f0dc8d155a66506817bff267d12 + label: The Firemen + name: Firemen, The + region: SNSP-AFMP-EUR + revision: SPAL-AFMP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 21d79cd5382ad5503fdee1c44416a7a425904cebe37bb531d508ef62aa4f2ed0 + label: Frank Thomas' Big Hurt Baseball + name: Frank Thomas' Big Hurt Baseball + region: SNSP-AFKP-EUR + revision: SPAL-AFKP-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 6a6a95528e4c8cfdf46cade2a354f3e28f63b55bba002e10af0f60227ec4c833 + label: Frantic Flea + name: Frantic Flea + region: SNSP-AF8P-EUR + revision: SPAL-AF8P-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 0d7a1649915d45b4c6e0752ea06ad353c2b1a590370912c18deeb42986821624 + label: Ghoul Patrol + name: Ghoul Patrol + region: SNSP-AGJP-EUR + revision: SPAL-AGJP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ee4ab0df49db4024b5da62d04c18c8c866830b54d286dec69440af7285ec2854 + label: Hagane + name: Hagane + region: SNSP-AHGP-EUR + revision: SPAL-AHGP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: d98487781da9307309eec8830c6a28c907b0f1848e351df7f5b6d005c653b4ac + label: Hurricanes + name: Hurricanes + region: SNSP-AHUP-EUR + revision: SPAL-AHUP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 21e8632a6da085cae5d4bcf7334c63fbda0028c2a37c0b0c3041ab59f307ebd3 + label: Incantation + name: Incantation + region: SNSP-AIYP-EUR + revision: SPAL-AIYP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 09d937a73595df67c473f1a4beba2f302570c1434d8093051d027ec1e440b984 + label: Indiana Jones' Greatest Adventures + name: Indiana Jones' Greatest Adventures + region: SNSP-AIJP-EUR + revision: SPAL-AIJP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 6fe482f91a59a71992e14014a0a4e23fb866cf4e870c10d57c81b0c20ae6688e + label: International Superstar Soccer + name: International Superstar Soccer + region: SNSP-3U-EUR + revision: SPAL-3U-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 686f2507e9969fd7617fc544c139e124668294d102e79a0eb34478c8deb75271 + label: Izzy's Quest for the Olympic Rings + name: Izzy's Quest for the Olympic Rings + region: SNSP-AIZP-EUR + revision: SPAL-AIZP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 02cb423199be3368fc2b40148f83b7a48900394983e04d43f94bb7d76ce44e94 + label: Judge Dredd + name: Judge Dredd + region: SNSP-AJDP-EUR + revision: SPAL-AJDP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 2516843fa405ab1aa1f242b57f19977519aefb68599474d2c7065aaef88ecb88 + label: Jungle Strike + name: Jungle Strike + region: SNSP-AJGP-EUR + revision: SPAL-AJGP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 9b1dbcac063b524eef533e78cf7051e3f566a49d5ac13d23474dc6afb293d6be + label: Jurassic Park Part 2: The Chaos Continues + name: Jurassic Park Part 2 - The Chaos Continues + region: SNSP-A2JP-EUR + revision: SPAL-A2JP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 07386ef7dfcc70a67beb01fa7e2300249914b2ce0b010a74cbfbf0714c32fcf1 + label: Justice League Task Force + name: Justice League Task Force + region: SNSP-AJLP-EUR + revision: SPAL-AJLP-0 + board: SHVC-BA0N-01 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: 51364bc86ba8f00f0eeb2dcd59c68b42f94595af5ce272e914dedb5fc4ffa191 + label: Lemmings 2: The Tribes + name: Lemmings 2 - The Tribes + region: SNSP-L2-EUR + revision: SPAL-L2-0 + board: SHVC-1A1M-11 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: bf0d2739c2bd1aeba9cc979928e0702341cb290023dbc39bd25f18c1412fe674 + label: Marko's Magic Football + name: Marko's Magic Football + region: SNSP-AMRP-EUR + revision: SPAL-AMRP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 4f83fc7c1fa4fae99568ae8e049a45e6e65176761fe3ac74315bee8eff846fd4 + label: Marvel Super Heroes in War of the Gems + name: Marvel Super Heroes in War of the Gems + region: SNSP-AHZP-EUR + revision: SPAL-AHZP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 9da7274457995b39ae7b00387c1eaab92f1fdb0beac55372726c3a3af1cb8f7e + label: MechWarrior 3050 + name: MechWarrior 3050 + region: SNSP-A35P-EUR + revision: SPAL-A35P-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 81f90a36c07221546c441d67689d951864f071f3218aa96994c0c54e93998a67 + label: Mega Man 7 + name: Mega Man 7 + region: SNSP-A7RP-EUR + revision: SPAL-A7RP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: ae6fb12b5077eaa9c13c6124368343bfef076bc1e42f53f442973576266255c4 + label: Mega Man X2 + name: Mega Man X2 + region: SNSP-ARXP-EUR + revision: SPAL-ARXP-0 + board: SHVC-2DC0N-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: ROM + size: 0xc00 + content: Data + manufacturer: Hitachi + architecture: HG51BS169 + identifier: Cx4 + memory + type: RAM + size: 0xc00 + content: Data + manufacturer: Hitachi + architecture: HG51BS169 + identifier: Cx4 + volatile + oscillator + frequency: 20000000 + +game + sha256: 14cd1e5d7a810426c566c1c4eff16398cace6e7a4c0d7f048fdb1f4c22c1c135 + label: Mega Man X3 + name: Mega Man X3 + region: SNSP-AR3P-EUR + revision: SPAL-AR3P-0 + board: SHVC-1DC0N-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: ROM + size: 0xc00 + content: Data + manufacturer: Hitachi + architecture: HG51BS169 + identifier: Cx4 + memory + type: RAM + size: 0xc00 + content: Data + manufacturer: Hitachi + architecture: HG51BS169 + identifier: Cx4 + volatile + oscillator + frequency: 20000000 + +game + sha256: 02a85c9e783add4e3d44f8f4718c014743f252585fedd9ae5583458237122b35 + label: Mohawk & Headphone Jack + name: Mohawk & Headphone Jack + region: SNSP-AJYP-EUR + revision: SPAL-AJYP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: b7fa4b79590ecdef2d0303b5cbccf1e1a3af31fca289652acbdb3d5381137f24 + label: Mortal Kombat 3 + name: Mortal Kombat 3 + region: SNSP-A3MP-EUR + revision: SPAL-A3MP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 964f8391806bc8d674f24aa2f201b20982d2f2f3e3efb2f730c4a34a289c3007 + label: Mortal Kombat II + name: Mortal Kombat II + region: SNSP-28-EUR + revision: SPAL-28-1 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: bfec7d5afdf0d41cfce7f4e73dc20d91981db0edc2a0f41c5737d861efd4ab2a + label: Mr. Do! + name: Mr. Do! + region: SNSP-AUNP-EUR + revision: SPAL-AUNP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x40000 + content: Program + +game + sha256: 65377b1f6dbf1b3258c0554fe54ab0fbe59d6c3f07d3cad1c69ff692e0872b9a + label: NBA Jam: Tournament Edition + name: NBA Jam - Tournament Edition + region: SNSP-AJTP-EUR + revision: SPAL-AJTP-0 + board: SHVC-BA1M-01 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: aa3f0608fa8723a21a4a5121f04098c53a76b5188f4dc30fcc26db9232c734d8 + label: NHL '96 + name: NHL '96 + region: SNSP-A6HP-EUR + revision: SPAL-A6HP-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 25d04bba3f3b12c63ae7ee4450e1d924df7aff077515d634721e22e6420c09b9 + label: Ninja Warriors: The New Generation + name: Ninja Warriors - The New Generation + region: SNSP-NI-EUR + revision: SPAL-NI-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: d9860f4f9b5e71290c5419b88c49b545f947a35cfe0549c2f32e54f05bc55815 + label: Olympic Summer Games + name: Olympic Summer Games + region: SNSP-AO9P-EUR + revision: SPAL-AO9P-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 2ec71aca4efc3791b6b3e65956df3eafd2a46e223d5ea71aead07d30ca48b6c9 + label: Operation Starfi5h + name: Operation Starfi5h + region: SNSP-AOSP-EUR + revision: SPAL-AOSP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 908b1b18403a1330e1af5844f8c9d11a66279ff107cf14b56e6be849fbd4a7f9 + label: Phantom 2040 + name: Phantom 2040 + region: SNSP-A24P-EUR + revision: SPAL-A24P-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 166fe888ac03f88cce5759c1008021082bd81254aab8fea8203cdb13080709d7 + label: Pinball Fantasies + name: Pinball Fantasies + region: SNSP-APFP-EUR + revision: SPAL-APFP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 1744a87d4817be07948e1b37b59c4de49c85e6aec2cf49879c7b9649d1b1fc90 + label: Primal Rage + name: Primal Rage + region: SNSP-AR9P-EUR + revision: SPAL-AR9P-0 + board: SHVC-BJ0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 00e2c72fd82d78c5bb6f144101df6145d0a7f68dd77632f49969f13c5623c59a + label: Realm + name: Realm + region: SNSP-ARQP-EUR + revision: SPAL-ARQP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 862a53905b9e2ed33bae8e01e755ab6ca9fe2f181567510cb0840ed9a19f20d8 + label: Rise of the Robots + name: Rise of the Robots + region: SNSP-AROP-EUR + revision: SPAL-AROP-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 2d5e3091ce4912e2325dedf99b439c5b4cb6ba6899e25bf8957b19eda942de88 + label: RoboCop vs. The Terminator + name: RoboCop vs. The Terminator + region: SNSP-VR-EUR + revision: SPAL-VR-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 09fdef0c959e7275563f65d8267d95a20104f054e9438e9ac739ef7f46120a2d + label: Smash Tennis + name: Smash Tennis + region: SNSP-JA-EUR + revision: SPAL-JA-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 9638d4daa7bc63fd178b77c4487c3b080def5b808c0b7ccc959101f33e221b42 + label: Spider-Man & Venom: Maximum Carnage + name: Spider-Man & Venom - Maximum Carnage + region: SNSP-AMCP-EUR + revision: SPAL-AMCP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 4001418ceb26f38efbea10b7bcc8233adc7bfcaa7e11dfb401d820f3254f06ef + label: Street Fighter Alpha 2 + name: Street Fighter Alpha 2 + region: SNSP-AUZP-EUR + revision: SPAL-AUZP-0 + board: SNSP-1N0N-01 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 4ef0053b294be64353df47e4f7d079cb97044e18263b55d46b6e4f9adda55766 + label: Super B.C. Kid + name: Super BC Kid + region: SNSP-ZH-EUR + revision: SPAL-ZH-0 + board: SHVC-2J0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 640acb63dae038ad6f0ae65e103416f5a1f84d4a37ddaeeab5046122def774d5 + label: Super Metroid + name: Super Metroid + region: SNSP-RI-EUR + revision: SPAL-RI-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 148f6bbf0578ff6ec62e6dacb9e3d266f6d7a427baa104e8ecd3cb2df64bca14 + label: Super Soccer + name: Super Soccer + region: SNSP-FS-EUR + revision: SPAL-FS-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 92946358ee4fbc5cb1df81a26ebd323c2f4e8cc76acd038e1191b8aa31ad1c24 + label: Super Star Wars III: Return of the Jedi + name: Super Star Wars III - Return of the Jedi + region: SNSP-ARJP-EUR + revision: SPAL-ARJP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a52b98da8f65bf2210b7d2e931548c672838fa7e44d852f2e3c6f3cd2ba950d6 + label: Super Street Fighter II: The New Challengers + name: Super Street Fighter II - The New Challengers + region: SNSP-XW-EUR + revision: SPAL-XW-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 299984b4148ee4503d67cba8469c5023f7ecb204949bc70c3271cc56b117bb8e + label: Super Tennis + name: Super Tennis + region: SNSP-ST-EUR + revision: SPAL-ST-1 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 93ba50d853e98e1ca227a2ca72389c0e3ac18d6b50c946b3f618c16c2d3edd38 + label: Terranigma + name: Terranigma + region: SNSP-AQTP-EUR + revision: SPAL-AQTP-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 41648e6d73bd1b998f5c0737a4e61cd603e574ce4a3439e579d2b74b14390159 + label: Tiny Toon Adventures: Wild & Wacky Sports + name: Tiny Toon Adventures - Wild & Wacky Sports + region: SNSP-5Z-EUR + revision: SPAL-5Z-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4ad736a9e1c7f34740afaa7777b8f1a31da4bb4a021e7ae341d1dafd74fa0acc + label: True Lies + name: True Lies + region: SNSP-ATLP-EUR + revision: SPAL-ATLP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: dbf11d4c77b9aa3416f687201d57d71a23bb8fb0b8fe5e9e8212db3fac036631 + label: Turbo Toons + name: Turbo Toons + region: SNSP-ATTP-EUR + revision: SPAL-ATTP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 03540084486c21724819515d1cb967c658f7f08ec180855fa7c191ca13d8bef1 + label: Ultimate Mortal Kombat 3 + name: Ultimate Mortal Kombat 3 + region: SNSP-A3ZP-EUR + revision: SPAL-A3ZP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: fc8c611bc46c850515a933d4388e2123e20ab24a3a3d3c1ac95afdc76c82c3d4 + label: Urban Strike + name: Urban Strike + region: SNSP-AUSP-EUR + revision: SPAL-AUSP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 1217ddf2fe475661a54f50e111864102faf854397ce5aceea4297204ebd6cbb6 + label: Val d'isère Championship + name: Val d'isere Championship + region: SNSP-8Z-EUR + revision: SPAL-8Z-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 150073c04e9c0e8b283a8eb237acea8fda3268c722f922ee42642009e17dc729 + label: Vortex + name: Vortex + region: SNSP-4V-EUR + revision: SPAL-4V-0 + board: SHVC-1CA0N5S-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + volatile + oscillator + frequency: 21440000 + +game + sha256: f47f1665d97d350dda8bf968543ed38b1daf63081d6f71e517867a5533ce4776 + label: Wild Guns + name: Wild Guns + region: SNSP-4W-EUR + revision: SPAL-4W-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: aceb9ac7cfd68e6740de47ad1a19be70d4efe3974caa4aa8ec50b0a0a6672e47 + label: Winter Gold + name: Winter Gold + region: SNSP-AXSP-EUR + revision: SPAL-AXSP-0 + board: SHVC-1CB7B-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x10000 + content: Save + oscillator + frequency: 21440000 + +game + sha256: 142b9b3f99811c2314a94d2c4b66aa9d434f5bdc9ccbb1574e3a6cbf2176b378 + label: X-Kaliber 2097 + name: X-Kaliber 2097 + region: SNSP-X7-EUR + revision: SPAL-X7-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +//Super Nintendo (FAH) + +database + revision: 2018-09-21 + +game + sha256: 0aafd04a43ae29266e43920a7f9954d4a49f6fe43a5abffecc9c2fd5ad7d6cea + label: Aero the Acro-Bat 2 + name: Aero the Acro-Bat 2 + region: SNSP-AE2P-FAH + revision: SPAL-AE2P-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a4b1e125b421c5a58e2fd73edc4d58b31d7a596c07dee263c565f00ee712223f + label: Alfred Chicken + name: Alfred Chicken + region: SNSP-8A-FAH + revision: SPAL-8A-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d54d2703e474d7f469766d2d095ffcbbcab893e3fe58bbbcc57e24082a44bb40 + label: Astérix + name: Asterix + region: SNSP-XE-FAH + revision: SPAL-XE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: d9127808fb02c47dd74fd22f39582c69f19936a794a8efc153cc0e51a0d4d782 + label: Astérix & Obelix + name: Asterix & Obelix + region: SNSP-AXOP-FAH + revision: SPAL-AXOP-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: e6adeeee287204b06300b790fe048358f54e322306806142fb4e667ae8b57378 + label: Le Cobaye + name: Cobaye, Le + region: SNSP-LW-FAH + revision: SPAL-LW-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: dde314fea056445685b97f9c8b554d2be81ea1fe6ace935934592464908d05fb + label: Donkey Kong Country + name: Donkey Kong Country + region: SNSP-8X-FAH + revision: SPAL-8X-0 + board: SHVC-BJ1M-10 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 259537561fc1a0ddf0beacf9169ccb5fbe8ad88a322c07fccb862a39b379ae62 + label: Donkey Kong Country 2: Diddy's Kong Quest + name: Donkey Kong Country 2 - Diddy's Kong Quest + region: SNSP-ADNP-FAH + revision: SPAL-ADNP-1 + board: SHVC-1J1M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 826a328f401cdf5a9ee87aaa7a2784cbb21813b165a6c7ca3f702fe6ba8c0804 + label: Eric Cantona: Football Challenge + name: Eric Cantona - Football Challenge + region: SNSP-EC-FAH + revision: SPAL-EC-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: ce09743d44a54f64862d8c53c11c2c84f2f861ec74c778bd8b05b0a3b07708d6 + label: FIFA International Soccer + name: FIFA International Soccer + region: SNSP-84-FAH + revision: SPAL-84-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5a181f25055298579d24571b4f1cd21dd81583fb41a235fc4f226fa28d9df916 + label: Jack Nicklaus Golf + name: Jack Nicklaus Golf + region: SNSP-JN-FAH + revision: SFRA-JN-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 9b52a2848b78aa7ecb7cac295bce7ae033089af6099e127c2c904f518c6d4b89 + label: The Lost Vikings + name: Lost Vikings, The + region: SNSP-LV-FAH + revision: SFRA-LV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8510491f99400115ccf33570269bc4e484fb56370f7ac36f12e73eec19d342da + label: Lucky Luke + name: Lucky Luke + region: SNSP-ALYP-FAH + revision: SPAL-ALYP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 1c41bb11c9df5aa8a6ca98caa5215418f37025f7a5e88ff62188b257338af3ab + label: Mega Man X + name: Mega Man X + region: SNSP-RX-FAH + revision: SPAL-RX-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: a6772914f3d0c2fda5bfde855a41f211c89d9452b7bd437b41d69b46727ed6e8 + label: Nintendo Scope 6 + name: Nintendo Scope 6 + region: SNSP-LR-FAH + revision: SPAL-LR-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 558b437e10915c2ca79f376634fa4623c87efdb9292a5878b886c7a6fbef61e2 + label: Parodius + name: Parodius + region: SNSP-PD-FAH + revision: SPAL-PD-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 034850392507ec2ea7219970a8be7ad4a4418a11eccbda9df7a5bbf4c74f0287 + label: Plok + name: Plok + region: SNSP-P4-FAH + revision: SFRA-P4-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 3a30a6aff66e1ab44b7f742eafde45710cd5a7165681649470c3f04afa579927 + label: R-Type III: The Third Lightning + name: R-Type III - The Third Lightning + region: SNSP-ER-FAH + revision: SPAL-ER-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 553940ad4b0bbcf375cf2a06f092b44fcd880db820828c8c900c4cd9d4f5753f + label: Starwing + name: Starwing + region: SNSP-FO-FAH + revision: SPAL-FO-0 + board: SNSP-1C0N5S-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + volatile + +game + sha256: 35c1d6623748f66e254843cf340121e3e268a8301951f35c7ba3ef666bc293bf + label: Street Fighter II: The World Warrior + name: Street Fighter II - The World Warrior + region: SNSP-S2-FAH + revision: SPAL-S2-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 54ac1f0c99f1521e4c390f43af5da2138ec0526a97912790bdb53f9ab1b10b63 + label: Street Fighter II Turbo: Hyper Fighting + name: Street Fighter II Turbo - Hyper Fighting + region: SNSP-TI-FAH + revision: SPAL-TI-1 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: abe8db202f9bd12d845a4c7ecb97d85fb149d7f17a608b3eae015d92f52f2c04 + label: Stunt Race FX + name: Stunt Race FX + region: SNSP-CQ-FAH + revision: SPAL-CQ-0 + board: SHVC-1CA6B-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x10000 + content: Save + oscillator + frequency: 21440000 + +game + sha256: 2b097fb72be6aff2030a488df87a349667eb204c2281fb0a2bb7eeafca33d5ed + label: Super Hockey + name: Super Hockey + region: SNSP-NH-FAH + revision: SFRA-NH-0 + board: SHVC-1A1M-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 9760fb407282d91005044fb08f9c15dc3e0ae65063a02eedfbbd285566501fd0 + label: Super Mario All-Stars + name: Super Mario All-Stars + region: SNSP-4M-FAH + revision: SPAL-4M-0 + board: SHVC-1A3B-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 12d04359329bd646fc65c62db6121b4a7e4ece68556d68252e81ced421069f4c + label: Super Mario Kart + name: Super Mario Kart + region: SNSP-MK-FAH + revision: SPAL-MK-0 + board: SHVC-1K1B-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + volatile + oscillator + frequency: 7600000 + +game + sha256: 5cc54b1e5c8d3c7701a5e20514145c3b36f15f26fe0a4fe6d2e43677e4b4eda9 + label: Super Mario World + name: Super Mario World + region: SNSP-MW-FAH + revision: SPAL-MW-1 + board: SHVC-1A1B-06 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 824f07e93c9ad38fe408af561e8979e3c0211f0c6c98aeb6e6bc85cd6f9edc91 + label: Super Mario World 2: Yoshi's Island + name: Super Mario World 2 - Yoshi's Island + region: SNSP-YI-FAH + revision: SPAL-YI-1 + board: SHVC-1CB5B-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + oscillator + frequency: 21440000 + +game + sha256: 640acb63dae038ad6f0ae65e103416f5a1f84d4a37ddaeeab5046122def774d5 + label: Super Metroid + name: Super Metroid + region: SNSP-RI-FAH + revision: SPAL-RI-0 + board: SHVC-BA3M-10 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 71de4dec6a8e8be685627b6e929317f7cefb836997059bbd3b438ccc07a60044 + label: Tintin: Le Temple du Soleil + name: Tintin - Le Temple du Soleil + region: SNSP-A2VP-FAH + revision: SPAL-A2VP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: da8b8bccebf51b70213adecda37387d1bdb55aeb7bc0805bb1be1cd9b514daf6 + label: Tintin au Tibet + name: Tintin au Tibet + region: SNSP-AT6P-FAH + revision: SPAL-AT6P-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 5a9103b04b9246f63af9018cbbd7934c6b79076dd9b0062887bd16077cd37c81 + label: Val d'Isère Championship + name: Val d'Isere Championship + region: SNSP-8V-FAH + revision: SPAL-8V-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +//Super Nintendo (FRA) + +database + revision: 2018-09-21 + +game + sha256: 65df600780021f13ced52e7fbc507b7b2e6491b2c5c25fe78d0515dcbe669403 + label: Aladdin + name: Aladdin + region: SNSP-RJ-FRA + revision: SFRA-RJ-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: 7baaa65ced8fed14e161615e1fffff971f10be4b723523b4a7302891db02ba09 + label: Blanco World Class Rugby + name: Blanco World Class Rugby + region: SNSP-WY-FRA + revision: SFRA-WY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: dd920a8f29dde8712a246a56d28ac0825d15c041d7f77f97dbeb37680751ce68 + label: Dragon Ball Z: La Légende Saien + name: Dragon Ball Z - La Legende Saien + region: SNSP-EF-FRA + revision: SFRA-EF-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: e135511707c68c16d07b656f63e2b9dc42f436a37b0c85a949fc9e75e1111b34 + label: Dragon Ball Z: Super Butouden + name: Dragon Ball Z - Super Butouden + region: SNSP-Z2-FRA + revision: SFRA-Z2-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 663116d015cad3398644608ca6f2506071ab23d38b03b4890e1a6caecb1a55aa + label: Dragon Ball Z: Ultime Menace + name: Dragon Ball Z - Ultime Menace + region: SNSP-AZ4F-FRA + revision: SPAL-AZ4F-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a97a5ffdef892d7574e5cb807ec657059fd65490186feae975079cd11baa2df7 + label: Goof Troop + name: Goof Troop + region: SNSP-G6-FRA + revision: SFRA-G6-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: b2a44f5bb49f6a033e5c82f05356246f5918cacf6f026b88cab5a0b410659b01 + label: Illusion of Time + name: Illusion of Time + region: SNSP-JG-FRA + revision: SFRA-JG-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 8dc982c6dd0dfd094b74e4af94a2b10ddc51d334f7f0fa77a9f70917fa324e84 + label: Jimmy Connors Pro Tennis Tour + name: Jimmy Connors Pro Tennis Tour + region: SNSP-JC-FRA + revision: SFRA-JC-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 7ba2709cffa654f73b3b1364c13d6a5b595b820629102fe3d51c10bca30d0e4e + label: Jurassic Park + name: Jurassic Park + region: SNSP-J8-FRA + revision: SFRA-J8-0 + board: SHVC-2A0N-01 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 29a0d5812ccbb4b11bdb55d8f751a2a797b4110bf402ca8ba15eb2bf85db7b39 + label: The Legend of Zelda: A Link to the Past + name: Legend of Zelda, The - A Link to the Past + region: SNSP-ZL-FRA + revision: SFRA-ZL-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 6d37b2ed794b2f3e5f3d28490ffe89a0ff3c8a0cfc0418bd2aa8e0c66d4868ff + label: Le Livre de la Jungle + name: Livre de la Jungle, Le + region: SNSP-7K-FRA + revision: SPAL-7K-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 18f5666860c36fabebc909d262e234bb0bf51a87b55945c134118a4c36b49b52 + label: Mario is Missing! + name: Mario is Missing! + region: SNSP-MU-FRA + revision: SFRA-MU-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 600df7da79c95e14c1b9e6e54e0b3a061d079831d015ef6f31bc3772c1d0efc6 + label: MechWarrior + name: MechWarrior + region: SNSP-WM-FRA + revision: SFRA-WM-0 + board: SHVC-1A1M-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 1432590492b63d7103caa715e10e3c3ebbc77b63b6472ee9dee0e5afda311551 + label: Mystic Quest Legend + name: Mystic Quest Legend + region: SNSP-MQ-FRA + revision: SFRA-MQ-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: a4621118ef174d2c8a9ffe934e31ff3a00f66a3aaa13340983eec43625a773f6 + label: Pac-Man 2: The New Adventures + name: Pac-Man 2 - The New Adventures + region: SNSP-25-FRA + revision: SFRA-25-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: febcb3325240293cc82b4038630b89bbd936f092cb172107eb82452a5555859e + label: Ranma ½ + name: Ranma Half + region: SNSP-R2-FRA + revision: SFRA-R2-0 + board: SHVC-2J0N-01 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 896e09a0d24bfec0412aa75d121063b015153a754ed542f7db7d66366b555de4 + label: Le Roi Lion + name: Roi Lion, Le + region: SNSP-ALKP-FRA + revision: SPAL-ALKP-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 0aa16d6b588ba05ab00936201e68a694746fc5e1b2e4f2dbf7cda09265a81379 + label: Sailor Moon + name: Sailor Moon + region: SNSP-AE-FRA + revision: SFRA-AE-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: b730adcbb34a19f8fd1c2abe27455cc3256329a9b8a021291e3009ea33004127 + label: Secret of Mana + name: Secret of Mana + region: SNSP-K2-FRA + revision: SFRA-K2-1 + board: SHVC-1J3M-11 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: f73e6da9e979c839c7c22ec487bea6667d3e65e7d8f9fcc97a2bcdeb4487cddf + label: SimCity + name: SimCity + region: SNSP-SC-FRA + revision: SFRA-SC-0 + board: SHVC-1A5M-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 1f226553ba05fe738d085a88154469bbc9f9058f7dfc320a327259d84ae5f393 + label: Soul Blazer + name: Soul Blazer + region: SNSP-SO-FRA + revision: SFRA-SO-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 5d0a234a2fcb343d169206d9d7d578507c44f800ead9cc9ccfa0b1d4cb1cc9e5 + label: Terranigma + name: Terranigma + region: SNSP-AQTF-FRA + revision: SPAL-AQTF-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +//Super Nintendo (FRG) + +database + revision: 2018-04-14 + +game + sha256: f415cafaaac4d5fe062b61be35e64ee6b5e8b925f12b9c82777b4566d31de8f4 + label: Choplifter III + name: Choplifter III + region: SNSP-3C-FRG + revision: SPAL-3C-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 5e1cce5ccedb20eff9d188eca445e54bd413db63570fd281f76b3ab56abffd82 + label: Claymates + name: Claymates + region: SNSP-Y5-FRG + revision: SPAL-Y5-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ddad4a3708b8cf760e520b784f42d7085154b0699f3824b8d722512ccab687cb + label: Killer Instinct + name: Killer Instinct + region: SNSP-AKLP-FRG + revision: SPAL-AKLP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +//Super Nintendo (GPS) + +database + revision: 2018-04-14 + +game + sha256: 0d4c05f75c95d5b8c0fc00e61027ce3fda2dd288fcf6695656232176fce7843e + label: Super Hockey + name: Super Hockey + region: SNSP-NH-GPS + revision: SPAL-NH-0 + board: SHVC-1A1M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +//Super Nintendo (HOL) + +database + revision: 2018-04-14 + +game + sha256: dc8b3144329a23459bfcce93c89e0e561d133709aca6bfc74f9e0755f1a04b91 + label: Lufia + name: Lufia + region: SNSP-ANIH-HOL + revision: SPAL-ANIH-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +//Super Nintendo (ITA) + +database + revision: 2018-09-21 + +game + sha256: deab7aad7c168423e43eae14e9e31efa29c7341ab84f936be508911ce508b372 + label: MechWarrior + name: MechWarrior + region: SNSP-WM-ITA + revision: SITA-WM-0 + board: SHVC-1A1M-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: aafbae4c2a7a5a35c81a183df0470027b4b5690f836592af21c15af6b259328d + label: Super Strike Gunner + name: Super Strike Gunner + region: SNSP-SG-ITA + revision: SPAL-SG-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +//Super Nintendo (LTN) + +database + revision: 2018-04-14 + +game + sha256: e678a29a93111cf2016c487ba9977b14de8f719040651a42c74bd74eea2d0d81 + label: The Death and Return of Superman + name: Death and Return of Superman, The + region: SNS-9D-LTN + revision: SNS-9D-1 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +//Super Nintendo (NOE) + +database + revision: 2020-01-01 + +game + sha256: b342d12d71729edebc1911725ea23d58c1a397b27253a5c8cd96cfb58af242a9 + label: Addams Family Values + name: Addams Family Values + region: SNSP-VY-NOE + revision: SPAL-VY-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 475c601df7384621539ebcf2586a50720cc8de5d089b71fc65ff3f605cff7c8f + label: The Addams Family + name: Addams Family, The + region: SNSP-AF-NOE + revision: SPAL-AF-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 12c00475e5d881c26fbdce025d05ca32d4f5534bfa441d9887624a843df74222 + label: Aero the Acro-Bat + name: Aero the Acro-Bat + region: SNSP-XB-NOE + revision: SPAL-XB-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a4b1e125b421c5a58e2fd73edc4d58b31d7a596c07dee263c565f00ee712223f + label: Alfred Chicken + name: Alfred Chicken + region: SNSP-8A-NOE + revision: SPAL-8A-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b2df16101a2daa0f718853be92e3cf5d88f8e8843d04962e4b403d13769c1119 + label: Alien vs. Predator + name: Alien vs. Predator + region: SNSP-AP-NOE + revision: SPAL-AP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: daa9a6a3872f252d74d7112094b6c97409fc166dae564e032b5158d12443b68c + label: An American Tail: Fievel Goes West + name: American Tail, An - Fievel Goes West + region: SNSP-9W-NOE + revision: SPAL-9W-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 85b88af9b1f2071804e27c3ff9d42da6b26417c26b6f8a9e878733b8c35724ab + label: Another World + name: Another World + region: SNSP-TW-NOE + revision: SPAL-TW-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d54d2703e474d7f469766d2d095ffcbbcab893e3fe58bbbcc57e24082a44bb40 + label: Asterix + name: Asterix + region: SNSP-XE-NOE + revision: SPAL-XE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: bb81d1730222c518084d06c5ce456ee860d5ccb6a410f14a73e68971305bdd12 + label: Axelay + name: Axelay + region: SNSP-AX-NOE + revision: SPAL-AX-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ffd6668607ee279d79ef3f2b35713b99f8b046a53c608a82df9d37ef39bb079b + label: Batman Returns + name: Batman Returns + region: SNSP-BJ-NOE + revision: SPAL-BJ-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 716214f0b17233021f8ee07500530947655c4c871cd041290adb204523984821 + label: Battletoads in Battlemaniacs + name: Battletoads in Battlemaniacs + region: SNSP-NX-NOE + revision: SPAL-NX-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 13cd21706cbb02536714c9f0a4d14b37d59a9161abe155e043fd74ba4d5dea15 + label: Beethoven: The Ultimate Canine Caper! + name: Beethoven - The Ultimate Canine Caper! + region: SNSP-2V-NOE + revision: SPAL-2V-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 08e02381cf59bdb3ad4d561587c8ccd001c722c7731705a9d84b39cb0337ca53 + label: Blackhawk + name: Blackhawk + region: SNSP-6Z-NOE + revision: SPAL-6Z-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 34221406999172e342b9442e30d12c467fbcd9afa86bedb5ec5ddb5ebc2ee8a1 + label: The Blues Brothers + name: Blues Brothers, The + region: SNSP-B6-NOE + revision: SPAL-B6-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 5a054466ffe0694599498b9d94427b25d4f4d55ab4fc1542335f69025e817a3f + label: B.O.B. + name: BOB + region: SNSP-B4-NOE + revision: SPAL-B4-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6df9b702c65183ef13dd2a66d1bc95e7ec1452e088e9c19a0e3beb9ef952e939 + label: Brawl Brothers: Rival Turf! 2 + name: Brawl Brothers - Rival Turf! 2 + region: SNSP-RE-NOE + revision: SPAL-RE-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 0a49023824d812c64cd262db6e85ce9900c88af7ac6dab3e47078ab0dd1e546c + label: Bubsy in Claws Encounters of the Furred Kind + name: Bubsy in Claws Encounters of the Furred Kind + region: SNSP-YN-NOE + revision: SPAL-YN-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 6795e22c6ddcbfa48de1e5b1b22ad72890214533a12e59763cb4b8d5b2535aef + label: Bugs Bunny: Rabbit Rampage + name: Bugs Bunny - Rabbit Rampage + region: SNSP-R7-NOE + revision: SPAL-R7-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: a20bdbdafccee20bf17eae28fdb0b79fced5b53f90a1cad259461a37903f9ad1 + label: California Games II + name: California Games II + region: SNSP-C2-NOE + revision: SPAL-C2-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a2e3a81f7dfbd50423bebfce8c2f6b85d58f7336810ee6c813fb74ac7d4427a3 + label: Captain America and The Avengers + name: Captain America and The Avengers + region: SNSP-6A-NOE + revision: SPAL-6A-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a60886ea6459861bb8d149023a975c4e83c172847264756840ca0754eb9f1f15 + label: Championship Pool + name: Championship Pool + region: SNSP-5P-NOE + revision: SPAL-5P-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: fd7e471b7855614f1a4782c2194e6d268406c694d0f674350317a3efed26c4aa + label: The Chaos Engine + name: Chaos Engine, The + region: SNSP-UD-NOE + revision: SPAL-UD-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 9f072794e9f379e35dabd50a714e08b98deab61e3dd97ef982d7504b85b28d24 + label: The Chessmaster + name: Chessmaster, The + region: SNSP-CH-NOE + revision: SPAL-CH-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 9ae517aef04a7157f9e8e13c874a9ac5f452d02ad6343e03fed9cce0aa515171 + label: Chuck Rock + name: Chuck Rock + region: SNSP-CK-NOE + revision: SPAL-CK-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f000606a504c7a51617c0e32865924a68bf899170aea2647cf403fede8491c0e + label: Clay Fighter + name: Clay Fighter + region: SNSP-8C-NOE + revision: SPAL-8C-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 1ee967210f980b76b6c810a8b130049405183d20e4c308b17c7ef982912fc628 + label: Cliffhanger + name: Cliffhanger + region: SNSP-6C-NOE + revision: SPAL-6C-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e0c51ca00f22716531cb9138cfe8d5af4680cde1c95bfbfcd52c35f246763e65 + label: Congo's Caper + name: Congo's Caper + region: SNSP-J2-NOE + revision: SPAL-J2-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 81220ffa1f167d9b5b909b0315a6734fae8957b8d708b3887fb0e9105f816edb + label: Cool Spot + name: Cool Spot + region: SNSP-C8-NOE + revision: SPAL-C8-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5d42cef66c529939b6038f4ecaf1aeb06acda2dabbf7bcf4e7203f3cb6b43f7a + label: Cybernator + name: Cybernator + region: SNSP-AV-NOE + revision: SPAL-AV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a9ababea552f9d7f756e99bfc0f7f88b30898297c762d35d603837475e713f86 + label: Daffy Duck: The Marvin Missions + name: Daffy Duck - The Marvin Missions + region: SNSP-YF-NOE + revision: SPAL-YF-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6ce516e3d1a7068cc9732cd3517cfd1e92179f2340c63a244625a1ff49815085 + label: Daze Before Christmas + name: Daze Before Christmas + region: SNSP-ADCP-NOE + revision: SPAL-ADCP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 3e4e16a5d47197a2f7bc724e3a6875b682f738800c7377ea655a6d7f54156a0e + label: Dennis + name: Dennis + region: SNSP-4D-NOE + revision: SPAL-4D-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a7612dbb5fd122090d4fcbffec81d295c0911ff5c83fa865c441c7b3996fcc92 + label: DinoCity + name: DinoCity + region: SNSP-DW-NOE + revision: SPAL-DW-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 984107f2dbccbcaec1f7e74b62af82785918438144221bd0228fa36419a11ed8 + label: Dragon's Lair + name: Dragon's Lair + region: SNSP-DI-NOE + revision: SPAL-DI-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: dddacae010766c1201f50810fcf15dff7c0f6d41ac1a1004c8eea4873a71db12 + label: F-Zero + name: F-Zero + region: SNSP-FZ-NOE + revision: SPAL-FZ-0 + board: SHVC-1A1B-06 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 450df78c9b7c92e9f8ce5c2ee0e1dbf939031c1e4f9e10c52c8d8f874364d1d6 + label: Fatal Fury + name: Fatal Fury + region: SNSP-GN-NOE + revision: SPAL-GN-0 + board: SHVC-2A0N-10 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: c7abc997e0f685a726dacd82e2734f557028490c1c9b8e575bc6cbc18de243a4 + label: Final Fight 2 + name: Final Fight 2 + region: SNSP-F2-NOE + revision: SPAL-F2-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: b7ab3afb4f63b95c2ceafcaf03fd691fe9fc53b173d7fd22a8a111b40f8713b3 + label: First Samurai + name: First Samurai + region: SNSP-FK-NOE + revision: SPAL-FK-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 6cce3d0c8b2eec350475e3c274d7ad80c9a208ba101d9cf9ac637c5d09760ab7 + label: Flashback + name: Flashback + region: SNSP-5F-NOE + revision: SPAL-5F-0 + board: SHVC-2J0N-01 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: c7935e5e147a8c1b2646fbb7776cf73198967bd053f2a58f4f01e9a3a5c2911a + label: The Flintstones: The Treasure of Sierra Madrock + name: Flintstones, The - The Treasure of Sierra Madrock + region: SNSP-9F-NOE + revision: SPAL-9F-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6d0095422fe380202e62ed5b34f038681f777dcd9a943cf3534645068e118fb2 + label: George Foreman's KO Boxing + name: George Foreman's KO Boxing + region: SNSP-GK-NOE + revision: SPAL-GK-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ddda02bc9fff44c702ce6b2d043c8c2dc520c568a1df221de0bde24e16e1618d + label: Harley's Humongous Adventure + name: Harley's Humongous Adventure + region: SNSP-HV-NOE + revision: SPAL-HV-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 320c9a88c2fa3221d8e8d2dc8eaae9d6143753b0b881166b5376bcd50031e1da + label: Home Alone + name: Home Alone + region: SNSP-HA-NOE + revision: SPAL-HA-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: ca2d67f208e3dc7aaeea88b60d7008b6e00b525bf935c259b642ad5cad783bb1 + label: Home Alone 2: Lost in New York + name: Home Alone 2 - Lost in New York + region: SNSP-HN-NOE + revision: SPAL-HN-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: e4b315f714529a9ba593ffa16ac7456db178294405e26811313c08177969a05f + label: Hook + name: Hook + region: SNSP-HO-NOE + revision: SPAL-HO-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a9dffa5d97855733f14b1b888bc478e8e0630107812b7b3df729c499e0e0734f + label: Hyper Zone + name: Hyper Zone + region: SNSP-HZ-NOE + revision: SPAL-HZ-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 039beb46f81ad9e0844ecec420cc78bfdbf2b1ae940adb4fdf08dbf1b55ac7ed + label: Illusion of Time + name: Illusion of Time + region: SNSP-JG-NOE + revision: SFRG-JG-1 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 42bc8987dda4f8e4a1d135f3327ef89fb51b9bea97a79dba0060f6fdf9f4c0ba + label: The Incredible Crash Dummies + name: Incredible Crash Dummies, The + region: SNSP-C7-NOE + revision: SPAL-C7-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 2c08b32ecbba97bea0fbb569186294f9ad738a301d90245d9729046ba0ecabab + label: James Bond Jr. + name: James Bond Jr. + region: SNSP-JJ-NOE + revision: SPAL-JJ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 09299d142e485ba2fcdbd9b3a6d1a5acfbc7fc70b06cf22be28479686419a7a9 + label: Jimmy Connors Pro Tennis Tour + name: Jimmy Connors Pro Tennis Tour + region: SNSP-JC-NOE + revision: SFRG-JC-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 74c55ea3c9733bf263628a260df7492fc840d7de1c3fceebb7bcf6d99a8c81d6 + label: Joe & Mac: Caveman Ninja + name: Joe & Mac - Caveman Ninja + region: SNSP-JT-NOE + revision: SPAL-JT-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 3fa82117fe88b0b5398995b68624f3027184259456123f2a61d55f668326c769 + label: Kevin Keegan's Player Manager + name: Kevin Keegan's Player Manager + region: SNSP-PJ-NOE + revision: SFRG-PJ-0 + board: SHVC-1A3M-10 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 53ccf6970d4577608893f38633cc0609ba0eec1b393f891df31e2e5c2f903a9c + label: Kid Klown in Crazy Chase + name: Kid Klown in Crazy Chase + region: SNSP-ZI-NOE + revision: SPAL-ZI-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 11a6c5de89b25836c8b66d3e3077bacdcaf52faab5a0f7fe2bc751aa85a8dd68 + label: King of the Monsters + name: King of the Monsters + region: SNSP-KM-NOE + revision: SPAL-KM-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 9bc7afdb9ffaca90db4390697e80a75bf4889cd8529e21c28ad42c41171e2630 + label: Knights of the Round + name: Knights of the Round + region: SNSP-LO-NOE + revision: SPAL-LO-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 9ed408bb30b32c0a86605ea80e2b431563a33d54354a4b68e8b7d4eedde25295 + label: Last Action Hero + name: Last Action Hero + region: SNSP-L5-NOE + revision: SPAL-L5-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4a7444780a750f97943d974589586d4cf89d8957e396cc5a7ad565cd4c1b70a7 + label: The Legend of the Mystical Ninja + name: Legend of the Mystical Ninja, The + region: SNSP-GG-NOE + revision: SFRG-GG-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5ec66298ddb579b35cc5d3df5bfeeee05bdf71347565c7c5f5f3869bf4f1e469 + label: Looney Tunes Basketball + name: Looney Tunes Basketball + region: SNSP-ALTP-NOE + revision: SPAL-ALTP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 0ecdd9d6fc78c0bdbc2f684c682ec834cda1148ed2e675cc783a95c601000d3b + label: Lothar Matthäus Super Soccer + name: Lothar Matthaus Super Soccer + region: SNSP-AOMD-NOE + revision: SPAL-AOMD-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8510491f99400115ccf33570269bc4e484fb56370f7ac36f12e73eec19d342da + label: Lucky Luke + name: Lucky Luke + region: SNSP-ALYP-NOE + revision: SPAL-ALYP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: be9c42913fee053a8d854054a27a0fb4d1cf6c092b46c7291d2743e94204a323 + label: Magic Boy + name: Magic Boy + region: SNSP-YG-NOE + revision: SPAL-YG-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 8f6920549b28a065a030fbdbe2ea2e9d966d42ab5ac1ef0e9dabc99875a51df2 + label: MechWarrior + name: MechWarrior + region: SNSP-WM-NOE + revision: SFRG-WM-0 + board: SHVC-1A1M-10 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 9283ac563e3d8244fb103db13256c669063e67be5eaf6e82b94527f079c9d8a3 + label: Michael Jordan: Chaos in the Windy City + name: Michael Jordan - Chaos in the Windy City + region: SNSP-AWCP-NOE + revision: SPAL-AWCP-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: 4703cb071611874b0d9e9555f102278e33dd494202875dc994a232029148bf67 + label: Mortal Kombat + name: Mortal Kombat + region: SNSP-KX-NOE + revision: SPAL-KX-0 + board: SHVC-2A0N-01 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 41803805d28cad8873029c4b648cc6dd7503b7a33afa8ff584434a970dc9d8c1 + label: Mr. Nutz + name: Mr. Nutz + region: SNSP-N8-NOE + revision: SPAL-N8-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 558b437e10915c2ca79f376634fa4623c87efdb9292a5878b886c7a6fbef61e2 + label: Parodius + name: Parodius + region: SNSP-PD-NOE + revision: SPAL-PD-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b8fcbad3c712a2ff69a5f9bb9fbe4c4284f91bbe96fe849275a8bcfcb497d204 + label: Phalanx: The Enforce Fighter A-144 + name: Phalanx - The Enforce Fighter A-144 + region: SNSP-PH-NOE + revision: SPAL-PH-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ec6f444dcab84d251c12eb4f47aeac23ed997bf0416c5a537bac6bb9d40b725d + label: The Pirates of Dark Water + name: Pirates of Dark Water, The + region: SNSP-8P-NOE + revision: SPAL-8P-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 9932ed1419bc606ea19337b74a8ef17adaa6b31be5fca8d2b6b266b3f6383e39 + label: Revolution X + name: Revolution X + region: SNSP-AXRD-NOE + revision: SPAL-AXRD-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: b2717bec03b627c4f02bd6dd77cfa790ea4eab91f0f47626ea452c50369d35d4 + label: Rival Turf + name: Rival Turf + region: SNSP-RB-NOE + revision: SPAL-RB-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a0888a9c02b0ca0c9e95246c9ea60407f7f9c4dfde1ff1c15b7f6d5bd4ea5b85 + label: Samurai Shodown + name: Samurai Shodown + region: SNSP-A7SP-NOE + revision: SPAL-A7SP-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: c341668847170d36fa5cfb720568b0b1ecbb24fc426a821f665f1d3853a46a6d + label: Secret of Evermore + name: Secret of Evermore + region: SNSP-AEOD-NOE + revision: SPAL-AEOD-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 1444ab11f96f7750db992e9a4160532b27abede8a7054128c09f448300c91ebf + label: Secret of Mana + name: Secret of Mana + region: SNSP-K2-NOE + revision: SFRG-K2-0 + board: SHVC-1J3M-11 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: bc819454a2082f93b03ad3dc11795eb8cd4ccec72a41560462a91b6f0edd432f + label: Starwing + name: Starwing + region: SNSP-FO-NOE + revision: SFRG-FO-0 + board: SHVC-1C0N + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + volatile + +game + sha256: e4df822294a12919b35cd73a1ca24105418ca2c2bc5e08f887fe1d10b3e4f200 + label: Starwing Competition + name: Starwing Competition + region: SNSP-FU-NOE + revision: SFRG-FU-0 + board: SHVC-1C0N + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + volatile + +game + sha256: 35c1d6623748f66e254843cf340121e3e268a8301951f35c7ba3ef666bc293bf + label: Street Fighter II: The World Warrior + name: Street Fighter II - The World Warrior + region: SNSP-S2-NOE + revision: SPAL-S2-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 54ac1f0c99f1521e4c390f43af5da2138ec0526a97912790bdb53f9ab1b10b63 + label: Street Fighter II Turbo: Hyper Fighting + name: Street Fighter II Turbo - Hyper Fighting + region: SNSP-TI-NOE + revision: SPAL-TI-1 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: 30291b60cb7bb0bf92dc48b922daff71f6bc4b29200bef5540a522bcb0a64cee + label: Super Air Diver + name: Super Air Diver + region: SNSP-AZ-NOE + revision: SPAL-AZ-0 + board: SHVC-1K0N-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + volatile + oscillator + frequency: 7600000 + +game + sha256: 4dcf9213cf22c9e28e58b42ca7808224399d89b9b33f1fd592be6866db42755d + label: Super Battleship + name: Super Battleship + region: SNSP-8B-NOE + revision: SPAL-8B-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 3b8e4da1435a548927a120a827eac01fef7d3636f3f763923063e5613adad42f + label: Super Castlevania IV + name: Super Castlevania IV + region: SNSP-AD-NOE + revision: SPAL-AD-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: bbedc3b9263993c1294793895b5901973fbb159157db4c6d1b79ee8245007791 + label: Super Double Dragon + name: Super Double Dragon + region: SNSP-WD-NOE + revision: SPAL-WD-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4d7fc331a811b8dc630b469262fd6f45e289243cef83101f32038158967d1b28 + label: Super Game Boy + name: Super Game Boy + region: SNSP-A-SG-NOE + revision: SYS-SGB-2 + board: SGB-R-10 + memory + type: ROM + size: 0x40000 + content: Program + memory + type: ROM + size: 0x100 + content: Boot + manufacturer: Nintendo + architecture: SM83 + identifier: SGB1 + +game + sha256: 4c5b426ea5950b66098ba4377f6a86d091d7af2f4783895086a621aa98811596 + label: Super Ice Hockey + name: Super Ice Hockey + region: SNSP-OX-NOE + revision: SPAL-OX-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 2b1ca521975c3010650fd2055be8c6b964ea4eff765ad03198ac71995285fee7 + label: Super Probotector: Alien Rebels + name: Super Probotector - Alien Rebels + region: SNSP-CS-NOE + revision: SPAL-CS-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 7c7e90fb7c762769219234baf7b5fa6bf574fff7dc63b7134d49ec7c8b38ea7e + label: Super R-Type + name: Super R-Type + region: SNSP-SR-NOE + revision: SPAL-SR-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 70c07b2c7bdff9353d3849e2d4bde2bfa631b29e0743862635c2212ac551cb27 + label: Super SWIV + name: Super SWIV + region: SNSP-WV-NOE + revision: SPAL-WV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 1bc2b230d6bb6091412fcc9b957192d9a729496f9f2123449d968afb088fc525 + label: Super Turrican + name: Super Turrican + region: SNSP-TU-NOE + revision: SPAL-TU-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 454dbc5383f36e1d611fcc76a23162ae03e269c76c98919b1e7505ea4c7c2402 + label: Super Turrican 2 + name: Super Turrican 2 + region: SNSP-A2TP-NOE + revision: SPAL-A2TP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: eea3584fe574b1e7ba6c559ef32f86a990f54c7fa36b25242656b4c6dc18e6f0 + label: Syndicate + name: Syndicate + region: SNSP-AFYP-NOE + revision: SPAL-AFYP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 3e26fbb8004635f4128f8e989d96f89fddc0a2cf85a8ede6b93ae6648bd6a717 + label: Teenage Mutant Hero Turtles V: Tournament Fighters + name: Teenage Mutant Hero Turtles V - Tournament Fighters + region: SNSP-8F-NOE + revision: SPAL-8F-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: d6968f79ec66cec751dcf54a1fd0c7321a8e1b69722d81b10d1969a8415412a6 + label: Terminator 2: The Arcade Game + name: Terminator 2 - The Arcade Game + region: SNSP-XV-NOE + revision: SPAL-XV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 2465335e0a16e65d41d42067f53d97ce0929d003ef41ec605d160cfb30c20df7 + label: Terranigma + name: Terranigma + region: SNSP-AQTD-NOE + revision: SPAL-AQTD-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 613cd1a31eaded18648168bd7453a57830ca9a6f3c10de5154625436fbd49556 + label: Terranigma + name: Terranigma + region: SNSP-AQTD-NOE + revision: SPAL-AQTD-1 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 3c94c600fefcf34e5d251885c209d6b61b40de119589b67badec38deeffb46f9 + label: Tiny Toon Adventures: Buster Busts Loose! + name: Tiny Toon Adventures - Buster Busts Loose! + region: SNSP-TA-NOE + revision: SPAL-TA-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 94e6fe78bb1a1d89ccfd74ad92e2a489f8e2e257d6dfe62404155741763f962f + label: True Lies + name: True Lies + region: SNSP-ATLD-NOE + revision: SPAL-ATLD-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a1105819d48c04d680c8292bbfa9abbce05224f1bc231afd66af43b7e0a1fd4e + label: Unirally + name: Unirally + region: SNSP-4L-NOE + revision: SPAL-4L-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 847c9189580fc92e785c8124cbde4f1d72be75e1941b35021f6b159e0470c1b0 + label: WeaponLord + name: WeaponLord + region: SNSP-ADWP-NOE + revision: SPAL-AWDP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 8315596b4fe517b970d004336c86ed2bc74e167692ffaa51c529a41e2197519e + label: Winter Olympics: Lillehammer '94 + name: Winter Olympics - Lillehammer '94 + region: SNSP-W4-NOE + revision: SPAL-W4-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 9eb2f90cae9958ae7f387d797cb28797b5ccaf520c41d4c5ca9494c74a87c422 + label: World Heroes + name: World Heroes + region: SNSP-WZ-NOE + revision: SPAL-WZ-0 + board: SHVC-1J0N-01 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 92dd66642e86b9b4156352a583bd479c200c342820a8b6cf906cca6bb923cf25 + label: Worms + name: Worms + region: SNSP-AW3P-NOE + revision: SPAL-AW3P-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x1e0000 + content: Program + +game + sha256: 24aad9739f8ffe9319f20d4fa1c4f58108e73843d20d65296926e00ba9c456be + label: Zombies + name: Zombies + region: SNSP-ZA-NOE + revision: SPAL-ZA-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +//Super Nintendo (SCN) + +database + revision: 2018-09-21 + +game + sha256: beb379ba48f63561c0f939ecd8f623ec06c1b5e06976eef9887e5c62f3df2766 + label: Gods + name: Gods + region: SNSP-GZ-SCN + revision: SPAL-GZ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 896e09a0d24bfec0412aa75d121063b015153a754ed542f7db7d66366b555de4 + label: The Lion King + name: Lion King, The + region: SNSP-ALKP-SCN + revision: SPAL-ALKP-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 4fb9eb8fa4d9c3a0b6c24bac5b0a0b0f079f083f5e6dfa937a161c8f4bcde853 + label: Shadowrun + name: Shadowrun + region: SNSP-WR-SCN + revision: SSWE-WR-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: e15247495311e91db9431d61777a264d4b42def011291d512b273fc8acd1cbfa + label: Soul Blazer + name: Soul Blazer + region: SNSP-SO-SCN + revision: SPAL-SO-0 + board: SHVC-1A3B-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 687c4f9a14cc16605f5e92aa0fe33bf083fe8e39ba781676259fadf932480890 + label: Tintin i Tibet + name: Tintin i Tibet + region: SNSP-AT6X-SCN + revision: SPAL-AT6X-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: a6297356fb06f1575b432fae463171f53e3b786fd77b841557547a9117fb52fe + label: X-Zone + name: X-Zone + region: SNSP-XZ-SCN + revision: SPAL-XZ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +//Super Nintendo (UKV) + +database + revision: 2018-04-14 + +game + sha256: 38e050ac3ffec01031c6dd8ead20676aacec78ebf8d890a3a00d1badaaba3d3b + label: The Adventures of Dr. Franken + name: Adventures of Dr. Franken, The + region: SNSP-6F-UKV + revision: SPAL-6F-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8c5f2f8d45d86b27e48313d136477ba6f30989c93748d800ad6bf82f14ecd4a1 + label: Battletoads & Double Dragon + name: Battletoads & Double Dragon + region: SNSP-UL-UKV + revision: SPAL-UL-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 0a49023824d812c64cd262db6e85ce9900c88af7ac6dab3e47078ab0dd1e546c + label: Bubsy in Claws Encounters of the Furred Kind + name: Bubsy in Claws Encounters of the Furred Kind + region: SNSP-YN-UKV + revision: SPAL-YN-0 + board: SHVC-2A0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 536f9c2ff7dfdc6e5b51389142151b1c9e9d73f1c2451eafe16d0224d15ad35f + label: Desert Fighter + name: Desert Fighter + region: SNSP-OS-UKV + revision: SPAL-OS-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 1c12660c99571692d2fba4ba871a1086b115486697e789f85fb939c55eeec7c7 + label: Doom + name: Doom + region: SNSP-AD8P-UKV + revision: SPAL-AD8P-0 + board: SHVC-1CB0N7S-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x10000 + content: Save + volatile + oscillator + frequency: 21440000 + +game + sha256: 3d4715ce44045fbb27b72c0925020a52b748c9236db1e7782ee62f74615182fc + label: Eek! The Cat + name: Eek! The Cat + region: SNSP-E7-UKV + revision: SPAL-E7-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: dddacae010766c1201f50810fcf15dff7c0f6d41ac1a1004c8eea4873a71db12 + label: F-Zero + name: F-Zero + region: SNSP-FZ-UKV + revision: SPAL-FZ-0 + board: SHVC-1A1B-05 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: b0d2439944b6ae85d4ec6f39c91e3c8b9c740a43d077f4d0675dc2c2235204df + label: Family Dog + name: Family Dog + region: SNSP-D8-UKV + revision: SPAL-D8-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 7d423c7d5ac4fef6ae608ae87e77608294ef7e51a6f0afff1042ed66a1c639fe + label: The Flintstones + name: Flintstones, The + region: SNSP-AFNP-UKV + revision: SPAL-AFNP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: e9e2152411fec3bd10e8cd4587b62717169a25a4cd28f491f8e477b9aae2fcee + label: fun 'n games + name: Fun & Games + region: SNSP-7N-UKV + revision: SPAL-7N-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 94b2e68503514afe956cbc8ef4fb2cb93a323761e9b7d205e44e544049a4ae3b + label: The Incredible Hulk + name: Incredible Hulk, The + region: SNSP-8U-UKV + revision: SPAL-8U-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 9d936f3b0b5bea0b7c4588e65fa147fff1108d0e630337dd75eb16133a55e317 + label: International Sensible Soccer: World Champions + name: International Sensible Soccer - World Champions + region: SNSP-8S-UKV + revision: SPAL-8S-1 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 975397a09ec1dfa518f1f0a2029ecb74e5b4c1113bf3376de94711672ff4e054 + label: James Pond's Crazy Sports + name: James Pond's Crazy Sports + region: SNSP-JX-UKV + revision: SPAL-JX-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: f5e74f09c485d58b444ef2b168d041a1d451056b5feb295901974ca73190dbdb + label: Jelly Boy + name: Jelly Boy + region: SNSP-AJBP-UKV + revision: SPAL-AJBP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 1be41a3a2d490be97b98f2ab8934d8e8812d7d2596598a7841e3027b23e95261 + label: Jurassic Park + name: Jurassic Park + region: SNSP-J8-UKV + revision: SPAL-J8-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: ddad4a3708b8cf760e520b784f42d7085154b0699f3824b8d722512ccab687cb + label: Killer Instinct + name: Killer Instinct + region: SNSP-AKLP-UKV + revision: SPAL-AKLP-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 6379d7d476a29ae2655e30fc20699772af81abefc903f5816872dd46e4e88242 + label: Legend + name: Legend + region: SNSP-6L-UKV + revision: SPAL-6L-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 654183585e88abf965b19570c194f3d69ef209a7f2d32f71881eceaea6a3487e + label: The Legend of Zelda: A Link to the Past + name: Legend of Zelda, The - A Link to the Past + region: SNSP-ZL-UKV + revision: SPAL-ZL-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0c4038eb0ee37c0faac6a04928b37b5c2f1047ab59c5345da16de48c92db5021 + label: Lethal Enforcers + name: Lethal Enforcers + region: SNSP-LK-UKV + revision: SPAL-LK-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 528f9697cdb5b50504aa4f6d6f7882c4997e7141898f9a00a630692b964204eb + label: Lethal Weapon + name: Lethal Weapon + region: SNSP-L3-UKV + revision: SPAL-L3-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 1c41bb11c9df5aa8a6ca98caa5215418f37025f7a5e88ff62188b257338af3ab + label: Mega Man X + name: Mega Man X + region: SNSP-RX-UKV + revision: SPAL-RX-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: d33f682605b3d6c8a162506ef333a24933ae26a32f10ff8e49fc113bcd189137 + label: Mighty Morphin Power Rangers: The Fighting Edition + name: Mighty Morphin Power Rangers - The Fighting Edition + region: SNSP-A3RP-UKV + revision: SPAL-A3RP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: d147bfe392e8c2129fb887379410804d79be426bbffdd01cec7bd2332e03f39e + label: Pilotwings + name: Pilotwings + region: SNSP-PW-UKV + revision: SPAL-PW-0 + board: SHVC-1B0N-10 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1B + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1B + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1B + volatile + oscillator + frequency: 7600000 + +game + sha256: 5702fb6978229e398075cf0d20927b47a5881b572532813557e86b8e9cf63db0 + label: Secret of Mana + name: Secret of Mana + region: SNSP-K2-UKV + revision: SPAL-K2-1 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: e95278ec68bf983111a52e38d5e6031c41141858e87e2cb8ef92fdfe17e41a15 + label: Sensible Soccer: European Champions + name: Sensible Soccer - European Champions + region: SNSP-8S-UKV + revision: SPAL-8S-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 21f4b54ed90de7bb0f5f02d64d11f80ba9f2147197b7a3bd09fc7aa1858ba0f5 + label: Side Pocket + name: Side Pocket + region: SNSP-4P-UKV + revision: SPAL-4P-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d02f8e6b75f9b9ede20a32b8ec93c06475f18160ced1eb069cd6a3cbbc3cba2e + label: Spectre + name: Spectre + region: SNSP-7Q-UKV + revision: SPAL-7Q-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0xe0000 + content: Program + +game + sha256: 8c7a8aa1d16aeef31244b016ac951eab0b9ccd46daea61adbe890e5c5daa29c6 + label: Star Trek: The Next Generation - Future's Past + name: Star Trek - The Next Generation - Future's Past + region: SNSP-XN-UKV + revision: SPAL-XN-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 80e7ba7c756c70eedd55ca4548c1965f84f9ef01d3a5ca91a2e5465a6930c49a + label: Starwing + name: Starwing + region: SNSP-FO-UKV + revision: SPAL-FO-1 + board: SNSP-1C0N5S-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + volatile + +game + sha256: 2a25bf4c1a4fc64f9312ddf039f5b3e8949054cbaeb4f86d1ccd9ea2bb779643 + label: Starwing Competition + name: Starwing Competition + region: SNSP-FU-UKV + revision: SPAL-FU-0 + board: SHVC-1C0N + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + volatile + +game + sha256: b8ee1b5b9deae5c84fa209815515030109cc271b645a18de882aaf1b254cda1f + label: Street Fighter II Turbo: Hyper Fighting + name: Street Fighter II Turbo - Hyper Fighting + region: SNSP-TI-UKV + revision: SPAL-TI-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: df43b3a4f511401a4d162ee6e7e3b08485533600dc44a29ee0a829b937b144d4 + label: Striker + name: Striker + region: SNSP-KE-UKV + revision: SPAL-KE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: f1a75578e6711716340bb26ea93bf05d5762bc7da21dbc19576fc65de1e885b5 + label: Super Aleste + name: Super Aleste + region: SNSP-AT-UKV + revision: SPAL-AT-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e8b1639acd44a536f060d6d8dbcc4ef368279e3e17e1e3862a463d3ebf07ea14 + label: Super Battletank 2 + name: Super Battletank 2 + region: SNSP-2X-UKV + revision: SPAL-2X-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 8bc56d4d23638ff592715e089dfd697fe7884a388c5ac95e147973bc2ff71e72 + label: Super International Cricket + name: Super International Cricket + region: SNSP-ACIP-UKV + revision: SPAL-ACIP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 9760fb407282d91005044fb08f9c15dc3e0ae65063a02eedfbbd285566501fd0 + label: Super Mario All-Stars + name: Super Mario All-Stars + region: SNSP-4M-UKV + revision: SPAL-4M-0 + board: SHVC-2A3M-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 12d04359329bd646fc65c62db6121b4a7e4ece68556d68252e81ced421069f4c + label: Super Mario Kart + name: Super Mario Kart + region: SNSP-MK-UKV + revision: SPAL-MK-0 + board: SHVC-1K1B-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + volatile + oscillator + frequency: 7600000 + +game + sha256: 640acb63dae038ad6f0ae65e103416f5a1f84d4a37ddaeeab5046122def774d5 + label: Super Metroid + name: Super Metroid + region: SNSP-RI-UKV + revision: SPAL-RI-0 + board: SHVC-BA3M-10 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 3438e78d35634d0ed7f58cb395c77da548fb601248725a18365edaed38a565d5 + label: Super Punch-Out!! + name: Super Punch-Out!! + region: SNSP-4Q-UKV + revision: SPAL-4Q-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 7c7e90fb7c762769219234baf7b5fa6bf574fff7dc63b7134d49ec7c8b38ea7e + label: Super R-Type + name: Super R-Type + region: SNSP-SR-UKV + revision: SPAL-SR-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a52b98da8f65bf2210b7d2e931548c672838fa7e44d852f2e3c6f3cd2ba950d6 + label: Super Street Fighter II: The New Challengers + name: Super Street Fighter II - The New Challengers + region: SNSP-XW-UKV + revision: SPAL-XW-0 + board: SHVC-BJ0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: d92b74678e58360db9b47a7044cedd6c57f191570a5677b1a1bf5e476f92721d + label: Terminator 2: Judgment Day + name: Terminator 2 - Judgment Day + region: SNSP-TP-UKV + revision: SPAL-TP-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c0a7e27131a7d8c9ef52a5227329e6de5846c045a9da1f3f84845e3be8e4efba + label: Theme Park + name: Theme Park + region: SNSP-ATQP-UKV + revision: SPAL-ATQP-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f899b083b29f34bee62cc022262ab4ff6aad9b16423011faff37f2c21a45fd89 + label: Total Carnage + name: Total Carnage + region: SNSP-XC-UKV + revision: SPAL-XC-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 717fe462a79c298581423c614f62e22dbf6a33e0bf75e691d96848086869418e + label: Tuff E Nuff + name: Tuff E Nuff + region: SNSP-TE-UKV + revision: SPAL-TE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +//Super Nintendo (USA) + +database + revision: 2020-01-01 + +game + sha256: 2ffe8828480f943056fb1ab5c3c84d48a0bf8cbe3ed7c9960b349b59adb07f3b + label: 3 Ninjas Kick Back + name: 3 Ninjas Kick Back + region: SNS-A3NE-USA + revision: SNS-A3NE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 4dd631433c867ba920997fd3add2c838b62e70e06e0ef55c53884b8b68b0dd27 + label: The 7th Saga + name: 7th Saga, The + region: SNS-EL-USA + revision: SNS-EL-0 + board: SHVC-2J3M-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: ce164872c4f5814bce04cf0565edcdb5b7969ae95a3b5cd515cfb626b5cde7b3 + label: Aaahh!!! Real Monsters + name: Aaahh!!! Real Monsters + region: SNS-ANNE-USA + revision: SNS-ANNE-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: bb83f982961c33b81fefc1f545e18ab572d1c43cf6c241948544f05a1a71f2ba + label: ABC Monday Night Football + name: ABC Monday Night Football + region: SNS-N5-USA + revision: SNS-N5-0 + board: SHVC-1A3M-10 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: d07e8802a6d9c777247874e05ec08fce7e0fa1bf122cc1ab9913f7d828e4072b + label: ACME Animation Factory + name: ACME Animation Factory + region: SNS-ACME-USA + revision: SNS-ACME-0 + board: SHVC-1A5M-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: b8055844825653210d252d29a2229f9a3e7e512004e83940620173c57d8723f0 + label: ActRaiser + name: ActRaiser + region: SNS-AR-USA + revision: SNS-AR-0 + board: SHVC-1A3B-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 71bdd448a30b88725864e55594ebb67a118b1f197a3f9e5dd39dbf23399efa15 + label: ActRaiser 2 + name: ActRaiser 2 + region: SNS-A8-USA + revision: SNS-A8-0 + board: SHVC-2J0N-01 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: f59a0a8ed11ea2ba6217b1640e74bab8d8d8161a4585f5ae4a02edd7958ad9a3 + label: Addams Family Values + name: Addams Family Values + region: SNS-VY-USA + revision: SNS-VY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: e645310d2406ace85523ed91070ee7ff6aa245217267dacb158ae9fc75109692 + label: The Addams Family + name: Addams Family, The + region: SNS-AF-USA + revision: SNS-AF-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b6957bae7fd97ba681afbf8962fe2138e209649fd88ed9add2d5233178680aaa + label: The Addams Family: Pugsley's Scavenger Hunt + name: Addams Family, The - Pugsley's Scavenger Hunt + region: SNS-AH-USA + revision: SNS-AH-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 0a8cd5101f849ccd4e40d55fdc4edce914b2825b69eb76ec31cf53b59719e79e + label: Advanced Dungeons & Dragons: Eye of the Beholder + name: Advanced Dungeons & Dragons - Eye of the Beholder + region: SNS-IB-USA + revision: SNS-IB-0 + board: SHVC-1A5M-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 8083307f3f4b7df9e5bf53d5f25877c2e548f0f677540d4ee62d60ccca3098f8 + label: The Adventures of Batman & Robin + name: Adventures of Batman & Robin, The + region: SNS-ABTE-USA + revision: SNS-ABTE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: ecd964ae44e61203bc8759cfc6441365bf0c6e7bae6ad2a0fd553d4c7efab71e + label: The Adventures of Dr. Franken + name: Adventures of Dr. Franken, The + region: SNS-6F-USA + revision: SNS-6F-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 670d898bdcf97d7ca3aab6c2dd1641f1270fcc2a070bbd3028ab413aef2b2ecc + label: The Adventures of Kid Kleets + name: Adventures of Kid Kleets, The + region: SNS-YK-USA + revision: SNS-YK-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: 889beb58d2a48a05a6230cabda14555cb030e2e986c0293bdf396e85af5c6798 + label: The Adventures of Mighty Max + name: Adventures of Mighty Max, The + region: SNS-AMOE-USA + revision: SNS-AMOE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b70099186d3774355ac5db370240e370c73f9ce5341f6c805cf9f771374b43ae + label: The Adventures of Rocky and Bullwinkle and Friends + name: Adventures of Rocky and Bullwinkle and Friends, The + region: SNS-RZ-USA + revision: SNS-RZ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8049175767eddbc3e21ca5b94ee23fc225f834ccfab4ded30d2e981b0ef73ab6 + label: Adventures of Yogi Bear + name: Adventures of Yogi Bear + region: SNS-Y8-USA + revision: SNS-Y8-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b737de81315eef8ded7cfd5df6b37aba01d9e6e14566486db7ec83eb0c1aa85e + label: Aero Fighters + name: Aero Fighters + region: SNS-AERE-USA + revision: SNS-AERE-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: 18a553dafd4980cc2869180b05f9fdf6e980bf092cc683e498ec6373c9701c6e + label: Aero the Acro-Bat + name: Aero the Acro-Bat + region: SNS-XB-USA + revision: SNS-XB-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: fc5df5db0a96d39d3df651f63993adf0f5cb5a6b92a36211f3a05d460d92c72d + label: Aero the Acro-Bat 2 + name: Aero the Acro-Bat 2 + region: SNS-AE2E-USA + revision: SNS-AE2E-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: d5f0fbeed3774bbccbd769698fc4051487a0a5eb699790a8a094451595600f60 + label: Aerobiz + name: Aerobiz + region: SNS-AL-USA + revision: SNS-AL-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 6b6921d7aba9ba353e96e39c8d79d24eef1b84eb5c7fa54edaa83d2447dcd954 + label: Aerobiz Supersonic + name: Aerobiz Supersonic + region: SNS-AG-USA + revision: SNS-AG-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 1f5738552c51de25ffe8aa44ff396c1ab238435296f1e8f99f8cf335483c03d5 + label: Air Cavalry + name: Air Cavalry + region: SNS-ACCE-USA + revision: SNS-ACCE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 69c5805ad0494703e7d636d3d40d615d33e79bebef9d2cdb4a23b73d44c7b6f9 + label: Air Strike Patrol + name: Air Strike Patrol + region: SNS-4A-USA + revision: SNS-4A-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0099bdb56e4190f81440c8c29395ecc15d78eeabfc38a93dca4773817d6f720f + label: Al Unser Jr.'s Road to the Top + name: Al Unser Jr.'s Road to the Top + region: SNS-AUJE-USA + revision: SNS-AUJE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: aa768b8b00123717c8d49f2c6731cdbfd80ab6a54128bae7594e93f45e38a19e + label: Aladdin + name: Aladdin + region: SNS-RJ-USA + revision: SNS-RJ-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: e637b8241d55ee334a3452888df5e30d72c520dbb55c498db1a984438bab3e55 + label: Alien 3 + name: Alien 3 + region: SNS-A3-USA + revision: SNS-A3-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 05eb897d7696555790591c431c9d55a43ff9a1c12162443c17c5fcddfa5eb3c5 + label: Alien vs. Predator + name: Alien vs. Predator + region: SNS-AP-USA + revision: SNS-AP-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: dc9cefb4dd50dce2e9d626ac71d4a06306516cba4bc784c90e4a30fe4e7ff4ef + label: American Gladiators + name: American Gladiators + region: SNS-AA-USA + revision: SNS-AA-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6931a3eacb7ab3c2f2fb57ba7d59c6da56fe6c7d60484cebec9332e6caca3ae9 + label: An American Tail: Fievel Goes West + name: American Tail, An - Fievel Goes West + region: SNS-9W-USA + revision: SNS-9W-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 9abb426bac62e03e4437f5a9a8455c3000042f339125cc60ae29382ae89d8493 + label: Andre Agassi Tennis + name: Andre Agassi Tennis + region: SNS-7A-USA + revision: SNS-7A-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 626f1fe52b0df0f8ede23f0062cd842321c8dabf14aefdca12e526876ecf383a + label: Animaniacs + name: Animaniacs + region: SNS-ANCE-USA + revision: SNS-ANCE-0 + board: MJSC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 31569bef662bc438194726967970bf19f504101060763cbd649350362fb6ef2f + label: Arcade's Greatest Hits: The Atari Collection 1 + name: Arcade's Greatest Hits - The Atari Collection 1 + region: SNS-AW7E-USA + revision: SNS-AW7E-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: aac9d6f2b8408e4bbdc83ebbba755428caf8021fefbfac7220fb4c772abd9944 + label: Arcana + name: Arcana + region: SNS-RF-USA + revision: SNS-RF-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0f474dafe5a26f3dea491d18073dd490d2f1f91313a7e91086565510d38d9a09 + label: Ardy Light Foot + name: Ardy Light Foot + region: SNS-A9-USA + revision: SNS-A9-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 14d3ece30898587eda20c661a4a55ec595ba6352ca1f0bfc177542aa0eef0039 + label: Arkanoid: Doh It Again! + name: Arkanoid - Doh It Again! + region: SNS-A6-USA + revision: SNS-A6-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 55e57c5e012583ff0fafd1aee16b3f8269ee2b34fe10f10b93ba0dde72f2b78d + label: Art of Fighting + name: Art of Fighting + region: SNS-RW-USA + revision: SNS-RW-0 + board: SHVC-1J0N-01 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 2431f8dc067ba27c6c3a846929f3deac6a45aa53a9a9ac20ede8ec5ca6854ea2 + label: Axelay + name: Axelay + region: SNS-AX-USA + revision: SNS-AX-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a3213e40d7abbc25a5b909642433103b06d8f90500c930bf64093ade0329da78 + label: Ballz 3D + name: Ballz 3D + region: SNS-ABZE-USA + revision: SNS-ABZE-0 + board: SHVC-1K0N-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1B + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1B + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1B + volatile + oscillator + frequency: 7600000 + +game + sha256: 865919b25a9d241c907bcda18b380e3c704f33f4997ad44559046f0f08c4968b + label: Barbie Super Model + name: Barbie Super Model + region: SNS-8L-USA + revision: SNS-8L-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: fe1ad128313b2b9a47f89cf0d95d4c0cc2cb35a817ac5d915ee6c4d98d47d675 + label: Barkley Shut Up and Jam! + name: Barkley Shut Up and Jam! + region: SNS-U5-USA + revision: SNS-U5-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: c670e16c076f6d92ba581b78769b604e79ad567c04c647dac557f45a48c3448f + label: Bass Masters Classic + name: Bass Masters Classic + region: SNS-ABAE-USA + revision: SNS-ABAE-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: db1ac03cc8b7daaa812da239029bcf999b30b2afe1c03d51f7ae849a796617ea + label: Bass Masters Classic: Pro Edition + name: Bass Masters Classic - Pro Edition + region: SNS-A9BE-USA + revision: SNS-A9BE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: e2be173c77bd1957787be36d13334f655e14d32dad99cacb0fd5e5fc65d96fa1 + label: Bassin's Black Bass + name: Bassin's Black Bass + region: SNS-AB2E-USA + revision: SNS-AB2E-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: e36aaba64be016cabc33a2dcf88913341e2edacc722e2a1ebe04eccda2a5d6e7 + label: Batman Forever + name: Batman Forever + region: SNS-A3BE-USA + revision: SNS-A3BE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: f8d5c51f74df33edc827fbf8df7aab70160770ab0a896db6e59438ad9208cc6e + label: Batman Returns + name: Batman Returns + region: SNS-BJ-USA + revision: SNS-BJ-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 983022203546e031773db0d1af7552c489187954882843f13ff123f09064c1d3 + label: Battle Blaze + name: Battle Blaze + region: SNS-BZ-USA + revision: SNS-BZ-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d19113964c4d268e986018e256e9358cde9a23a05e6053b54c0f2d950dcdf395 + label: Battle Cars + name: Battle Cars + region: SNS-4B-USA + revision: SNS-4B-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 32f42fda0667d9435a2de84c7ce7b067bcbab1164f8f6d837992ad6cfac4f8de + label: Battle Clash + name: Battle Clash + region: SNS-BT-USA + revision: SNS-BT-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6e436020d967d35a0f7ce43e38e83a616b70696ae7d35b37cd56601cfb3822ba + label: Battle Grand Prix + name: Battle Grand Prix + region: SNS-BG-USA + revision: SNS-BG-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c7f0269498d190e4fd0f6f880a148fbe3713cd3a632083bac1e5bd18f8172371 + label: Battletoads & Double Dragon + name: Battletoads & Double Dragon + region: SNS-UL-USA + revision: SNS-UL-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b0dbd4d7e5689c32234e80b0c5362ef67c425ab72d6ddb49d1cb1133ef630ef7 + label: Battletoads in Battlemaniacs + name: Battletoads in Battlemaniacs + region: SNS-NX-USA + revision: SNS-NX-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 0b0f991da7ce4b3c2974d6adf62191ec554db9793c5def14cdfb62b7ae28cc98 + label: Bazooka Blitzkrieg + name: Bazooka Blitzkrieg + region: SNS-BY-USA + revision: SNS-BY-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: d7271ca08400bbf5ae165b0aaa6e8a8a1b266f72e6e0ae10aae529732a472f7c + label: Beauty and the Beast + name: Beauty and the Beast + region: SNS-EW-USA + revision: SNS-EW-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 15d4fc90cb202a9391718cd40b9f0384165aef03018ed932540e8f7c18b397dd + label: Beavis and Butt-Head + name: Beavis and Butt-Head + region: SNS-ABUE-USA + revision: SNS-ABUE-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 4958eda26f2419f473449017c64121caee5e49c480ffa205422e7dd45cd23e31 + label: Bebe's Kids + name: Bebe's Kids + region: SNS-6B-USA + revision: SNS-6B-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4d22279e534848012e0f1595468687742ae18cabc3fe44eeef938bc3a4dd08bf + label: Beethoven: The Ultimate Canine Caper! + name: Beethoven - The Ultimate Canine Caper! + region: SNS-2V-USA + revision: SNS-2V-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: e4e9beaeeb3e968af772d1c4c9e4c1b4dfdba4e47c0205b458e1ab3a62a96060 + label: Best of the Best: Championship Karate + name: Best of the Best - Championship Karate + region: SNS-BE-USA + revision: SNS-BE-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4cb601168c91fa0608c16a8cf2f292d991c6a5615d51861dee2f9b91c8d6bb19 + label: Big Sky Trooper + name: Big Sky Trooper + region: SNS-AB9E-USA + revision: SNS-AB9E-0 + board: SHVC-1A1M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 91ba5691dea3cdf103177ae5779110fc372fce8229cf91f263073667e7a8b5b7 + label: Biker Mice from Mars + name: Biker Mice from Mars + region: SNS-ABME-USA + revision: SNS-ABME-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6fa6b8a8804ff6544bdedf94339a86ba64ce0b6dbf059605abb1cd6f102d3483 + label: Bill Laimbeer's Combat Basketball + name: Bill Laimbeer's Combat Basketball + region: SNS-CB-USA + revision: SNS-CB-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: ec2d91e238c26a5ddf7067d104b3b3e2eaee89255377e1eb6c4df8f301300e64 + label: Bill Walsh College Football + name: Bill Walsh College Football + region: SNS-7F-USA + revision: SNS-7F-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: de1de85ad549a6aaf0431cceb47cbd07e1f6e81f9e16fd62575305e2c1f06240 + label: Bio Metal + name: Bio Metal + region: SNS-BV-USA + revision: SNS-BV-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 328c8f57e2ea371f6fd5b8a9834c56e35eb3bfe710502dd80f370739f9ccb7e1 + label: Blackthorne + name: Blackthorne + region: SNS-6Z-USA + revision: SNS-6Z-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 0d4e0d134396bd1c7254cdc1da356eb944ca14910b6690f484a75a9c3a8106e7 + label: BlaZeon: The Bio-Cyborg Challenge + name: BlaZeon - The Bio-Cyborg Challenge + region: SNS-BL-USA + revision: SNS-BL-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 99f40f06fa4dbeeea4fe67d2de5b4c1bf301bedac1958ba1c239dcaf39b0a998 + label: The Blues Brothers + name: Blues Brothers, The + region: SNS-B6-USA + revision: SNS-B6-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 9e6ebebcf14609c2a38a5f4409d0c8c859949cded70c5b6fd16fd15d9983d9d3 + label: B.O.B. + name: BOB + region: SNS-B4-USA + revision: SNS-B4-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 854d2492d1cb059749bb0904ca5f92a5eeec09167abf84f7cca4023b1819e4f0 + label: Bonkers + name: Bonkers + region: SNS-ABNE-USA + revision: SNS-ABNE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8f131182b286bd87f12cf4f00453336538ce690d0e1f0972ac0be98df4d48987 + label: Boogerman: A Pick and Flick Adventure + name: Boogerman - A Pick and Flick Adventure + region: SNS-AB4E-USA + revision: SNS-AB4E-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: e67940a2106c1507f3a8d38790f263bbbf814578ebf3dbc4e3eb6007d310793c + label: Boxing Legends of the Ring + name: Boxing Legends of the Ring + region: SNS-LL-USA + revision: SNS-LL-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f4666355e7fea434843dc6d5119673bd6c23e69b884aac0b382ff036997e52b5 + label: Brain Lord + name: Brain Lord + region: SNS-3B-USA + revision: SNS-3B-0 + board: SHVC-2J3M-11 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 9885ca148d32c4df6230642bcfa153f7e51b9559415042a831db14d07b3e6c3d + label: The Brainies + name: Brainies, The + region: SNS-B7-USA + revision: SNS-B7-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: bbde8b46c7262f9d4a5b3926a00850cb00b4f7711f6421f0adf4e2b0c847a5d6 + label: Bram Stoker's Dracula + name: Bram Stoker's Dracula + region: SNS-5D-USA + revision: SNS-5D-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 130a74e76369b0ec4d6378a014550921433f1ae1ac1dddffb51f77c9f21a818f + label: Brandish + name: Brandish + region: SNS-QF-USA + revision: SNS-QF-0 + board: SHVC-2J5M-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 044b61613ed66eae08abd5fa5dcd13b24aab11a942e3309cdff624d198c47440 + label: Brawl Brothers + name: Brawl Brothers + region: SNS-RE-USA + revision: SNS-RE-0 + board: SHVC-2A0N-10 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: aad8c9be1b7a9662256b0c3d76f5b7a273bcd497aa838232d307e9f2e80cf699 + label: BreakThru! + name: BreakThru! + region: SNS-ABXE-USA + revision: SNS-ABXE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: cbc496a7879ba78f32c51c3df4ba1a1a42f17d78d48a39ea9c709d1ad18cb8df + label: Breath of Fire + name: Breath of Fire + region: SNS-BF-USA + revision: SNS-BF-0 + board: SHVC-2A3M-11 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: fede9d4aec8c35ed11e2868c3c517bce53ee3e6af724085c92500e99e43e63de + label: Breath of Fire II + name: Breath of Fire II + region: SNS-AF2E-USA + revision: SNS-AF2E-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 99450b45ccc70a1ed387f968c8f863a3c7f6a4b86809e841c25a71e1e904ac61 + label: Brett Hull Hockey + name: Brett Hull Hockey + region: SNS-5Y-USA + revision: SNS-5Y-0 + board: SHVC-2A0N-01 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a427db4860cb5140935f263ba872fe14949c3548db644fed46b2edf3dff3d4a8 + label: Brett Hull Hockey '95 + name: Brett Hull Hockey '95 + region: SNS-ABHE-USA + revision: SNS-ABHE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: f2bc4cb460dfc5d5288065a2f529190b72e69d4e02634246086244c20f30521c + label: Bronkie the Bronchiasaurus + name: Bronkie the Bronchiasaurus + region: SNS-AB6E-USA + revision: SNS-AB6E-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ee00c57ddfa9b967d1857acb518df039ba73055bdebe78db014de0f5da262fd9 + label: Brunswick World Tournament of Champions + name: Brunswick World Tournament of Champions + region: SNS-AWUE-USA + revision: SNS-AWUE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 9e3ad5e521e759a2e2260ea8072eb3314b6fcf67a3b7247357a5de9bcb24eeaa + label: Brutal: Paws of Fury + name: Brutal - Paws of Fury + region: SNS-ABLE-USA + revision: SNS-ABLE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 2357d344af77d25dda030520ce203045fd9060f83e3b9609a228dba859d9017b + label: Bubsy II + name: Bubsy II + region: SNS-ABBE-USA + revision: SNS-ABBE-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 811cbc3287c0959e8eb242e817684d36de664ebebc5873a1fa9958693857c438 + label: Bubsy in Claws Encounters of the Furred Kind + name: Bubsy in Claws Encounters of the Furred Kind + region: SNS-UY-USA + revision: SNS-UY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 49020695a017acc3dfadea97a60e28609e583571f69c5abeb3c6b1c2db8113fa + label: Bugs Bunny: Rabbit Rampage + name: Bugs Bunny - Rabbit Rampage + region: SNS-R7-USA + revision: SNS-R7-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: ba4f31353e0e1233b574391ad97a80901d7de212e2c55d7be2af11a9a57c8225 + label: Bulls vs. Blazers and the NBA Playoffs + name: Bulls vs. Blazers and the NBA Playoffs + region: SNS-BU-USA + revision: SNS-BU-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d8b3d9267470adb8ef2d197ade44476e504c0823f8fe9d2cf2883a03aa75bd49 + label: Bulls vs. Blazers and the NBA Playoffs + name: Bulls vs. Blazers and the NBA Playoffs + region: SNS-BU-USA + revision: SNS-BU-1 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d6f6c30732dae8d00cd83628c3156acbdf26f99df701f779522e21de74dae5fe + label: Bust-a-Move + name: Bust-a-Move + region: SNS-AYKE-USA + revision: SNS-AYKE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: a8294d449bbb8370816efe0374704e8af20dbbde9c19afe969d898528bc293d0 + label: Cacoma Knight in Bizyland + name: Cacoma Knight in Bizyland + region: SNS-CC-USA + revision: SNS-CC-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 75993076c8773e7c7d555ef290be10590def40ca7b83307b8dc86556b04a6565 + label: Cal Ripken Jr. Baseball + name: Cal Ripken Jr. Baseball + region: SNS-CJ-USA + revision: SNS-CJ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 19f4a1f08aa55ff3cc8ff7ae60ffe03f0e436e8d8901455f1311f2276497a492 + label: California Games II + name: California Games II + region: SNS-C2-USA + revision: SNS-C2-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6cdec3cb9c91aa23feb13005f874bda580c2f548302874491a31951031c9dbbd + label: Cannondale Cup + name: Cannondale Cup + region: SNS-ASCE-USA + revision: SNS-ASCE-0 + board: SHVC-2A1M-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 9590110a990e90f525d5c8d70fc2a3da10879378003173b6761afb8bf042ee0d + label: Capcom's MVP Football + name: Capcom's MVP Football + region: SNS-NL-USA + revision: SNS-NL-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: fd5761f9dd1f2b87ad11df6085046d0dfcdc3a79139263e47b0cff707966ba51 + label: Capcom's Soccer Shootout + name: Capcom's Soccer Shootout + region: SNS-JL-USA + revision: SNS-JL-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 2a117951adcfbc4298763673a834d502c3f7a3964db1e59650f113c07bb831fb + label: Captain America and The Avengers + name: Captain America and The Avengers + region: SNS-6A-USA + revision: SNS-6A-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d9b7f9356be0780f0037093a86ef8450f15e569cbd3680073d1cd345dfadb709 + label: Captain Commando + name: Captain Commando + region: SNS-QM-USA + revision: SNS-QM-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 8784614896e2b3e8d98c8166613ca5d2329643795a4dc107791c58c6c51e1268 + label: Captain Novolin + name: Captain Novolin + region: SNS-CP-USA + revision: SNS-CP-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: ee5fc27dd19a2ecb3c3c7c73d558a18ffd5ff365710c18b88150e277f08d587e + label: Carrier Aces + name: Carrier Aces + region: SNS-ACAE-USA + revision: SNS-ACAE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: b9b982cd8f91c51089d49b550f11882b1ee785ebddcb7355cfc465916d61a042 + label: Casper + name: Casper + region: SNS-AXCE-USA + revision: SNS-AXCE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 367725a149a471411e4f72ad77603b61fb101c9cab4521be5647e13708cc97ba + label: Castlevania: Dracula X + name: Castlevania - Dracula X + region: SNS-ADZE-USA + revision: SNS-ADZE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 32008c429eafe7eb59aff7a89f77e1a267f02f9061ff8830ade7b99081e27f7c + label: Champions World Class Soccer + name: Champions World Class Soccer + region: SNS-8W-USA + revision: SNS-8W-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e6c4f468b39f2dea3436b63758db8ac9b29731357b982ec373334a36f202623f + label: Championship Pool + name: Championship Pool + region: SNS-5P-USA + revision: SNS-5P-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: fdd763dffc6fb38975d4c6d6e3123f9738122781b7d13e1fc7f9820464cbaeb5 + label: Championship Soccer '94 + name: Championship Soccer '94 + region: SNS-67-USA + revision: SNS-67-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: aa69d4e19c2eb206fe88eba65994c830256c220e5506f59824aefa0a75dd44d5 + label: Chavez + name: Chavez + region: SNS-ZV-USA + revision: SNS-ZV-0 + board: SHVC-1A1M-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 39de64101cf7f25863ce55e03a27d13422ea572ee996746578b5936fea80228b + label: Chavez II + name: Chavez II + region: SNS-AC2E-USA + revision: SNS-AC2E-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ee0e51d922d1cf8abe3dfc6b0d84a988a6635dc96b2a96962007c41aaa542774 + label: The Chessmaster + name: Chessmaster, The + region: SNS-CH-USA + revision: SNS-CH-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: c7e7df8932bf0056aa530f3dc3c913c1171a359af4c197094c2b972946dc6051 + label: Chester Cheetah: Too Cool to Fool + name: Chester Cheetah - Too Cool to Fool + region: SNS-CE-USA + revision: SNS-CE-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 21a2aa488cb8140ca318f7d1f513103d14e758181aa336a594097d32ba0a7587 + label: Chester Cheetah: Wild, Wild Quest + name: Chester Cheetah - Wild, Wild Quest + region: SNS-7C-USA + revision: SNS-7C-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: 9a064b67f522b75b82d0857519c0e33b4dbbe494c2ef79a44fdc913d605d0b26 + label: Choplifter III + name: Choplifter III + region: SNS-3C-USA + revision: SNS-3C-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 06d1c2b06b716052c5596aaa0c2e5632a027fee1a9a28439e509f813c30829a9 + label: Chrono Trigger + name: Chrono Trigger + region: SNS-ACTE-USA + revision: SNS-ACTE-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 63ab79e86ea13e2cf9bb67aec971febb68450db9865b00b5f412610653822393 + label: Chuck Rock + name: Chuck Rock + region: SNS-CK-USA + revision: SNS-CK-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8b7525b2aa30cbea9e3deee601dd26e0100b8169c1948f19866be15cae0ac00d + label: Clay Fighter + name: Clay Fighter + region: SNS-8C-USA + revision: SNS-8C-0 + board: SHVC-1J0N-01 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: ea52b39a8e1ea15bfad6b92883c9a5fe744cecd7c0e175aa3bd40280cf7a966e + label: Clay Fighter: Tournament Edition + name: Clay Fighter - Tournament Edition + region: SNS-7E-USA + revision: SNS-7E-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 2d40c86bc19d85555bf2672acf515b04dbf56a6a59b29ad503e672310b0fae3b + label: Clay Fighter 2: Judgment Clay + name: Clay Fighter 2 - Judgment Clay + region: SNS-ACZE-USA + revision: SNS-ACZE-0 + board: SHVC-BJ0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 6d9cd7f0cda3c0a82ed3f6a92cbbba4fe8365438e0a7867ad1cae2044d1738eb + label: Claymates + name: Claymates + region: SNS-Y5-USA + revision: SNS-Y5-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e5980b990605a9c91fa89101c440b2ec9993329296ba09a9538042d724a080fb + label: Cliffhanger + name: Cliffhanger + region: SNS-6C-USA + revision: SNS-6C-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 03f6c69aef92d36b5ea25a6023368da0e1da9fa160e8316ebd533d4f358ffacf + label: Clue + name: Clue + region: SNS-CL-USA + revision: SNS-CL-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 5536cea2da39f2572abe3b0fcf71f8fcd981376b470b174969772aae4a7a1845 + label: College Football USA '97 + name: College Football USA '97 + region: SNS-AC7E-USA + revision: SNS-AC7E-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: b0be35a0d5e500f4fffca5f2940e0ec52c81ce99dacd773c3ca9cf92f592d943 + label: College Slam + name: College Slam + region: SNS-ANYE-USA + revision: SNS-ANYE-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: c88a882ad72dfa07a9b1eb8a2183aa10057d60877a02edf90cf2cd8c78abe65e + label: The Combatribes + name: Combatribes, The + region: SNS-CR-USA + revision: SNS-CR-0 + board: SHVC-2A0N-01 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 26e09f5bc2bde28d57aeca0bf5be7f7fb8e3b3887af975bcbf2e6f29b07df56f + label: Congo's Caper + name: Congo's Caper + region: SNS-J2-USA + revision: SNS-J2-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: a93ea87fc835c530b5135c5294433d15eef6dbf656144b387e89ac19cf864996 + label: Contra III: The Alien Wars + name: Contra III - The Alien Wars + region: SNS-CS-USA + revision: SNS-CS-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c7d622391f7699fb0dc6367e141c894e700cc9bd8abca69f36785e7bc2f42a49 + label: Cool Spot + name: Cool Spot + region: SNS-C8-USA + revision: SNS-C8-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 9674cc269d89a52d1719a487b44acf004fb777cbd58d76b19a2cd25749728215 + label: Cool World + name: Cool World + region: SNS-CD-USA + revision: SNS-CD-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 7c722f9941957630467c1784d0eb3f92fbfc0a2a1da3c8f5c27f593eca2a5a04 + label: CutThroat Island + name: CutThroat Island + region: SNS-AC8E-USA + revision: SNS-AC8E-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: c4ae2797fac2586b8640064be6398f2b4f2b3158a07f26c66912b29f7fd197de + label: Cyber Spin + name: Cyber Spin + region: SNS-CF-USA + revision: SNS-CF-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: ad31b94ce928ecff605e2b89082154671691509e95d38370ed381437f2c36698 + label: Cybernator + name: Cybernator + region: SNS-AV-USA + revision: SNS-AV-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 337e643d3e63915de06429992f306e8d2b73aed6849b795f9c855c2d03c18180 + label: D-Force + name: D-Force + region: SNS-DF-USA + revision: SNS-DF-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4068add412571bd85adac32dff9835e4a4886077d752adb104fee3908e42b7ef + label: Daffy Duck: The Marvin Missions + name: Daffy Duck - The Marvin Missions + region: SNS-YF-USA + revision: SNS-YF-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ceb470157576eac3b8b8c16e8ab6b59672409681ffb4232e4ec39dd0cb37ef91 + label: Darius Twin + name: Darius Twin + region: SNS-DT-USA + revision: SNS-DT-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e6efb6361af04963f22c772f879a466543f56b3b6a084204fef2dcb4659d82d9 + label: David Crane's Amazing Tennis + name: David Crane's Amazing Tennis + region: SNS-ZT-USA + revision: SNS-ZT-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 300c1937e4b68108302e9b0f49974d1ec6b6c45dd8da69dddc19443f9562ecf4 + label: The Death and Return of Superman + name: Death and Return of Superman, The + region: SNS-9D-USA + revision: SNS-9D-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 752d24fab240f4dd1dfbfea5ec83438998316806ad44488bf8c84430ca5a2cd0 + label: Demolition Man + name: Demolition Man + region: SNS-AD6E-USA + revision: SNS-AD6E-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 18d40a807d5f88c5b6a1ad849eec7e0f189225d9a1586037c850f6680b5844de + label: Demon's Crest + name: Demon's Crest + region: SNS-3Z-USA + revision: SNS-3Z-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a362033d0d7e754d79202b255679186ad799b9e784719614b913ec8c9857ae33 + label: Dennis the Menace + name: Dennis the Menace + region: SNS-4D-USA + revision: SNS-4D-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 606abf536440173ae36466db360c7db6b474beb7a105c8a62bc74a54cbe1c38b + label: Desert Strike: Return to the Gulf + name: Desert Strike - Return to the Gulf + region: SNS-RG-USA + revision: SNS-RG-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 9c4721339a197185d61e0697ea0149db143a27ddb2f57ebd398f18bcf4d7724b + label: Dig & Spike Volleyball + name: Dig & Spike Volleyball + region: SNS-VH-USA + revision: SNS-VH-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 7dbfc44d28a46e6d399628e43086aa9fd0b2abeda4c108751a5ad91c102c3aaf + label: DinoCity + name: DinoCity + region: SNS-DW-USA + revision: SNS-DW-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c5474de3592e2a99aac0e5511516658f9f0b50167c754a018409842ec35bcd45 + label: Dirt Trax FX + name: Dirt Trax FX + region: SNS-AF9E-USA + revision: SNS-AF9E-0 + board: SHVC-1CA0N6S-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x10000 + content: Save + volatile + oscillator + frequency: 21440000 + +game + sha256: fa8cacf5bbfc39ee6bbaa557adf89133d60d42f6cf9e1db30d5a36a469f74d15 + label: Donkey Kong Country + name: Donkey Kong Country + region: SNS-8X-USA + revision: SNS-8X-0 + board: SHVC-1J1M-11 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: df2644d435330192a13768cc1f79c5aa3084a64217a5250c6dd4ffdbe2175be4 + label: Donkey Kong Country + name: Donkey Kong Country + region: SNS-8X-USA + revision: SNS-8X-1 + board: SHVC-1J1M-11 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 628147468c3539283197f58f03b94df49758a332831857481ea9cc31645f0527 + label: Donkey Kong Country + name: Donkey Kong Country + region: SNS-8X-USA + revision: SNS-8X-2 + board: SHVC-1J1M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 07ff03fa8c8e31d2f8277ef2a9785022edebf7f79b694c66a00c66d8e563bce5 + label: Donkey Kong Country: Competition Cartridge + name: Donkey Kong Country - Competition Cartridge + region: SNS-8E-USA + revision: SNS-8E-0 + board: SHVC-1J1M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 35421a9af9dd011b40b91f792192af9f99c93201d8d394026bdfb42cbf2d8633 + label: Donkey Kong Country 2: Diddy's Kong Quest + name: Donkey Kong Country 2 - Diddy's Kong Quest + region: SNS-ADNE-USA + revision: SNS-ADNE-0 + board: SHVC-1J1M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: b79c2bb86f6fc76e1fc61c62fc16d51c664c381e58bc2933be643bbc4d8b610c + label: Donkey Kong Country 2: Diddy's Kong Quest + name: Donkey Kong Country 2 - Diddy's Kong Quest + region: SNS-ADNE-USA + revision: SNS-ADNE-1 + board: SHVC-BJ1M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 2277a2d8dddb01fe5cb0ae9a0fa225d42b3a11adccaeafa18e3c339b3794a32b + label: Donkey Kong Country 3: Dixie Kong's Double Trouble + name: Donkey Kong Country 3 - Dixie Kong's Double Trouble + region: SNS-A3CE-USA + revision: SNS-A3CE-0 + board: SHVC-1J1M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: d45e26eb10c323ecd480e5f2326b223e29264c3adde67f48f0d2791128e519e8 + label: Doom + name: Doom + region: SNS-AD8E-USA + revision: SNS-AD8E-0 + board: SHVC-1CB0N7S-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x10000 + content: Save + volatile + oscillator + frequency: 21440000 + +game + sha256: bb915b286b33842e39e9022366169233a4041515c7ecc60ac428420b28e48dd5 + label: Doomsday Warrior + name: Doomsday Warrior + region: SNS-DM-USA + revision: SNS-DM-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b32aa9cbf8f6baacc84f6418fa6fbc33b9ce71458fecc91275aafdbf6f743a99 + label: Double Dragon V: The Shadow Falls + name: Double Dragon V - The Shadow Falls + region: SNS-5E-USA + revision: SNS-5E-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: d98d7da1e7636e067563e2e480d7dfbc013b7e9bdf1329fd61c5cacac0293e1d + label: Dragon: The Bruce Lee Story + name: Dragon - The Bruce Lee Story + region: SNS-AD5E-USA + revision: SNS-AD5E-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a3b1cae3fe55fe52c035ab122e7f850640b0935524496d45b1915ca3c8a934f4 + label: Dragon View + name: Dragon View + region: SNS-ADVE-USA + revision: SNS-ADVE-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 49a1f9f5e6084b3daa1b13ab5a37ebe8bd3cf20e1c7429fbf722298092893e81 + label: Dragon's Lair + name: Dragon's Lair + region: SNS-DI-USA + revision: SNS-DI-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 74910ce01d19d25cb97a243a51f21c3d522f02fb116682f60440da3292bb14f7 + label: Drakkhen + name: Drakkhen + region: SNS-DK-USA + revision: SNS-DK-0 + board: SHVC-1A3B-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 1a79d51a2ad7dd4848205a07ff8e5d873b155dc420de5e52158c9bab935e05c3 + label: Dream T.V. + name: Dream TV + region: SNS-VE-USA + revision: SNS-VE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 03d25227fb88899d0f3234c4a3f76f1dbe8d582cb6429454fd6f1c4cf14d5c6e + label: Dungeon Master + name: Dungeon Master + region: SNS-V2-USA + revision: SNS-V2-0 + board: SHVC-1B5B-02 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP2 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP2 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP2 + volatile + oscillator + frequency: 7600000 + +game + sha256: 0408e3d9f2259044344a3bfbd7a7ca3c3427f82108fbecd6e5c4c41e80cd303b + label: Earth Defense Force + name: Earth Defense Force + region: SNS-ED-USA + revision: SNS-ED-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a8fe2226728002786d68c27ddddf0b90a894db52e4dfe268fdf72a68cae5f02e + label: EarthBound + name: EarthBound + region: SNS-MB-USA + revision: SNS-MB-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 4579e437279f79eedd6b9cf648a814df2ab2c83d937a1bcec1578d28965fb9a0 + label: Earthworm Jim + name: Earthworm Jim + region: SNS-AEJE-USA + revision: SNS-AEJE-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 10eadaab168707829418702386e1bcedd2619d9bbefc37cf31c4118313bcf6de + label: Earthworm Jim 2 + name: Earthworm Jim 2 + region: SNS-A2EE-USA + revision: SNS-A2EE-0 + board: MJSC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 5d658b63d35e2e0baf48ae3bb04ea5e1553855b34bb39fc2c7ca41fbd3894d52 + label: Eek! The Cat + name: Eek! The Cat + region: SNS-E7-USA + revision: SNS-E7-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b296054effb1948039635044bc905fdf8ff53e7a73038fd5d8436a913ea5ad8a + label: Elite Soccer + name: Elite Soccer + region: SNS-L7-USA + revision: SNS-L7-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f14e30ee452ec930a6d08094094b287d0c40c8108f2017c418015242987649b3 + label: Emmitt Smith Football + name: Emmitt Smith Football + region: SNS-AESE-USA + revision: SNS-AESE-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: cfd666f0bbabec59613d9fe189db7d0a060a78047bc084c0c365840769047bf2 + label: Equinox + name: Equinox + region: SNS-EX-USA + revision: SNS-EX-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: c702c3860e9dffdaa1917d013ecbcefdd2c47f89726992f7f810d879772dcc4d + label: ESPN Baseball Tonight + name: ESPN Baseball Tonight + region: SNS-EV-USA + revision: SNS-EV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 3326061160ad12c7aef5176544ec1c8ef2f534a51960ca882dbc7fcb9b1a7384 + label: ESPN National Hockey Night + name: ESPN National Hockey Night + region: SNS-AEHE-USA + revision: SNS-AEHE-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 7b2fdab972e393395f5379d7fb13e40464db152f6acf58b2d2a6a18f81cefecb + label: ESPN Speed World + name: ESPN Speed World + region: SNS-ASWE-USA + revision: SNS-ASWE-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: faf595b4671f005fa9367ba3fcd30dbff371bc7a9ca8bbfbc0ebfcc5826b60f8 + label: ESPN Sunday Night NFL + name: ESPN Sunday Night NFL + region: SNS-ASNE-USA + revision: SNS-ASNE-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 8481e47381bd98c27b9782b5727a5d5f0976fbb3aa3df25c2c42aa37e0586815 + label: E.V.O.: Search for Eden + name: EVO - Search for Eden + region: SNS-46-USA + revision: SNS-46-0 + board: SHVC-2A3M-01#A + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: f2455253db316b6ccd0c5c686d1f1e2d94cd5e37534e70a3a07a409120d58df6 + label: Exertainment Mountain Bike Rally + name: Exertainment Mountain Bike Rally + region: SNS-9X-USA + revision: SNS-9X-0 + board: SHVC-1A1M-11 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: a0521f50b0d0bff6666bfb712498476eb8d5974ef38caf157e2f67cbce5475bb + label: Exertainment Mountain Bike Rally + Speed Racer + name: Exertainment Mountain Bike Rally + Speed Racer + region: SNS-ALFE-USA + revision: SNS-ALFE-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 1576066e0cb771a91caf79e7d4f6dc00eb0daa47f0786f1604b32537429a7f45 + label: Extra Innings + name: Extra Innings + region: SNS-GL-USA + revision: SNS-GL-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: bf16c3c867c58e2ab061c70de9295b6930d63f29f81cc986f5ecae03e0ad18d2 + label: F-Zero + name: F-Zero + region: SNS-FZ-USA + revision: SNS-FZ-0 + board: SHVC-1A1B-04 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 55c33efb514568c9946c4b866c160ed190fe436faee265ee2fb107f7fe94d524 + label: F1 Pole Position + name: F1 Pole Position + region: SNS-6P-USA + revision: SNS-6P-0 + board: SHVC-1A1M-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 1d38e3af9e3a6409e93f4705b68c42558f558c68f3e83ef2a40e46cf560b26cc + label: F1 Race of Champions + name: F1 Race of Champions + region: SNS-EH-USA + revision: SNS-EH-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 3ae7bfd38a3dc273f4d387af3b15621beefebf5056731af06e3822f5e57db5c5 + label: F1 Race of Champions II + name: F1 Race of Champions II + region: SNS-E2-USA + revision: SNS-E2-0 + board: SHVC-1DS0B-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: ROM + size: 0xc000 + content: Program + manufacturer: NEC + architecture: uPD96050 + identifier: ST010 + memory + type: ROM + size: 0x1000 + content: Data + manufacturer: NEC + architecture: uPD96050 + identifier: ST010 + memory + type: RAM + size: 0x1000 + content: Data + manufacturer: NEC + architecture: uPD96050 + identifier: ST010 + oscillator + frequency: 11000000 + +game + sha256: d689392884df91c2bb84b1411a96f3919b6c9cc8a583dff901a98f0d86d31c30 + label: Faceball 2000 + name: Faceball 2000 + region: SNS-2F-USA + revision: SNS-2F-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 2891f1eab285133364ecc379a5c9e1d0026d60f425f1a458d149014f386cfa50 + label: Family Dog + name: Family Dog + region: SNS-D8-USA + revision: SNS-D8-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4f43ce12e1d8cd195468d7048494ad2930721e5bf9e69bfd86eeee707ffc634b + label: Family Feud + name: Family Feud + region: SNS-FN-USA + revision: SNS-FN-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: d5c651d726dd957b80d03ab6fdbed4cdd26a3cccf5ec9d91af67251b3ec26a3c + label: Family Feud + name: Family Feud + region: SNS-FN-USA + revision: SNS-FN-1 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: c92f389d25870aada3002775838ec9f69a988120c0238af885fd08d46bd94930 + label: Fatal Fury + name: Fatal Fury + region: SNS-GN-USA + revision: SNS-GN-0 + board: SHVC-2A0N-01 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: a0c554d46034caef231c36dd6849828ca39703678fb7fdd15a11f292b93bcd6b + label: Fatal Fury 2 + name: Fatal Fury 2 + region: SNS-DJ-USA + revision: SNS-DJ-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: 410e90db3d38507ccc85ad3bca6b27a080123fd5160e82b5de4d914d4b6d6e61 + label: Fatal Fury Special + name: Fatal Fury Special + region: SNS-3R-USA + revision: SNS-3R-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 1f454f2ce16fb96ba0b950ceaa098fe6eabed9e4a0e512252debad8fa6bc5ef5 + label: FIFA International Soccer + name: FIFA International Soccer + region: SNS-84-USA + revision: SNS-84-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 26ff143c2f1a4a16ca838cc4b5555e39bbe7208515dca8f1c4b1a00dec61cf09 + label: FIFA Soccer '96 + name: FIFA Soccer '96 + region: SNS-A6SE-USA + revision: SNS-A6SE-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: c514f855ad377242582952eee95513a2152ebbf6bb5b06bdf9f031fc5ac748ab + label: FIFA Soccer '97 + name: FIFA Soccer '97 + region: SNS-A7IE-USA + revision: SNS-A7IE-0 + board: EA-1A3M-30 + memory + type: ROM + size: 0x1e0000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: b9594d588816ae570ea5fea14577ed47de4db9ac9a40a116c84e0ad7a2ce58f8 + label: Fighter's History + name: Fighter's History + region: SNS-YH-USA + revision: SNS-YH-1 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: 6151389f33ce2e53db3cd99592440c0020f5f4668f581ce3bd615bc92077f255 + label: Final Fantasy: Mystic Quest + name: Final Fantasy - Mystic Quest + region: SNS-MQ-USA + revision: SNS-MQ-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 680535dc1c4196c53b40dc9c2c9bc159a77802ab8d4b474bef5dc0281c15ad06 + label: Final Fantasy II + name: Final Fantasy II + region: SNS-F4-USA + revision: SNS-F4-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0f51b4fca41b7fd509e4b8f9d543151f68efa5e97b08493e4b2a0c06f5d8d5e2 + label: Final Fantasy III + name: Final Fantasy III + region: SNS-F6-USA + revision: SNS-F6-0 + board: SHVC-BJ3M-10 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 60cca2592d0756b8c4c7a0a254fafa5ac47aa752521fd1f77dcbf4b6ee1bee90 + label: Final Fight + name: Final Fight + region: SNS-FT-USA + revision: SNS-FT-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 744d1a16c3f99970283597ae8f43b7c3621c5f995c4566ef24b8d70b0692007b + label: Final Fight 2 + name: Final Fight 2 + region: SNS-F2-USA + revision: SNS-F2-0 + board: SHVC-2A0N-01 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: f9dac709b2c2859f828103a0dd980716817e2bde3b9d7e2fdea36e9bb9bed7f2 + label: Final Fight 3 + name: Final Fight 3 + region: SNS-AFZE-USA + revision: SNS-AFZE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 8c47f9dc79748c0ae6c648f8480614d22eaefade065612ad1fe749fc3db4d1bc + label: Final Fight Guy + name: Final Fight Guy + region: SNS-FY-USA + revision: SNS-FY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 003dba0193acc5336840307194643ca3b1f848dcfc77580b4e17c605105b27f5 + label: Firepower 2000 + name: Firepower 2000 + region: SNS-FW-USA + revision: SNS-FW-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6f32355bef68d4ad58822f50074b46bcc9a68357cd2c6a5470c96bf5344f84d8 + label: Firestriker + name: Firestriker + region: SNS-3S-USA + revision: SNS-3S-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4c1354337efa788169387458fa6bdbcf4be0c98369920af2bd876ad98d29070f + label: First Samurai + name: First Samurai + region: SNS-FK-USA + revision: SNS-FK-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 064a880a8dfcf576f74ae8a17c3ec7b0a27e8cb0300a5e5959452fcc30422f14 + label: Flashback: The Quest for Identity + name: Flashback - The Quest for Identity + region: SNS-5F-USA + revision: SNS-5F-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: ff09d72d6241b331dc429d1cf27c04c26546f23312a22c7a14e6a4bf41ed1069 + label: The Flintstones + name: Flintstones, The + region: SNS-AFNE-USA + revision: SNS-AFNE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 3d5bbc06e7e9797d937c803610c40b262c14c3f0a39e8048dd6b0b052a040fc1 + label: The Flintstones: The Treasure of Sierra Madrock + name: Flintstones, The - The Treasure of Sierra Madrock + region: SNS-9F-USA + revision: SNS-9F-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 40b55ee44bc6f1c83daac3e1806dcf7ecd5b35280cdb6a63c7a5e52fbd2115e6 + label: Football Fury + name: Football Fury + region: SNS-UF-USA + revision: SNS-UF-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: bc6b0344a434644c391ac69a53c7720c51e2d3c5c082b8d78598ae4df100c464 + label: Foreman For Real + name: Foreman For Real + region: SNS-AFEE-USA + revision: SNS-AFEE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: ba93721bdb0f19506e722bc580d0b4dad6e8648dddbc52e3ce45dd75ea165f72 + label: Frank Thomas' Big Hurt Baseball + name: Frank Thomas' Big Hurt Baseball + region: SNS-AFKE-USA + revision: SNS-AFKE-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 25b380f529f5a9295df7c0adcc5213d67f131f552d078a3d8f545f988047c90a + label: Frantic Flea + name: Frantic Flea + region: SNS-AF8E-USA + revision: SNS-AF8E-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 1ce72767795f41049a1f4d2829e837a8885eb91e1c14faf1ca62d05839ebe3c9 + label: Frogger + name: Frogger + region: SNS-AF7E-USA + revision: SNS-AF7E-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 3db8a496a49d47b1ac2a893feaf682722765b2cde63c22af3aa68212dcfa975f + label: Full Throttle: All-American Racing + name: Full Throttle - All-American Racing + region: SNS-AFTE-USA + revision: SNS-AFTE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: dcceb5be536c9b91bf34f65e7fcec4b55a78af0192323cf86f3b9555072037ee + label: fun 'n games + name: Fun & Games + region: SNS-7N-USA + revision: SNS-7N-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 78e2b8210d8dd8776ee23153eb3dce2cbf7d8ddc3e8a5d25b580428f59d98bdb + label: Gemfire + name: Gemfire + region: SNS-RL-USA + revision: SNS-RL-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 05e9404bfe0689e484a34991f22712c9da718cf000b0f748378af5758b654a3d + label: Genghis Khan II: Clan of the Gray Wolf + name: Genghis Khan II - Clan of the Gray Wolf + region: SNS-6G-USA + revision: SNS-6G-0 + board: SHVC-1J3B-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: fc993c122079b94ebc9b9452b46a55d5ddcd3715a4b97af795222b264827e90f + label: George Foreman's KO Boxing + name: George Foreman's KO Boxing + region: SNS-GK-USA + revision: SNS-GK-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a4ceb31b82ea532e6eb640fa2eda61625758e72251efa5f0ae9a984f4a98a8a0 + label: Ghoul Patrol + name: Ghoul Patrol + region: SNS-AGJE-USA + revision: SNS-AGJE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: feff03cfa195512ad87dc876012d70520cf192e2874c518b6dbdf3d876ea60c4 + label: Goal! + name: Goal! + region: SNS-SU-USA + revision: SNS-SU-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 8796ca4de3aeffd3a494fe28e7d7e2aeb220ca652b43684f29e2cc94f02c20c4 + label: Gods + name: Gods + region: SNS-GZ-USA + revision: SNS-GZ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 2bb368c47189ce813ad716eef16c01cd47685cb98e2c1cb35fa6f0173c97dd7c + label: Goof Troop + name: Goof Troop + region: SNS-G6-USA + revision: SNS-G6-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 342ddf438aec3f0696de8f2cd74bb7f48a956f488f1246eeccaff5ef246ca50b + label: GP-1 + name: GP-1 + region: SNS-G7-USA + revision: SNS-G7-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 2e478569949c3935529c956448947ef90bae64abaf3d523bd89e7f4cf5e83702 + label: GP-1: Part II + name: GP-1 - Part II + region: SNS-AGRE-USA + revision: SNS-AGRE-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 93da752a0c76167d0907efa832367e5d14aab8e835b864f345c386071a9af718 + label: Gradius III + name: Gradius III + region: SNS-G3-USA + revision: SNS-G3-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: b5492aea296ee4bfcd2c677fbec5153fd4c4db758c835b372ef750cf2399649b + label: The Great Circus Mystery: Starring Micky & Minnie + name: Great Circus Mystery, The - Starring Micky & Minnie + region: SNS-4C-USA + revision: SNS-4C-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 3ab1ca181000f10cb7c2ae8dc9fafeecd5d77314ee92960e26dff0d6a1fd11ee + label: The Great Waldo Search + name: Great Waldo Search, The + region: SNS-GW-USA + revision: SNS-GW-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: f921297c361f16ad3f1257e91829638fc795f9323172015d7237ed648c8f7515 + label: GunForce + name: GunForce + region: SNS-GU-USA + revision: SNS-GU-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 5a6deb5617e86a9f4b981031e939510e30c5c8ad047f5f012e40442113fd28c2 + label: Hagane + name: Hagane + region: SNS-AHGE-USA + revision: SNS-AHGE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: de1cf1512e48473b03adb87b7504f394e8b330b346bac24044f833d83609799a + label: Hal's Hole in One Golf + name: Hal's Hole in One Golf + region: SNS-JO-USA + revision: SNS-JO-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 21cd6d749674c55342f5f1a895642d4b58b9bd7eb211f5df3a35dc6c2f5d4501 + label: Hammer Lock Wrestling + name: Hammer Lock Wrestling + region: SNS-LJ-USA + revision: SNS-LJ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 4fb9b010e4b1dc166ab7995a6f9491114063b68aac344004b1edfc555951d959 + label: Hard Ball III + name: Hard Ball III + region: SNS-3Y-USA + revision: SNS-3Y-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 6e2a02a8944c19db3da76d2646f232fbe3ed039bc7d44cc03910814fa77a7acf + label: Harley's Humongous Adventure + name: Harley's Humongous Adventure + region: SNS-HV-USA + revision: SNS-HV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 73a3aa87ddd5ce5df5ba51292316f42b6e128280179b0a1b11b4dcddc17d4163 + label: Harvest Moon + name: Harvest Moon + region: SNS-AYWE-USA + revision: SNS-AYWE-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 9ff6bbcce7dc1f3bded96860a86698cab161d13ee167c57b5b114ac646eea0ea + label: Head-On Soccer + name: Head-On Soccer + region: SNS-AVSE-USA + revision: SNS-AVSE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: fa418618787145291201b3d9247048b2d7dfba37f6556dcb1d40db499124dd60 + label: Hit the Ice + name: Hit the Ice + region: SNS-HC-USA + revision: SNS-HC-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 7c34908526db2a634216fab0276c42a8e4e22d59c728cd586200142a12dd2c2c + label: Home Alone + name: Home Alone + region: SNS-HA-USA + revision: SNS-HA-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 27eaccb4eea93832639565a664bf3561ed5a11ac025d377a3f33262d851c1b2b + label: Home Alone 2: Lost in New York + name: Home Alone 2 - Lost in New York + region: SNS-HN-USA + revision: SNS-HN-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 48a3ac52e2c9128abc2dc60e07817a51898e8a93be0d51d6f541a8635263a089 + label: Home Improvement + name: Home Improvement + region: SNS-AHIE-USA + revision: SNS-AHIE-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: acad4c594f156e0f30dec2532b35fcb3bab800e08263377634e2d96dfd055f3e + label: Hook + name: Hook + region: SNS-HO-USA + revision: SNS-HO-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a03528344d40bf800cdbde2dd240b30442cec7aea6026fbbe312a7c36bf0f74a + label: The Hunt for Red October + name: Hunt for Red October, The + region: SNS-RO-USA + revision: SNS-RO-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 41cc900d2461a8dc4706640e493885ddf85db04d8dffceebf7a0ed89cc983d8d + label: Hurricanes + name: Hurricanes + region: SNS-AHUE-USA + revision: SNS-AHUE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: db57f45e113127b7148c1b0add2da888e16e16b3e46749f95973b3ef497ae90b + label: Hyper V-Ball + name: Hyper V-Ball + region: SNS-HQ-USA + revision: SNS-HQ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f57c49cc3e4c5e34929e12658db0de8794265c517e42f3c518bb1466ba46f14a + label: Hyper Zone + name: Hyper Zone + region: SNS-HZ-USA + revision: SNS-HZ-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: fa143784fd20721d61101920e6aae9b7f5012b8157b1ce0c7ea83ea6c875d84d + label: The Ignition Factor + name: Ignition Factor, The + region: SNS-AIFE-USA + revision: SNS-AIFE-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 32adc048fd89228a4310c03df243e83de7d436cdb2460b4cc83ade20d359b2bd + label: Illusion of Gaia + name: Illusion of Gaia + region: SNS-JG-USA + revision: SNS-JG-0 + board: SHVC-1J3B-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 4dc2b5de98e9109583d9b61b38d26a8216af4dba246ef71350122213630562d0 + label: Imperium + name: Imperium + region: SNS-DN-USA + revision: SNS-DN-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c41150c0e84055801377fb7cb273cc51ca442b269ca6287cadf514f553e34750 + label: Incantation + name: Incantation + region: SNS-AIYE-USA + revision: SNS-AIYE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 0415adfe80977485f84cdffaaa79f18c91c004c7dba202b4cf9a94eb11adeada + label: The Incredible Crash Dummies + name: Incredible Crash Dummies, The + region: SNS-C7-USA + revision: SNS-C7-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8d170628d2d2fdf142bb82ad80e908bba54c45fa33241c779b8eafaf1b21171f + label: The Incredible Hulk + name: Incredible Hulk, The + region: SNS-8U-USA + revision: SNS-8U-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: cf611b40f9570e8fcfdc21db623965da62561e8ca82ded59e432ba6fb0bfb562 + label: Indiana Jones' Greatest Adventures + name: Indiana Jones' Greatest Adventures + region: SNS-AIJE-USA + revision: SNS-AIJE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 5e5cac64fdcf09a52a9c0ab1ebc8bd309dcb1256faf1405284443569b5284fe5 + label: Inindo: Way of the Ninja + name: Inindo - Way of the Ninja + region: SNS-IN-USA + revision: SNS-IN-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: c7b1706a0ee96f3e0d65cd043c05966bfe3d5c57d08bbd2df3118817424adf82 + label: Inspector Gadget + name: Inspector Gadget + region: SNS-5G-USA + revision: SNS-5G-0 + board: SHVC-YJ0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6443fecebcdc2ff7061a40432f3ad1db6dfd354909a5f306972cf6afa122752c + label: International Superstar Soccer + name: International Superstar Soccer + region: SNS-3U-USA + revision: SNS-3U-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d2fe66c1ce66c65ce14e478c94be2e616f9e2cad374b5783a6a64d3c1a99cfa9 + label: International Superstar Soccer Deluxe + name: International Superstar Soccer Deluxe + region: SNS-AWJE-USA + revision: SNS-AWJE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 4e8044b1e7a779685d6751351eef2391272ac8b2bd909edeecfc3d3c5a594bef + label: International Tennis Tour + name: International Tennis Tour + region: SNS-IT-USA + revision: SNS-IT-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8304d8bc55aa9e64bdd144d384f4b185af2426e7d64888c6c23dd41366a53981 + label: The Irem Skins Game + name: Irem Skins Game, The + region: SNS-MT-USA + revision: SNS-MT-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 39bfe828571cdb23e7c85c23cf5b175979dcc2042c5841add58f5ae6492168a9 + label: The Itchy & Scratchy Game + name: Itchy & Scratchy Game, The + region: SNS-AISE-USA + revision: SNS-AISE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 183af7d642b55d52cd594786ec2f031d033cc6c8c1a2a84a834e4ada04301b26 + label: Izzy's Quest for the Olympic Rings + name: Izzy's Quest for the Olympic Rings + region: SNS-AIZE-USA + revision: SNS-AIZE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 3ffbb6e0ccf8e9f5e4c72d9fe526a16371e562b71a91d6430e562bf358a5126b + label: Jack Nicklaus Golf + name: Jack Nicklaus Golf + region: SNS-JN-USA + revision: SNS-JN-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 9cf82dd9a851cdc38bf2afc286c077ff18a0a5d3bb301eba606cc52db62f8965 + label: James Bond Jr. + name: James Bond Jr. + region: SNS-JJ-USA + revision: SNS-JJ-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 8b7b33f3d2edb844f1d43cfdd595b8c2cb6fc005d59acb899a1afda999e47638 + label: Jammit + name: Jammit + region: SNS-J6-USA + revision: SNS-J6-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 85e5f6fedc420925557092d728e1dc6b4e2042368fb78bf93c0df447f8c9c0c0 + label: Jeopardy! + name: Jeopardy! + region: SNS-JY-USA + revision: SNS-JY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 76d760da59aa7fc2fd4426c1d1aec57412703ab901b9df60ac2be16ede80b0e7 + label: Jeopardy! - Deluxe Edition + name: Jeopardy! - Deluxe Edition + region: SNS-7J-USA + revision: SNS-7J-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: d7110ddc0b34aa4ecd5e55f7b846657edb982db82cf0ba340fe0464daf0ca9be + label: Jeopardy! - Sports Edition + name: Jeopardy! - Sports Edition + region: SNS-8Y-USA + revision: SNS-8Y-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: ee7a29eb9c302ea2bb235ef990fd8344a6beb9817499941c40a8a94ad5f7c964 + label: The Jetsons: Invasion of the Planet Pirates + name: Jetsons, The - Invasion of the Planet Pirates + region: SNS-8J-USA + revision: SNS-8J-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a314583b11d594b8245b5177aa64a4d3b7497d096edabbea7c1842c57aa2ad2b + label: Jim Lee's Wild Covert Action Teams + name: Jim Lee's Wild Covert Action Teams + region: SNS-AWIE-USA + revision: SNS-AWIE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 6f0bec87ece503b0fbe108cd159ed6f5fa7711b1c4fe31e982af41ad5c638093 + label: Jim Power: The Lost Dimension in 3D + name: Jim Power - The Lost Dimension in 3D + region: SNS-6J-USA + revision: SNS-6J-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 205890f94e27e7c1b381124cc35c866351bafa906383e507cd17ccb9d1b68ffd + label: Jimmy Connors' Pro Tennis Tour + name: Jimmy Connors' Pro Tennis Tour + region: SNS-JC-USA + revision: SNS-JC-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 6abe908b4005a68d1f6e9a54339c94a33db41801890d8c058ce974fdab3d0bcd + label: Jimmy Houston's Bass Tournament, U.S.A. + name: Jimmy Houston's Bass Tournament, USA + region: SNS-AFUE-USA + revision: SNS-AFUE-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 3b2b8b813b58049a4a86ce1c42d2a651f19fd9bbab2407a494e20cf343d3c1a4 + label: Joe & Mac + name: Joe & Mac + region: SNS-JT-USA + revision: SNS-JT-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c9889799a9ae8558f26d66ae546db930c99acb78d921b4395afbbc38da6272aa + label: Joe & Mac 2: Lost in the Tropics + name: Joe & Mac 2 - Lost in the Tropics + region: SNS-J3-USA + revision: SNS-J3-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5a76347672ea7d27bb334b1e30bbc73e06f92373883bed499245377327a8f0cf + label: John Madden Football + name: John Madden Football + region: SNS-JM-USA + revision: SNS-JM-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 3e62872bf69ea90dd7093608268f8defa2c6016adb1011745dab3c2af45d69b7 + label: John Madden Football '93 + name: John Madden Football '93 + region: SNS-MF-USA + revision: SNS-MF-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 67fa7115eb6bf292c024c3a8b06ce9bd457c4d46de182a06a573afff968cc0f1 + label: Judge Dredd + name: Judge Dredd + region: SNS-AJDE-USA + revision: SNS-AJDE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 771a0322d9f5f8e13a52d01e80257a1f75cc693cf4abf74793520eb5f8b5580e + label: The Jungle Book + name: Jungle Book, The + region: SNS-7K-USA + revision: SNS-7K-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 8d812ea4fa897274116f7f43bc689e110f1cfbd3f7eb3a1737c2a85d36369159 + label: Jungle Strike + name: Jungle Strike + region: SNS-AJGE-USA + revision: SNS-AJGE-0 + board: MJSC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: fe91d45201753ae9655d5ce38838e352f478b26b2d933c1bcb5bd8330121f9ff + label: Jurassic Park + name: Jurassic Park + region: SNS-J8-USA + revision: SNS-J8-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 0a4e9d6fa2ac16aa51da5538d93280734de480e44c430173ed14826c84553c7d + label: Jurassic Park + name: Jurassic Park + region: SNS-J8-USA + revision: SNS-J8-1 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 5eff7c27f69b3ebc1ec1294ffcd1debf3512bc3e6c1c75fbdc5e778dcaaba1c9 + label: Jurassic Park 2: The Chaos Continues + name: Jurassic Park 2 - The Chaos Continues + region: SNS-A2JE-USA + revision: SNS-A2JE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 7f05959f423bc656091ea3bddfbc89c877ae243dca346f63233e27973f34e0eb + label: Justice League Task Force + name: Justice League Task Force + region: SNS-AJLE-USA + revision: SNS-AJLE-0 + board: SHVC-BA0N-10 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: 05152bcf9bf086e7bcdbfa7dd8edfe2085f1339c4d7e193e0071c49a10471ef4 + label: Ka-Blooey + name: Ka-Blooey + region: SNS-BB-USA + revision: SNS-BB-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 7cc3693cc5e1e834d57795f04b048fab27864a898a9507e7ca383771e2035414 + label: Kawasaki Caribbean Challenge + name: Kawasaki Caribbean Challenge + region: SNS-KC-USA + revision: SNS-KC-0 + board: SHVC-2A0N-10 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: fec6dd097e378e795dd164be658b10b1c60672b2351a7f4a7722d1fe5736410e + label: Kawasaki Superbike Challenge + name: Kawasaki Superbike Challenge + region: SNS-AKEE-USA + revision: SNS-AKEE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 3104d6c06c8909c56f6adb2faecf1b4382f2490370798b605631da926c5306d8 + label: Ken Griffey Jr. Presents Major League Baseball + name: Ken Griffey Jr. Presents Major League Baseball + region: SNS-JR-USA + revision: SNS-JR-0 + board: SHVC-1A3B-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: f9f7a2de8cbafd6f9042841dfc42529f8245d75f436bed1c23f9ba1663182e61 + label: Ken Griffey Jr. Presents Major League Baseball + name: Ken Griffey Jr. Presents Major League Baseball + region: SNS-JR-USA + revision: SNS-JR-1 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 18b5276be764c06531219c1757d40214aeec06fae68f4ce3ec78b58ee750a43e + label: Ken Griffey Jr.'s Winning Run + name: Ken Griffey Jr.'s Winning Run + region: SNS-A9GE-USA + revision: SNS-A9GE-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: b16661d5151d73cea5ac46d7c899531c7b2cdee2558092c23a5460c8092b80b8 + label: Kendo Rage + name: Kendo Rage + region: SNS-M7-USA + revision: SNS-M7-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 914652f72d6ceb83b8b43414d6c42581ec12e9b3f45259b8b2768d26b8d4f073 + label: Kid Klown in Crazy Chase + name: Kid Klown in Crazy Chase + region: SNS-ZI-USA + revision: SNS-ZI-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 618a23636e07110e094277ec1d1e60c3620a6e9a5f386292808267593fa803ad + label: Killer Instinct + name: Killer Instinct + region: SNS-AKLE-USA + revision: SNS-AKLE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 1b58d0aed4510811c73d267244a7e915aa0b334c86e68f3fa5883f5cb534e4d7 + label: King Arthur & The Knights of Justice + name: King Arthur & The Knights of Justice + region: SNS-AAKE-USA + revision: SNS-AAKE-0 + board: SHVC-BJ0N-20 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: aca9eb59d6783e2cae3787c69053888fea98f5dfe4c8af8b5a6360e0afb3b5d7 + label: King Arthur's World + name: King Arthur's World + region: SNS-RC-USA + revision: SNS-RC-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 6638b5541059814d4c34574e5e277ef613aebf81c91d3def557a7642fb5840e1 + label: King of Dragons + name: King of Dragons + region: SNS-EI-USA + revision: SNS-EI-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 1135858a1ce686a0a163bb0e6f3a4d7cd71c0cd56efbc79677372f2624cf2306 + label: King of the Monsters + name: King of the Monsters + region: SNS-KM-USA + revision: SNS-KM-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a9729d049ce580839bbfef1836a13dc16f2fc934d203ebf7390e0b1c47ea9a2d + label: King of the Monsters 2 + name: King of the Monsters 2 + region: SNS-KT-USA + revision: SNS-KT-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 4e095fbbdec4a16b075d7140385ff68b259870ca9e3357f076dfff7f3d1c4a62 + label: Kirby Super Star + name: Kirby Super Star + region: SNS-AKFE-USA + revision: SNS-AKFE-0 + board: SHVC-1L3B-11 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + memory + type: RAM + size: 0x800 + content: Internal + volatile + +game + sha256: 67937dd7a29a93b1aaabb6df89f0748369ff47f3f6c655a402c00d5657973140 + label: Kirby's Avalanche + name: Kirby's Avalanche + region: SNS-PQ-USA + revision: SNS-PQ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 0f984dc5fe8293f75e3b8fad98b0cb564706d9b1e3902b56415aa399c2d4df2b + label: Kirby's Dream Course + name: Kirby's Dream Course + region: SNS-CG-USA + revision: SNS-CG-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: b50bf9d95485e8aeb7a6730e9f9f9c9c4ec23a85b336a4fb2e3b63034531e36f + label: Kirby's Dream Land 3 + name: Kirby's Dream Land 3 + region: SNS-AFJE-USA + revision: SNS-AFJE-0 + board: SHVC-1L5B-20 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + memory + type: RAM + size: 0x800 + content: Internal + volatile + +game + sha256: fb601ead645edce139b0483d3155b4e3d7ab245bf87a3a66cb88c0a617c0a526 + label: Knights of the Round + name: Knights of the Round + region: SNS-LO-USA + revision: SNS-LO-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: bed18c968aee0eb0c866c1964c28135364cd6d65fff7bcb5873342c04e63750d + label: Krusty's Super Fun House + name: Krusty's Super Fun House + region: SNS-FH-USA + revision: SNS-FH-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: e36322697c48baae6492db91e6cbf3844a420f6e0cc8a75f3a73556026ddbbb8 + label: Krusty's Super Fun House + name: Krusty's Super Fun House + region: SNS-FH-USA + revision: SNS-FH-1 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: daf3e45bafbec81ffa5911b94810b2cd267574de717292360f9940f41fb2a6a9 + label: Kyle Petty's No Fear Racing + name: Kyle Petty's No Fear Racing + region: SNS-AKPE-USA + revision: SNS-AKPE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 46c811f0cacffe8f20e1d63072d25d7c47e9bb3fd5124851fd05aca9884d21fb + label: Lagoon + name: Lagoon + region: SNS-LA-USA + revision: SNS-LA-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 48cd9476fef1ed685b9c30dd1669b46048f7295cbbb2abcfa5b1a48699346ea3 + label: Lamborghini American Challenge + name: Lamborghini American Challenge + region: SNS-L8-USA + revision: SNS-L8-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 314d53f409b66ba3f4426a6f1bb7c69f6779aeed277ce2e19535f94d7c8ca586 + label: Last Action Hero + name: Last Action Hero + region: SNS-L5-USA + revision: SNS-L5-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a179a1188220b59787c49a78a0dde79b89380e3a8a8a0ab558f0102c5796f873 + label: The Lawnmower Man + name: Lawnmower Man, The + region: SNS-LW-USA + revision: SNS-LW-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c7814cee0fc95d6422cf19a3dc8c9a65b60f6f56da75f09cebea02cc5f99261b + label: Legend + name: Legend + region: SNS-6L-USA + revision: SNS-6L-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c865fb17e8c59a21d32b9a605319241fa74ec732e3f0ee58f5d7fcbd8ee57c6b + label: The Legend of the Mystical Ninja + name: Legend of the Mystical Ninja, The + region: SNS-GG-USA + revision: SNS-GG-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb + label: The Legend of Zelda: A Link to the Past + name: Legend of Zelda, The - A Link to the Past + region: SNS-ZL-USA + revision: SNS-ZL-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 4b28d2ddab405976bb56e41a40ec1ea11d7362a8f398d5f8c117d715a15719ca + label: Lemmings + name: Lemmings + region: SNS-LE-USA + revision: SNS-LE-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: cd016c41c7ef9f4f243d57c2b1564b4ceb3b4c38cc165cd02ab6c8e35c93aa2e + label: Lemmings + name: Lemmings + region: SNS-LE-USA + revision: SNS-LE-1 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 63ecdca7f89b2432ccd57bdb81c0875f6336353f5897f756ef162ab2ec2ee707 + label: Lemmings 2: The Tribes + name: Lemmings 2 - The Tribes + region: SNS-L2-USA + revision: SNS-L2-0 + board: SHVC-1A1M-11 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: a2c1970670e2831e47e24ced01bf4ba5aba05cac3773bf524c62d689c35687e1 + label: Lester the Unlikely + name: Lester the Unlikely + region: SNS-LY-USA + revision: SNS-LY-0 + board: SHVC-1J0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 3bc5f296c3dbee012e93a5cf25568f9288ce87b34d74085401a560350eaca03f + label: Lethal Enforcers + name: Lethal Enforcers + region: SNS-LK-USA + revision: SNS-LK-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 80c22cc92d51a54de9cd9fd00db5ff58a35fff35e822169c94e445d50834fba3 + label: Lethal Weapon + name: Lethal Weapon + region: SNS-L3-USA + revision: SNS-L3-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8fcb9c34aea863d49ff08a0ace3f83d301b81f01e2ede28bee7e6d778878d0cc + label: Liberty or Death + name: Liberty or Death + region: SNS-7L-USA + revision: SNS-7L-0 + board: SHVC-2J3M-01 + memory + type: ROM + size: 0x140000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 457abe634e0a8be03e29513a3dca8f3e9d0ddc6bf97d8931f2316094260f3712 + label: The Lion King + name: Lion King, The + region: SNS-ALKE-USA + revision: SNS-ALKE-0 + board: MJSC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 0e2ba574ff73587f211c8f818d444631584832e9240548f003171c11b898ad62 + label: Lock On + name: Lock On + region: SNS-AZ-USA + revision: SNS-AZ-0 + board: SHVC-1K0N-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + volatile + oscillator + frequency: 7600000 + +game + sha256: 76ba0fc1f5c1f39354bb3173a600f23915f1191f400f7d525d220b4b3c8d958d + label: Looney Tunes B-Ball + name: Looney Tunes B-Ball + region: SNS-ALTE-USA + revision: SNS-ALTE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 62557ee2a3fc3b5a3f59431f966eb61bb380ba983ef6c7742cb55cf075f15f6c + label: The Lord of the Rings: Volume 1 + name: Lord of the Rings, The - Volume 1 + region: SNS-64-USA + revision: SNS-64-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ab3d97c1a3a979e1680a428ec65df54cfb72997bbfe2173292248a4fa8c51ba1 + label: Lost Vikings 2 + name: Lost Vikings 2 + region: SNS-ALVE-USA + revision: SNS-ALVE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 9f7782a92fda789f9d119b1f0a2f7da0f35606357556a48eca9487797ee1a888 + label: The Lost Vikings + name: Lost Vikings, The + region: SNS-LV-USA + revision: SNS-LV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 73731a5a7932965de02a9e98055dcf88b4d17b8f710a6ecfde3e36a1f248773b + label: Lufia & The Fortress of Doom + name: Lufia & The Fortress of Doom + region: SNS-ES-USA + revision: SNS-ES-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 7c34ecb16c10f551120ed7b86cfbc947042f479b52ee74bb3c40e92fdd192b3a + label: Lufia II: Rise of the Sinistrals + name: Lufia II - Rise of the Sinistrals + region: SNS-ANIE-USA + revision: SNS-ANIE-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x280000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 7e77e196db47e87a5b297e60f0dfa7ce41df8d2d1fdd9152e06628d0b0e586af + label: Madden NFL '94 + name: Madden NFL '94 + region: SNS-9M-USA + revision: SNS-9M-0 + board: SHVC-1J0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 0ad77ae7af231313e1369a52d1622b88e3751aa5ec774628df7071f9e4244abc + label: Madden NFL '95 + name: Madden NFL '95 + region: SNS-ANLE-USA + revision: SNS-ANLE-0 + board: SHVC-1J3M-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 3059d86cdc383985c564a7a891fe18e08f5222ead7ede9fa309159d60cde13a1 + label: Madden NFL '96 + name: Madden NFL '96 + region: SNS-A6FE-USA + revision: SNS-A6FE-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 6874568d985f65dd817d4b03998e71c8cbacc8d8707411fde7bffee350605a88 + label: Madden NFL '97 + name: Madden NFL '97 + region: SNS-A7NE-USA + revision: SNS-A7NE-0 + board: EA-1J3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: e3c62c9fe55d2311aa6a264f41b45d6cbc7b1b069ed3aa82ee57d381c062547d + label: Madden NFL '98 + name: Madden NFL '98 + region: SNS-A8NE-USA + revision: SNS-A8NE-0 + board: EA-1J3M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: c01fb8989d391d3e343003934937f02bd8ef9aacdad68c32c3d3f56feb72f5b0 + label: Magic Boy + name: Magic Boy + region: SNS-YG-USA + revision: SNS-YG-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 1d3cceaa05e054b002caeb09fd5fb9e718ec446764f4169d97bc185da76fdf4d + label: Magic Sword + name: Magic Sword + region: SNS-MD-USA + revision: SNS-MD-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f301bb8ea867e530ecb64e8eff504ed5b9697cf076c70e2036ecf2ffbe6c487a + label: The Magical Quest Starring Mickey Mouse + name: Magical Quest Starring Mickey Mouse, The + region: SNS-MI-USA + revision: SNS-MI-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8267e2f092c86d5a29c9a826db82c7473638e28e2507cdaf5c86981f07cd0bef + label: Mario is Missing! + name: Mario is Missing! + region: SNS-MU-USA + revision: SNS-MU-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e842cac1a4301be196f1e137fbd1a16866d5c913f24dbca313f4dd8bd7472f45 + label: Mario Paint + name: Mario Paint + region: SNS-MP-USA + revision: SHVC-MP-0 + board: SHVC-1A5M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 22b21fb39d40447846f6ff77a07f7b4aba2a7473941ba50c787aae6153b1fb5e + label: Mario's Early Years: Fun with Letters + name: Mario's Early Years - Fun with Letters + region: SNS-AMYE-USA + revision: SNS-AMYE-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 57b94f5f576abbe8bd8f5a4eeb6cf927300ec1b5f0596610f3539ba733505c12 + label: Mario's Early Years: Fun with Numbers + name: Mario's Early Years - Fun with Numbers + region: SNS-YR-USA + revision: SNS-YR-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c646b1e60e2cd5a2741915f5d3dfe3c17f45ff7283f8052e840bd4354b0990e1 + label: Mario's Early Years: Preschool Fun + name: Mario's Early Years - Preschool Fun + region: SNS-AMEE-USA + revision: SNS-AMEE-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4b69d4958e099c3b3f6ae45e153ced9b24755d8c161dfee06c9f67886a7c0f09 + label: Mario's Time Machine + name: Mario's Time Machine + region: SNS-8M-USA + revision: SNS-8M-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 908440f96fd0df14602fc6d1daee8519fc31f765ad00bf64aaba35c2c6ef0b56 + label: Mark Davis' The Fishing Master + name: Mark Davis' The Fishing Master + region: SNS-AOAE-USA + revision: SNS-AOAE-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 49dd77b310b476c875633335243553be59ecfb0bffae62e46f2e53ff05c20fcd + label: Marvel Super Heroes in War of the Gems + name: Marvel Super Heroes in War of the Gems + region: SNS-AHZE-USA + revision: SNS-AHZE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 2731f0bd1c87e75121f41d1ed5cc9fbf177f414b8bf831c76fd9c4b58c86ed08 + label: Mary Shelley's Frankenstein + name: Mary Shelley's Frankenstein + region: SNS-AFRE-USA + revision: SNS-AFRE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 44cc113ce1e7616cc737adea9e8f140436c9f1c3fba57e8e9db48025d4ace632 + label: The Mask + name: Mask, The + region: SNS-AMGE-USA + revision: SNS-AMGE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 22453182d44380f08004a12c6492a0c4b2e1f584e268dcc3296a03ea03ae0909 + label: Math Blaster: Episode One + name: Math Blaster - Episode One + region: SNS-AMME-USA + revision: SNS-AMME-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a203a13870eaec92095daef1196a0c9fe8416e600504d55dd0dc724d4f5f5cb0 + label: Maui Mallard in Cold Shadow + name: Maui Mallard in Cold Shadow + region: SNS-AZBE-USA + revision: SNS-AZBE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: c3c4afdeb67136619c643bd9a9f3fe90337541a40745503b5d4eb9b9e6e64b67 + label: Mecarobot Golf + name: Mecarobot Golf + region: SNS-TS-USA + revision: SNS-TS-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 2a08704748f5ef6488348c4099729feca600412d331bda3756e51efd8b94e113 + label: MechWarrior + name: MechWarrior + region: SNS-WM-USA + revision: SNS-WM-0 + board: SHVC-1A1B-06 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 7bffa1dc31604fa3d61e06ce2c59168098cc8dd7e59998e1d5f30c49bdf8d617 + label: MechWarrior 3050 + name: MechWarrior 3050 + region: SNS-A35E-USA + revision: SNS-A35E-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: a255fec32453739903a1954149f19bc9658f4a415600b44badf1d4e5e13a16f9 + label: Mega Man 7 + name: Mega Man 7 + region: SNS-A7RE-USA + revision: SNS-A7RE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: cf4d603dc0a3759da571224c671a9bfd29f9e52ca8dbb61bcc8ac8be5481e9b2 + label: Mega Man Soccer + name: Mega Man Soccer + region: SNS-RQ-USA + revision: SNS-RQ-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: 3e1209f473bff8cd4bcbf71d071e7f8df17a2d564e9a5c4c427ee8198cebb615 + label: Mega Man X + name: Mega Man X + region: SNS-RX-USA + revision: SNS-RX-0 + board: SHVC-2A0N-01 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: b8f70a6e7fb93819f79693578887e2c11e196bdf1ac6ddc7cb924b1ad0be2d32 + label: Mega Man X + name: Mega Man X + region: SNS-RX-USA + revision: SNS-RX-1 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: da484f2a636b8d692840f40e5468e992c5f2af26d365c69fbc12ef2923588d23 + label: Mega Man X2 + name: Mega Man X2 + region: SNS-ARXE-USA + revision: SNS-ARXE-0 + board: SHVC-2DC0N-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: ROM + size: 0xc00 + content: Data + manufacturer: Hitachi + architecture: HG51BS169 + identifier: Cx4 + memory + type: RAM + size: 0xc00 + content: Data + manufacturer: Hitachi + architecture: HG51BS169 + identifier: Cx4 + volatile + oscillator + frequency: 20000000 + +game + sha256: b2aa2c0a621dfbed3b528de93282fc91abb16325d358680d34753d43629263cf + label: Mega Man X3 + name: Mega Man X3 + region: SNS-AR3E-USA + revision: SNS-AR3E-0 + board: SHVC-1DC0N-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: ROM + size: 0xc00 + content: Data + manufacturer: Hitachi + architecture: HG51BS169 + identifier: Cx4 + memory + type: RAM + size: 0xc00 + content: Data + manufacturer: Hitachi + architecture: HG51BS169 + identifier: Cx4 + volatile + oscillator + frequency: 20000000 + +game + sha256: d4f2cb6b209db29f7aec62e5a23846681c14665fb007e94d7bcfc7b5611e938b + label: Metal Combat: Falcon's Revenge + name: Metal Combat - Falcon's Revenge + region: SNS-KD-USA + revision: SNS-KD-0 + board: SHVC-2E3M-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0a9609a505dd1555006b16f53d961b3ce50c518aa1597a77dcd46e55ecc716ff + label: Metal Marines + name: Metal Marines + region: SNS-6M-USA + revision: SNS-6M-0 + board: SHVC-2A0N-01 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 057484558ebd18165f98e556b994080535e31cefdd98b5edb190516f7040fc9d + label: Metal Morph + name: Metal Morph + region: SNS-AMHE-USA + revision: SNS-AMHE-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 0d7f875877fe856066cfb39b4ecdbbe7d48393a75770720876c94419f809bb1c + label: Metal Warriors + name: Metal Warriors + region: SNS-AWME-USA + revision: SNS-AWME-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 88545d24c60c18c695cc3fce8c4074f46ad1bac905e8a39a61d8a6ae6b608621 + label: Michael Andretti's Indy Car Challenge + name: Michael Andretti's Indy Car Challenge + region: SNS-AMAE-USA + revision: SNS-AMAE-0 + board: SHVC-1K0N-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + volatile + oscillator + frequency: 7600000 + +game + sha256: 1b425ea5a883b7464637b74c2937fde699ffff52b53ad6940a66285e0663194a + label: Michael Jordan: Chaos in the Windy City + name: Michael Jordan - Chaos in the Windy City + region: SNS-AWCE-USA + revision: SNS-AWCE-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: 0773eb741ce28f963f767fc7dd44678eb3d37ed4dc7fc82bb9cce7d55f1cfc64 + label: Mickey Mania: The Timeless Adventures of Mickey Mouse + name: Mickey Mania - The Timeless Adventures of Mickey Mouse + region: SNS-AMIE-USA + revision: SNS-AMIE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: add082caffe707df2c0259489c3e272d6557ab07ba3ff856cbc0adba0d7db6a5 + label: Mickey's Ultimate Challenge + name: Mickey's Ultimate Challenge + region: SNS-6U-USA + revision: SNS-6U-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a2adeb4bf0e7cc943611ac726e5578da404373a79e91436c9bbd15480688b15c + label: Micro Machines + name: Micro Machines + region: SNS-AH3E-USA + revision: SNS-AH3E-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 835ded9479f0e7babae00405d85233d767e82fa247aa1a9cdc14fd1f147b62ef + label: Might & Magic III: Isles of Terra + name: Might & Magic III - Isles of Terra + region: SNS-3H-USA + revision: SNS-3H-0 + board: SHVC-2A3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 624a66607caef2ca34920ea15b84b28cdd1916ee089d496cec4f1d43621fdbb3 + label: Mighty Morphin Power Rangers + name: Mighty Morphin Power Rangers + region: SNS-52-USA + revision: SNS-52-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 1b85c0690aa156a255c7f79e133e453345452698fa98abf8df744c262d0cf865 + label: Mighty Morphin Power Rangers: The Fighting Edition + name: Mighty Morphin Power Rangers - The Fighting Edition + region: SNS-A3RE-USA + revision: SNS-A3RE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: c706b70097c679f6f0ced6f77a30620807d0b2555fc3c683c0ec2fc791176039 + label: Mighty Morphin Power Rangers: The Movie + name: Mighty Morphin Power Rangers - The Movie + region: SNS-A2RE-USA + revision: SNS-A2RE-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 8546dfc91f6256df8b21083531457e3edf0021da12fce6858e2c59ff239c31da + label: The Miracle Piano Teaching System + name: Miracle Piano Teaching System, The + region: SNS-MR-USA + revision: SNS-MR-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: d32f194e27d177e64bf3bda046889b8198276fca2e8772e4b02a17152e9273e4 + label: MLBPA Baseball + name: MLBPA Baseball + region: SNS-XH-USA + revision: SNS-XH-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8715a641f2e4dd8b6066be7f2683d9129fff3fcccaf0a09cc8bdd2aa56460764 + label: Mohawk & Headphone Jack + name: Mohawk & Headphone Jack + region: SNS-AJYE-USA + revision: SNS-AJYE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 480ae7186fd5b28200cd88e136b9cd3b6600d32508e280a0bc27ea0ed8d3c0bb + label: Monopoly + name: Monopoly + region: SNS-ML-USA + revision: SNS-ML-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 6b0ac4d52d24536cdb7d9d0dc7d19ee30d08ac34363983290c5912ccc850fa0d + label: Monopoly + name: Monopoly + region: SNS-ML-USA + revision: SNS-ML-1 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 3c6d3e4a9c9af160f1c1cf11ce4ead531d9500c1f58f1cbe682c90a5eaa3efb2 + label: Mortal Kombat + name: Mortal Kombat + region: SNS-KX-USA + revision: SNS-KX-0 + board: SHVC-2A0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 417874aa57856fe93eefdb24066fa1a9ca3f23c72c09d5247ae2b3ab4b3d09d1 + label: Mortal Kombat 3 + name: Mortal Kombat 3 + region: SNS-A3ME-USA + revision: SNS-A3ME-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 43e36a74fb73a7efc46b380599e269b1fff8f55ecf80f5cf50c34d02ceda041a + label: Mortal Kombat II + name: Mortal Kombat II + region: SNS-28-USA + revision: SNS-28-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: ca2f86ca77f822fcd8e86f5a287f2a76d0becbb81a7bce73ae22909beb2f834c + label: Mortal Kombat II + name: Mortal Kombat II + region: SNS-28-USA + revision: SNS-28-1 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 340293c06536d7b6981ad7c681e404f4390ff6c62340f844a4558877c1b82af0 + label: Mr. Do! + name: Mr. Do! + region: SNS-AUNE-USA + revision: SNS-AUNE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x40000 + content: Program + +game + sha256: 3472dd574b50aed2fa998f464398db4fbb00f5a300a672c3737ee9336a008a16 + label: Mr. Nutz + name: Mr. Nutz + region: SNS-N8-USA + revision: SNS-N8-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 007735e68a91cab403f1c955d9d562e9311124e660fa5b32e5c5d0a2e052160e + label: Ms. Pac-Man + name: Ms. Pac-Man + region: SNS-AN8E-USA + revision: SNS-AN8E-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x40000 + content: Program + +game + sha256: f292598ac462fdfcd32ad9b6b35ac01d4bab020391dff92bfe94780ec604289a + label: Musya: The Classic Japanese Tale of Horror + name: Musya - The Classic Japanese Tale of Horror + region: SNS-MY-USA + revision: SNS-MY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8d4ada4f98464d176ae7f0fb8a20032056680f3241637a0f903f23f31f41ff36 + label: Mutant Chronicles: Doom Troopers + name: Mutant Chronicles - Doom Troopers + region: SNS-AM9E-USA + revision: SNS-AM9E-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 22d2260de02552b1205aac2ff5a202a4c80532ac28045ef5a058d88279ab758e + label: Natsume Championship Wrestling + name: Natsume Championship Wrestling + region: SNS-7W-USA + revision: SNS-7W-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: c70b812a9d2df7f95b279e4050e03a4b8a68588a370816e645f378296b84e5d1 + label: NBA All-Star Challenge + name: NBA All-Star Challenge + region: SNS-NB-USA + revision: SNS-NB-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5874b942f974bb906d8cbc33b601a1faf8f14aee8d0995124c8dc84bb4973808 + label: NBA Give 'n Go + name: NBA Give & Go + region: SNS-ANJE-USA + revision: SNS-ANJE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: af2fe0627de2bb2672f4f65dcbdaaee22b211275f679f123d5fa5d37fd699363 + label: NBA Hang Time + name: NBA Hang Time + region: SNS-AXGE-USA + revision: SNS-AXGE-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0f18c496426bb97fe5e8b91ad5299f0b1c3898ac17047b745c86b167c212ab7a + label: NBA Jam + name: NBA Jam + region: SNS-8N-USA + revision: SNS-8N-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: b257cffb3484e6be051a56268cb99ee888bd6d3e9c0e8d6d0779ff66c411f6ba + label: NBA Jam: Tournament Edition + name: NBA Jam - Tournament Edition + region: SNS-AJTE-USA + revision: SNS-AJTE-0 + board: SHVC-BA1M-01 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 2115c39f0580ce19885b5459ad708eaa80cc80fabfe5a9325ec2280a5bcd7870 + label: NBA Live '95 + name: NBA Live '95 + region: SNS-ANBE-USA + revision: SNS-ANBE-0 + board: SHVC-2A3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 2d6fc4214245684a8f8f9bb553de637b7c660919ec775bfe3baaf74060c9157e + label: NBA Live '96 + name: NBA Live '96 + region: SNS-A6BE-USA + revision: SNS-A6BE-0 + board: SHVC-2A3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 4b945493d28653d5d047a375136ec9792f27e652be4af00e2c03c40369bd6ecf + label: NBA Live '97 + name: NBA Live '97 + region: SNS-A7LE-USA + revision: SNS-A7LE-0 + board: EA-1A3M-30 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 1d1b257dcf859cc412d3a9521fc58dc876a5917e6a69cd1d960a8e9840454bb4 + label: NBA Live '98 + name: NBA Live '98 + region: SNS-A8LE-USA + revision: SNS-A8LE-0 + board: EA-1A3M-30 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 6a7324734004d99206439430243b51a05fa8c25ffa314dafc7f127235d1a730f + label: NBA Showdown + name: NBA Showdown + region: SNS-6N-USA + revision: SNS-6N-0 + board: SHVC-1A3M-10 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 351587366eca8aeb38236e4ad6cbd4a1b6e37b8cc592725a79249c3a054fa3a7 + label: NCAA Basketball + name: NCAA Basketball + region: SNS-DU-USA + revision: SNS-DU-0 + board: SHVC-1A1B-06 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 8ef5d5c50ffeca1e62e88e4fe2909eaf191e28fbb5a9faf98b7b10bea72c9ed9 + label: NCAA Basketball + name: NCAA Basketball + region: SNS-DU-USA + revision: SNS-DU-1 + board: SHVC-1A1B-06 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: d297c76efbcd9a528d8ee51025f8774ab2cb6bbc676c24e28592c50f47e71bfc + label: NCAA Final Four Basketball + name: NCAA Final Four Basketball + region: SNS-AFIE-USA + revision: SNS-AFIE-0 + board: SHVC-2A3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 8c43b7c2f2ef1fca9237c64c2f4c9e98d1a48940dae500ce8eac71278d34efb3 + label: NCAA Football + name: NCAA Football + region: SNS-AFBE-USA + revision: SNS-AFBE-0 + board: SHVC-1A1M-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 489d6d704d3d917d9b46ce382230700419983a8d0d61a98fe07e08c935522dde + label: Newman-Haas IndyCar featuring Nigel Mansell + name: Newman-Haas IndyCar featuring Nigel Mansell + region: SNS-ANME-USA + revision: SNS-ANME-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: f651a42bb351f7691b880827178c36fcf6c265c7833c6de1d94f7ed69bac0517 + label: NFL Football + name: NFL Football + region: SNS-NF-USA + revision: SNS-NF-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6a59115a9958d4a9fa167095505a2ddf222ca6291209d07618319e39a2be8b61 + label: NFL Quarterback Club + name: NFL Quarterback Club '95 + region: SNS-Q9-USA + revision: SNS-Q9-0 + board: SHVC-1A1M-11 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: f43f8ec546b8060e9d191fca860c38caf5a43eda86a304f0073647c6fad7b2c9 + label: NFL Quarterback Club '96 + name: NFL Quarterback Club '96 + region: SNS-AQBE-USA + revision: SNS-AQBE-0 + board: SHVC-1A1M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 5132e1c0d466963e6adc09e8a608ebd90619ab94f7fc908d626bbaf6a99dfa19 + label: NHL '94 + name: NHL '94 + region: SNS-4H-USA + revision: SNS-4H-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 01c0b58d5fd5d5484fea988455a55a71ed9e606538d2b3ce3f216159cc6929b0 + label: NHL '95 + name: NHL '95 + region: SNS-ANHE-USA + revision: SNS-ANHE-0 + board: SHVC-1J3M-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: d24c0175ee4eafed88e277691c5f5dafd4e197723097e2eb68aa6b40f449fff2 + label: NHL '96 + name: NHL '96 + region: SNS-A6HE-USA + revision: SNS-A6HE-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 2a2dc2ef84efd9a773d1e8231b7e3e57f0de7e4528968670963f2f1f358eef39 + label: NHL '97 + name: NHL '97 + region: SNS-AH7E-USA + revision: SNS-AH7E-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0d933149242a2a5278b9ada9294481db5b30aaa134c660951dc340bf8ab441e8 + label: NHL '97 + name: NHL '97 + region: SNS-AH7E-USA + revision: SNS-AH7E-1 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 8113c2cedafc8fd5a56c8638ae340fb275f263ff5c5e18d04dc6c3ebc5cfffee + label: NHL '98 + name: NHL '98 + region: SNS-A8HE-USA + revision: SNS-A8HE-0 + board: SHVC-1J5M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: d44f487d84f5bb761955b7b70a5464b2f094e199875f595f312c88e04ac647ff + label: NHL Stanley Cup + name: NHL Stanley Cup + region: SNS-NH-USA + revision: SNS-NH-0 + board: SHVC-1A1M-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 55f3432a130085c112d65aa6443c41eb7a8aeec59aad2c2b4b2ac536b604b449 + label: NHLPA Hockey '93 + name: NHLPA Hockey '93 + region: SNS-HY-USA + revision: SNS-HY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: d7ad6f67860da78fe25d9e79dd13af7ac7efaa0c8e0103898a4849ab4af9e438 + label: Nickelodeon GUTS + name: Nickelodeon GUTS + region: SNS-ANGE-USA + revision: SNS-ANGE-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: ce9c819d6496e58901b39d9b04558a89e09ccc3aac33690b8d02bb0406682a57 + label: Nigel Mansell's World Championship Racing + name: Nigel Mansell's World Championship Racing + region: SNS-M8-USA + revision: SNS-M8-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: fccc96af24a2463b1c53253e1c5c8ef63641355fae53c0fb410427f29743262b + label: Ninja Gaiden Trilogy + name: Ninja Gaiden Trilogy + region: SNS-ANRE-USA + revision: SNS-ANRE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 3c109e50b91ec6df3bb8509778ae544c99433fb40dda9b801178dfe513053618 + label: Ninja Warriors + name: Ninja Warriors + region: SNS-NI-USA + revision: SNS-NI-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: f099937ac4c8afb38c517c5d85475224985fb8f345dacb44994a617ea05bf4e5 + label: No Escape + name: No Escape + region: SNS-ANOE-USA + revision: SNS-ANOE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 437ea48711d54c2275286170a17948cb57ba9d961ba475715c0dba5fbd61a2db + label: Nobunga's Ambition + name: Nobunga's Ambition + region: SNS-NZ-USA + revision: SNS-NZ-0 + board: SHVC-1J3M-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: ae572a51ebe429cfc06a3b75d7db9581f2884f9adc78827dc162b4c4ddc6ce2d + label: Nobunga's Ambition: Lord of Darkness + name: Nobunga's Ambition - Lord of Darkness + region: SNS-IZ-USA + revision: SNS-IZ-0 + board: SHVC-1A5M-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 7f3d0ebac6ecfb99cfd1d5b13210e989df9e8b2f2319a63c42faef8ad115a964 + label: Nolan Ryan's Baseball + name: Nolan Ryan's Baseball + region: SNS-NR-USA + revision: SNS-NR-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 9712829b38f23229d4e3d65da78237659c790235f425c6b12487e4d9e9a37ae9 + label: Nosferatu + name: Nosferatu + region: SNS-NS-USA + revision: SNS-NS-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 31bc862ab0a8eabf23b5124e13940cb3501e7ecdd3f15e34142248ceb4aa139a + label: Obitus + name: Obitus + region: SNS-7B-USA + revision: SNS-7B-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: b766c26498d0afd63f44aefdef42642d2483b54f18d2b81a4f1d67a57f641044 + label: Ogre Battle: The March of the Black Queen + name: Ogre Battle - The March of the Black Queen + region: SNS-OB-USA + revision: SNS-OB-0 + board: SHVC-2A3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: a137f4fc1c635f706d10e0c7927e71f52da171ce2d27394ce0deb451b5bed8ae + label: Olympic Summer Games + name: Olympic Summer Games + region: SNS-AO9E-USA + revision: SNS-AO9E-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: e153195de7b59dd5b9854952cccca6bb93164e5fdff8292124bee6bbe5dbf16f + label: On the Ball + name: On the Ball + region: SNS-CT-USA + revision: SNS-CT-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 9e1a39aaf3585af0d6a5d79de3c35fcfe030c34bd4b09606a6fb8c7def19340b + label: Operation Europe: Path to Victory 1939-45 + name: Operation Europe - Path to Victory 1939-45 + region: SNS-YP-USA + revision: SNS-YP-0 + board: SHVC-2J5M-01 + memory + type: ROM + size: 0x140000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 190742792a950a112f893cba0e083eb787cf24293f698967defff929635ba0e7 + label: Operation Logic Bomb + name: Operation Logic Bomb + region: SNS-IY-USA + revision: SNS-IY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5cbed0401734142184166917427d24f9e5f107a7adea665e2f4b4101491ad54b + label: Operation Thunderbolt + name: Operation Thunderbolt + region: SNS-36-USA + revision: SNS-36-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: 0c08e6b817e4d0b333acb910a0bde3d79bd2dc188defc5df9a7c1233fa81c98d + label: Oscar + name: Oscar + region: SNS-AOZE-USA + revision: SNS-AOZE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 582548dc86598a3557e9e3c27285c81964b006a954affe5c73948da5375ea11c + label: Out of This World + name: Out of This World + region: SNS-TW-USA + revision: SNS-TW-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 54b2f03393109ac7fd36d8c7752f15a44d9607ab0187a371b853191db3592c01 + label: Out to Lunch + name: Out to Lunch + region: SNS-P8-USA + revision: SNS-P8-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: db44f8b58a31b640a47aa4390101c3c6a5f613e4e49c636d44786278033dec19 + label: Outlander + name: Outlander + region: SNS-LD-USA + revision: SNS-LD-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 10c8abce67b49f8afbe880d2f13e0fd6d5efc162df34d5941e4a94851f23b2ff + label: Pac-Attack + name: Pac-Attack + region: SNS-P9-USA + revision: SNS-P9-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 7fe4cb9c294d66589ff78e225774471ecb7db80df25f2b6199ca25671358072b + label: Pac-in-Time + name: Pac-in-Time + region: SNS-APTE-USA + revision: SNS-APTE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4cb52ba751c42d9e12ca429e5d657622a370b608002880a997f64de453f0de20 + label: Pac-Man 2: The New Adventures + name: Pac-Man 2 - The New Adventures + region: SNS-25-USA + revision: SNS-25-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 83727f6954bce024edac7f3fd18a6fbf63d05b580f692d96faa37e60893c91cd + label: P.T.O.: Pacific Theater of Operations + name: Pacific Theater of Operations + region: SNS-TK-USA + revision: SNS-TK-0 + board: SHVC-2A5M-01 + memory + type: ROM + size: 0x140000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 2c6119fbe40d23576adde568d60ffae793bbf6b512f8fea8dcd0b1cd2623ef02 + label: P.T.O. II: Pacific Theater of Operations + name: Pacific Theater of Operations II + region: SNS-ATEE-USA + revision: SNS-ATEE-0 + board: SHVC-1J5M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: b1586c8ece4da9697f0602a684d7a9108027247a34652c3771831d31f82ee078 + label: Packy & Marlon + name: Packy & Marlon + region: SNS-APYE-USA + revision: SNS-APYE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ecaf51852e111512385c5f209d51578e65b45fcaa17b295ca06120c8d1464520 + label: The Pagemaster + name: Pagemaster, The + region: SNS-APME-USA + revision: SNS-APME-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 46286d0839a4397fc4c067b39783f98d2aefeca870a468bae601a1434f1dde90 + label: Paladin's Quest + name: Paladin's Quest + region: SNS-LN-USA + revision: SNS-LN-0 + board: SHVC-2A3M-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 7cec4ffc3eda0441561717cf55927901b5fbbd669c254079f78ca74c67c4a17b + label: Paperboy 2 + name: Paperboy 2 + region: SNS-P2-USA + revision: SNS-P2-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: c414a4084b3d03aba19496d2efdd68fcf826194d8f1308f5c98e3a7af2fcc063 + label: The Peace Keepers + name: Peace Keepers, The + region: SNS-R6-USA + revision: SNS-R6-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 5abfb974ca0e56aabb3f4126817d14a546c57a5a5c6042d31196063d80996698 + label: PGA European Tour + name: PGA European Tour + region: SNS-AEPE-USA + revision: SNS-AEPE-0 + board: SHVC-1L3B-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + memory + type: RAM + size: 0x800 + content: Internal + volatile + +game + sha256: 571d3129350bfb7cca2285499cf31dda48d1047cf9eaef122c8c33dffa9ad296 + label: PGA Tour '96 + name: PGA Tour '96 + region: SNS-A3GE-USA + revision: SNS-A3GE-0 + board: SHVC-1L3B-02 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + memory + type: RAM + size: 0x800 + content: Internal + volatile + +game + sha256: 5c0b5266a191852ca593235f07180e673cb79e3f0b0dd31f65808eef83bf6e90 + label: PGA Tour Golf + name: PGA Tour Golf + region: SNS-PG-USA + revision: SNS-PG-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0663330bc061f4b768fa1806610878ef6e6cf546f36041ae087c8e55703693b8 + label: Phalanx: The Enforce Fighter A-144 + name: Phalanx - The Enforce Fighter A-144 + region: SNS-PH-USA + revision: SNS-PH-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b7291088f5c49e1fc55bf932076ec03f7b39f6e409ae06e884b57024c56cdc87 + label: Phantom 2040 + name: Phantom 2040 + region: SNS-A24E-USA + revision: SNS-A24E-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a0b39d7fd7c39c5b0f41f3542fb8d2887530ded1c111b4ffb2a863845e704ecc + label: Pieces + name: Pieces + region: SNS-Z5-USA + revision: SNS-Z5-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 724144e34990069213591b5df067dd437a613b30f669840e9098db1dce626d2d + label: Pilotwings + name: Pilotwings + region: SNS-PW-USA + revision: SNS-PW-0 + board: SHVC-1B0N-02 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + volatile + oscillator + frequency: 7600000 + +game + sha256: 3a52bf09850aa054dca443f7ea74d43f201dffecc40326924ecba9b0f1450e43 + label: Pinball Dreams + name: Pinball Dreams + region: SNS-7D-USA + revision: SNS-7D-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 0888d20ab2f834c77b0a2dc2162c43890a1640adc78c6b0bb5892ca8d5008ad3 + label: Pinball Fantasies + name: Pinball Fantasies + region: SNS-APFE-USA + revision: SNS-APFE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d0f4a5040ecf96dc49aa0084160e291a38f2ee75319750db4d6687ab36828da9 + label: Pink Goes to Hollywood + name: Pink Goes to Hollywood + region: SNS-YW-USA + revision: SNS-YW-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 98c51c3bb577600fe79577c323333a791baa30904f37c695890e6e380b75e3c8 + label: Pinocchio + name: Pinocchio + region: SNS-ACGE-USA + revision: SNS-ACGE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 447dfa710e69479159e9d407474fbf5f67d3a3330ab0c7627afd123ded3fdb3a + label: The Pirates of Dark Water + name: Pirates of Dark Water, The + region: SNS-8P-USA + revision: SNS-8P-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c2a1a66648a0a0bfe2f201cf4f926d138e410fbf85ecf436ccb9aac70c0df3de + label: Pit-Fighter + name: Pit-Fighter + region: SNS-PF-USA + revision: SNS-PF-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: e03d117d8b3093b0bbad5224638f85378b254b81eb304e506a732b4338802e0f + label: Pitfall: The Mayan Adventure + name: Pitfall - The Mayan Adventure + region: SNS-APAE-USA + revision: SNS-APAE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 0b3b0fd42bbe06a812053df376b183412fc0de335c4b7cb8e45f3fe47b0044e9 + label: Plok + name: Plok + region: SNS-P4-USA + revision: SNS-P4-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 72b2b3bead3fcd27a1610ad5d4d8be3235efeaff96df2e7858911992a5892d21 + label: Pocky & Rocky + name: Pocky & Rocky + region: SNS-KK-USA + revision: SNS-KK-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: cc33ae02114ea18a86592de327b2b4bcc80728b11a5e4c61666dca71480d4169 + label: Pocky & Rocky 2 + name: Pocky & Rocky 2 + region: SNS-29-USA + revision: SNS-29-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 5e580f220ed16281df8ee9a5f450b553f39f8c4078d3f3048d66bda15f98e19f + label: Populous + name: Populous + region: SNS-PO-USA + revision: SNS-PO-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: ee9759fdb590ba908f569c2bb8a63703d282b58b84bd1fe0a472ea47685acdc5 + label: Porky Pig's Haunted Holiday + name: Porky Pig's Haunted Holiday + region: SNS-APPE-USA + revision: SNS-APPE-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 06c8fc466805f97c9147711b2d8370d4f4d05d9fa3a916f17aa1682f73c9a63b + label: Power Instinct + name: Power Instinct + region: SNS-AGKE-USA + revision: SNS-AGKE-0 + board: SHVC-BJ0N-20 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: 42ee7829d3db0213b718168c29674879bb4532573e9fb3450a5b417174a16ed0 + label: Power Moves + name: Power Moves + region: SNS-P3-USA + revision: SNS-P3-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 0288ec049723cd0c7f1148cdc1aef0b6922b8a756affe373c99d5690e0dfceaa + label: Power Piggs of the Dark Age + name: Power Piggs of the Dark Age + region: SNS-AOTE-USA + revision: SNS-AOTE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 2e2a8c0da7f6def617077a25b222062f6988ef14b36b2edfe10d47c6a942d023 + label: Power Rangers Zeo: Battle Racers + name: Power Rangers Zeo - Battle Racers + region: SNS-A4RE-USA + revision: SNS-A4RE-0 + board: SHVC-1L3B-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + memory + type: RAM + size: 0x800 + content: Internal + volatile + +game + sha256: 8f387d083de1399bb79e5312c31a6f1757f2a536bfa25cecf1aea77bfd77058b + label: Prehistorik Man + name: Prehistorik Man + region: SNS-APUE-USA + revision: SNS-APUE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 55376715f243b1bacd9aeecf1092bbc7837fe512592a2c1703d24b0829fc1934 + label: Primal Rage + name: Primal Rage + region: SNS-AR9E-USA + revision: SNS-AR9E-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 494190cd6d7fd68882cbe255a6e237d9c4bdaf3988615ede0297a5e285ad5dd9 + label: Prince of Persia + name: Prince of Persia + region: SNS-PR-USA + revision: SNS-PR-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 04ca1a481093c4a7e12f18b33697d6e05e50e30e0f5b1655aa265abd14719bba + label: Prince of Persia 2: The Shadow and the Flame + name: Prince of Persia 2 - The Shadow and the Flame + region: SNS-AUPE-USA + revision: SNS-AUPE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 85e2e58e1f99fce366c85d49f77446395584ca4959ef772a707fe454ed46c68f + label: Pro Quarterback + name: Pro Quarterback + region: SNS-QB-USA + revision: SNS-QB-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 00b5b3d3febd1a6f28ceb49e39cdd9476a944fe62ea3850808cdeafaaaa63040 + label: Pro Sport Hockey + name: Pro Sport Hockey + region: SNS-UI-USA + revision: SNS-UI-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 475c9baa1c2b76a6b3119e47d32814dc1c08e84e23250ae015bb0bccea915637 + label: Push-Over + name: Push-Over + region: SNS-PV-USA + revision: SNS-PV-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 89d57bf308033ef17f770a80080cbeed2d112244635d5b5f860f2016398cd2f6 + label: Q*bert 3 + name: Q-bert 3 + region: SNS-Q3-USA + revision: SNS-Q3-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 4d6c7d6d2693d8d43bafaff7582f9a94885362dadd9ee4012bbbdce1ba10c30e + label: R-Type III: The Third Lightning + name: R-Type III - The Third Lightning + region: SNS-ER-USA + revision: SNS-ER-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: dd0feb78e2d5d81f59241baf3bca5e2edaebbe98f0ac860a4eb6d448718f1ca5 + label: Race Drivin' + name: Race Drivin' + region: SNS-RV-USA + revision: SNS-RV-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: edf990e502c646a2fe83fcd1d359ca0ed5003ace06cb4c3de5a51a0c56d6ec54 + label: Radical Psycho Machine Racing + name: Radical Psycho Machine Racing + region: SNS-RP-USA + revision: SNS-RP-0 + board: SHVC-1A1B-05 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 1869c0faf93bf21b7ff965f1925fad4b2924a64b1e48f4837221eebdf741226c + label: Radical Rex + name: Radical Rex + region: SNS-ARRE-USA + revision: SNS-ARRE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5fd7666e509f9d3cf1fd6b209dc22f2f3848f74eae7b83239d1090e031fc6df2 + label: Raiden Trad + name: Raiden Trad + region: SNS-RD-USA + revision: SNS-RD-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e19f7d8d5c3e4cefeff5889380d8780495e01f0553d13be4182a15a5d4b615bb + label: Rampart + name: Rampart + region: SNS-RM-USA + revision: SNS-RM-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 32d32ef56af83887cdc2c04b3da4be1cd82a473988deaa2e7dd50d38ef79c3a1 + label: Ranma ½: Hard Battle + name: Ranma Half - Hard Battle + region: SNS-R2-USA + revision: SNS-R2-0 + board: SHVC-2J0N-01 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 920bbaaf6a32cab5feabb5bc8b2b427dccd53bfd31d0da8acb7ea4e819139e4f + label: Rap Jam: Volume One + name: Rap Jam - Volume One + region: SNS-ARVE-USA + revision: SNS-ARVE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 097cbe9720903bc14599158b80e0cc314ef2fe8a585d6d0a8962eb1626031492 + label: Realm + name: Realm + region: SNS-ARQE-USA + revision: SNS-ARQE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 549f2e5b17f685cad25ba71ce7bc6e004e7bfd09e6be12a827af9a9a26556fff + label: Red Line: F-1 Racer + name: Red Line - F1 Racer + region: SNS-6R-USA + revision: SNS-6R-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b2221d0a59a399e437710e1191a37071d0a59c72d8e62427cd499de8d8fd7b61 + label: Relief Pitcher + name: Relief Pitcher + region: SNS-5R-USA + revision: SNS-5R-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: d322ce440076be0e3678277596acee8089098f4397b35ac8b3df88be5ce5e02f + label: The Ren & Stimpy Show: Buckeroo$! + name: Ren & Stimpy Show, The - Buckeroo$! + region: SNS-ARBE-USA + revision: SNS-ARBE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 71e7083cfcf32b738f60f5eeffd4f9d1fd9250afbde0c56e22a4b97abac377a1 + label: The Ren & Stimpy Show: Fire Dogs + name: Ren & Stimpy Show, The - Fire Dogs + region: SNS-6Y-USA + revision: SNS-6Y-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: ad7dd4efb8836d4009f6c76bd21865d8f5dcf9c3cbd8fa7bb32d686488847120 + label: The Ren & Stimpy Show: Time Warp + name: Ren & Stimpy Show, The - Time Warp + region: SNS-ARTE-USA + revision: SNS-ARTE-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x140000 + content: Program + +game + sha256: ba54d715abf100b94fee801351986fa818e4309730cefbacf9b4fad36e284c1c + label: The Ren & Stimpy Show: Veediots! + name: Ren & Stimpy Show, The - Veediots! + region: SNS-V8-USA + revision: SNS-V8-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5fb072c3c2e9d8e7f84bea9c4bf2253e6868eb2b1f13e35a7d75fdf05896d873 + label: Revolution X: Music is the Weapon + name: Revolution X - Music is the Weapon + region: SNS-AXRE-USA + revision: SNS-AXRE-0 + board: SHVC-2A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: f44482e2cccd9fcfd5875d84ff700f6e783f3bd8abd1ac4d939074cd6ad3fe65 + label: Rex Ronan: Experimental Surgeon + name: Rex Ronan - Experimental Surgeon + region: SNS-XR-USA + revision: SNS-XR-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: e3ea89964ee82d2ae1e5739b8503acf62732aedef28d1b3d5caa9ebae0feec06 + label: Riddick Bowe Boxing + name: Riddick Bowe Boxing + region: SNS-XG-USA + revision: SNS-XG-0 + board: SHVC-1A1M-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: cce455b7074f62ffdb41863ee8c160ea06f7acd028837666329bc1e0c3567ad0 + label: Rise of the Phoenix + name: Rise of the Phoenix + region: SNS-QG-USA + revision: SNS-QG-0 + board: SHVC-2J3M-11 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 38be8013bbe07b2020ba30031fb0a2c77bad8a3eb61fac8217adfe82d6c402af + label: Rise of the Robots + name: Rise of the Robots + region: SNS-AROE-USA + revision: SNS-AROE-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 3f59cc687d22cd1b23cc33ae6e4518234c9da813c01f79f4c43716e12d32a12d + label: Rival Turf! + name: Rival Turf! + region: SNS-RB-USA + revision: SNS-RB-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 864aa9068fb23cd20022a9ac36fb9082299278ea0cb07a20deec2b6a1c6cbc70 + label: Road Riot 4WD + name: Road Riot 4WD + region: SNS-RR-USA + revision: SNS-RR-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 2e8203e421f97cf165f03a5d4f69dadf0bcca18c42c6a1dfe79c8705c522cc54 + label: Road Runner's Death Valley Rally + name: Road Runner's Death Valley Rally + region: SNS-DV-USA + revision: SNS-DV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 055d9c6311a663af7c899a6f76a419c274c57baada3ef64c52fadb1c676b1446 + label: RoboCop 3 + name: RoboCop 3 + region: SNS-R3-USA + revision: SNS-R3-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a2115e7576dec06e0de613efb89de861815a78ef72e78a3784be09fb7541928f + label: RoboCop versus The Terminator + name: RoboCop vs. The Terminator + region: SNS-VR-USA + revision: SNS-VR-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 1e2ded7b1e350449b7a99b7ec414525e4b9b086c416deeee5eb3e48e032c46bd + label: Robotrek + name: Robotrek + region: SNS-E9-USA + revision: SNS-E9-0 + board: SHVC-2J3M-11 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 9d721753301278325c851f1843d669a697aed757dcf6495a31fc31ddf664b182 + label: Rock n' Roll Racing + name: Rock & Roll Racing + region: SNS-RN-USA + revision: SNS-RN-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b072fd9b08042e3262446fdf418a41848251072a32bd7f8335cc03543c4ae6c8 + label: The Rocketeer + name: Rocketeer, The + region: SNS-RK-USA + revision: SNS-RK-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: cde8876b99c337ff932322506ceef05519e5882b853c54bb8c650d9500cd5957 + label: Rocko's Modern Life: Spunky's Dangerous Day + name: Rocko's Modern Life - Spunky's Dangerous Day + region: SNS-8D-USA + revision: SNS-8D-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 7c0f915b581796e5b6dd384ecdc0dad8af4d956492fbcedec628c8845d911d7e + label: Rocky Rodent + name: Rocky Rodent + region: SNS-NP-USA + revision: SNS-NP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e21300c8c4170e084fd83ce4c842dd73f939fbd10ddfe47c9a49b6e291dcd52d + label: Roger Clemens' MVP Baseball + name: Roger Clemens' MVP Baseball + region: SNS-VP-USA + revision: SNS-VP-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f7e3c3012af2dbad350646b6ef3470f0b4c42e4a2873109f7aa6c81d7157c887 + label: Roger Clemens' MVP Baseball + name: Roger Clemens' MVP Baseball + region: SNS-VP-USA + revision: SNS-VP-1 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 815bfcf4fd6eb23a20c2e50dde023c210b273ffb6cd86a93909d803c3643ce46 + label: Romance of the Three Kingdoms II + name: Romance of the Three Kingdoms II + region: SNS-XL-USA + revision: SNS-XL-0 + board: SHVC-1A5B-04 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 88fa0a78ca98c6386e086c7fa9e81a2625bdecc55115dde6c6f4770b0670aa40 + label: Romance of the Three Kingdoms III: Dragon of Destiny + name: Romance of the Three Kingdoms III - Dragon of Destiny + region: SNS-S3-USA + revision: SNS-S3-0 + board: SHVC-2J5M-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 9670c67eeeb5581fa5345025a2e2ee875179e0da9f5be4bf78641e477d785f17 + label: Romance of the Three Kingdoms IV: Wall of Fire + name: Romance of the Three Kingdoms IV - Wall of Fire + region: SNS-AS4E-USA + revision: SNS-AS4E-0 + board: SHVC-1J5M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 4158e3e8890a52f0b12dc9ad5a29276058a247ff41e9f1d22897ebde1eb11269 + label: Run Saber + name: Run Saber + region: SNS-RU-USA + revision: SNS-RU-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5db804171fca42486485ed85e4afe45b29e6d01304bdf75d520bfc42429739e3 + label: Samurai Shodown + name: Samurai Shodown + region: SNS-A7SE-USA + revision: SNS-A7SE-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 34e1af0642c85148c5a3dc3c7ab4bcbda13a9fea190934b5526c555fff035651 + label: Saturday Night Slam Masters + name: Saturday Night Slam Masters + region: SNS-ZW-USA + revision: SNS-ZW-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 7fb5236d10852125f0f37c2188b907d636647400a57bccbdb2f63098ffae8b2d + label: Scooby-Doo Mystery + name: Scooby-Doo Mystery + region: SNS-AXDE-USA + revision: SNS-AXDE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: a4ab8cfad2f236675b1c0124f8484688e149f38e8628a3b38e9ec14d491ec07e + label: SeaQuest DSV + name: SeaQuest DSV + region: SNS-ASQE-USA + revision: SNS-ASQE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 17c864a76d498feb6479eee8e7d6807b951c66225033228622bb66754baab1db + label: Secret of Evermore + name: Secret of Evermore + region: SNS-AEOE-USA + revision: SNS-AEOE-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 4c15013131351e694e05f22e38bb1b3e4031dedac77ec75abecebe8520d82d5f + label: Secret of Mana + name: Secret of Mana + region: SNS-K2-USA + revision: SNS-K2-0 + board: SHVC-1J3M-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: e6bc0a595d5c7c4bc0bbb61ffe35a70288a77eb78544ed74682d489a9e6f07f4 + label: Shadowrun + name: Shadowrun + region: SNS-WR-USA + revision: SNS-WR-0 + board: SHVC-1A3M-10 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: bdbcc53b266159b5a08e307e5b60fdb0cb5a1ba8f8c1c6c7f89d81eaf5133e85 + label: Shanghai II: Dragon's Eye + name: Shanghai II - Dragon's Eye + region: SNS-DE-USA + revision: SNS-DE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c73757eea258e169e506eaef989227a59918060f94117917f338183db14c50b6 + label: Shaq-Fu + name: Shaq-Fu + region: SNS-AQFE-USA + revision: SNS-AQFE-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 454c580498a7d317ed61cb5863b1999eff57ad440ecd30ebb76e193c9c52f3ac + label: Shien's Revenge + name: Shien's Revenge + region: SNS-OO-USA + revision: SNS-OO-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: de2d5a952096c5f50368b9270d342aa6e7a39007ffbec27117e182e30ef4cf32 + label: Sid Meier's Civilization + name: Sid Meier's Civilization + region: SNS-EQ-USA + revision: SNS-EQ-0 + board: SHVC-1J5M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: d09ca5adaee65cfd686742482bc55b1a3ce9bc5ebed61f24c5631555151a7fc7 + label: Side Pocket + name: Side Pocket + region: SNS-4P-USA + revision: SNS-4P-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c0bd1b378337c32047a6b7122a3813beb646e496fbdb1fa5c87ab9856271e4c5 + label: SimAnt: The Electronic Ant Colony + name: SimAnt - The Electronic Ant Colony + region: SNS-AN-USA + revision: SNS-AN-0 + board: SHVC-1A5M-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: e9c0bc05511e05a0d7c3e7cc42e761e1e8e532d46f59b9854b6902e1a2e9dd0a + label: SimCity + name: SimCity + region: SNS-SC-USA + revision: SNS-SC-0 + board: SHVC-1A5B-02 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: bf74c58e4190faca2f3a967dc190fe529d13887d1262b72e057b5353e43cf67f + label: SimCity 2000 + name: SimCity 2000 + region: SNS-AWWE-USA + revision: SNS-AWWE-0 + board: SHVC-1J5M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 446a1036d036986fdea7906c83832d3ba79ef63a6ed8c4e88b89ab9cb25daded + label: SimEarth: The Living Planet + name: SimEarth - The Living Planet + region: SNS-SE-USA + revision: SNS-SE-0 + board: SHVC-1A3B-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: f0d98e9061d0f6a193bb856de8a592f336dada97c41966e8d03119ba97465413 + label: The Simpsons: Bart's Nightmare + name: Simpsons, The - Bart's Nightmare + region: SNS-BN-USA + revision: SNS-BN-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 29c28188234ddbb0b72fc84253dcd3514e23034779c773db8097b073b73390c8 + label: The Simpsons: Virtual Bart + name: Simpsons, The - Virtual Bart + region: SNS-AVBE-USA + revision: SNS-AVBE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 70008efe51185eb0a2f8d8d8ac2bdbb99bd3dfcc169dcc474962f82692998051 + label: S.O.S.: Sink or Swim + name: Sink or Swim + region: SNS-9J-USA + revision: SNS-9J-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: e10070f01845505ae8bfdf7b5b492e7209c2ae876f169fb6ff420dea269f4da3 + label: Skuljagger: Revolt of the Westicans + name: Skuljagger - Revolt of the Westicans + region: SNS-SL-USA + revision: SNS-SL-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: a4ba1483db79c3f6278082387bce216d8f3e3b11ca32d49516d27f5ac07135a5 + label: Skyblazer + name: Skyblazer + region: SNS-LZ-USA + revision: SNS-LZ-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: cbca00fa5dfd6c72db2f21d010255657c33f7ac48de2554262035ead11bdf314 + label: Smart Ball + name: Smart Ball + region: SNS-JB-USA + revision: SNS-JB-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f653b8308b617e1cba1caf004e5a670088b882e320fa6afcc7a29dd3b2dd0ea0 + label: Snow White in Happily Ever After + name: Snow White in Happily Ever After + region: SNS-ASHE-USA + revision: SNS-ASHE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6fe7c8d39fcfab7f0a18e837a7ee0dd162e0557d6989c6e0d10c81616d3a0b8b + label: Soldiers of Fortune + name: Soldiers of Fortune + region: SNS-UD-USA + revision: SNS-UD-0 + board: SHVC-2J0N-01 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 75a7b5b8ad0329dc828d3201089e125fd55fdfc99d4cec704ffcd7e3036c2410 + label: Sonic Blast Man + name: Sonic Blast Man + region: SNS-SK-USA + revision: SNS-SK-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: efe78f6fc68ddd0f6ef0ad9e0223d9417c14fcadece987dc8f50423fd6723b27 + label: Sonic Blast Man II + name: Sonic Blast Man II + region: SNS-2C-USA + revision: SNS-2C-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 8f0a7670fe53d30f721784e5fff78349eb157a9f0eb2246206f9d7db478b7c56 + label: SOS + name: SOS + region: SNS-TT-USA + revision: SNS-TT-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8438da09de8ce9aded3bb08644543f7b60fb60cffc68ce2d67d6a0643f2ecfc2 + label: Soul Blazer + name: Soul Blazer + region: SNS-SO-USA + revision: SNS-SO-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 85887dfa92374048fb20809c00eabea428992024cf875d287d0431b9767cc7cb + label: Space Ace + name: Space Ace + region: SNS-5A-USA + revision: SNS-5A-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 24f3f22949f36ebf8ab4beaa8cba22db107efe7a7585f749343f2860bf041fe1 + label: Space Football: One on One + name: Space Football - One on One + region: SNS-FL-USA + revision: SNS-FL-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: dc5353ddc350816619230f25f8c51bddabf7438e6dfba21662eb1c4794856735 + label: Space Invaders + name: Space Invaders + region: SNS-IC-USA + revision: SNS-IC-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x40000 + content: Program + +game + sha256: f5b7418c00ccac44615cfc57c7e17d57533837056886f6d733e6b714c36dec1f + label: Space Megaforce + name: Space Megaforce + region: SNS-AT-USA + revision: SNS-AT-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 14dc44687c8da35aec63b9edadbaac21bf7293f5171646f614139192e82ab071 + label: Spanky's Quest + name: Spanky's Quest + region: SNS-HJ-USA + revision: SNS-HJ-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: eaa06470734ea57eff9b888137aa468fcb7bb149a0870a85e68c9db123de4670 + label: Sparkster + name: Sparkster + region: SNS-ASSE-USA + revision: SNS-ASSE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 32d0f1ca5b91fd9b2caf81422fb9e8fb30bc091f0b2a429b9269dd307fcba4fd + label: Spawn + name: Spawn + region: SNS-A9WE-USA + revision: SNS-A9WE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 22d0b7687d66436abaf447bb29558e43f562283ec4dbe744df7d79a3e27a2577 + label: Spectre + name: Spectre + region: SNS-7Q-USA + revision: SNS-7Q-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0xe0000 + content: Program + +game + sha256: 54046ec1fc57f6165ad33080502f72809d1b06b438a5a0d0a80ffa2bb3df8b0b + label: Speed Racer in My Most Dangerous Adventures + name: Speed Racer in My Most Dangerous Adventures + region: SNS-9S-USA + revision: SNS-9S-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: df02d0f4f40e2732138309d38e91b48aef482490979007ecb63359a35115dfd4 + label: Speedy Gonzales: Los Gatos Bandidos + name: Speedy Gonzales - Los Gatos Bandidos + region: SNS-ASEE-USA + revision: SNS-ASEE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 68a51b7a06b6a9e7100a89521e52b5c467c46c828c0f6504bee677beac2aa6fd + label: Speedy Gonzales: Los Gatos Bandidos + name: Speedy Gonzales - Los Gatos Bandidos + region: SNS-ASEE-USA + revision: SNS-ASEE-1 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 964d21996e385e032b5d18baf716692ba1db780245cd71956c212045c1b8eb9a + label: Spider-Man & Venom: Maximum Carnage + name: Spider-Man & Venom - Maximum Carnage + region: SNS-AMCE-USA + revision: SNS-AMCE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: b72fbbfe737eff49f59dcef9f13b963e50c5bc322d7eb0e7b4c25f3a71aa0815 + label: Spider-Man & Venom: Separation Anxiety + name: Spider-Man & Venom - Separation Anxiety + region: SNS-A2CE-USA + revision: SNS-A2CE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 63210a91573fa8e19592f2e6c746a400831d804c00453739447d2df32e731df7 + label: Spider-Man & X-Men: Arcade's Revenge + name: Spider-Man & X-Men - Arcade's Revenge + region: SNS-MN-USA + revision: SNS-MN-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f05d777e3de69aab18d336cac0af07f794f8d00090d085f86cebaed3679cabad + label: Spider-Man: The Animated Series + name: Spider-Man - The Animated Series + region: SNS-ADME-USA + revision: SNS-ADME-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: fe10238ae42ed9eb4d906a81dd50ebe585140982cdfe266308ce1f16e78e6903 + label: Spindizzy Worlds + name: Spindizzy Worlds + region: SNS-SX-USA + revision: SNS-SX-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 8d3f20af0be588cf2edc39aee0d96d4085512919a05c0e90a7848e414cc20e42 + label: The Sporting News Baseball + name: Sporting News Baseball, The + region: SNS-AWBE-USA + revision: SNS-AWBE-0 + board: SHVC-1J3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 254d17a82a32d8bd231ca3a87d356b65e65cb0229902a69a57c21a4c99bbba1f + label: Sports Illustrated: Championship Football & Baseball + name: Sports Illustrated - Championship Football & Baseball + region: SNS-LU-USA + revision: SNS-LU-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 3857b5294ea8f7468849437bb2d8271564e8a0ff30774622e9c872bcbd53a84d + label: Star Fox + name: Star Fox + region: SNS-FO-USA + revision: SNS-FO-0 + board: SHVC-1C0N5S-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + volatile + +game + sha256: 82e39dfbb3e4fe5c28044e80878392070c618b298dd5a267e5ea53c8f72cc548 + label: Star Fox + name: Star Fox + region: SNS-FO-USA + revision: SNS-FO-2 + board: SHVC-1C0N + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + volatile + +game + sha256: 2c0bac12a7866fad1cb306da768a201c12f2520332df1ef51cba1576db21ff06 + label: Star Fox: Super Weekend + name: Star Fox - Super Weekend + region: SNS-FU-USA + revision: SNS-FU-0 + board: SHVC-1C0N + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + volatile + +game + sha256: 3a16ad45ae3d89b13c9e53e21c2a4c725ff7cec7fbe7896d538d163f92cb4aac + label: Star Trek: Deep Space Nine - Crossroads of Time + name: Star Trek - Deep Space Nine - Crossroads of Time + region: SNS-A9DE-USA + revision: SNS-A9DE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b4d0b4a3fd73469f5469dfcc2316e50848ebf0630a225df2969c740759e321f4 + label: Star Trek: Starfleet Academy - Starship Bridge Simulator + name: Star Trek - Starfleet Academy - Starship Bridge Simulator + region: SNS-ASTE-USA + revision: SNS-ASTE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 22c907b56ac6f414365801ed375c3fbf75696ce7f34ec89e1724628dc5622957 + label: Star Trek: The Next Generation - Future's Past + name: Star Trek - The Next Generation - Future's Past + region: SNS-XN-USA + revision: SNS-XN-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 9ffd95486904804aca1f7068c99f1c9e91c2c0e5474ec758df1a913393571cc7 + label: Stargate + name: Stargate + region: SNS-AGTE-USA + revision: SNS-AGTE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 91f938b4989215b1cd39635797f23b59b9d7b6d36e583f9eb69d022abe537bfc + label: Steel Talons + name: Steel Talons + region: SNS-5S-USA + revision: SNS-5S-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: e3b07a59f969ced91c4579bb459f2c747a6c3f12c45ae4776483ef4830f5f00f + label: Sterling Sharpe: End 2 End + name: Sterling Sharpe - End 2 End + region: SNS-AS2E-USA + revision: SNS-AS2E-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: dad9c116283322d5a13fd659874c681582abdff3df182cc4c90511d33fb7110a + label: Stone Protectors + name: Stone Protectors + region: SNS-ASOE-USA + revision: SNS-ASOE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: b4626cf0c876a124b50f9421c48a7d762e9ed808ad336c799d543d60b484897c + label: Street Combat + name: Street Combat + region: SNS-RA-USA + revision: SNS-RA-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 910a29f834199c63c22beddc749baba746da9922196a553255deade59f4fc127 + label: Street Fighter Alpha 2 + name: Street Fighter Alpha 2 + region: SNS-AUZE-USA + revision: SNS-AUZE-0 + board: SHVC-1N0N-01 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 2b34161e96ef3f0f48cecd67e531a9bb94310652d8686f301bac426e4ab97e77 + label: Street Fighter II: The World Warrior + name: Street Fighter II - The World Warrior + region: SNS-S2-USA + revision: SNS-S2-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 3e487f8ba48c0b5e31744e3281d6bce375089db6075c8eb3d9a929376b817381 + label: Street Fighter II Turbo: Hyper Fighting + name: Street Fighter II Turbo - Hyper Fighting + region: SNS-TI-USA + revision: SNS-TI-0 + board: SHVC-3J0N-01 + memory + type: ROM + size: 0x280000 + content: Program + +game + sha256: 6756f92fe8e066be4b204cfdc94c1615ba6ece7e78fb5d2c77c81a9d298aa744 + label: Street Hockey '95 + name: Street Hockey '95 + region: SNS-AHYE-USA + revision: SNS-AHYE-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: d1f61b6bb4bb6879a4fbd2c82d77390c546ee7f821edddc884fb9cc7463ad79b + label: Street Racer + name: Street Racer + region: SNS-ASRE-USA + revision: SNS-ASRE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 05f14e6ed3394d9273e2397769a8acf1a9db646be6066e82269521e8eec53562 + label: Strike Gunner S.T.G. + name: Strike Gunner STG + region: SNS-SG-USA + revision: SNS-SG-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c04d80b84514202ff319384ca20641eb0189e975eed5612915bd9c224b2ab30a + label: Stunt Race FX + name: Stunt Race FX + region: SNS-CQ-USA + revision: SNS-CQ-1 + board: SHVC-1CA6B-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x10000 + content: Save + oscillator + frequency: 21440000 + +game + sha256: e9c406d4f773697b9b671e7ddf2207c9d0ab242d7f23e502cdd453fbb264d392 + label: Sunset Riders + name: Sunset Riders + region: SNS-6S-USA + revision: SNS-6S-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 190999122aacc2cff20c5677b3f60ed938d8a36b696d16cc1bf416705efe151e + label: Super Adventure Island + name: Super Adventure Island + region: SNS-H2-USA + revision: SNS-H2-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: eaf1b83e95d8a04f9a84d4960cf87cc182fc60ef07be35eb8929c4033d6fef67 + label: Super Adventure Island II + name: Super Adventure Island II + region: SNS-E4-USA + revision: SNS-E4-0 + board: SHVC-2J3M-11 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 0deb7a91fbe5848f1733ce668daaa49b0dad3d821bacc0791837c1ba15e60d7c + label: Super Alfred Chicken + name: Super Alfred Chicken + region: SNS-8A-USA + revision: SNS-8A-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b64f9f95fb244feddb3ff50bf0972af88f5d006e9b09050b930374fef8b37862 + label: The Super Aquatic Games starring the Aquabats + name: Super Aquatic Games starring the Aquabats, The + region: SNS-AU-USA + revision: SNS-AU-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 8808783f789ca6413364a7abea240f6f7291b5906026f360ba8cfdd2791fc179 + label: Super Baseball 2020 + name: Super Baseball 2020 + region: SNS-SA-USA + revision: SNS-SA-0 + board: SHVC-2J0N-01 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 1622371a5a4001fff9690323e89b7a8d449cdc3cae6dcd1249f0c7dc8c651d33 + label: Super Baseball Simulator 1.000 + name: Super Baseball Simulator 1.000 + region: SNS-UB-USA + revision: SNS-UB-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: a8239355631d303ecebfd43fc14e80f148e4ac9937234e29cc87d6f939b033a0 + label: Super Bases Loaded + name: Super Bases Loaded + region: SNS-SP-USA + revision: SNS-SP-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 327745aceb708d82419c3d2cffdffa78f55df0878bb1786e1b7fc294385f20ba + label: Super Bases Loaded 2 + name: Super Bases Loaded 2 + region: SNS-3D-USA + revision: SNS-3D-0 + board: SHVC-2B3B-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + volatile + oscillator + frequency: 7600000 + +game + sha256: b21a161fed748920e54cd72c54095416b1d999636e0388d7d147884779c52833 + label: Super Bases Loaded 3: License to Steal + name: Super Bases Loaded 3 - License to Steal + region: SNS-AB3E-USA + revision: SNS-AB3E-0 + board: SHVC-1A3M-30 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 165938810948f3226f7446978fa36ae8bc781616d95b39cd126d5c8afbf6e2ee + label: Super Batter Up + name: Super Batter Up + region: SNS-FA-USA + revision: SNS-FA-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 1d6573e3db2efab0c98d1940b4171d569348d27a1cc20e80a83094e6c0e66e35 + label: Super Battleship + name: Super Battleship + region: SNS-8B-USA + revision: SNS-8B-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 94496e73fc7fdf2f72f16bf2becb0c3935db2ebd97555eac73b63400acbceec6 + label: Super Battletank: War in the Gulf + name: Super Battletank - War in the Gulf + region: SNS-SB-USA + revision: SNS-SB-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: b68e865b0b5fe6af421a171e94fb1cb0006ae3e412b6361f6f858c44adaa304b + label: Super Battletank 2 + name: Super Battletank 2 + region: SNS-2X-USA + revision: SNS-2X-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: f0913358cb0870c3dcc7f0c0d2d69704874c31a113150eda668c95024c0d6fd9 + label: Super Black Bass + name: Super Black Bass + region: SNS-BQ-USA + revision: SNS-BQ-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4efab3f49cbe91ec77b6cba747ddfedfdc0b080c755a8b6ba51234f0676c000f + label: Super Bomberman + name: Super Bomberman + region: SNS-H6-USA + revision: SNS-H6-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 0a4b4a783a7faf6ada3e1326ecf85de77e8c2a171659b42a78a1fae43f806ca6 + label: Super Bomberman 2 + name: Super Bomberman 2 + region: SNS-M4-USA + revision: SNS-M4-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 21d4a72461d8680cf75cf3b8eba42e13127815bc17b6249d89a5e39beb3f1406 + label: Super Bonk + name: Super Bonk + region: SNS-ANKE-USA + revision: SNS-ANKE-0 + board: SHVC-2J0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 946de556b4f877e54e16b5c828db89c038e50349cfd0ddf8ea96b6541f9d70fa + label: Super Bowling + name: Super Bowling + region: SNS-BW-USA + revision: SNS-BW-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 5965bde449ff775c1a0d9fd3cf2fb8c51a86b44ad1942dfb5c14a91f103be030 + label: Super Buster Brothers + name: Super Buster Brothers + region: SNS-SN-USA + revision: SNS-SN-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: d42f8c7969b4c434f9ca04ce0080d897877a5e71c2926d309ef5dae93ba25548 + label: Super Caesers Palace + name: Super Caesers Palace + region: SNS-C6-USA + revision: SNS-C6-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 0ef6f4cce5a2273fa49fe1ce724e0048a8e39c91da6b00dbb693fe1ba909177d + label: Super Castlevania IV + name: Super Castlevania IV + region: SNS-AD-USA + revision: SNS-AD-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: b839253b878821ff00847491d11452e933baaf303f49dd39d22e3a524ea1ff81 + label: Super Chase H.Q. + name: Super Chase HQ + region: SNS-QT-USA + revision: SNS-QT-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6cbc4db85cb8420020f9edbfd290c0f435b313a59577aca65314d31f8b816620 + label: Super Conflict + name: Super Conflict + region: SNS-CN-USA + revision: SNS-CN-0 + board: SHVC-1A1B-06 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: db7d727de86a1ac886ce3c243bf5941910154eaef3be50209187b9711592830d + label: Super Copa + name: Super Copa + region: SNS-75-USA + revision: SNS-75-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: bcced1be76ef920b562a555696bcb4583d1c8cea4d4b057cab6e0e09be8ef8c4 + label: Super Double Dragon + name: Super Double Dragon + region: SNS-WD-USA + revision: SNS-WD-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4d7fc331a811b8dc630b469262fd6f45e289243cef83101f32038158967d1b28 + label: Super Game Boy + name: Super Game Boy + region: SNS-A-SG-USA + revision: SYS-SGB-2 + board: SGB-R-10 + memory + type: ROM + size: 0x40000 + content: Program + memory + type: ROM + size: 0x100 + content: Boot + manufacturer: Nintendo + architecture: SM83 + identifier: SGB1 + +game + sha256: 7468c271d7240cf4e0d08c16e9969a1b1b1caf5adc0e5adc568d93c92651a057 + label: Super Ghouls 'n Ghosts + name: Super Ghouls & Ghosts + region: SNS-CM-USA + revision: SNS-CM-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d4caa6683ee1b6c70c10fd0555ade33dadcc6551d94e791586e64fd683d8f3a8 + label: Super Goal! 2 + name: Super Goal! 2 + region: SNS-JV-USA + revision: SNS-JV-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 33dda5838264c93341ef865512e4b86e16fd4a0387eda04e331517bfaecf1c0b + label: Super Godzilla + name: Super Godzilla + region: SNS-7G-USA + revision: SNS-7G-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: d78ff42efdbb0e180777d17b5f7a96e08530ab77f15a99237f60714f7cfe2b74 + label: Super High Impact + name: Super High Impact + region: SNS-HX-USA + revision: SNS-HX-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 3f8efb19eae68f24feb42c018b7dc7a819bfd8d993ab36899681caa7ee94b06e + label: Super James Pond + name: Super James Pond + region: SNS-J5-USA + revision: SNS-J5-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: a9e3e57d591e995e8e0dd228b619b6aed42205eaf55316fa8ff33f236b3a32b3 + label: Super Mario All-Stars + name: Super Mario All-Stars + region: SNS-4M-USA + revision: SNS-4M-0 + board: SHVC-2A3B-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: a8806bfe07cd3c9945d9fd3fcea932ae1cd671cab5cae12bb7a2ae726cbf9175 + label: Super Mario All-Stars + Super Mario World + name: Super Mario All-Stars + Super Mario World + region: SNS-5M-USA + revision: SNS-5M-0 + board: SHVC-BA3M-01 + memory + type: ROM + size: 0x280000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 89ad4ba02a2518ca792cf96b61b36613f86baac92344c9c10d7fab5433bebc16 + label: Super Mario Kart + name: Super Mario Kart + region: SNS-MK-USA + revision: SNS-MK-0 + board: SHVC-1K1B-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + volatile + oscillator + frequency: 7600000 + +game + sha256: 76d293e5a772eb2f326e173eac62ca323873b1f329f9b935a97ba86974e1fcd5 + label: Super Mario Kart + name: Super Mario Kart + region: SNS-MK-USA + revision: SNS-MK-0 + board: SHVC-1K1X-10 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1B + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1B + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1B + volatile + oscillator + frequency: 7600000 + +game + sha256: 740646f3535bfb365ca44e70d46ab433467b142bd84010393070bd0b141af853 + label: Super Mario RPG: Legend of the Seven Stars + name: Super Mario RPG - Legend of the Seven Stars + region: SNS-ARWE-USA + revision: SNS-ARWE-0 + board: SHVC-1L5B-11 + memory + type: ROM + size: 0x400000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + memory + type: RAM + size: 0x800 + content: Internal + volatile + +game + sha256: 0838e531fe22c077528febe14cb3ff7c492f1f5fa8de354192bdff7137c27f5b + label: Super Mario World + name: Super Mario World + region: SNS-MW-USA + revision: SNS-MW-0 + board: SHVC-1A1B-06 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 9b4957466798bbdb5b43a450bbb60b2591ae81d95b891430f62d53ca62e8bc7b + label: Super Mario World 2: Yoshi's Island + name: Super Mario World 2 - Yoshi's Island + region: SNS-YI-USA + revision: SNS-YI-0 + board: SHVC-1CB5B-01 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + oscillator + frequency: 21440000 + +game + sha256: bd763c1a56365c244be92e6cffefd318780a2a19eda7d5baf1c6d5bd6c1b3e06 + label: Super Mario World 2: Yoshi's Island + name: Super Mario World 2 - Yoshi's Island + region: SNS-YI-USA + revision: SNS-YI-1 + board: SHVC-1CB5B-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + oscillator + frequency: 21440000 + +game + sha256: 12b77c4bc9c1832cee8881244659065ee1d84c70c3d29e6eaf92e6798cc2ca72 + label: Super Metroid + name: Super Metroid + region: SNS-RI-USA + revision: SHVC-RI-0 + board: SHVC-BA3M-01 + memory + type: ROM + size: 0x300000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 40b46bb29785fb431b325f22377faa8b099be4d77aecc1f03000b8a4cb589b63 + label: Super Ninja Boy + name: Super Ninja Boy + region: SNS-CW-USA + revision: SNS-CW-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a8acbbd6f8afbf289a6b837da6cd8bd109a00cd38625c956ab8ff739732d9e4f + label: Super Nova + name: Super Nova + region: SNS-DH-USA + revision: SNS-DH-0 + board: SHVC-1J0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 24b687f95bb9737d223738f13c00aeaa7d697fa9e2fd50597b81d0cfa2160daa + label: Super Off Road + name: Super Off Road + region: SNS-OR-USA + revision: SNS-OR-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 16f9c90d75bd23d0620be00ecf818fcb25c5935d4ee26b1fe17b926f8987aa65 + label: Super Off Road: The Baja + name: Super Off Road - The Baja + region: SNS-R8-USA + revision: SNS-R8-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6bf0e7a7b95613b9d0e5c8cc98eee5d0ac200e88b5d4444ad5cf93d3e8265118 + label: Super Pinball: Behind the Mask + name: Super Pinball - Behind the Mask + region: SNS-XP-USA + revision: SNS-XP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 65aff1403838c938d7c6170f3044a2b0317cd2ee13ad79353a4cdd2aa82f4e87 + label: Super Pinball: Behind the Mask + name: Super Pinball - Behind the Mask + region: SNS-XP-USA + revision: SNS-XP-1 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 5a4b0c89606f71182fa5552ac476cc3bbda5ddc7d44e33f9184114aaea38020d + label: Super Play Action Football + name: Super Play Action Football + region: SNS-SF-USA + revision: SNS-SF-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: a3d803b8c6b0b6ac55085671040b840f993543915c7f802e14fb651beabe9b63 + label: Super Punch-Out!! + name: Super Punch-Out!! + region: SNS-4Q-USA + revision: SNS-4Q-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 3dff3513ae6acb85a02b00b9f5adb4757ab97661993bded4f329127a792cef87 + label: Super Putty + name: Super Putty + region: SNS-YU-USA + revision: SNS-YU-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 05c7f6461209020785fba33007e1830820aa44ada4b1a6f991d936bf2335b15b + label: Super R-Type + name: Super R-Type + region: SNS-SR-USA + revision: SNS-SR-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 607bfa0f74e57298f59ebe237c2e7b59364024d844534f3befb9ad1301bbedf8 + label: Super R.B.I Baseball + name: Super RBI Baseball + region: SNS-ARLE-USA + revision: SNS-ARLE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 7a8ffaf8bb549b400ec2f0bda9f3c0dbf5852c38618cdb21cd783c368383e2c7 + label: Super Scope 6 + name: Super Scope 6 + region: SNS-LR-USA + revision: SNS-LR-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e987ceb53cc1407b1ba612b13a7b5391db6c41ea14552c165ae62ad42eeaa0ae + label: Super Slam Dunk + name: Super Slam Dunk + region: SNS-D9-USA + revision: SNS-D9-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c39ebf88af138e87ca5d963ed71a8b7defba3e2bc271d72186d00056e8225721 + label: Super Slap Shot + name: Super Slap Shot + region: SNS-ZX-USA + revision: SNS-ZX-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 8b75ab4bb1b63c45a56e7a4c5a37c0864f14375ab3131edc33489764426ad888 + label: Super Smash T.V. + name: Super Smash TV + region: SNS-TV-USA + revision: SNS-TV-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 694ad2b34ab808bd8a1aa9dda359594cfd3a5fd9d95d4cf262ccaa0eb57eef67 + label: Super Soccer + name: Super Soccer + region: SNS-FS-USA + revision: SNS-FS-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 5eb9736d66b3ac730ebbfdd19ef2397282b5f1a62dc0048093e041e23b807741 + label: Super Soccer Champ + name: Super Soccer Champ + region: SNS-HT-USA + revision: SNS-HT-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 5985cdad45958a5b8c5967ad39efe51569f560bf237a4e9864f21111082a8500 + label: Super Solitaire + name: Super Solitaire + region: SNS-LT-USA + revision: SNS-LT-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: c6bd7239cb2074ff1c471d14535bead6290bba2d7c75b4f03209cb114877b4c8 + label: Super Star Wars: A New Hope + name: Super Star Wars - A New Hope + region: SNS-V4-USA + revision: SNS-V4-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 1dd01da68cb61def641389bf3fa87b7a29113c9c8dd172cf303c0f7e03ba6e47 + label: Super Star Wars II: The Empire Strikes Back + name: Super Star Wars II - The Empire Strikes Back + region: SNS-E5-USA + revision: SNS-E5-0 + board: SHVC-2A0N-10 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 46370b3bd6ff9ee04c425eef0f482f521f3b61bd4b058f2f4e9d322253d7b5de + label: Super Star Wars II: The Empire Strikes Back + name: Super Star Wars II - The Empire Strikes Back + region: SNS-E5-USA + revision: SNS-E5-1 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: c49be867cdd276703a3ae46a6b17673b9e359af4f9af2329c8eb747120245817 + label: Super Star Wars III: Return of the Jedi + name: Super Star Wars III - Return of the Jedi + region: SNS-ARJE-USA + revision: SNS-ARJE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: f7df5cd16ce6624567d1a24e9b9c0b9050ea9b6a9fe5a7973484589637756596 + label: Super Star Wars III: Return of the Jedi + name: Super Star Wars III - Return of the Jedi + region: SNS-ARJE-USA + revision: SNS-ARJE-1 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: d17cb5c73174060fcbd9cba6c705643f19c3b8be24d0f7ee43aee674ff1ea38e + label: Super Street Fighter II: The New Challengers + name: Super Street Fighter II - The New Challengers + region: SNS-XW-USA + revision: SNS-XW-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 830c900083cccc6ded74c167c4e257db34df4786ecd6e2f053de454db7d31fe5 + label: Super Strike Eagle + name: Super Strike Eagle + region: SNS-EG-USA + revision: SNS-EG-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 6e45a80ea148654514cb4e8604a0ffcbc726946e70f9e0b9860e36c0f3fa4877 + label: Super Tennis + name: Super Tennis + region: SNS-ST-USA + revision: SNS-ST-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 02cb7f1ed21ed6bfb9eaa0e91df2adb063a9bf4cbd6feb6cd024d676829e227e + label: Super Troll Islands + name: Super Troll Islands + region: SNS-5L-USA + revision: SNS-5L-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 056ac8160363d577e3ffc2f593801b8bb3d024fe4f3a3331b711dc556204949d + label: Super Turrican + name: Super Turrican + region: SNS-TU-USA + revision: SNS-TU-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 96da3512a1aa05a40f1e5d61c48932b0d55d9f136d6418b848153a9fecab06de + label: Super Turrican 2 + name: Super Turrican 2 + region: SNS-A2TE-USA + revision: SNS-A2TE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 792e615a34ceae5a1b9a4f54c5a5d9b53e39299332fece83e4bceca2c22efb21 + label: Super Valis IV + name: Super Valis IV + region: SNS-VA-USA + revision: SNS-VA-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 62d3d650e956f23f3b221f83c5c5bd204afd0e4f4d9c47a3251962323de96089 + label: Super Widget + name: Super Widget + region: SNS-WI-USA + revision: SNS-WI-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: dfada65f4497f482d5f81964322d9952f678f50e65418d307d4503f9bf9a32d9 + label: Suzuka 8 Hours + name: Suzuka 8 Hours + region: SNS-8H-USA + revision: SNS-8H-0 + board: SHVC-1K0N-01 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP1 + volatile + oscillator + frequency: 7600000 + +game + sha256: d802715fb4f09d7e499b5b3e577af641598a723dae7cedeaa93943bb53c6edbb + label: SWAT Kats: The Radical Squadron + name: SWAT Kats - The Radical Squadron + region: SNS-AK9E-USA + revision: SNS-AK9E-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: c2015d03dd3db08069b2a6ea1ed6b3e1ac1e3a5f804b02295c3cd3717add91ef + label: Syndicate + name: Syndicate + region: SNS-AFYE-USA + revision: SNS-AFYE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 1711fe9010232b41ec406900e5b4ef528dd2beaa97b27d94ed7eef57d63904a0 + label: Taz-Mania + name: Taz-Mania + region: SNS-TZ-USA + revision: SNS-TZ-1 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 7da4a3cfa5de4bb4722a6e2a42c26aae322b5e668f1645d8c870fb99e6080600 + label: Tecmo Secret of the Stars + name: Tecmo Secret of the Stars + region: SNS-AQ-USA + revision: SNS-AQ-0 + board: SHVC-2A3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: c3cb1d2fd9775aa9d15b7eedd45ad82519b73d47ca166737ed398c748717bcc4 + label: Tecmo Super Baseball + name: Tecmo Super Baseball + region: SNS-ATBE-USA + revision: SNS-ATBE-0 + board: SHVC-2A3M-11 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 35dd020cf57fc402417ab6e4a6c49866c5a86bba25218c0aaf7ce85cb134bcf8 + label: Tecmo Super Bowl + name: Tecmo Super Bowl + region: SNS-7T-USA + revision: SNS-7T-0 + board: SHVC-2A3B-01 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 2972057a0087f8239d2523eaa995405f06e5d5ba3a3203b6b50d401379c8ebde + label: Tecmo Super Bowl II: Special Edition + name: Tecmo Super Bowl II - Special Edition + region: SNS-ASBE-USA + revision: SNS-ASBE-0 + board: SHVC-1A5M-11 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 8cfd4c5525f4bd4bba5af7e2323f1e61f27ce97c6d5617cfa685c9276fbf6407 + label: Tecmo Super Bowl III: Final Edition + name: Tecmo Super Bowl III - Final Edition + region: SNS-AW4E-USA + revision: SNS-AW4E-0 + board: SHVC-1A5M-20 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 14bce564f976d1431127259edbcb23c52c79361fed9814d307d627c4650e800e + label: Tecmo Super NBA Basketball + name: Tecmo Super NBA Basketball + region: SNS-XM-USA + revision: SNS-XM-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 5b82cdd6f2da56f43680d6a5021faebe2e06036d30602c1a7917aa414cf8b5f4 + label: Teenage Mutant Ninja Turtles IV: Turtles in Time + name: Teenage Mutant Ninja Turtles IV - Turtles in Time + region: SNS-TM-USA + revision: SNS-TM-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 849141370f164d6db3e5709da670726f958ce13ffef69319564db3fb0b12c69d + label: Teenage Mutant Ninja Turtles V: Tournament Fighters + name: Teenage Mutant Ninja Turtles V - Tournament Fighters + region: SNS-KY-USA + revision: SNS-KY-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: bd7074ef4a05d790646abe145ffd2587fb48044e4b730286d807abe102841177 + label: The Terminator + name: Terminator + region: SNS-TN-USA + revision: SNS-TN-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 06db3be569a587d79b51bfc684fd2ebdea977863875aedec88218fbb4169c21b + label: Terminator 2: Judgment Day + name: Terminator 2 - Judgment Day + region: SNS-TP-USA + revision: SNS-TP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 365f10f9d9f68cc59e769eeb451c417e1ff7415022a625de9976a3b924c0bd61 + label: Terminator 2: The Arcade Game + name: Terminator 2 - The Arcade Game + region: SNS-XV-USA + revision: SNS-XV-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c9563cb57314588aa3db22b76dc8acfba3e73733dd3538edd90af5a15595830e + label: Test Drive II: The Duel + name: Test Drive II - The Duel + region: SNS-DL-USA + revision: SNS-DL-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 3cdebbd8adc4bb6773a7995f542fdac49adefca71cba583255a1c1bf37ac3946 + label: Tetris & Dr. Mario + name: Tetris & Dr. Mario + region: SNS-ATFE-USA + revision: SNS-ATFE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: accc836c3adabadc810fbe35702c6a64d50a09f4c672d2734fa58b251d7a20aa + label: Tetris 2 + name: Tetris 2 + region: SNS-27-USA + revision: SNS-27-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 70dea29a928c1625def31c862dc74960e39e587e416b45829efc21f13ebd9630 + label: Tetris 2 + name: Tetris 2 + region: SNS-27-USA + revision: SNS-27-1 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 579bf1a1988d4af06a69cc1d82a2478ebe51940c5ced7f97e83029a24e6aa778 + label: Tetris Attack + name: Tetris Attack + region: SNS-AYLE-USA + revision: SNS-AYLE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 1121df3f05dd9dbb749f6b785eb9b3eb69968004f9d6ceffa6f84757af2f3702 + label: Thomas the Tank Engine & Friends + name: Thomas the Tank Engine & Friends + region: SNS-6T-USA + revision: SNS-6T-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: d50aaa41e153ca356eee16a9deccb1a763ee56ebbe6c80cd28c5ad1db66a5316 + label: Thunder Spirits + name: Thunder Spirits + region: SNS-TH-USA + revision: SNS-TH-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: eb958801fd1f08771e5a0933f7701d633262efbfe8d47de21dda18e3b77670de + label: The Tick + name: Tick, The + region: SNS-ATHE-USA + revision: SNS-ATHE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 16fb965130e57f37dda2466f23820f091f8b96758aa7e30ba4fd63cb618e5ddb + label: Time Cop + name: Time Cop + region: SNS-ATCE-USA + revision: SNS-ATCE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 8e82f98d2e62bc1e5fcf2386c2b5ca54998398220efcedd67858aaaa92289a42 + label: Time Slip + name: Time Slip + region: SNS-XT-USA + revision: SNS-XT-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: fa7e2b40093f0cc7233cc77e95bbbea2144c8183dec10446590396fffd7cda37 + label: Time Trax + name: Time Trax + region: SNS-X8-USA + revision: SNS-X8-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 271a67b32b3bb00ceb0f4e7d81494888d0d821635f0f936d481dfbe671567c08 + label: Timon & Pumbaa's Jungle Games + name: Timon & Pumbaa's Jungle Games + region: SNS-AJ9E-USA + revision: SNS-AJ9E-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: 0503cd93b4d211a825acd47ff3813668b4ce68890c8be2fbfe5ac2b46882dfcf + label: Tin Star + name: Tin Star + region: SNS-9N-USA + revision: SNS-9N-0 + board: SHVC-1A1M-11 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: ba679a11264e9695895a6c17358a41e8459be06166d056811df9c2738fef3d0d + label: Tiny Toon Adventures: Buster Busts Loose! + name: Tiny Toon Adventures - Buster Busts Loose! + region: SNS-TA-USA + revision: SNS-TA-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: f753de4a38bd83f7d937fc7bf5565a3c351a794c113dead8fdee6d86c85633e8 + label: Tiny Toon Adventures: Wacky Sports Challenge + name: Tiny Toon Adventures - Wacky Sports Challenge + region: SNS-5Z-USA + revision: SNS-5Z-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 08d808e9c5851e4301a38a56b350a20ea9e3adbef51546e87e1785d691d0f2d5 + label: TKO Super Championship Boxing + name: TKO Super Championship Boxing + region: SNS-BX-USA + revision: SNS-BX-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: ced8c0bc2791ffe47cb9eec03db67567945af8c58b5330326722f1cfca41bf51 + label: TNN Bass Tournament of Champions + name: TNN Bass Tournament of Champions + region: SNS-ATNE-USA + revision: SNS-ATNE-0 + board: SHVC-2J3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 4f500da19dbb1557a7bc0ce14437098c1402478d573fb569303b81c011f86fbf + label: Tom and Jerry + name: Tom and Jerry + region: SNS-TJ-USA + revision: SNS-TJ-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: d99008d2181986dc7f65228696d940b5d31be8471f166d1ab9b1c14f1503bcfb + label: Tommy Moe's Winter Extreme: Skiing and Snowboarding + name: Tommy Moe's Winter Extreme - Skiing and Snowboarding + region: SNS-XS-USA + revision: SNS-XS-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e0fbf731550266d79a0b6ca460afd04c8c312f7023b2c9882c4fc3acc3e7932f + label: Tony Meola's Sidekicks Soccer + name: Tony Meola's Sidekicks Soccer + region: SNS-6K-USA + revision: SNS-6K-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ca9889f17f184b3d99a2eaaa82af73e366f03ed00313fdd369e5e023b208e788 + label: Top Gear + name: Top Gear + region: SNS-TR-USA + revision: SNS-TR-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 76b2702c4be8b668c1017f2817c280283c275eaa41535bf6ffa2b8d2220b68c6 + label: Top Gear 2 + name: Top Gear 2 + region: SNS-2P-USA + revision: SNS-2P-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: ede60f0d283b6ea3a45308981d99e7c422a0296e5fadde51c6bafd4dcc789ca2 + label: Top Gear 3000 + name: Top Gear 3000 + region: SNS-A3TE-USA + revision: SNS-A3TE-0 + board: SHVC-1B0N-03 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: ROM + size: 0x1800 + content: Program + manufacturer: NEC + architecture: uPD7725 + identifier: DSP4 + memory + type: ROM + size: 0x800 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP4 + memory + type: RAM + size: 0x200 + content: Data + manufacturer: NEC + architecture: uPD7725 + identifier: DSP4 + volatile + oscillator + frequency: 7600000 + +game + sha256: 9bf884be5627d38f060ad7f3a61ea1fea1474d416e1d037d33014ca9d5205c1d + label: Total Carnage + name: Total Carnage + region: SNS-XC-USA + revision: SNS-XC-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 345e795000e74f51704774edfc8049473461761a65eb47cab710caa29e09897b + label: Toy Story + name: Toy Story + region: SNS-AQHE-USA + revision: SNS-AQHE-0 + board: SHVC-BJ0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: 7a6e5da46b026900fba4584a32ad40d940b9ecf9fccfb11f96a205a914014784 + label: Toys: Let the Toy Wars Begin! + name: Toys - Let the Toy Wars Begin! + region: SNS-YT-USA + revision: SNS-YT-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 4070a7702dc506a1ceb6f65b5c330b3a162df6f01735c8f206934fd47b810ed4 + label: Troddlers + name: Troddlers + region: SNS-TX-USA + revision: SNS-TX-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 46fcca4ce29f472afa8519958d256eec347c2dc2da154c95f263a051c5c02dbb + label: Troy Aikman Football + name: Troy Aikman Football + region: SNS-YQ-USA + revision: SNS-YQ-0 + board: SHVC-2A3M-11 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: dd96a8f4f9c8988301ff710a4c70ebe3bf7914901f3547abe1d5f0dd5c0b921b + label: True Golf: Wicked 18 + name: True Golf - Wicked 18 + region: SNS-W8-USA + revision: SNS-W8-0 + board: SHVC-1A3M-10 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 5c7b28bb24bad697156ad444ff23bd15ad6744dbf9899b3cccf2aa36d559d825 + label: True Golf Classics: Pebble Beach Golf Links + name: True Golf Classics - Pebble Beach Golf Links + region: SNS-GB-USA + revision: SNS-GB-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 72088194a65fc057f2910945a33d9f071682a4cecac8996f0bdabcdb5ef39962 + label: True Golf Classics: Waialae Country Club + name: True Golf Classics - Waialae Country Club + region: SNS-TG-USA + revision: SNS-TG-0 + board: SHVC-1A3B-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 47dd8ea2d12a6bb2a9774de1d492259fc4fb9f8ec7976383bbfd922532671f6b + label: True Lies + name: True Lies + region: SNS-ATLE-USA + revision: SNS-ATLE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 8f62d014f513a7dcbca5aa76cbe476c3e4526100f34913af831bc05dab029bd1 + label: Tuff E Nuff + name: Tuff E Nuff + region: SNS-TE-USA + revision: SNS-TE-0 + board: SHVC-2A0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: e4343c0fadc00ffdc3dc31345068d751eea5d639f826731f08cb81673d508c40 + label: Turn and Burn: No-Fly Zone + name: Turn and Burn - No-Fly Zone + region: SNS-ZN-USA + revision: SNS-ZN-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 259c25d4613f97f5fa7992900fb583625d7fb912c7ae09fa9def2e682834dc9f + label: The Twisted Tales of Spike McFang + name: Twisted Tales of Spike McFang, The + region: SNS-83-USA + revision: SNS-83-0 + board: SHVC-1A1M-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 094555d5720158ee60c9d5ab9a13110192db5ebf0f6cf69abbb59a00bc470345 + label: Ultima: Runes of Virtue II + name: Ultima - Runes of Virtue II + region: SNS-7U-USA + revision: SNS-7U-0 + board: SHVC-1A1M-11 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 11659bd8dd620d50400d16042aeb2d0ddb00c7183fc1ecb95b1a34f07db0431b + label: Ultima VI: The False Prophet + name: Ultima VI - The False Prophet + region: SNS-U6-USA + revision: SNS-U6-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: a31af0e39afb55bbc92a5543b504327fbe7e8cd0a5e08626976bed7b65376737 + label: Ultima VII: The Black Gate + name: Ultima VII - The Black Gate + region: SNS-7I-USA + revision: SNS-7I-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 78bf82963cded9162e25035053c8b1a9f760748ff0beacc230d005204992737d + label: Ultimate Fighter + name: Ultimate Fighter + region: SNS-HP-USA + revision: SNS-HP-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: cb2fdfce61858063bf4c9da4228381c3ec3abe423f4d378cddd174ae4adb261e + label: Ultimate Mortal Kombat 3 + name: Ultimate Mortal Kombat 3 + region: SNS-A3ZE-USA + revision: SNS-A3ZE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x400000 + content: Program + +game + sha256: e9fae4c2e171a1fc4f2bd800abd9e42750aaf7a4db9e40c5b9142e15029500bd + label: Ultraman: Towards the Future + name: Ultraman - Towards the Future + region: SNS-UM-USA + revision: SNS-UM-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 0b155a54b6134601fc0791252a63ca73efd522667c3d6fd7a44f5b3c500039d7 + label: U.N. Squadron + name: UN Squadron + region: SNS-E8-USA + revision: SNS-E8-0 + board: SHVC-1A0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 794152fc6f55cb15a0b203fa645ac9fa314a293da999d8ec8b3dda080434d175 + label: Uncharted Waters + name: Uncharted Waters + region: SNS-QK-USA + revision: SNS-QK-0 + board: SHVC-1A3B-13 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 64bc4707f422661a66618088887e2363a5f896ea683c58984fffd96dd21ab5f0 + label: Uncharted Waters: New Horizons + name: Uncharted Waters - New Horizons + region: SNS-QL-USA + revision: SNS-QL-0 + board: SHVC-1J5M-11 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + +game + sha256: 859ec99fdc25dd9b239d9085bf656e4f49c93a32faa5bb248da83efd68ebd478 + label: Uniracers + name: Uniracers + region: SNS-4L-USA + revision: SNS-4L-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x200000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: ecefb4117a6aae117e033c8cc07f0db2797d6be93dd5cdcefc23692a21fae02e + label: The Untouchables + name: Untouchables, The + region: SNS-UC-USA + revision: SNS-UC-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: dcb33a89fcb8d8ca8f3a467034728ad6375273d8eb51a60418ca51ef745e9b38 + label: Urban Strike + name: Urban Strike + region: SNS-AUSE-USA + revision: SNS-AUSE-0 + board: MJSC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 2500d6c846c78bcb729f15535bf2b852a120411891cabaaaa6fc407906d0214e + label: Utopia: The Creation of a Nation + name: Utopia - The Creation of a Nation + region: SNS-UP-USA + revision: SNS-UP-0 + board: SHVC-1A3M-10 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 78bf9d79fb2ff3f9d03ecc1176d070e53ddaca2c6b0cda69e74c19a4e50b195b + label: Vegas Stakes + name: Vegas Stakes + region: SNS-VS-USA + revision: SNS-VS-0 + board: SHVC-1A1B-06 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 41b5561de9e4984276e52987ea46c5f4fa8526d8141c70c738875a9eb9fe9d70 + label: Vortex + name: Vortex + region: SNS-4V-USA + revision: SNS-4V-0 + board: SHVC-1CA0N5S-01 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x8000 + content: Save + volatile + oscillator + frequency: 21440000 + +game + sha256: b0e74f0fe8d1e7fe2fe404341fea7c68e28f3a0ab78552d5092d413f2ecec417 + label: Wanderers from Ys III + name: Wanderers from Ys III + region: SNS-YS-USA + revision: SNS-YS-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 82bba8ae2bb4dbc74a18af31aaec19c368576e4369dd70b396caa5e8729540bb + label: War 2410 + name: War 2410 + region: SNS-A2AE-USA + revision: SNS-A2AE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 8b12e5e4553fc921c23739d1aec2ed517535ec239daef800f39f602d8473847f + label: War 3010: The Revolution + name: War 3010 - The Revolution + region: SNS-AZNE-USA + revision: SNS-AZNE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: be420715152394e0e4a25ab10931b67f92f910cfcf7793e31dfee1c6334808e5 + label: Wario's Woods + name: Wario's Woods + region: SNS-65-USA + revision: SNS-65-0 + board: SHVC-1A3M-21 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 8579dd352d20589072ed5c026bde7adadd6229d18a022e7cb47cf5602b54015e + label: Warlock + name: Warlock + region: SNS-AWKE-USA + revision: SNS-AWKE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 36ec2f409f08a08f8327570eadcd8960b6a47bf5797441c2df05fcc50c5b762b + label: Warp Speed + name: Warp Speed + region: SNS-WP-USA + revision: SNS-WP-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: dd73690dd3165a16580e191c92a497102758f312c759353f685e371755c663a8 + label: Wayne Gretzky and the NHLPA All-Stars + name: Wayne Gretzky and the NHLPA All-Stars + region: SNS-AWZE-USA + revision: SNS-AWZE-0 + board: SHVC-2A3M-20 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 56ba3d585bf6b701e342d86a0bd164ab0a97dfbd5df46b3a964506842633459c + label: Wayne's World + name: Wayne's World + region: SNS-WW-USA + revision: SNS-WW-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 215ab7e576b31462e3284d035006dc638cae06bbfb1af2c5617403b15ab2b25a + label: WCW Super Brawl Wrestling + name: WCW Super Brawl Wrestling + region: SNS-AWRE-USA + revision: SNS-AWRE-0 + board: SHVC-2A0N-11 + memory + type: ROM + size: 0x180000 + content: Program + +game + sha256: e931c3c08f20f78e3a43ad92d16eb472be619abaa17c2d8e2b0fcd5d05dbd74d + label: We're Back!: A Dinosaur's Story + name: We're Back! - A Dinosaur's Story + region: SNS-6D-USA + revision: SNS-6D-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 0b1ba31ae95b61d7d9a0f5509b5836fff84f60915802e3b3ba1170a5c50a4b71 + label: WeaponLord + name: WeaponLord + region: SNS-AWDE-USA + revision: SNS-AWDE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 12abf1ba063c120c1a98495a1c85e67a0007aff771ef92adcb94b4a0a2fd5adb + label: Wheel of Fortune + name: Wheel of Fortune + region: SNS-WL-USA + revision: SNS-WL-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: c7af9e7f3243ba1b5dd81f32f710e60c2ae1d443ecaf7140bf42d71a1b69d8a2 + label: Wheel of Fortune: Deluxe Edition + name: Wheel of Fortune - Deluxe Edition + region: SNS-XF-USA + revision: SNS-XF-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 1bd3af0125743bf9bbbac6e7dc215fe32c4ff7043a2ee034d56b627e3f6875f0 + label: Where in the World is Carmen Sandiego? + name: Where in the World is Carmen Sandiego + region: SNS-WX-USA + revision: SNS-WX-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: e3177f066bf004fd99aef31f2692ba0b412dd280d613dc3f4cf334d97f4c9af8 + label: Where in Time is Carmen Sandiego? + name: Where in Time is Carmen Sandiego + region: SNS-WN-USA + revision: SNS-WN-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 0a52dc1e7820f5541f53ce0e1e96144fe079af0efe3dae5c2c89d86365feb8b1 + label: Whizz + name: Whizz + region: SNS-AZWE-USA + revision: SNS-AZWE-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c8f159e2625ac8078535c06857ea28475706da45df494de8e46f50888272cf71 + label: Wild Guns + name: Wild Guns + region: SNS-4W-USA + revision: SNS-4W-0 + board: SHVC-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 39bb99eddb224de5f0789f807ffef06b9efa2efb7962dced31fb272f986699cd + label: Wild Snake + name: Wild Snake + region: SNS-AWSE-USA + revision: SNS-AWSE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 60d01a3f499463156546ecdee18ee3e946b95302ee0b1569decb97f52372d2eb + label: Williams Arcade's Greatest Hits + name: Williams Arcade's Greatest Hits + region: SNS-AW8E-USA + revision: SNS-AW8E-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 2167fc7c5447b2287668d2f3e4ef1a285361b2292ecc8a4cbd9f966a460ad7a2 + label: Wing Commander + name: Wing Commander + region: SNS-WC-USA + revision: SNS-WC-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 132ca0b6a4888edf7de785d48f4417fac28522646e6c7514f80c5e9ff1438d5f + label: Wing Commander: The Secret Missions + name: Wing Commander - The Secret Missions + region: SNS-2W-USA + revision: SNS-2W-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: c3bcd5c716f96e6359ebcfd85c3e9b07b46c5124bf4010d89ceef5b6f2f868f6 + label: Wings 2: Aces High + name: Wings 2 - Aces High + region: SNS-WG-USA + revision: SNS-WG-0 + board: SHVC-1A0N-02 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 0e834647669783c2b79cc1120c057c870c541079a7abd1eee3f787d59dc3c3eb + label: Winter Olympic Games: Lillehammer '94 + name: Winter Olympic Games - Lillehammer '94 + region: SNS-W4-USA + revision: SNS-W4-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 025dd3047c474d879e69b91a3918add9cdabedf4182e1c1e10e5f0c13a124bf9 + label: The Wizard of Oz + name: Wizard of Oz, The + region: SNS-W6-USA + revision: SNS-W6-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: bc68f40075f9983f5027fe264c3037d1a831e8e76a6c9adb60d10226f6ef005b + label: Wizardry V: Heart of the Maelstrom + name: Wizardry V - Heart of the Maelstrom + region: SNS-W5-USA + revision: SNS-W5-0 + board: SHVC-1A3M-20 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: e0165bafeb8d65be08a5a4079f8651104471f450c60794b761b1255853ca2d98 + label: Wolf Child + name: Wolf Child + region: SNS-WH-USA + revision: SNS-WH-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 9c2b458e8fda5cb437a4c6d28fb430e45c4cfef98420c40546b8e08563a4fc7d + label: Wolfenstein 3D + name: Wolfenstein 3D + region: SNS-6W-USA + revision: SNS-6W-0 + board: SHVC-1J0N-10 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 44428a3d1c796fbd41da7620e321c45f11cd80a0e5f4ab8c48177106cb960d77 + label: Wolverine: Adamantium Rage + name: Wolverine - Adamantium Rage + region: SNS-AWXE-USA + revision: SNS-AWXE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 82e2b636e66c4edbae27a5be91a61194ef2881ec93f40d1de93a6153617b12f2 + label: Wordtris + name: Wordtris + region: SNS-WT-USA + revision: SNS-WT-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 86e9d76a8834732e511253d8092727bdbfb409b3d0ff1c06b6b6e481c9a039ef + label: World Cup USA '94 + name: World Cup USA '94 + region: SNS-U4-USA + revision: SNS-U4-0 + board: SHVC-2J3M-11 + memory + type: ROM + size: 0x180000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: ea76cfdbb2a555a7b6eff8b466a879f9a9189639416e8c2fb45bf074e695105f + label: World Heroes + name: World Heroes + region: SNS-WZ-USA + revision: SNS-WZ-0 + board: SHVC-2J0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 159d5341d13d6801324e8271f7191c0223617c9d30984676319b2df7937c78c0 + label: World Heroes 2 + name: World Heroes 2 + region: SNS-JI-USA + revision: SNS-JI-0 + board: SHVC-BA0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: d4d9f1b41dad7e7a126a9adbe8d86c4b339e120c866156796de1cb0c9a214189 + label: World League Soccer + name: World League Soccer + region: SNS-WS-USA + revision: SNS-WS-0 + board: SHVC-1A1B-05 + memory + type: ROM + size: 0x80000 + content: Program + memory + type: RAM + size: 0x800 + content: Save + +game + sha256: 2143bbd87ea1c5cfe5eaf46ae39e3ebb11a2e929d05cbb929904037f4d72acfe + label: World Soccer '94: Road to Glory + name: World Soccer '94 - Road to Glory + region: SNS-WO-USA + revision: SNS-WO-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 0af7b0d3022acd24a1fb15865a076519f7f56e7a4b33f12b6d851b3a91e5388c + label: WWF Raw + name: WWF Raw + region: SNS-AWFE-USA + revision: SNS-AWFE-0 + board: SHVC-BJ0N-01 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: 51c53e36ed0b959b0695fc6ef036fa7302d1c995eca35c28261d6f3cb77df0ca + label: WWF Royal Rumble + name: WWF Royal Rumble + region: SNS-WU-USA + revision: SNS-WU-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 0b9abf2fc25a5f07c71f9d8efbb0d0e616c1494060138fbb63f7398e9c26198e + label: WWF Super Wrestlemania + name: WWF Super Wrestlemania + region: SNS-WF-USA + revision: SNS-WF-0 + board: MAXI-1A0N-30 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 67faa6ed3406a5ab0d7224b811c0960bb36560040ee959bb3304c9293ceaa093 + label: WWF Wrestlemania: The Arcade Game + name: WWF Wrestlemania - The Arcade Game + region: SNS-AWVE-USA + revision: SNS-AWVE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x300000 + content: Program + +game + sha256: dc3792e9fe7ef7aaea4ac675a48ad06129dd3ebdd4b96a513bc8241549cbd579 + label: X-Kaliber 2097 + name: X-Kaliber 2097 + region: SNS-X7-USA + revision: SNS-X7-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 65fe17fd6b297f52df6ce9812ecb02c3bb1bfda3ebc05a19c4a8decbf9a446ae + label: X-Men: Mutant Apocalypse + name: X-Men - Mutant Apocalypse + region: SNS-AXME-USA + revision: SNS-AXME-0 + board: MAXI-1J0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 93272180090e8418582f69b79c5cee6b28638b9a93192cc4bcd96291a4fca02d + label: X-Zone + name: X-Zone + region: SNS-XZ-USA + revision: SNS-XZ-0 + board: SHVC-1A0N-10 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 71b69490c78d0bbaf47da25217c5dae295190311aa5df75653c3fac0a1b45358 + label: Xardion + name: Xardion + region: SNS-XA-USA + revision: SNS-XA-0 + board: SHVC-1A3B-12 + memory + type: ROM + size: 0x100000 + content: Program + memory + type: RAM + size: 0x2000 + content: Save + +game + sha256: 90ad69a489194aca7ef7b7fd1d30e0105da4934a81ac8b0333ea20f9248df92d + label: Yoshi's Cookie + name: Yoshi's Cookie + region: SNS-YC-USA + revision: SNS-YC-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x80000 + content: Program + +game + sha256: 12fba2aff04c8e39968e828629ebd16caa314bca397a9418d35fdaffe8188e20 + label: Yoshi's Safari + name: Yoshi's Safari + region: SNS-RH-USA + revision: SNS-RH-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: fbe8926fc0149d3e8e2aec20f15640ea6814f4f4b01c3960f3c477f5f17e890f + label: Young Merlin + name: Young Merlin + region: SNS-Y6-USA + revision: SNS-Y6-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: 7d414b7f5941f1eddc35259a22accbbbd7b47c517dfcf8bad86c4dcfa9e50b1e + label: Zero the Kamikaze Squirrel + name: Zero the Kamikaze Squirrel + region: SNS-AZKE-USA + revision: SNS-AZKE-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x200000 + content: Program + +game + sha256: b27e2e957fa760f4f483e2af30e03062034a6c0066984f2e284cc2cb430b2059 + label: Zombies Ate My Neighbors + name: Zombies Ate My Neighbors + region: SNS-ZA-USA + revision: SNS-ZA-0 + board: SHVC-YA0N-01 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: 25414de02c6805ca62574cfb39c23bf292b3d8c4ff33eb8f212ccdbcd61c5ae3 + label: Zool: Ninja of the "Nth" Dimension + name: Zool - Ninja of the 'Nth' Dimension + region: SNS-Z8-USA + revision: SNS-Z8-0 + board: SHVC-1A0N-20 + memory + type: ROM + size: 0x100000 + content: Program + +game + sha256: a3f1abf2740ff64042d82f7a940fb4269ece57d7c6967571549d8b60b20f305a + label: Zoop + name: Zoop + region: SNS-AZPE-USA + revision: SNS-AZPE-0 + board: SHVC-1J0N-20 + memory + type: ROM + size: 0x80000 + content: Program + diff --git a/Database/boards.bml b/Database/boards.bml new file mode 100644 index 0000000..915da6a --- /dev/null +++ b/Database/boards.bml @@ -0,0 +1,962 @@ +database + revision: 2018-07-25 + +//Boards (Production) + +database + revision: 2018-05-16 + +board: BANDAI-PT-923 + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + slot type=SufamiTurbo + rom + map address=20-3f,a0-bf:8000-ffff mask=0x8000 + ram + map address=60-6f,e0-ef:0000-ffff + slot type=SufamiTurbo + rom + map address=40-5f,c0-df:0000-ffff mask=0x8000 + ram + map address=70-7d,f0-ff:0000-ffff + +board: BSC-1A5B9P-01 + memory type=RAM content=Save + map address=10-17:5000-5fff mask=0xf000 + processor identifier=MCC + map address=00-0f:5000-5fff + mcu + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + map address=20-3f,a0-bf:6000-7fff + memory type=ROM content=Program + memory type=RAM content=Download + slot type=BSMemory + +board: BSC-1A5M-02 + memory type=ROM content=Program + map address=00-1f:8000-ffff mask=0xe08000 base=0x000000 + map address=20-3f:8000-ffff mask=0xe08000 base=0x100000 + map address=80-9f:8000-ffff mask=0xe08000 base=0x200000 + map address=a0-bf:8000-ffff mask=0xe08000 base=0x100000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + slot type=BSMemory + map address=c0-ef:0000-ffff + +board: BSC-1A7M-(01,10) + memory type=ROM content=Program + map address=00-1f:8000-ffff mask=0xe08000 base=0x000000 + map address=20-3f:8000-ffff mask=0xe08000 base=0x100000 + map address=80-9f:8000-ffff mask=0xe08000 base=0x200000 + map address=a0-bf:8000-ffff mask=0xe08000 base=0x100000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + slot type=BSMemory + map address=c0-ef:0000-ffff + +board: BSC-1J3M-01 + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff + map address=40-5f,c0-df:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + slot type=BSMemory + map address=20-3f,a0-bf:8000-ffff + map address=60-7d,e0-ff:0000-ffff + +board: BSC-1J5M-01 + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff + map address=40-5f,c0-df:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + slot type=BSMemory + map address=20-3f,a0-bf:8000-ffff + map address=60-7d,e0-ff:0000-ffff + +board: BSC-1L3B-01 + processor architecture=W65C816S + map address=00-3f,80-bf:2200-23ff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x408000 + map address=c0-ff:0000-ffff + memory type=ROM content=Program + slot type=BSMemory + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=40-4f:0000-ffff + memory type=RAM content=Internal + map address=00-3f,80-bf:3000-37ff size=0x800 + +board: BSC-1L5B-01 + processor architecture=W65C816S + map address=00-3f,80-bf:2200-23ff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x408000 + map address=c0-ff:0000-ffff + memory type=ROM content=Program + slot type=BSMemory + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=40-4f:0000-ffff + memory type=RAM content=Internal + map address=00-3f,80-bf:3000-37ff size=0x800 + +board: SGB-R-10 + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + map address=40-7d,c0-ff:0000-7fff mask=0x8000 + processor identifier=ICD revision=2 + map address=00-3f,80-bf:6000-67ff,7000-7fff + memory type=ROM content=Boot architecture=SM83 + slot type=GameBoy + +board: SHVC-1A0N-(01,02,10,20,30) + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + map address=40-7d,c0-ff:0000-7fff mask=0x8000 + +board: SHVC-1A1B-(04,05,06) + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-ffff + +board: SHVC-1A1M-(01,10,11,20) + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-1A3B-(11,12,13) + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-ffff + +board: SHVC-1A3B-20 + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-1A3M-(10,20,21,30) + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-1A5B-(02,04) + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-ffff + +board: SHVC-1A5M-(01,11,20) + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-1B0N-(02,03,10) + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + processor architecture=uPD7725 + map address=30-3f,b0-bf:8000-ffff mask=0x3fff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: SHVC-1B5B-02 + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-ffff + processor architecture=uPD7725 + map address=20-3f,a0-bf:8000-ffff mask=0x3fff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: SHVC-1C0N + processor architecture=GSU + map address=00-3f,80-bf:3000-34ff + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=60-7d,e0-ff:0000-ffff + +board: SHVC-1C0N5S-01 + processor architecture=GSU + map address=00-3f,80-bf:3000-34ff + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=60-7d,e0-ff:0000-ffff + +board: SHVC-1CA0N5S-01 + processor architecture=GSU + map address=00-3f,80-bf:3000-34ff + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + map address=40-5f,c0-df:0000-ffff + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=70-71,f0-f1:0000-ffff + +board: SHVC-1CA0N6S-01 + processor architecture=GSU + map address=00-3f,80-bf:3000-34ff + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + map address=40-5f,c0-df:0000-ffff + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=70-71,f0-f1:0000-ffff + +board: SHVC-1CA6B-01 + processor architecture=GSU + map address=00-3f,80-bf:3000-34ff + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + map address=40-5f,c0-df:0000-ffff + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=70-71,f0-f1:0000-ffff + +board: SHVC-1CB0N7S-01 + processor architecture=GSU + map address=00-3f,80-bf:3000-34ff + memory type=ROM content=Program + map address=00-3f:8000-ffff mask=0x8000 + map address=40-5f:0000-ffff + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=70-71:0000-ffff + +board: SHVC-1CB5B-(01,20) + processor architecture=GSU + map address=00-3f,80-bf:3000-34ff + memory type=ROM content=Program + map address=00-3f:8000-ffff mask=0x8000 + map address=40-5f:0000-ffff + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=70-71:0000-ffff + +board: SHVC-1CB7B-01 + processor architecture=GSU + map address=00-3f,80-bf:3000-34ff + memory type=ROM content=Program + map address=00-3f:8000-ffff mask=0x8000 + map address=40-5f:0000-ffff + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=70-71:0000-ffff + +board: SHVC-1DC0N-01 + processor architecture=HG51BS169 + map address=00-3f,80-bf:6c00-6fff,7c00-7fff + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-77:0000-7fff + memory type=ROM content=Data architecture=HG51BS169 + memory type=RAM content=Data architecture=HG51BS169 + map address=00-3f,80-bf:6000-6bff,7000-7bff mask=0xf000 + oscillator + +board: SHVC-1DS0B-20 + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + processor architecture=uPD96050 + map address=60-67,e0-e7:0000-3fff + memory type=ROM content=Program architecture=uPD96050 + memory type=ROM content=Data architecture=uPD96050 + memory type=RAM content=Data architecture=uPD96050 + map address=68-6f,e8-ef:0000-7fff mask=0x8000 + oscillator + +board: SHVC-1J0N-(01,10,20) + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + +board: SHVC-1J1M-(11,20) + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + +board: SHVC-1J3B-01 + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + +board: SHVC-1J3M-(01,11,20) + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + +board: SHVC-1J5M-(01,11,20) + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + +board: SHVC-1K0N-01 + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + processor architecture=uPD7725 + map address=00-1f,80-9f:6000-7fff mask=0xfff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: SHVC-1K1B-01 + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + processor architecture=uPD7725 + map address=00-1f,80-9f:6000-7fff mask=0xfff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: SHVC-1L0N3S-01 + processor architecture=W65C816S + map address=00-3f,80-bf:2200-23ff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x408000 + map address=c0-ff:0000-ffff + memory type=ROM content=Program + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=40-4f:0000-ffff + memory type=RAM content=Internal + map address=00-3f,80-bf:3000-37ff size=0x800 + +board: SHVC-1L3B-(02,11) + processor architecture=W65C816S + map address=00-3f,80-bf:2200-23ff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x408000 + map address=c0-ff:0000-ffff + memory type=ROM content=Program + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=40-4f:0000-ffff + memory type=RAM content=Internal + map address=00-3f,80-bf:3000-37ff size=0x800 + +board: SHVC-1L5B-(11,20) + processor architecture=W65C816S + map address=00-3f,80-bf:2200-23ff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x408000 + map address=c0-ff:0000-ffff + memory type=ROM content=Program + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=40-4f:0000-ffff + memory type=RAM content=Internal + map address=00-3f,80-bf:3000-37ff size=0x800 + +board: SHVC-1N0N-(01,10) + processor identifier=SDD1 + map address=00-3f,80-bf:4800-480f + mcu + map address=00-3f,80-bf:8000-ffff + map address=c0-ff:0000-ffff + memory type=ROM content=Program + +board: SHVC-2A0N-01#A + memory type=ROM content=Program + map address=00-2f,80-af:8000-ffff mask=0x8000 + map address=40-6f,c0-ef:0000-ffff mask=0x8000 + +board: SHVC-2A0N-(01,10,11,20) + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + map address=40-7d,c0-ff:0000-7fff mask=0x8000 + +board: SHVC-2A1M-01 + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-2A3B-01 + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-2A3M-01#A + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-2A3M-(01,11,20) + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-2A5M-01 + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-2B3B-01 + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + processor architecture=uPD7725 + map address=60-6f,e0-ef:0000-7fff mask=0x3fff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: SHVC-2DC0N-01 + processor architecture=HG51BS169 + map address=00-3f,80-bf:6c00-6fff,7c00-7fff + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-77:0000-7fff + memory type=ROM content=Data architecture=HG51BS169 + memory type=RAM content=Data architecture=HG51BS169 + map address=00-3f,80-bf:6000-6bff,7000-7bff mask=0xf000 + oscillator + +board: SHVC-2E3M-01 + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + processor identifier=OBC1 + map address=00-3f,80-bf:6000-7fff mask=0xe000 + map address=70-71,f0-f1:6000-7fff,e000-ffff mask=0xe000 + memory type=RAM content=Save + +board: SHVC-2J0N-(01,10,11,20) + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + +board: SHVC-2J3M-(01,11,20) + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=10-1f,30-3f,90-9f,b0-bf:6000-7fff mask=0xe000 + +board: SHVC-2J5M-01 + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=10-1f,30-3f,90-9f,b0-bf:6000-7fff mask=0xe000 + +board: SHVC-3J0N-01 + memory type=ROM content=Program + map address=00-2f,80-af:8000-ffff + map address=40-6f,c0-ef:0000-ffff + +board: SHVC-BA0N-(01,10) + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + map address=40-7d,c0-ff:0000-7fff mask=0x8000 + +board: SHVC-BA1M-01 + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-BA3M-(01,10) + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: SHVC-BJ0N-(01,20) + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + +board: SHVC-BJ1M-(10,20) + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + +board: SHVC-BJ3M-(10,20) + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + +board: SHVC-LDH3C-01 + processor identifier=SPC7110 + map address=00-3f,80-bf:4800-483f + map address=50,58:0000-ffff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x800000 + map address=c0-ff:0000-ffff mask=0xc00000 + memory type=ROM content=Program + memory type=ROM content=Data + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff mask=0xe000 + rtc manufacturer=Epson + map address=00-3f,80-bf:4840-4842 + memory type=RTC content=Time manufacturer=Epson + +board: SHVC-LN3B-01 + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff mask=0xe000 + map address=70-73:0000-ffff + processor identifier=SDD1 + map address=00-3f,80-bf:4800-480f + mcu + map address=00-3f,80-bf:8000-ffff + map address=c0-ff:0000-ffff + memory type=ROM content=Program + +board: SHVC-SGB2-01 + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + map address=40-7d,c0-ff:0000-7fff mask=0x8000 + processor identifier=ICD revision=2 + map address=00-3f,80-bf:6000-67ff,7000-7fff + memory type=ROM content=Boot architecture=SM83 + oscillator + slot type=GameBoy + +board: SHVC-YA0N-01 + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + map address=40-7d,c0-ff:0000-7fff mask=0x8000 + +board: SHVC-YJ0N-01 + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + +//Boards (Prototypes) + +board: SHVC-2P3B-01 + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + map address=40-7d,c0-ff:0000-7fff mask=0x8000 + +board: SHVC-4PV5B-01 + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + map address=40-7d,c0-ff:0000-7fff mask=0x8000 + +//Boards (Generic) + +database + revision: 2018-07-25 + +board: ARM-LOROM-RAM + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + map address=40-6f,c0-ef:0000-7fff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-ffff + processor architecture=ARM6 + map address=00-3f,80-bf:3800-38ff + memory type=ROM content=Program architecture=ARM6 + memory type=ROM content=Data architecture=ARM6 + memory type=RAM content=Data architecture=ARM6 + oscillator + +board: BS-HIROM-RAM + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff + map address=40-5f,c0-df:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + slot type=BSMemory + map address=20-3f,a0-bf:8000-ffff + map address=60-7d,e0-ff:0000-ffff + +board: BS-LOROM-RAM + memory type=ROM content=Program + map address=00-1f:8000-ffff mask=0xe08000 base=0x000000 + map address=20-3f:8000-ffff mask=0xe08000 base=0x100000 + map address=80-9f:8000-ffff mask=0xe08000 base=0x200000 + map address=a0-bf:8000-ffff mask=0xe08000 base=0x100000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + slot type=BSMemory + map address=c0-ef:0000-ffff + +board: BS-MCC-RAM + memory type=RAM content=Save + map address=10-17:5000-5fff mask=0xf000 + processor identifier=MCC + map address=00-0f:5000-5fff + mcu + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + map address=20-3f,a0-bf:6000-7fff + memory type=ROM content=Program + memory type=RAM content=Download + slot type=BSMemory + +board: BS-SA1-RAM + processor architecture=W65C816S + map address=00-3f,80-bf:2200-23ff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x408000 + map address=c0-ff:0000-ffff + memory type=ROM content=Program + slot type=BSMemory + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=40-4f:0000-ffff + memory type=RAM content=Internal + map address=00-3f,80-bf:3000-37ff size=0x800 + +board: EVENT-CC92 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + processor manufacturer=NEC architecture=uPD78214 + identifier: Campus Challenge '92 + map address=c0,e0:0000 + mcu + map address=00-1f,80-9f:8000-ffff + memory type=ROM content=Program + memory type=ROM content=Level-1 + memory type=ROM content=Level-2 + memory type=ROM content=Level-3 + dip + processor manufacturer=NEC architecture=uPD7725 + map address=20-3f,a0-bf:8000-ffff mask=0x7fff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: EVENT-PF94 + memory type=RAM content=Save + map address=30-3f,b0-bf:6000-7fff mask=0xe000 + processor manufacturer=NEC architecture=uPD78214 + identifier: PowerFest '94 + map address=10,20:6000 + mcu + map address=00-3f,80-bf:8000-ffff + map address=c0-ff:0000-ffff + memory type=ROM content=Program + memory type=ROM content=Level-1 + memory type=ROM content=Level-2 + memory type=ROM content=Level-3 + dip + processor manufacturer=NEC architecture=uPD7725 + map address=00-0f,80-8f:6000-7fff mask=0xfff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: EXHIROM + memory type=ROM content=Program + map address=00-3f:8000-ffff base=0x400000 + map address=40-7d:0000-ffff base=0x400000 + map address=80-bf:8000-ffff mask=0xc00000 + map address=c0-ff:0000-ffff mask=0xc00000 + +board: EXHIROM-RAM + memory type=ROM content=Program + map address=00-3f:8000-ffff base=0x400000 + map address=40-7d:0000-ffff base=0x400000 + map address=80-bf:8000-ffff mask=0xc00000 + map address=c0-ff:0000-ffff mask=0xc00000 + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + map address=70-7d:0000-7fff + +board: EXHIROM-RAM-SHARPRTC + memory type=ROM content=Program + map address=00-3f:8000-ffff base=0x400000 + map address=40-7d:0000-ffff base=0x400000 + map address=80-bf:8000-ffff mask=0xc00000 + map address=c0-ff:0000-ffff mask=0xc00000 + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + map address=70-7d:0000-7fff + rtc manufacturer=Sharp + map address=00-3f,80-bf:2800-2801 + memory type=RTC content=Time manufacturer=Sharp + +board: EXLOROM + memory type=ROM content=Program + map address=00-7d:8000-ffff mask=0x808000 base=0x400000 + map address=80-ff:8000-ffff mask=0x808000 base=0x000000 + +board: EXLOROM-RAM + memory type=ROM content=Program + map address=00-7d:8000-ffff mask=0x808000 base=0x400000 + map address=80-ff:8000-ffff mask=0x808000 base=0x000000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: EXNEC-LOROM + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + processor architecture=uPD96050 + map address=60-67,e0-e7:0000-3fff + memory type=ROM content=Program architecture=uPD96050 + memory type=ROM content=Data architecture=uPD96050 + memory type=RAM content=Data architecture=uPD96050 + map address=68-6f,e8-ef:0000-7fff mask=0x8000 + oscillator + +board: EXSPC7110-RAM-EPSONRTC + memory type=ROM content=Expansion + map address=40-4f:0000-ffff + processor identifier=SPC7110 + map address=00-3f,80-bf:4800-483f + map address=50,58:0000-ffff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x800000 + map address=c0-ff:0000-ffff mask=0xc00000 + memory type=ROM content=Program + memory type=ROM content=Data + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff mask=0xe000 + rtc manufacturer=Epson + map address=00-3f,80-bf:4840-4842 + memory type=RTC content=Time manufacturer=Epson + +board: GB-LOROM + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + map address=40-7d,c0-ff:0000-7fff mask=0x8000 + processor identifier=ICD revision=2 + map address=00-3f,80-bf:6000-67ff,7000-7fff + memory type=ROM content=Boot architecture=SM83 + oscillator + slot type=GameBoy + +board: GSU-RAM + processor architecture=GSU + map address=00-3f,80-bf:3000-34ff + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + map address=40-5f,c0-df:0000-ffff + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=70-71,f0-f1:0000-ffff + +board: HIROM + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + +board: HIROM-RAM + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + +board: HITACHI-LOROM + processor architecture=HG51BS169 + map address=00-3f,80-bf:6c00-6fff,7c00-7fff + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-77:0000-7fff + memory type=ROM content=Data architecture=HG51BS169 + memory type=RAM content=Data architecture=HG51BS169 + map address=00-3f,80-bf:6000-6bff,7000-7bff mask=0xf000 + oscillator + +board: LOROM + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + +board: LOROM-RAM + memory type=ROM content=Program + map address=00-7d,80-ff:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + +board: LOROM-RAM#A + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-ffff mask=0x8000 + +board: NEC-HIROM + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + processor architecture=uPD7725 + map address=00-1f,80-9f:6000-7fff mask=0xfff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: NEC-HIROM-RAM + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff + map address=40-7d,c0-ff:0000-ffff + memory type=RAM content=Save + map address=20-3f,a0-bf:6000-7fff mask=0xe000 + processor architecture=uPD7725 + map address=00-1f,80-9f:6000-7fff mask=0xfff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: NEC-LOROM + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + processor architecture=uPD7725 + map address=30-3f,b0-bf:8000-ffff mask=0x3fff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: NEC-LOROM-RAM + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-7fff mask=0x8000 + processor architecture=uPD7725 + map address=60-6f,e0-ef:0000-7fff mask=0x3fff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: NEC-LOROM-RAM#A + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + memory type=RAM content=Save + map address=70-7d,f0-ff:0000-ffff + processor architecture=uPD7725 + map address=20-3f,a0-bf:8000-ffff mask=0x3fff + memory type=ROM content=Program architecture=uPD7725 + memory type=ROM content=Data architecture=uPD7725 + memory type=RAM content=Data architecture=uPD7725 + oscillator + +board: OBC1-LOROM-RAM + memory type=ROM content=Program + map address=00-3f,80-bf:8000-ffff mask=0x8000 + processor identifier=OBC1 + map address=00-3f,80-bf:6000-7fff mask=0xe000 + map address=70-71,f0-f1:6000-7fff,e000-ffff mask=0xe000 + memory type=RAM content=Save + +board: SA1 + processor architecture=W65C816S + map address=00-3f,80-bf:2200-23ff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x408000 + map address=c0-ff:0000-ffff + memory type=ROM content=Program + memory type=RAM content=Internal + map address=00-3f,80-bf:3000-37ff size=0x800 + +board: SA1-RAM + processor architecture=W65C816S + map address=00-3f,80-bf:2200-23ff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x408000 + map address=c0-ff:0000-ffff + memory type=ROM content=Program + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff size=0x2000 + map address=40-4f:0000-ffff + memory type=RAM content=Internal + map address=00-3f,80-bf:3000-37ff size=0x800 + +board: SDD1 + processor identifier=SDD1 + map address=00-3f,80-bf:4800-480f + mcu + map address=00-3f,80-bf:8000-ffff + map address=c0-ff:0000-ffff + memory type=ROM content=Program + +board: SDD1-RAM + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff mask=0xe000 + map address=70-73:0000-ffff mask=0x8000 + processor identifier=SDD1 + map address=00-3f,80-bf:4800-480f + mcu + map address=00-3f,80-bf:8000-ffff + map address=c0-ff:0000-ffff + memory type=ROM content=Program + +board: SPC7110-RAM + processor identifier=SPC7110 + map address=00-3f,80-bf:4800-483f + map address=50,58:0000-ffff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x800000 + map address=c0-ff:0000-ffff mask=0xc00000 + memory type=ROM content=Program + memory type=ROM content=Data + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff mask=0xe000 + +board: SPC7110-RAM-EPSONRTC + processor identifier=SPC7110 + map address=00-3f,80-bf:4800-483f + map address=50,58:0000-ffff + mcu + map address=00-3f,80-bf:8000-ffff mask=0x800000 + map address=c0-ff:0000-ffff mask=0xc00000 + memory type=ROM content=Program + memory type=ROM content=Data + memory type=RAM content=Save + map address=00-3f,80-bf:6000-7fff mask=0xe000 + rtc manufacturer=Epson + map address=00-3f,80-bf:4840-4842 + memory type=RTC content=Time manufacturer=Epson + +board: ST-LOROM + memory type=ROM content=Program + map address=00-1f,80-9f:8000-ffff mask=0x8000 + slot type=SufamiTurbo + rom + map address=20-3f,a0-bf:8000-ffff mask=0x8000 + ram + map address=60-6f,e0-ef:0000-ffff + slot type=SufamiTurbo + rom + map address=40-5f,c0-df:0000-ffff mask=0x8000 + ram + map address=70-7d,f0-ff:0000-ffff + diff --git a/Database/ipl.rom b/Database/ipl.rom new file mode 100644 index 0000000000000000000000000000000000000000..c467694560419accfde1ec0d6cd9dcb454341309 GIT binary patch literal 64 zcmV-G0Kfmu@4e^%#vRc7kE-;KyY+a?^w9e+8SC`W{C@P%3*`07^w$9V(DSPS5bu8U W5bL`3+5o!r#Pr==(AysX0Kos7kSe(V literal 0 HcmV?d00001 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f2b151b --- /dev/null +++ b/LICENSE @@ -0,0 +1,41 @@ +---------------------------------------------------------------------- +bsnes - Super Nintendo emulator + + Copyright © 2004-2020 byuu et al + + https://github.com/bsnes-emu + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +---------------------------------------------------------------------- + +---------------------------------------------------------------------- +libco - C cooperative threading library +nall - C++ template library + + Copyright © 2006-2020 byuu et al + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted, provided that the +above copyright notice and this permission notice appear in all +copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +---------------------------------------------------------------------- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ccebab4 --- /dev/null +++ b/Makefile @@ -0,0 +1,123 @@ +CC ?= cc +CXX ?= c++ +CFLAGS ?= -O2 -march=native +CXXFLAGS ?= -O2 -march=native +FLAGS := -fPIC -std=c++17 -fno-strict-aliasing -fwrapv +FLAGS_CO := -fPIC -std=c89 +FLAGS_GB := -fPIC -std=c11 +CPPFLAGS_GB := -DGB_INTERNAL -DDISABLE_DEBUGGER -D_GNU_SOURCE +INCLUDES := -I. -I.. +INCLUDES_GB := -I../sameboy +WARNINGS := -Wno-multichar -Wno-narrowing -Wno-trigraphs +WARNINGS_CO := -Wall +WARNINGS_GB := -Wno-multichar +LIBS := -lm -lstdc++ +SHARED := -fPIC + +NAME := bsnes +PREFIX ?= /usr/local +DATADIR ?= $(PREFIX)/share/jollygood/$(NAME) +LIBDIR ?= $(PREFIX)/lib/jollygood + +UNAME := $(shell uname -s) +ifeq ($(UNAME), Darwin) + SHARED += -dynamiclib + TARGET := $(NAME).dylib +else ifeq ($(OS), Windows_NT) + SHARED += -shared + TARGET := $(NAME).dll +else + SHARED += -shared + TARGET := $(NAME).so +endif + +ifeq ($(UNAME), Linux) + LIBS += -Wl,--no-undefined +endif + +CSRCS := objs/gb/Core/apu.c \ + objs/gb/Core/camera.c \ + objs/gb/Core/display.c \ + objs/gb/Core/gb.c \ + objs/gb/Core/joypad.c \ + objs/gb/Core/mbc.c \ + objs/gb/Core/memory.c \ + objs/gb/Core/printer.c \ + objs/gb/Core/random.c \ + objs/gb/Core/rewind.c \ + objs/gb/Core/save_state.c \ + objs/gb/Core/sgb.c \ + objs/gb/Core/sm83_cpu.c \ + objs/gb/Core/symbol_hash.c \ + objs/gb/Core/timing.c \ + objs/libco/libco.c + +CXXSRCS := objs/emulator/emulator.cpp \ + objs/filter/filter.cpp \ + objs/lzma/lzma.cpp \ + objs/processor/arm7tdmi/arm7tdmi.cpp \ + objs/processor/spc700/spc700.cpp \ + objs/processor/wdc65816/wdc65816.cpp \ + objs/sfc/cartridge/cartridge.cpp \ + objs/sfc/controller/controller.cpp \ + objs/sfc/coprocessor/coprocessor.cpp \ + objs/sfc/cpu/cpu.cpp \ + objs/sfc/dsp/dsp.cpp \ + objs/sfc/expansion/expansion.cpp \ + objs/sfc/interface/interface.cpp \ + objs/sfc/memory/memory.cpp \ + objs/sfc/ppu/ppu.cpp \ + objs/sfc/ppu-fast/ppu.cpp \ + objs/sfc/slot/slot.cpp \ + objs/sfc/smp/smp.cpp \ + objs/sfc/system/system.cpp \ + objs/jg.cpp + +# Object dirs +OBJDIRS := objs objs/emulator objs/filter objs/lzma objs/sfc/interface \ + objs/sfc/system objs/sfc/controller objs/sfc/cartridge objs/sfc/memory \ + objs/sfc/cpu objs/sfc/smp objs/sfc/dsp objs/sfc/ppu objs/sfc/ppu-fast \ + objs/sfc/expansion objs/sfc/coprocessor objs/sfc/slot \ + objs/processor/arm7tdmi objs/processor/gsu objs/processor/hg51b \ + objs/processor/sm83 objs/processor/spc700 objs/processor/upd96050 \ + objs/processor/wdc65816 objs/gb/Core objs/libco + +# List of object files +OBJS := $(CSRCS:.c=.o) $(CXXSRCS:.cpp=.o) + +# libco rules +objs/libco/%.o: libco/%.c + $(CC) $(CFLAGS) $(FLAGS_CO) $(WARNINGS_CO) -c $< -o $@ + +# Game Boy rules +objs/gb/Core/%.o: gb/Core/%.c + $(CC) $(CFLAGS) $(FLAGS_GB) $(INCLUDES_GB) $(WARNINGS_GB) $(CPPFLAGS_GB) -c $< -o $@ + +# SNES rules +objs/%.o: %.cpp + $(CXX) $(CXXFLAGS) $(FLAGS) $(INCLUDES) $(WARNINGS) -c $< -o $@ + +all: maketree $(TARGET) + +maketree: $(sort $(OBJDIRS)) + +$(sort $(OBJDIRS)): + @mkdir -p $@ + +$(TARGET): $(OBJS) + @mkdir -p $(NAME) + $(CXX) $^ $(LDFLAGS) $(LIBS) $(SHARED) -o $(NAME)/$(TARGET) + @cp Database/boards.bml $(NAME)/ + +clean: + rm -rf $(OBJDIRS) $(NAME)/ + +install: + @mkdir -p $(DESTDIR)$(DATADIR) + @mkdir -p $(DESTDIR)$(LIBDIR) + cp $(NAME)/$(TARGET) $(DESTDIR)$(LIBDIR)/ + cp $(NAME)/boards.bml $(DESTDIR)$(DATADIR)/ + +uninstall: + rm -rf $(DESTDIR)$(DATADIR) + rm $(DESTDIR)$(LIBDIR)/$(TARGET) diff --git a/emulator/audio/audio.cpp b/emulator/audio/audio.cpp new file mode 100644 index 0000000..8fc279c --- /dev/null +++ b/emulator/audio/audio.cpp @@ -0,0 +1,73 @@ +namespace Emulator { + +#include "stream.cpp" +Audio audio; + +Audio::~Audio() { + reset(nullptr); +} + +auto Audio::reset(Interface* interface) -> void { + _interface = interface; + _streams.reset(); + _channels = 0; +} + +auto Audio::setFrequency(double frequency) -> void { + _frequency = frequency; + for(auto& stream : _streams) { + stream->setFrequency(stream->inputFrequency, frequency); + } +} + +auto Audio::setVolume(double volume) -> void { + _volume = volume; +} + +auto Audio::setBalance(double balance) -> void { + _balance = balance; +} + +auto Audio::createStream(uint channels, double frequency) -> shared_pointer { + _channels = max(_channels, channels); + shared_pointer stream = new Stream; + stream->reset(channels, frequency, _frequency); + _streams.append(stream); + return stream; +} + +auto Audio::process() -> void { + while(_streams) { + for(auto& stream : _streams) { + if(!stream->pending()) return; + } + + double samples[_channels]; + for(auto& sample : samples) sample = 0.0; + + for(auto& stream : _streams) { + double buffer[_channels]; + uint length = stream->read(buffer), offset = 0; + + for(auto& sample : samples) { + sample += buffer[offset]; + if(++offset >= length) offset = 0; + } + } + + for(auto c : range(_channels)) { + samples[c] = max(-1.0, min(+1.0, samples[c] * _volume)); + } + + if(_channels == 2) { + if(_balance < 0.0) samples[1] *= 1.0 + _balance; + if(_balance > 0.0) samples[0] *= 1.0 - _balance; + } + + platform->audioFrame(samples, _channels); + } +} + +} + +#undef double diff --git a/emulator/audio/audio.hpp b/emulator/audio/audio.hpp new file mode 100644 index 0000000..d170552 --- /dev/null +++ b/emulator/audio/audio.hpp @@ -0,0 +1,94 @@ +#pragma once + +#include +#include +#include +#include + +namespace Emulator { + +struct Interface; +struct Audio; +struct Filter; +struct Stream; + +struct Audio { + ~Audio(); + auto reset(Interface* interface) -> void; + + inline auto channels() const -> uint { return _channels; } + inline auto frequency() const -> double { return _frequency; } + inline auto volume() const -> double { return _volume; } + inline auto balance() const -> double { return _balance; } + + auto setFrequency(double frequency) -> void; + auto setVolume(double volume) -> void; + auto setBalance(double balance) -> void; + + auto createStream(uint channels, double frequency) -> shared_pointer; + +private: + auto process() -> void; + + Interface* _interface = nullptr; + vector> _streams; + + uint _channels = 0; + double _frequency = 48000.0; + + double _volume = 1.0; + double _balance = 0.0; + + friend class Stream; +}; + +struct Filter { + enum class Mode : uint { DCRemoval, OnePole, Biquad } mode; + enum class Type : uint { None, LowPass, HighPass } type; + enum class Order : uint { None, First, Second } order; + + DSP::IIR::DCRemoval dcRemoval; + DSP::IIR::OnePole onePole; + DSP::IIR::Biquad biquad; +}; + +struct Stream { + auto reset(uint channels, double inputFrequency, double outputFrequency) -> void; + auto reset() -> void; + + auto frequency() const -> double; + auto setFrequency(double inputFrequency, maybe outputFrequency = nothing) -> void; + + auto addDCRemovalFilter() -> void; + auto addLowPassFilter(double cutoffFrequency, Filter::Order order, uint passes = 1) -> void; + auto addHighPassFilter(double cutoffFrequency, Filter::Order order, uint passes = 1) -> void; + + auto pending() const -> uint; + auto read(double samples[]) -> uint; + auto write(const double samples[]) -> void; + + template auto sample(P&&... p) -> void { + double samples[sizeof...(P)] = {forward

(p)...}; + write(samples); + } + + auto serialize(serializer&) -> void; + +private: + struct Channel { + vector filters; + vector nyquist; + DSP::Resampler::Cubic resampler; + }; + vector channels; + double inputFrequency; + double outputFrequency; + + friend class Audio; +}; + +extern Audio audio; + +} + +#undef double diff --git a/emulator/audio/stream.cpp b/emulator/audio/stream.cpp new file mode 100644 index 0000000..3fe659f --- /dev/null +++ b/emulator/audio/stream.cpp @@ -0,0 +1,125 @@ +auto Stream::reset(uint channelCount, double inputFrequency, double outputFrequency) -> void { + channels.reset(); + channels.resize(channelCount); + + for(auto& channel : channels) { + channel.filters.reset(); + } + + setFrequency(inputFrequency, outputFrequency); +} + +auto Stream::reset() -> void { + for(auto& channel : channels) { + channel.resampler.reset(this->inputFrequency, this->outputFrequency); + } +} + +auto Stream::frequency() const -> double { + return inputFrequency; +} + +auto Stream::setFrequency(double inputFrequency, maybe outputFrequency) -> void { + this->inputFrequency = inputFrequency; + if(outputFrequency) this->outputFrequency = outputFrequency(); + + for(auto& channel : channels) { + channel.nyquist.reset(); + channel.resampler.reset(this->inputFrequency, this->outputFrequency); + } + + if(this->inputFrequency >= this->outputFrequency * 2) { + //add a low-pass filter to prevent aliasing during resampling + double cutoffFrequency = min(25000.0, this->outputFrequency / 2.0 - 2000.0); + for(auto& channel : channels) { + uint passes = 3; + for(uint pass : range(passes)) { + DSP::IIR::Biquad filter; + double q = DSP::IIR::Biquad::butterworth(passes * 2, pass); + filter.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, this->inputFrequency, q); + channel.nyquist.append(filter); + } + } + } +} + +auto Stream::addDCRemovalFilter() -> void { + return; //todo: test to ensure this is desirable before enabling + for(auto& channel : channels) { + Filter filter{Filter::Mode::DCRemoval, Filter::Type::None, Filter::Order::None}; + channel.filters.append(filter); + } +} + +auto Stream::addLowPassFilter(double cutoffFrequency, Filter::Order order, uint passes) -> void { + for(auto& channel : channels) { + for(uint pass : range(passes)) { + if(order == Filter::Order::First) { + Filter filter{Filter::Mode::OnePole, Filter::Type::LowPass, Filter::Order::First}; + filter.onePole.reset(DSP::IIR::OnePole::Type::LowPass, cutoffFrequency, inputFrequency); + channel.filters.append(filter); + } + if(order == Filter::Order::Second) { + Filter filter{Filter::Mode::Biquad, Filter::Type::LowPass, Filter::Order::Second}; + double q = DSP::IIR::Biquad::butterworth(passes * 2, pass); + filter.biquad.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, inputFrequency, q); + channel.filters.append(filter); + } + } + } +} + +auto Stream::addHighPassFilter(double cutoffFrequency, Filter::Order order, uint passes) -> void { + for(auto& channel : channels) { + for(uint pass : range(passes)) { + if(order == Filter::Order::First) { + Filter filter{Filter::Mode::OnePole, Filter::Type::HighPass, Filter::Order::First}; + filter.onePole.reset(DSP::IIR::OnePole::Type::HighPass, cutoffFrequency, inputFrequency); + channel.filters.append(filter); + } + if(order == Filter::Order::Second) { + Filter filter{Filter::Mode::Biquad, Filter::Type::HighPass, Filter::Order::Second}; + double q = DSP::IIR::Biquad::butterworth(passes * 2, pass); + filter.biquad.reset(DSP::IIR::Biquad::Type::HighPass, cutoffFrequency, inputFrequency, q); + channel.filters.append(filter); + } + } + } +} + +auto Stream::pending() const -> uint { + if(!channels) return 0; + return channels[0].resampler.pending(); +} + +auto Stream::read(double samples[]) -> uint { + for(uint c : range(channels.size())) samples[c] = channels[c].resampler.read(); + return channels.size(); +} + +auto Stream::write(const double samples[]) -> void { + for(auto c : range(channels.size())) { + double sample = samples[c] + 1e-25; //constant offset used to suppress denormals + for(auto& filter : channels[c].filters) { + switch(filter.mode) { + case Filter::Mode::DCRemoval: sample = filter.dcRemoval.process(sample); break; + case Filter::Mode::OnePole: sample = filter.onePole.process(sample); break; + case Filter::Mode::Biquad: sample = filter.biquad.process(sample); break; + } + } + for(auto& filter : channels[c].nyquist) { + sample = filter.process(sample); + } + channels[c].resampler.write(sample); + } + + audio.process(); +} + +auto Stream::serialize(serializer& s) -> void { + for(auto& channel : channels) { + channel.resampler.serialize(s); + } + s.real(inputFrequency); + s.real(outputFrequency); +} diff --git a/emulator/cheat.hpp b/emulator/cheat.hpp new file mode 100644 index 0000000..20f194b --- /dev/null +++ b/emulator/cheat.hpp @@ -0,0 +1,57 @@ +#pragma once + +namespace Emulator { + +struct Cheat { + struct Code { + auto operator==(const Code& code) const -> bool { + if(address != code.address) return false; + if(data != code.data) return false; + if((bool)compare != (bool)code.compare) return false; + if(compare && code.compare && compare() != code.compare()) return false; + return true; + } + + uint address; + uint data; + maybe compare; + bool enable; + uint restore; + }; + + explicit operator bool() const { + return codes.size() > 0; + } + + auto reset() -> void { + codes.reset(); + } + + auto append(uint address, uint data, maybe compare = {}) -> void { + codes.append({address, data, compare}); + } + + auto assign(const vector& list) -> void { + reset(); + for(auto& entry : list) { + for(auto code : entry.split("+")) { + auto part = code.transform("=?", "//").split("/"); + if(part.size() == 2) append(part[0].hex(), part[1].hex()); + if(part.size() == 3) append(part[0].hex(), part[2].hex(), part[1].hex()); + } + } + } + + auto find(uint address, uint compare) -> maybe { + for(auto& code : codes) { + if(code.address == address && (!code.compare || code.compare() == compare)) { + return code.data; + } + } + return nothing; + } + + vector codes; +}; + +} diff --git a/emulator/emulator.cpp b/emulator/emulator.cpp new file mode 100644 index 0000000..ce4b705 --- /dev/null +++ b/emulator/emulator.cpp @@ -0,0 +1,8 @@ +#include +#include + +namespace Emulator { + +Platform* platform = nullptr; + +} diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp new file mode 100644 index 0000000..cb17296 --- /dev/null +++ b/emulator/emulator.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace nall; + +#include +#include +#include +#include + +namespace Emulator { + static const string Name = "bsnes"; + static const string Version = "115"; + static const string Copyright = "byuu"; + static const string License = "GPLv3"; + static const string Website = "https://byuu.org"; + + //incremented only when serialization format changes + static const string SerializerVersion = "115"; + + namespace Constants { + namespace Colorburst { + static constexpr double NTSC = 315.0 / 88.0 * 1'000'000.0; + static constexpr double PAL = 283.75 * 15'625.0 + 25.0; + } + } + + //nall/vfs shorthand constants for open(), load() + namespace File { + static const auto Read = vfs::file::mode::read; + static const auto Write = vfs::file::mode::write; + static const auto Optional = false; + static const auto Required = true; + }; +} + +#include "platform.hpp" +#include "interface.hpp" +#include "game.hpp" diff --git a/emulator/game.hpp b/emulator/game.hpp new file mode 100644 index 0000000..cad2141 --- /dev/null +++ b/emulator/game.hpp @@ -0,0 +1,112 @@ +#pragma once + +namespace Emulator { + +struct Game { + struct Memory; + struct Oscillator; + + inline auto load(string_view) -> void; + inline auto memory(Markup::Node) -> maybe; + inline auto oscillator(natural = 0) -> maybe; + + struct Memory { + Memory() = default; + inline Memory(Markup::Node); + explicit operator bool() const { return (bool)type; } + inline auto name() const -> string; + + string type; + natural size; + string content; + string manufacturer; + string architecture; + string identifier; + boolean nonVolatile; + }; + + struct Oscillator { + Oscillator() = default; + inline Oscillator(Markup::Node); + explicit operator bool() const { return frequency; } + + natural frequency; + }; + + Markup::Node document; + string sha256; + string label; + string name; + string title; + string region; + string revision; + string board; + vector memoryList; + vector oscillatorList; +}; + +auto Game::load(string_view text) -> void { + document = BML::unserialize(text); + + sha256 = document["game/sha256"].text(); + label = document["game/label"].text(); + name = document["game/name"].text(); + title = document["game/title"].text(); + region = document["game/region"].text(); + revision = document["game/revision"].text(); + board = document["game/board"].text(); + + for(auto node : document.find("game/board/memory")) { + memoryList.append(Memory{node}); + } + + for(auto node : document.find("game/board/oscillator")) { + oscillatorList.append(Oscillator{node}); + } +} + +auto Game::memory(Markup::Node node) -> maybe { + if(!node) return nothing; + for(auto& memory : memoryList) { + auto type = node["type"].text(); + auto size = node["size"].natural(); + auto content = node["content"].text(); + auto manufacturer = node["manufacturer"].text(); + auto architecture = node["architecture"].text(); + auto identifier = node["identifier"].text(); + if(type && type != memory.type) continue; + if(size && size != memory.size) continue; + if(content && content != memory.content) continue; + if(manufacturer && manufacturer != memory.manufacturer) continue; + if(architecture && architecture != memory.architecture) continue; + if(identifier && identifier != memory.identifier) continue; + return memory; + } + return nothing; +} + +auto Game::oscillator(natural index) -> maybe { + if(index < oscillatorList.size()) return oscillatorList[index]; + return nothing; +} + +Game::Memory::Memory(Markup::Node node) { + type = node["type"].text(); + size = node["size"].natural(); + content = node["content"].text(); + manufacturer = node["manufacturer"].text(); + architecture = node["architecture"].text(); + identifier = node["identifier"].text(); + nonVolatile = !(bool)node["volatile"]; +} + +auto Game::Memory::name() const -> string { + if(architecture) return string{architecture, ".", content, ".", type}.downcase(); + return string{content, ".", type}.downcase(); +} + +Game::Oscillator::Oscillator(Markup::Node node) { + frequency = node["frequency"].natural(); +} + +} diff --git a/emulator/interface.hpp b/emulator/interface.hpp new file mode 100644 index 0000000..f21399f --- /dev/null +++ b/emulator/interface.hpp @@ -0,0 +1,109 @@ +#pragma once + +namespace Emulator { + +struct Interface { + struct Information { + string manufacturer; + string name; + string extension; + bool resettable = false; + }; + + struct Display { + struct Type { enum : uint { + CRT, + LCD, + };}; + uint id = 0; + string name; + uint type = 0; + uint colors = 0; + uint width = 0; + uint height = 0; + uint internalWidth = 0; + uint internalHeight = 0; + double aspectCorrection = 0; + }; + + struct Port { + uint id; + string name; + }; + + struct Device { + uint id; + string name; + }; + + struct Input { + struct Type { enum : uint { + Hat, + Button, + Trigger, + Control, + Axis, + Rumble, + };}; + + uint type; + string name; + }; + + //information + virtual auto information() -> Information { return {}; } + + virtual auto display() -> Display { return {}; } + virtual auto color(uint32 color) -> uint64 { return 0; } + + //game interface + virtual auto loaded() -> bool { return false; } + virtual auto hashes() -> vector { return {}; } + virtual auto manifests() -> vector { return {}; } + virtual auto titles() -> vector { return {}; } + virtual auto title() -> string { return {}; } + virtual auto load() -> bool { return false; } + virtual auto save() -> void {} + virtual auto unload() -> void {} + + //system interface + virtual auto ports() -> vector { return {}; } + virtual auto devices(uint port) -> vector { return {}; } + virtual auto inputs(uint device) -> vector { return {}; } + virtual auto connected(uint port) -> uint { return 0; } + virtual auto connect(uint port, uint device) -> void {} + virtual auto power() -> void {} + virtual auto reset() -> void {} + virtual auto run() -> void {} + + //time functions + virtual auto rtc() -> bool { return false; } + virtual auto synchronize(uint64 timestamp = 0) -> void {} + + //state functions + virtual auto serialize(bool synchronize = true) -> serializer { return {}; } + virtual auto unserialize(serializer&) -> bool { return false; } + + //cheat functions + virtual auto read(uint24 address) -> uint8 { return 0; } + virtual auto cheats(const vector& = {}) -> void {} + + //configuration + virtual auto configuration() -> string { return {}; } + virtual auto configuration(string name) -> string { return {}; } + virtual auto configure(string configuration = "") -> bool { return false; } + virtual auto configure(string name, string value) -> bool { return false; } + + //settings + virtual auto cap(const string& name) -> bool { return false; } + virtual auto get(const string& name) -> any { return {}; } + virtual auto set(const string& name, const any& value) -> bool { return false; } + + virtual auto frameSkip() -> uint { return 0; } + virtual auto setFrameSkip(uint frameSkip) -> void {} + + virtual auto runAhead() -> bool { return false; } + virtual auto setRunAhead(bool runAhead) -> void {} +}; + +} diff --git a/emulator/memory/memory.hpp b/emulator/memory/memory.hpp new file mode 100644 index 0000000..8e6ce4b --- /dev/null +++ b/emulator/memory/memory.hpp @@ -0,0 +1,30 @@ +#pragma once + +namespace Emulator::Memory { + +inline auto mirror(uint address, uint size) -> uint { + if(size == 0) return 0; + uint base = 0; + uint mask = 1 << 31; + while(address >= size) { + while(!(address & mask)) mask >>= 1; + address -= mask; + if(size > mask) { + size -= mask; + base += mask; + } + mask >>= 1; + } + return base + address; +} + +inline auto reduce(uint address, uint mask) -> uint { + while(mask) { + uint bits = (mask & -mask) - 1; + address = address >> 1 & ~bits | address & bits; + mask = (mask & mask - 1) >> 1; + } + return address; +} + +} diff --git a/emulator/memory/readable.hpp b/emulator/memory/readable.hpp new file mode 100644 index 0000000..688a2df --- /dev/null +++ b/emulator/memory/readable.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include + +namespace Emulator::Memory { + +template +struct Readable { + ~Readable() { reset(); } + + inline auto reset() -> void { + delete[] self.data; + self.data = nullptr; + self.size = 0; + self.mask = 0; + } + + inline auto allocate(uint size, T fill = ~0ull) -> void { + if(!size) return reset(); + delete[] self.data; + self.size = size; + self.mask = bit::round(self.size) - 1; + self.data = new T[self.mask + 1]; + memory::fill(self.data, self.mask + 1, fill); + } + + inline auto load(shared_pointer fp) -> void { + fp->read(self.data, min(fp->size(), self.size * sizeof(T))); + for(uint address = self.size; address <= self.mask; address++) { + self.data[address] = self.data[mirror(address, self.size)]; + } + } + + inline auto save(shared_pointer fp) -> void { + fp->write(self.data, self.size * sizeof(T)); + } + + explicit operator bool() const { return (bool)self.data; } + inline auto data() const -> const T* { return self.data; } + inline auto size() const -> uint { return self.size; } + inline auto mask() const -> uint { return self.mask; } + + inline auto operator[](uint address) const -> T { return self.data[address & self.mask]; } + inline auto read(uint address) const -> T { return self.data[address & self.mask]; } + inline auto write(uint address, T data) const -> void {} + + auto serialize(serializer& s) -> void { + const uint size = self.size; + s.integer(self.size); + s.integer(self.mask); + if(self.size != size) allocate(self.size); + s.array(self.data, self.size); + } + +private: + struct { + T* data = nullptr; + uint size = 0; + uint mask = 0; + } self; +}; + +} diff --git a/emulator/memory/writable.hpp b/emulator/memory/writable.hpp new file mode 100644 index 0000000..8ae5bd9 --- /dev/null +++ b/emulator/memory/writable.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include + +namespace Emulator::Memory { + +template +struct Writable { + ~Writable() { reset(); } + + inline auto reset() -> void { + delete[] self.data; + self.data = nullptr; + self.size = 0; + self.mask = 0; + } + + inline auto allocate(uint size, T fill = ~0ull) -> void { + if(!size) return reset(); + delete[] self.data; + self.size = size; + self.mask = bit::round(self.size) - 1; + self.data = new T[self.mask + 1]; + memory::fill(self.data, self.mask + 1, fill); + } + + inline auto load(shared_pointer fp) -> void { + fp->read(self.data, min(fp->size(), self.size * sizeof(T))); + for(uint address = self.size; address <= self.mask; address++) { + self.data[address] = self.data[mirror(address, self.size)]; + } + } + + inline auto save(shared_pointer fp) -> void { + fp->write(self.data, self.size * sizeof(T)); + } + + explicit operator bool() const { return (bool)self.data; } + inline auto data() -> T* { return self.data; } + inline auto data() const -> const T* { return self.data; } + inline auto size() const -> uint { return self.size; } + inline auto mask() const -> uint { return self.mask; } + + inline auto operator[](uint address) -> T& { return self.data[address & self.mask]; } + inline auto operator[](uint address) const -> T { return self.data[address & self.mask]; } + inline auto read(uint address) const -> T { return self.data[address & self.mask]; } + inline auto write(uint address, T data) -> void { self.data[address & self.mask] = data; } + + auto serialize(serializer& s) -> void { + const uint size = self.size; + s.integer(self.size); + s.integer(self.mask); + if(self.size != size) allocate(self.size); + s.array(self.data, self.size); + } + +private: + struct { + T* data = nullptr; + uint size = 0; + uint mask = 0; + } self; +}; + +} diff --git a/emulator/platform.hpp b/emulator/platform.hpp new file mode 100644 index 0000000..8eae0c0 --- /dev/null +++ b/emulator/platform.hpp @@ -0,0 +1,29 @@ +#pragma once + +namespace Emulator { + +struct Platform { + struct Load { + Load() = default; + Load(uint pathID, string option = "") : valid(true), pathID(pathID), option(option) {} + explicit operator bool() const { return valid; } + + bool valid = false; + uint pathID = 0; + string option; + }; + + virtual auto path(uint id) -> string { return ""; } + virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> shared_pointer { return {}; } + virtual auto load(uint id, string name, string type, vector options = {}) -> Load { return {}; } + virtual auto videoFrame(const uint16* data, uint pitch, uint width, uint height, uint scale) -> void {} + virtual auto audioFrame(const double* samples, uint channels) -> void {} + virtual auto inputPoll(uint port, uint device, uint input) -> int16 { return 0; } + virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {} + virtual auto dipSettings(Markup::Node node) -> uint { return 0; } + virtual auto notify(string text) -> void {} +}; + +extern Platform* platform; + +} diff --git a/emulator/random.hpp b/emulator/random.hpp new file mode 100644 index 0000000..b622887 --- /dev/null +++ b/emulator/random.hpp @@ -0,0 +1,96 @@ +#pragma once + +namespace Emulator { + +struct Random { + enum class Entropy : uint { None, Low, High }; + + auto operator()() -> uint64 { + return random(); + } + + auto entropy(Entropy entropy) -> void { + _entropy = entropy; + seed(); + } + + auto seed(maybe seed = nothing, maybe sequence = nothing) -> void { + if(!seed) seed = (uint32)clock(); + if(!sequence) sequence = 0; + + _state = 0; + _increment = sequence() << 1 | 1; + step(); + _state += seed(); + step(); + } + + auto random() -> uint64 { + if(_entropy == Entropy::None) return 0; + return (uint64)step() << 32 | (uint64)step() << 0; + } + + auto bias(uint64 bias) -> uint64 { + if(_entropy == Entropy::None) return bias; + return random(); + } + + auto bound(uint64 bound) -> uint64 { + uint64 threshold = -bound % bound; + while(true) { + uint64 result = random(); + if(result >= threshold) return result % bound; + } + } + + auto array(uint8* data, uint32 size) -> void { + if(_entropy == Entropy::None) { + memory::fill(data, size); + return; + } + + if(_entropy == Entropy::High) { + for(uint32 address : range(size)) { + data[address] = random(); + } + return; + } + + //Entropy::Low + uint lobit = random() & 3; + uint hibit = (lobit + 8 + (random() & 3)) & 15; + uint lovalue = random() & 255; + uint hivalue = random() & 255; + if((random() & 3) == 0) lovalue = 0; + if((random() & 1) == 0) hivalue = ~lovalue; + + for(uint32 address : range(size)) { + uint8 value = (address & 1ull << lobit) ? lovalue : hivalue; + if((address & 1ull << hibit)) value = ~value; + if((random() & 511) == 0) value ^= 1 << (random() & 7); + if((random() & 2047) == 0) value ^= 1 << (random() & 7); + data[address] = value; + } + } + + auto serialize(serializer& s) -> void { + s.integer((uint&)_entropy); + s.integer(_state); + s.integer(_increment); + } + +private: + auto step() -> uint32 { + uint64 state = _state; + _state = state * 6364136223846793005ull + _increment; + uint32 xorshift = (state >> 18 ^ state) >> 27; + uint32 rotate = state >> 59; + return xorshift >> rotate | xorshift << (-rotate & 31); + } + + Entropy _entropy = Entropy::High; + uint64 _state; + uint64 _increment; +}; + +} diff --git a/emulator/types.hpp b/emulator/types.hpp new file mode 100644 index 0000000..6c1fcda --- /dev/null +++ b/emulator/types.hpp @@ -0,0 +1,72 @@ +#pragma once + +using int1 = nall::Integer< 1>; +using int2 = nall::Integer< 2>; +using int3 = nall::Integer< 3>; +using int4 = nall::Integer< 4>; +using int5 = nall::Integer< 5>; +using int6 = nall::Integer< 6>; +using int7 = nall::Integer< 7>; +using int8 = int8_t; +using int9 = nall::Integer< 9>; +using int10 = nall::Integer<10>; +using int11 = nall::Integer<11>; +using int12 = nall::Integer<12>; +using int13 = nall::Integer<13>; +using int14 = nall::Integer<14>; +using int15 = nall::Integer<15>; +using int16 = int16_t; +using int17 = nall::Integer<17>; +using int18 = nall::Integer<18>; +using int19 = nall::Integer<19>; +using int20 = nall::Integer<20>; +using int21 = nall::Integer<21>; +using int22 = nall::Integer<22>; +using int23 = nall::Integer<23>; +using int24 = nall::Integer<24>; +using int25 = nall::Integer<25>; +using int26 = nall::Integer<26>; +using int27 = nall::Integer<27>; +using int28 = nall::Integer<28>; +using int29 = nall::Integer<29>; +using int30 = nall::Integer<30>; +using int31 = nall::Integer<31>; +using int32 = int32_t; +using int48 = nall::Integer<48>; //Cx4 +using int64 = int64_t; + +using uint1 = nall::Natural< 1>; +using uint2 = nall::Natural< 2>; +using uint3 = nall::Natural< 3>; +using uint4 = nall::Natural< 4>; +using uint5 = nall::Natural< 5>; +using uint6 = nall::Natural< 6>; +using uint7 = nall::Natural< 7>; +using uint8 = uint8_t; +using uint9 = nall::Natural< 9>; +using uint10 = nall::Natural<10>; +using uint11 = nall::Natural<11>; +using uint12 = nall::Natural<12>; +using uint13 = nall::Natural<13>; +using uint14 = nall::Natural<14>; +using uint15 = nall::Natural<15>; +using uint16 = uint16_t; +using uint17 = nall::Natural<17>; +using uint18 = nall::Natural<18>; +using uint19 = nall::Natural<19>; +using uint20 = nall::Natural<20>; +using uint21 = nall::Natural<21>; +using uint22 = nall::Natural<22>; +using uint23 = nall::Natural<23>; +using uint24 = nall::Natural<24>; +using uint25 = nall::Natural<25>; +using uint26 = nall::Natural<26>; +using uint27 = nall::Natural<27>; +using uint28 = nall::Natural<28>; +using uint29 = nall::Natural<29>; +using uint30 = nall::Natural<30>; +using uint31 = nall::Natural<31>; +using uint32 = uint32_t; +using uint40 = nall::Natural<40>; //SA1 +using uint48 = nall::Natural<48>; //Cx4 +using uint64 = uint64_t; diff --git a/filter/2xsai.cpp b/filter/2xsai.cpp new file mode 100644 index 0000000..9cc43d1 --- /dev/null +++ b/filter/2xsai.cpp @@ -0,0 +1,25 @@ +namespace Filter::_2xSaI { + +auto size(uint& width, uint& height) -> void { + width *= 2; + height *= 2; +} + +uint32_t temp[512 * 480]; + +auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + for(unsigned y = 0; y < height; y++) { + const uint16_t *line_in = (const uint16_t*)(((const uint8_t*)input) + pitch * y); + uint32_t *line_out = temp + y * width; + for(unsigned x = 0; x < width; x++) { + line_out[x] = colortable[line_in[x]]; + } + } + + _2xSaI32((unsigned char*)temp, width * sizeof(uint32_t), 0, (unsigned char*)output, outpitch, width, height); +} + +} diff --git a/filter/filter.cpp b/filter/filter.cpp new file mode 100644 index 0000000..469b9b7 --- /dev/null +++ b/filter/filter.cpp @@ -0,0 +1,25 @@ +#include + +#undef register +#define register +#include "sai/sai.cpp" + +uint32_t* colortable; +#include "snes_ntsc/snes_ntsc.h" +#include "snes_ntsc/snes_ntsc.c" + +#include "none.cpp" +#include "scanlines-light.cpp" +#include "scanlines-dark.cpp" +#include "scanlines-black.cpp" +#include "pixellate2x.cpp" +#include "scale2x.cpp" +#include "2xsai.cpp" +#include "super-2xsai.cpp" +#include "super-eagle.cpp" +#include "lq2x.cpp" +#include "hq2x.cpp" +#include "ntsc-rf.cpp" +#include "ntsc-composite.cpp" +#include "ntsc-svideo.cpp" +#include "ntsc-rgb.cpp" diff --git a/filter/filter.hpp b/filter/filter.hpp new file mode 100644 index 0000000..ac6b199 --- /dev/null +++ b/filter/filter.hpp @@ -0,0 +1,129 @@ +#pragma once + +#include + +namespace Filter { + using Size = auto (*)(uint& width, uint& height) -> void; + using Render = auto (*)(uint32_t* palette, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height) -> void; +} + +namespace Filter::None { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::ScanlinesLight { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::ScanlinesDark { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::ScanlinesBlack { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::Pixellate2x { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::Scale2x { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::_2xSaI { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::Super2xSaI { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::SuperEagle { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::LQ2x { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::HQ2x { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::NTSC_RF { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::NTSC_Composite { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::NTSC_SVideo { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} + +namespace Filter::NTSC_RGB { + auto size(uint& width, uint& height) -> void; + auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height + ) -> void; +} diff --git a/filter/hq2x.cpp b/filter/hq2x.cpp new file mode 100644 index 0000000..8b3691b --- /dev/null +++ b/filter/hq2x.cpp @@ -0,0 +1,200 @@ +namespace Filter::HQ2x { + +enum { + diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407, + diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0, +}; + +uint32_t *yuvTable; +uint8_t rotate[256]; + +const uint8_t hqTable[256] = { + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13, + 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14, + 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14, + 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14, + 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14, +}; + +static void initialize() { + static bool initialized = false; + if(initialized == true) return; + initialized = true; + + yuvTable = new uint32_t[32768]; + + for(unsigned i = 0; i < 32768; i++) { + uint8_t R = (i >> 0) & 31; + uint8_t G = (i >> 5) & 31; + uint8_t B = (i >> 10) & 31; + + //bgr555->bgr888 + double r = (R << 3) | (R >> 2); + double g = (G << 3) | (G >> 2); + double b = (B << 3) | (B >> 2); + + //bgr888->yuv + double y = (r + g + b) * (0.25f * (63.5f / 48.0f)); + double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f); + double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f); + + yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v); + } + + //counter-clockwise rotation table; one revolution: + //123 369 12346789 + //4.6 -> 2.8 = + //789 147 36928147 + for(unsigned n = 0; n < 256; n++) { + rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88) + | ((n & 0x01) << 5) | ((n & 0x08) << 3) + | ((n & 0x10) >> 3) | ((n & 0x80) >> 5); + } +} + +static void terminate() { + delete[] yuvTable; +} + +static bool same(uint16_t x, uint16_t y) { + return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask); +} + +static bool diff(uint32_t x, uint16_t y) { + return ((x - yuvTable[y]) & diff_mask); +} + +static void grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; } +static uint16_t pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); } + +static uint16_t blend1(uint32_t A, uint32_t B) { + grow(A); grow(B); + return pack((A * 3 + B) >> 2); +} + +static uint16_t blend2(uint32_t A, uint32_t B, uint32_t C) { + grow(A); grow(B); grow(C); + return pack((A * 2 + B + C) >> 2); +} + +static uint16_t blend3(uint32_t A, uint32_t B, uint32_t C) { + grow(A); grow(B); grow(C); + return pack((A * 5 + B * 2 + C) >> 3); +} + +static uint16_t blend4(uint32_t A, uint32_t B, uint32_t C) { + grow(A); grow(B); grow(C); + return pack((A * 6 + B + C) >> 3); +} + +static uint16_t blend5(uint32_t A, uint32_t B, uint32_t C) { + grow(A); grow(B); grow(C); + return pack((A * 2 + (B + C) * 3) >> 3); +} + +static uint16_t blend6(uint32_t A, uint32_t B, uint32_t C) { + grow(A); grow(B); grow(C); + return pack((A * 14 + B + C) >> 4); +} + +static uint16_t blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) { + switch(rule) { default: + case 0: return E; + case 1: return blend1(E, A); + case 2: return blend1(E, D); + case 3: return blend1(E, B); + case 4: return blend2(E, D, B); + case 5: return blend2(E, A, B); + case 6: return blend2(E, A, D); + case 7: return blend3(E, B, D); + case 8: return blend3(E, D, B); + case 9: return blend4(E, D, B); + case 10: return blend5(E, D, B); + case 11: return blend6(E, D, B); + case 12: return same(B, D) ? blend2(E, D, B) : E; + case 13: return same(B, D) ? blend5(E, D, B) : E; + case 14: return same(B, D) ? blend6(E, D, B) : E; + case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A); + case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A); + case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A); + case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D); + case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B); + } +} + +auto size(uint& width, uint& height) -> void { + width *= 2; + height *= 2; +} + +auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + initialize(); + + pitch >>= 1; + outpitch >>= 2; + + for(uint y = 0; y < height; y++) { + const uint16_t* in = input + y * pitch; + uint32_t* out0 = output + y * outpitch * 2; + uint32_t* out1 = output + y * outpitch * 2 + outpitch; + + int prevline = (y == 0 ? 0 : pitch); + int nextline = (y == height - 1 ? 0 : pitch); + + in++; + *out0++ = 0; *out0++ = 0; + *out1++ = 0; *out1++ = 0; + + for(unsigned x = 1; x < width - 1; x++) { + uint16_t A = *(in - prevline - 1); + uint16_t B = *(in - prevline + 0); + uint16_t C = *(in - prevline + 1); + uint16_t D = *(in - 1); + uint16_t E = *(in + 0); + uint16_t F = *(in + 1); + uint16_t G = *(in + nextline - 1); + uint16_t H = *(in + nextline + 0); + uint16_t I = *(in + nextline + 1); + uint32_t e = yuvTable[E] + diff_offset; + + uint8_t pattern; + pattern = diff(e, A) << 0; + pattern |= diff(e, B) << 1; + pattern |= diff(e, C) << 2; + pattern |= diff(e, D) << 3; + pattern |= diff(e, F) << 4; + pattern |= diff(e, G) << 5; + pattern |= diff(e, H) << 6; + pattern |= diff(e, I) << 7; + + *(out0 + 0) = colortable[blend(hqTable[pattern], E, A, B, D, F, H)]; pattern = rotate[pattern]; + *(out0 + 1) = colortable[blend(hqTable[pattern], E, C, F, B, H, D)]; pattern = rotate[pattern]; + *(out1 + 1) = colortable[blend(hqTable[pattern], E, I, H, F, D, B)]; pattern = rotate[pattern]; + *(out1 + 0) = colortable[blend(hqTable[pattern], E, G, D, H, B, F)]; + + in++; + out0 += 2; + out1 += 2; + } + + in++; + *out0++ = 0; *out0++ = 0; + *out1++ = 0; *out1++ = 0; + } +} + +} diff --git a/filter/lq2x.cpp b/filter/lq2x.cpp new file mode 100644 index 0000000..31b90e0 --- /dev/null +++ b/filter/lq2x.cpp @@ -0,0 +1,46 @@ +namespace Filter::LQ2x { + +auto size(uint& width, uint& height) -> void { + width *= 2; + height *= 2; +} + +auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + pitch >>= 1; + outpitch >>= 2; + + for(uint y = 0; y < height; y++) { + const uint16_t* in = input + y * pitch; + uint32_t* out0 = output + y * outpitch * 2; + uint32_t* out1 = output + y * outpitch * 2 + outpitch; + + int prevline = (y == 0 ? 0 : pitch); + int nextline = (y == height - 1 ? 0 : pitch); + + for(uint x = 0; x < width; x++) { + uint16_t A = *(in - prevline); + uint16_t B = (x > 0) ? *(in - 1) : *in; + uint16_t C = *in; + uint16_t D = (x < width - 1) ? *(in + 1) : *in; + uint16_t E = *(in++ + nextline); + uint32_t c = colortable[C]; + + if(A != E && B != D) { + *out0++ = (A == B ? colortable[C + A - ((C ^ A) & 0x0421) >> 1] : c); + *out0++ = (A == D ? colortable[C + A - ((C ^ A) & 0x0421) >> 1] : c); + *out1++ = (E == B ? colortable[C + E - ((C ^ E) & 0x0421) >> 1] : c); + *out1++ = (E == D ? colortable[C + E - ((C ^ E) & 0x0421) >> 1] : c); + } else { + *out0++ = c; + *out0++ = c; + *out1++ = c; + *out1++ = c; + } + } + } +} + +} diff --git a/filter/none.cpp b/filter/none.cpp new file mode 100644 index 0000000..ce148ce --- /dev/null +++ b/filter/none.cpp @@ -0,0 +1,24 @@ +namespace Filter::None { + +auto size(uint& width, uint& height) -> void { + width = width; + height = height; +} + +auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + pitch >>= 1; + outpitch >>= 2; + + for(uint y = 0; y < height; y++) { + const uint16_t* in = input + y * pitch; + uint32_t* out = output + y * outpitch; + for(uint x = 0; x < width; x++) { + *out++ = colortable[*in++]; + } + } +} + +} diff --git a/filter/ntsc-composite.cpp b/filter/ntsc-composite.cpp new file mode 100644 index 0000000..fa171c7 --- /dev/null +++ b/filter/ntsc-composite.cpp @@ -0,0 +1,50 @@ +namespace Filter::NTSC_Composite { + +struct snes_ntsc_t *ntsc; +snes_ntsc_setup_t setup; +int burst; +int burst_toggle; + +void initialize() { + static bool initialized = false; + if(initialized == true) return; + initialized = true; + + ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc); + setup = snes_ntsc_composite; + setup.merge_fields = 1; + snes_ntsc_init(ntsc, &setup); + + burst = 0; + burst_toggle = (setup.merge_fields ? 0 : 1); +} + +void terminate() { + if(ntsc) free(ntsc); +} + +auto size(uint& width, uint& height) -> void { + width = SNES_NTSC_OUT_WIDTH(256); + height = height; +} + +auto render( + uint32_t* colortable_, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + initialize(); + colortable = colortable_; + + pitch >>= 1; + outpitch >>= 2; + + if(width <= 256) { + snes_ntsc_blit (ntsc, input, pitch, burst, width, height, output, outpitch << 2); + } else { + snes_ntsc_blit_hires(ntsc, input, pitch, burst, width, height, output, outpitch << 2); + } + + burst ^= burst_toggle; +} + +} diff --git a/filter/ntsc-rf.cpp b/filter/ntsc-rf.cpp new file mode 100644 index 0000000..675a57c --- /dev/null +++ b/filter/ntsc-rf.cpp @@ -0,0 +1,50 @@ +namespace Filter::NTSC_RF { + +struct snes_ntsc_t *ntsc; +snes_ntsc_setup_t setup; +int burst; +int burst_toggle; + +void initialize() { + static bool initialized = false; + if(initialized == true) return; + initialized = true; + + ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc); + setup = snes_ntsc_composite; + setup.merge_fields = 0; + snes_ntsc_init(ntsc, &setup); + + burst = 0; + burst_toggle = (setup.merge_fields ? 0 : 1); +} + +void terminate() { + if(ntsc) free(ntsc); +} + +auto size(uint& width, uint& height) -> void { + width = SNES_NTSC_OUT_WIDTH(256); + height = height; +} + +auto render( + uint32_t* colortable_, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + initialize(); + colortable = colortable_; + + pitch >>= 1; + outpitch >>= 2; + + if(width <= 256) { + snes_ntsc_blit (ntsc, input, pitch, burst, width, height, output, outpitch << 2); + } else { + snes_ntsc_blit_hires(ntsc, input, pitch, burst, width, height, output, outpitch << 2); + } + + burst ^= burst_toggle; +} + +} diff --git a/filter/ntsc-rgb.cpp b/filter/ntsc-rgb.cpp new file mode 100644 index 0000000..effd79d --- /dev/null +++ b/filter/ntsc-rgb.cpp @@ -0,0 +1,50 @@ +namespace Filter::NTSC_RGB { + +struct snes_ntsc_t *ntsc; +snes_ntsc_setup_t setup; +int burst; +int burst_toggle; + +void initialize() { + static bool initialized = false; + if(initialized == true) return; + initialized = true; + + ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc); + setup = snes_ntsc_rgb; + setup.merge_fields = 1; + snes_ntsc_init(ntsc, &setup); + + burst = 0; + burst_toggle = (setup.merge_fields ? 0 : 1); +} + +void terminate() { + if(ntsc) free(ntsc); +} + +auto size(uint& width, uint& height) -> void { + width = SNES_NTSC_OUT_WIDTH(256); + height = height; +} + +auto render( + uint32_t* colortable_, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + initialize(); + colortable = colortable_; + + pitch >>= 1; + outpitch >>= 2; + + if(width <= 256) { + snes_ntsc_blit (ntsc, input, pitch, burst, width, height, output, outpitch << 2); + } else { + snes_ntsc_blit_hires(ntsc, input, pitch, burst, width, height, output, outpitch << 2); + } + + burst ^= burst_toggle; +} + +} diff --git a/filter/ntsc-svideo.cpp b/filter/ntsc-svideo.cpp new file mode 100644 index 0000000..e4045b0 --- /dev/null +++ b/filter/ntsc-svideo.cpp @@ -0,0 +1,50 @@ +namespace Filter::NTSC_SVideo { + +struct snes_ntsc_t *ntsc; +snes_ntsc_setup_t setup; +int burst; +int burst_toggle; + +void initialize() { + static bool initialized = false; + if(initialized == true) return; + initialized = true; + + ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc); + setup = snes_ntsc_svideo; + setup.merge_fields = 1; + snes_ntsc_init(ntsc, &setup); + + burst = 0; + burst_toggle = (setup.merge_fields ? 0 : 1); +} + +void terminate() { + if(ntsc) free(ntsc); +} + +auto size(uint& width, uint& height) -> void { + width = SNES_NTSC_OUT_WIDTH(256); + height = height; +} + +auto render( + uint32_t* colortable_, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + initialize(); + colortable = colortable_; + + pitch >>= 1; + outpitch >>= 2; + + if(width <= 256) { + snes_ntsc_blit (ntsc, input, pitch, burst, width, height, output, outpitch << 2); + } else { + snes_ntsc_blit_hires(ntsc, input, pitch, burst, width, height, output, outpitch << 2); + } + + burst ^= burst_toggle; +} + +} diff --git a/filter/pixellate2x.cpp b/filter/pixellate2x.cpp new file mode 100644 index 0000000..ac18fb2 --- /dev/null +++ b/filter/pixellate2x.cpp @@ -0,0 +1,40 @@ +namespace Filter::Pixellate2x { + +auto size(uint& width, uint& height) -> void { + width = (width <= 256) ? width * 2 : width; + height = (height <= 240) ? height * 2 : height; +} + +auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + pitch >>= 1; + outpitch >>= 2; + + uint32_t *out0 = output; + uint32_t *out1 = output + outpitch; + + for(unsigned y = 0; y < height; y++) { + for(unsigned x = 0; x < width; x++) { + uint32_t p = colortable[*input++]; + + *out0++ = p; + if(height <= 240) *out1++ = p; + if(width > 256) continue; + + *out0++ = p; + if(height <= 240) *out1++ = p; + } + + input += pitch - width; + if(height <= 240) { + out0 += outpitch + outpitch - 512; + out1 += outpitch + outpitch - 512; + } else { + out0 += outpitch - 512; + } + } +} + +} diff --git a/filter/sai/sai.cpp b/filter/sai/sai.cpp new file mode 100644 index 0000000..463326d --- /dev/null +++ b/filter/sai/sai.cpp @@ -0,0 +1,1175 @@ +#if defined(ENDIAN_MSB) + #define WORDS_BIGENDIAN +#endif + +static uint32_t colorMask = 0xFEFEFE; +static uint32_t lowPixelMask = 0x010101; +static uint32_t qcolorMask = 0xFCFCFC; +static uint32_t qlowpixelMask = 0x030303; +static uint32_t redblueMask = 0xFF00FF; +static uint32_t greenMask = 0xFF00; + +uint32_t qRGB_COLOR_MASK[2] = { 0xFEFEFE, 0xFEFEFE }; + +static inline int GetResult1 (uint32_t A, uint32_t B, uint32_t C, uint32_t D, + uint32_t /* E */) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r += 1; + if (y <= 1) + r -= 1; + return r; +} + +static inline int GetResult2 (uint32_t A, uint32_t B, uint32_t C, uint32_t D, + uint32_t /* E */) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r -= 1; + if (y <= 1) + r += 1; + return r; +} + +static inline int GetResult (uint32_t A, uint32_t B, uint32_t C, uint32_t D) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r += 1; + if (y <= 1) + r -= 1; + return r; +} + +static inline uint32_t INTERPOLATE (uint32_t A, uint32_t B) +{ + if (A != B) { + return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + + (A & B & lowPixelMask)); + } else + return A; +} + +static inline uint32_t Q_INTERPOLATE (uint32_t A, uint32_t B, uint32_t C, uint32_t D) +{ + register uint32_t x = ((A & qcolorMask) >> 2) + + ((B & qcolorMask) >> 2) + + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2); + register uint32_t y = (A & qlowpixelMask) + + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask); + + y = (y >> 2) & qlowpixelMask; + return x + y; +} + +static inline int GetResult1_32 (uint32_t A, uint32_t B, uint32_t C, uint32_t D, + uint32_t /* E */) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r += 1; + if (y <= 1) + r -= 1; + return r; +} + +static inline int GetResult2_32 (uint32_t A, uint32_t B, uint32_t C, uint32_t D, + uint32_t /* E */) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r -= 1; + if (y <= 1) + r += 1; + return r; +} + +#define BLUE_MASK565 0x001F001F +#define RED_MASK565 0xF800F800 +#define GREEN_MASK565 0x07E007E0 + +#define BLUE_MASK555 0x001F001F +#define RED_MASK555 0x7C007C00 +#define GREEN_MASK555 0x03E003E0 + +void Super2xSaI (uint8_t *srcPtr, uint32_t srcPitch, + uint8_t *deltaPtr, uint8_t *dstPtr, uint32_t dstPitch, + int width, int height) +{ + uint16_t *bP; + uint8_t *dP; + uint32_t inc_bP; + uint32_t Nextline = srcPitch >> 1; + { + inc_bP = 1; + + for (; height; height--) { + bP = (uint16_t *) srcPtr; + dP = (uint8_t *) dstPtr; + + for (uint32_t finish = width; finish; finish -= inc_bP) { + uint32_t color4, color5, color6; + uint32_t color1, color2, color3; + uint32_t colorA0, colorA1, colorA2, colorA3, + colorB0, colorB1, colorB2, colorB3, colorS1, colorS2; + uint32_t product1a, product1b, product2a, product2b; + + //--------------------------------------- B1 B2 + // 4 5 6 S2 + // 1 2 3 S1 + // A1 A2 + + colorB0 = *(bP - Nextline - 1); + colorB1 = *(bP - Nextline); + colorB2 = *(bP - Nextline + 1); + colorB3 = *(bP - Nextline + 2); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + Nextline - 1); + color2 = *(bP + Nextline); + color3 = *(bP + Nextline + 1); + colorS1 = *(bP + Nextline + 2); + + colorA0 = *(bP + Nextline + Nextline - 1); + colorA1 = *(bP + Nextline + Nextline); + colorA2 = *(bP + Nextline + Nextline + 1); + colorA3 = *(bP + Nextline + Nextline + 2); + + //-------------------------------------- + if (color2 == color6 && color5 != color3) { + product2b = product1b = color2; + } else if (color5 == color3 && color2 != color6) { + product2b = product1b = color5; + } else if (color5 == color3 && color2 == color6) { + register int r = 0; + + r += GetResult (color6, color5, color1, colorA1); + r += GetResult (color6, color5, color4, colorB1); + r += GetResult (color6, color5, colorA2, colorS1); + r += GetResult (color6, color5, colorB2, colorS2); + + if (r > 0) + product2b = product1b = color6; + else if (r < 0) + product2b = product1b = color5; + else { + product2b = product1b = INTERPOLATE (color5, color6); + } + } else { + if (color6 == color3 && color3 == colorA1 + && color2 != colorA2 && color3 != colorA0) + product2b = + Q_INTERPOLATE (color3, color3, color3, color2); + else if (color5 == color2 && color2 == colorA2 + && colorA1 != color3 && color2 != colorA3) + product2b = + Q_INTERPOLATE (color2, color2, color2, color3); + else + product2b = INTERPOLATE (color2, color3); + + if (color6 == color3 && color6 == colorB1 + && color5 != colorB2 && color6 != colorB0) + product1b = + Q_INTERPOLATE (color6, color6, color6, color5); + else if (color5 == color2 && color5 == colorB2 + && colorB1 != color6 && color5 != colorB3) + product1b = + Q_INTERPOLATE (color6, color5, color5, color5); + else + product1b = INTERPOLATE (color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 + && color5 != colorA2) + product2a = INTERPOLATE (color2, color5); + else + if (color5 == color1 && color6 == color5 + && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE (color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 + && color2 != colorB2) + product1a = INTERPOLATE (color2, color5); + else + if (color4 == color2 && color3 == color2 + && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE (color2, color5); + else + product1a = color5; + +#ifdef WORDS_BIGENDIAN + product1a = (product1a << 16) | product1b; + product2a = (product2a << 16) | product2b; +#else + product1a = product1a | (product1b << 16); + product2a = product2a | (product2b << 16); +#endif + + *((uint32_t *) dP) = product1a; + *((uint32_t *) (dP + dstPitch)) = product2a; + + bP += inc_bP; + dP += sizeof (uint32_t); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch << 1; + deltaPtr += srcPitch; + } // endof: for (; height; height--) + } +} + +void Super2xSaI32 (uint8_t *srcPtr, uint32_t srcPitch, + uint8_t * /* deltaPtr */, uint8_t *dstPtr, uint32_t dstPitch, + int width, int height) +{ + uint32_t *bP; + uint32_t *dP; + uint32_t inc_bP; + uint32_t Nextline = srcPitch >> 2; + inc_bP = 1; + + for (; height; height--) { + bP = (uint32_t *) srcPtr; + dP = (uint32_t *) dstPtr; + + for (uint32_t finish = width; finish; finish -= inc_bP) { + uint32_t color4, color5, color6; + uint32_t color1, color2, color3; + uint32_t colorA0, colorA1, colorA2, colorA3, + colorB0, colorB1, colorB2, colorB3, colorS1, colorS2; + uint32_t product1a, product1b, product2a, product2b; + + //--------------------------------------- B1 B2 + // 4 5 6 S2 + // 1 2 3 S1 + // A1 A2 + + colorB0 = *(bP - Nextline - 1); + colorB1 = *(bP - Nextline); + colorB2 = *(bP - Nextline + 1); + colorB3 = *(bP - Nextline + 2); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + Nextline - 1); + color2 = *(bP + Nextline); + color3 = *(bP + Nextline + 1); + colorS1 = *(bP + Nextline + 2); + + colorA0 = *(bP + Nextline + Nextline - 1); + colorA1 = *(bP + Nextline + Nextline); + colorA2 = *(bP + Nextline + Nextline + 1); + colorA3 = *(bP + Nextline + Nextline + 2); + + //-------------------------------------- + if (color2 == color6 && color5 != color3) { + product2b = product1b = color2; + } else if (color5 == color3 && color2 != color6) { + product2b = product1b = color5; + } else if (color5 == color3 && color2 == color6) { + register int r = 0; + + r += GetResult (color6, color5, color1, colorA1); + r += GetResult (color6, color5, color4, colorB1); + r += GetResult (color6, color5, colorA2, colorS1); + r += GetResult (color6, color5, colorB2, colorS2); + + if (r > 0) + product2b = product1b = color6; + else if (r < 0) + product2b = product1b = color5; + else { + product2b = product1b = INTERPOLATE (color5, color6); + } + } else { + if (color6 == color3 && color3 == colorA1 + && color2 != colorA2 && color3 != colorA0) + product2b = + Q_INTERPOLATE (color3, color3, color3, color2); + else if (color5 == color2 && color2 == colorA2 + && colorA1 != color3 && color2 != colorA3) + product2b = + Q_INTERPOLATE (color2, color2, color2, color3); + else + product2b = INTERPOLATE (color2, color3); + + if (color6 == color3 && color6 == colorB1 + && color5 != colorB2 && color6 != colorB0) + product1b = + Q_INTERPOLATE (color6, color6, color6, color5); + else if (color5 == color2 && color5 == colorB2 + && colorB1 != color6 && color5 != colorB3) + product1b = + Q_INTERPOLATE (color6, color5, color5, color5); + else + product1b = INTERPOLATE (color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 + && color5 != colorA2) + product2a = INTERPOLATE (color2, color5); + else + if (color5 == color1 && color6 == color5 + && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE (color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 + && color2 != colorB2) + product1a = INTERPOLATE (color2, color5); + else + if (color4 == color2 && color3 == color2 + && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE (color2, color5); + else + product1a = color5; + *(dP) = product1a; + *(dP+1) = product1b; + *(dP + (dstPitch >> 2)) = product2a; + *(dP + (dstPitch >> 2) + 1) = product2b; + + bP += inc_bP; + dP += 2; + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch << 1; + // deltaPtr += srcPitch; + } // endof: for (; height; height--) +} + +void SuperEagle (uint8_t *srcPtr, uint32_t srcPitch, uint8_t *deltaPtr, + uint8_t *dstPtr, uint32_t dstPitch, int width, int height) +{ + uint8_t *dP; + uint16_t *bP; + uint16_t *xP; + uint32_t inc_bP; + + { + inc_bP = 1; + + uint32_t Nextline = srcPitch >> 1; + + for (; height; height--) { + bP = (uint16_t *) srcPtr; + xP = (uint16_t *) deltaPtr; + dP = dstPtr; + for (uint32_t finish = width; finish; finish -= inc_bP) { + uint32_t color4, color5, color6; + uint32_t color1, color2, color3; + uint32_t colorA1, colorA2, colorB1, colorB2, colorS1, colorS2; + uint32_t product1a, product1b, product2a, product2b; + + colorB1 = *(bP - Nextline); + colorB2 = *(bP - Nextline + 1); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + Nextline - 1); + color2 = *(bP + Nextline); + color3 = *(bP + Nextline + 1); + colorS1 = *(bP + Nextline + 2); + + colorA1 = *(bP + Nextline + Nextline); + colorA2 = *(bP + Nextline + Nextline + 1); + + // -------------------------------------- + if (color2 == color6 && color5 != color3) { + product1b = product2a = color2; + if ((color1 == color2) || (color6 == colorB2)) { + product1a = INTERPOLATE (color2, color5); + product1a = INTERPOLATE (color2, product1a); + // product1a = color2; + } else { + product1a = INTERPOLATE (color5, color6); + } + + if ((color6 == colorS2) || (color2 == colorA1)) { + product2b = INTERPOLATE (color2, color3); + product2b = INTERPOLATE (color2, product2b); + // product2b = color2; + } else { + product2b = INTERPOLATE (color2, color3); + } + } else if (color5 == color3 && color2 != color6) { + product2b = product1a = color5; + + if ((colorB1 == color5) || (color3 == colorS1)) { + product1b = INTERPOLATE (color5, color6); + product1b = INTERPOLATE (color5, product1b); + // product1b = color5; + } else { + product1b = INTERPOLATE (color5, color6); + } + + if ((color3 == colorA2) || (color4 == color5)) { + product2a = INTERPOLATE (color5, color2); + product2a = INTERPOLATE (color5, product2a); + // product2a = color5; + } else { + product2a = INTERPOLATE (color2, color3); + } + + } else if (color5 == color3 && color2 == color6) { + register int r = 0; + + r += GetResult (color6, color5, color1, colorA1); + r += GetResult (color6, color5, color4, colorB1); + r += GetResult (color6, color5, colorA2, colorS1); + r += GetResult (color6, color5, colorB2, colorS2); + + if (r > 0) { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE (color5, color6); + } else if (r < 0) { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE (color5, color6); + } else { + product2b = product1a = color5; + product1b = product2a = color2; + } + } else { + product2b = product1a = INTERPOLATE (color2, color6); + product2b = + Q_INTERPOLATE (color3, color3, color3, product2b); + product1a = + Q_INTERPOLATE (color5, color5, color5, product1a); + + product2a = product1b = INTERPOLATE (color5, color3); + product2a = + Q_INTERPOLATE (color2, color2, color2, product2a); + product1b = + Q_INTERPOLATE (color6, color6, color6, product1b); + + // product1a = color5; + // product1b = color6; + // product2a = color2; + // product2b = color3; + } +#ifdef WORDS_BIGENDIAN + product1a = (product1a << 16) | product1b; + product2a = (product2a << 16) | product2b; +#else + product1a = product1a | (product1b << 16); + product2a = product2a | (product2b << 16); +#endif + + *((uint32_t *) dP) = product1a; + *((uint32_t *) (dP + dstPitch)) = product2a; + *xP = color5; + + bP += inc_bP; + xP += inc_bP; + dP += sizeof (uint32_t); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch << 1; + deltaPtr += srcPitch; + } // endof: for (height; height; height--) + } +} + +void SuperEagle32 (uint8_t *srcPtr, uint32_t srcPitch, uint8_t */*deltaPtr*/, + uint8_t *dstPtr, uint32_t dstPitch, int width, int height) +{ + uint32_t *dP; + uint32_t *bP; + //uint32_t *xP; + uint32_t inc_bP; + + inc_bP = 1; + + uint32_t Nextline = srcPitch >> 2; + + for (; height; height--) { + bP = (uint32_t *) srcPtr; + //xP = (uint32_t *) deltaPtr; + dP = (uint32_t *)dstPtr; + for (uint32_t finish = width; finish; finish -= inc_bP) { + uint32_t color4, color5, color6; + uint32_t color1, color2, color3; + uint32_t colorA1, colorA2, colorB1, colorB2, colorS1, colorS2; + uint32_t product1a, product1b, product2a, product2b; + + colorB1 = *(bP - Nextline); + colorB2 = *(bP - Nextline + 1); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + Nextline - 1); + color2 = *(bP + Nextline); + color3 = *(bP + Nextline + 1); + colorS1 = *(bP + Nextline + 2); + + colorA1 = *(bP + Nextline + Nextline); + colorA2 = *(bP + Nextline + Nextline + 1); + + // -------------------------------------- + if (color2 == color6 && color5 != color3) { + product1b = product2a = color2; + if ((color1 == color2) || (color6 == colorB2)) { + product1a = INTERPOLATE (color2, color5); + product1a = INTERPOLATE (color2, product1a); + // product1a = color2; + } else { + product1a = INTERPOLATE (color5, color6); + } + + if ((color6 == colorS2) || (color2 == colorA1)) { + product2b = INTERPOLATE (color2, color3); + product2b = INTERPOLATE (color2, product2b); + // product2b = color2; + } else { + product2b = INTERPOLATE (color2, color3); + } + } else if (color5 == color3 && color2 != color6) { + product2b = product1a = color5; + + if ((colorB1 == color5) || (color3 == colorS1)) { + product1b = INTERPOLATE (color5, color6); + product1b = INTERPOLATE (color5, product1b); + // product1b = color5; + } else { + product1b = INTERPOLATE (color5, color6); + } + + if ((color3 == colorA2) || (color4 == color5)) { + product2a = INTERPOLATE (color5, color2); + product2a = INTERPOLATE (color5, product2a); + // product2a = color5; + } else { + product2a = INTERPOLATE (color2, color3); + } + + } else if (color5 == color3 && color2 == color6) { + register int r = 0; + + r += GetResult (color6, color5, color1, colorA1); + r += GetResult (color6, color5, color4, colorB1); + r += GetResult (color6, color5, colorA2, colorS1); + r += GetResult (color6, color5, colorB2, colorS2); + + if (r > 0) { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE (color5, color6); + } else if (r < 0) { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE (color5, color6); + } else { + product2b = product1a = color5; + product1b = product2a = color2; + } + } else { + product2b = product1a = INTERPOLATE (color2, color6); + product2b = + Q_INTERPOLATE (color3, color3, color3, product2b); + product1a = + Q_INTERPOLATE (color5, color5, color5, product1a); + + product2a = product1b = INTERPOLATE (color5, color3); + product2a = + Q_INTERPOLATE (color2, color2, color2, product2a); + product1b = + Q_INTERPOLATE (color6, color6, color6, product1b); + + // product1a = color5; + // product1b = color6; + // product2a = color2; + // product2b = color3; + } + *(dP) = product1a; + *(dP+1) = product1b; + *(dP + (dstPitch >> 2)) = product2a; + *(dP + (dstPitch >> 2) +1) = product2b; + //*xP = color5; + + bP += inc_bP; + //xP += inc_bP; + dP += 2; + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch << 1; + //deltaPtr += srcPitch; + } // endof: for (height; height; height--) +} + +void _2xSaI (uint8_t *srcPtr, uint32_t srcPitch, uint8_t *deltaPtr, + uint8_t *dstPtr, uint32_t dstPitch, int width, int height) +{ + uint8_t *dP; + uint16_t *bP; + uint32_t inc_bP; + + { + inc_bP = 1; + + uint32_t Nextline = srcPitch >> 1; + + for (; height; height--) { + bP = (uint16_t *) srcPtr; + dP = dstPtr; + + for (uint32_t finish = width; finish; finish -= inc_bP) { + + register uint32_t colorA, colorB; + uint32_t colorC, colorD, + colorE, colorF, colorG, colorH, + colorI, colorJ, colorK, colorL, + + colorM, colorN, colorO, colorP; + uint32_t product, product1, product2; + + //--------------------------------------- + // Map of the pixels: I|E F|J + // G|A B|K + // H|C D|L + // M|N O|P + colorI = *(bP - Nextline - 1); + colorE = *(bP - Nextline); + colorF = *(bP - Nextline + 1); + colorJ = *(bP - Nextline + 2); + + colorG = *(bP - 1); + colorA = *(bP); + colorB = *(bP + 1); + colorK = *(bP + 2); + + colorH = *(bP + Nextline - 1); + colorC = *(bP + Nextline); + colorD = *(bP + Nextline + 1); + colorL = *(bP + Nextline + 2); + + colorM = *(bP + Nextline + Nextline - 1); + colorN = *(bP + Nextline + Nextline); + colorO = *(bP + Nextline + Nextline + 1); + colorP = *(bP + Nextline + Nextline + 2); + + if ((colorA == colorD) && (colorB != colorC)) { + if (((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ))) { + product = colorA; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if (((colorA == colorG) && (colorC == colorO)) || + ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM))) { + product1 = colorA; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + product2 = colorA; + } else if ((colorB == colorC) && (colorA != colorD)) { + if (((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI))) { + product = colorB; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if (((colorC == colorH) && (colorA == colorF)) || + ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI))) { + product1 = colorC; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + product2 = colorB; + } else if ((colorA == colorD) && (colorB == colorC)) { + if (colorA == colorB) { + product = colorA; + product1 = colorA; + product2 = colorA; + } else { + register int r = 0; + + product1 = INTERPOLATE (colorA, colorC); + product = INTERPOLATE (colorA, colorB); + + r += + GetResult1 (colorA, colorB, colorG, colorE, + colorI); + r += + GetResult2 (colorB, colorA, colorK, colorF, + colorJ); + r += + GetResult2 (colorB, colorA, colorH, colorN, + colorM); + r += + GetResult1 (colorA, colorB, colorL, colorO, + colorP); + + if (r > 0) + product2 = colorA; + else if (r < 0) + product2 = colorB; + else { + product2 = + Q_INTERPOLATE (colorA, colorB, colorC, + colorD); + } + } + } else { + product2 = Q_INTERPOLATE (colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ)) { + product = colorA; + } else if ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI)) { + product = colorB; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM)) { + product1 = colorA; + } else if ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI)) { + product1 = colorC; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + } + +#ifdef WORDS_BIGENDIAN + product = (colorA << 16) | product ; + product1 = (product1 << 16) | product2 ; +#else + product = colorA | (product << 16); + product1 = product1 | (product2 << 16); +#endif + *((int32_t *) dP) = product; + *((uint32_t *) (dP + dstPitch)) = product1; + + bP += inc_bP; + dP += sizeof (uint32_t); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch << 1; + deltaPtr += srcPitch; + } // endof: for (height; height; height--) + } +} + +void _2xSaI32 (uint8_t *srcPtr, uint32_t srcPitch, uint8_t * /* deltaPtr */, + uint8_t *dstPtr, uint32_t dstPitch, int width, int height) +{ + uint32_t *dP; + uint32_t *bP; + uint32_t inc_bP = 1; + + uint32_t Nextline = srcPitch >> 2; + + for (; height; height--) { + bP = (uint32_t *) srcPtr; + dP = (uint32_t *) dstPtr; + + for (uint32_t finish = width; finish; finish -= inc_bP) { + register uint32_t colorA, colorB; + uint32_t colorC, colorD, + colorE, colorF, colorG, colorH, + colorI, colorJ, colorK, colorL, + + colorM, colorN, colorO, colorP; + uint32_t product, product1, product2; + + //--------------------------------------- + // Map of the pixels: I|E F|J + // G|A B|K + // H|C D|L + // M|N O|P + colorI = *(bP - Nextline - 1); + colorE = *(bP - Nextline); + colorF = *(bP - Nextline + 1); + colorJ = *(bP - Nextline + 2); + + colorG = *(bP - 1); + colorA = *(bP); + colorB = *(bP + 1); + colorK = *(bP + 2); + + colorH = *(bP + Nextline - 1); + colorC = *(bP + Nextline); + colorD = *(bP + Nextline + 1); + colorL = *(bP + Nextline + 2); + + colorM = *(bP + Nextline + Nextline - 1); + colorN = *(bP + Nextline + Nextline); + colorO = *(bP + Nextline + Nextline + 1); + colorP = *(bP + Nextline + Nextline + 2); + + if ((colorA == colorD) && (colorB != colorC)) { + if (((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ))) { + product = colorA; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if (((colorA == colorG) && (colorC == colorO)) || + ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM))) { + product1 = colorA; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + product2 = colorA; + } else if ((colorB == colorC) && (colorA != colorD)) { + if (((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI))) { + product = colorB; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if (((colorC == colorH) && (colorA == colorF)) || + ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI))) { + product1 = colorC; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + product2 = colorB; + } else if ((colorA == colorD) && (colorB == colorC)) { + if (colorA == colorB) { + product = colorA; + product1 = colorA; + product2 = colorA; + } else { + register int r = 0; + + product1 = INTERPOLATE (colorA, colorC); + product = INTERPOLATE (colorA, colorB); + + r += + GetResult1 (colorA, colorB, colorG, colorE, + colorI); + r += + GetResult2 (colorB, colorA, colorK, colorF, + colorJ); + r += + GetResult2 (colorB, colorA, colorH, colorN, + colorM); + r += + GetResult1 (colorA, colorB, colorL, colorO, + colorP); + + if (r > 0) + product2 = colorA; + else if (r < 0) + product2 = colorB; + else { + product2 = + Q_INTERPOLATE (colorA, colorB, colorC, + colorD); + } + } + } else { + product2 = Q_INTERPOLATE (colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ)) { + product = colorA; + } else if ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI)) { + product = colorB; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM)) { + product1 = colorA; + } else if ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI)) { + product1 = colorC; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + } + *(dP) = colorA; + *(dP + 1) = product; + *(dP + (dstPitch >> 2)) = product1; + *(dP + (dstPitch >> 2) + 1) = product2; + + bP += inc_bP; + dP += 2; + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch << 1; + // deltaPtr += srcPitch; + } // endof: for (height; height; height--) +} + +static uint32_t Bilinear (uint32_t A, uint32_t B, uint32_t x) +{ + unsigned long areaA, areaB; + unsigned long result; + + if (A == B) + return A; + + areaB = (x >> 11) & 0x1f; // reduce 16 bit fraction to 5 bits + areaA = 0x20 - areaB; + + A = (A & redblueMask) | ((A & greenMask) << 16); + B = (B & redblueMask) | ((B & greenMask) << 16); + + result = ((areaA * A) + (areaB * B)) >> 5; + + return (result & redblueMask) | ((result >> 16) & greenMask); +} + +static uint32_t Bilinear4 (uint32_t A, uint32_t B, uint32_t C, uint32_t D, uint32_t x, + uint32_t y) +{ + unsigned long areaA, areaB, areaC, areaD; + unsigned long result, xy; + + x = (x >> 11) & 0x1f; + y = (y >> 11) & 0x1f; + xy = (x * y) >> 5; + + A = (A & redblueMask) | ((A & greenMask) << 16); + B = (B & redblueMask) | ((B & greenMask) << 16); + C = (C & redblueMask) | ((C & greenMask) << 16); + D = (D & redblueMask) | ((D & greenMask) << 16); + + areaA = 0x20 + xy - x - y; + areaB = x - xy; + areaC = y - xy; + areaD = xy; + + result = ((areaA * A) + (areaB * B) + (areaC * C) + (areaD * D)) >> 5; + + return (result & redblueMask) | ((result >> 16) & greenMask); +} + +void Scale_2xSaI (uint8_t *srcPtr, uint32_t srcPitch, uint8_t * /* deltaPtr */, + uint8_t *dstPtr, uint32_t dstPitch, + uint32_t dstWidth, uint32_t dstHeight, int width, int height) +{ + uint8_t *dP; + uint16_t *bP; + + uint32_t w; + uint32_t h; + uint32_t dw; + uint32_t dh; + uint32_t hfinish; + uint32_t wfinish; + + uint32_t Nextline = srcPitch >> 1; + + wfinish = (width - 1) << 16; // convert to fixed point + dw = wfinish / (dstWidth - 1); + hfinish = (height - 1) << 16; // convert to fixed point + dh = hfinish / (dstHeight - 1); + + for (h = 0; h < hfinish; h += dh) { + uint32_t y1, y2; + + y1 = h & 0xffff; // fraction part of fixed point + bP = (uint16_t *) (srcPtr + ((h >> 16) * srcPitch)); + dP = dstPtr; + y2 = 0x10000 - y1; + + w = 0; + + for (; w < wfinish;) { + uint32_t A, B, C, D; + uint32_t E, F, G, H; + uint32_t I, J, K, L; + uint32_t x1, x2, a1, f1, f2; + uint32_t position, product1; + + position = w >> 16; + A = bP[position]; // current pixel + B = bP[position + 1]; // next pixel + C = bP[position + Nextline]; + D = bP[position + Nextline + 1]; + E = bP[position - Nextline]; + F = bP[position - Nextline + 1]; + G = bP[position - 1]; + H = bP[position + Nextline - 1]; + I = bP[position + 2]; + J = bP[position + Nextline + 2]; + K = bP[position + Nextline + Nextline]; + L = bP[position + Nextline + Nextline + 1]; + + x1 = w & 0xffff; // fraction part of fixed point + x2 = 0x10000 - x1; + + /*0*/ + if (A == B && C == D && A == C) + product1 = A; + else /*1*/ if (A == D && B != C) { + f1 = (x1 >> 1) + (0x10000 >> 2); + f2 = (y1 >> 1) + (0x10000 >> 2); + if (y1 <= f1 && A == J && A != E) // close to B + { + a1 = f1 - y1; + product1 = Bilinear (A, B, a1); + } else if (y1 >= f1 && A == G && A != L) // close to C + { + a1 = y1 - f1; + product1 = Bilinear (A, C, a1); + } + else if (x1 >= f2 && A == E && A != J) // close to B + { + a1 = x1 - f2; + product1 = Bilinear (A, B, a1); + } + else if (x1 <= f2 && A == L && A != G) // close to C + { + a1 = f2 - x1; + product1 = Bilinear (A, C, a1); + } + else if (y1 >= x1) // close to C + { + a1 = y1 - x1; + product1 = Bilinear (A, C, a1); + } + else if (y1 <= x1) // close to B + { + a1 = x1 - y1; + product1 = Bilinear (A, B, a1); + } + } + else + /*2*/ + if (B == C && A != D) + { + f1 = (x1 >> 1) + (0x10000 >> 2); + f2 = (y1 >> 1) + (0x10000 >> 2); + if (y2 >= f1 && B == H && B != F) // close to A + { + a1 = y2 - f1; + product1 = Bilinear (B, A, a1); + } + else if (y2 <= f1 && B == I && B != K) // close to D + { + a1 = f1 - y2; + product1 = Bilinear (B, D, a1); + } + else if (x2 >= f2 && B == F && B != H) // close to A + { + a1 = x2 - f2; + product1 = Bilinear (B, A, a1); + } + else if (x2 <= f2 && B == K && B != I) // close to D + { + a1 = f2 - x2; + product1 = Bilinear (B, D, a1); + } + else if (y2 >= x1) // close to A + { + a1 = y2 - x1; + product1 = Bilinear (B, A, a1); + } + else if (y2 <= x1) // close to D + { + a1 = x1 - y2; + product1 = Bilinear (B, D, a1); + } + } + /*3*/ + else + { + product1 = Bilinear4 (A, B, C, D, x1, y1); + } + + //end First Pixel + *(uint32_t *) dP = product1; + dP += 2; + w += dw; + } + dstPtr += dstPitch; + } +} diff --git a/filter/scale2x.cpp b/filter/scale2x.cpp new file mode 100644 index 0000000..6a0dc6a --- /dev/null +++ b/filter/scale2x.cpp @@ -0,0 +1,46 @@ +namespace Filter::Scale2x { + +auto size(uint& width, uint& height) -> void { + width *= 2; + height *= 2; +} + +auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + pitch >>= 1; + outpitch >>= 2; + + for(uint y = 0; y < height; y++) { + const uint16_t* in = input + y * pitch; + uint32_t* out0 = output + y * outpitch * 2; + uint32_t* out1 = output + y * outpitch * 2 + outpitch; + + int prevline = (y == 0 ? 0 : pitch); + int nextline = (y == height - 1 ? 0 : pitch); + + for(unsigned x = 0; x < width; x++) { + uint16_t A = *(in - prevline); + uint16_t B = (x > 0) ? *(in - 1) : *in; + uint16_t C = *in; + uint16_t D = (x < width - 1) ? *(in + 1) : *in; + uint16_t E = *(in++ + nextline); + uint32_t c = colortable[C]; + + if(A != E && B != D) { + *out0++ = (A == B ? colortable[A] : c); + *out0++ = (A == D ? colortable[A] : c); + *out1++ = (E == B ? colortable[E] : c); + *out1++ = (E == D ? colortable[E] : c); + } else { + *out0++ = c; + *out0++ = c; + *out1++ = c; + *out1++ = c; + } + } + } +} + +} diff --git a/filter/scanlines-black.cpp b/filter/scanlines-black.cpp new file mode 100644 index 0000000..d007a5e --- /dev/null +++ b/filter/scanlines-black.cpp @@ -0,0 +1,28 @@ +namespace Filter::ScanlinesBlack { + +auto size(uint& width, uint& height) -> void { + width = width; + height = height * 2; +} + +auto render( + uint32_t* palette, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + pitch >>= 1; + outpitch >>= 2; + + for(unsigned y = 0; y < height; y++) { + const uint16_t *in = input + y * pitch; + uint32_t *out0 = output + y * outpitch * 2; + uint32_t *out1 = output + y * outpitch * 2 + outpitch; + + for(unsigned x = 0; x < width; x++) { + uint16_t color = *in++; + *out0++ = palette[color]; + *out1++ = 0; + } + } +} + +} diff --git a/filter/scanlines-dark.cpp b/filter/scanlines-dark.cpp new file mode 100644 index 0000000..e41bb36 --- /dev/null +++ b/filter/scanlines-dark.cpp @@ -0,0 +1,48 @@ +namespace Filter::ScanlinesDark { + +uint16_t adjust[32768]; + +void initialize() { + static bool initialized = false; + if(initialized == true) return; + initialized = true; + + for(unsigned i = 0; i < 32768; i++) { + uint8_t r = (i >> 10) & 31; + uint8_t g = (i >> 5) & 31; + uint8_t b = (i >> 0) & 31; + r *= 0.333; + g *= 0.333; + b *= 0.333; + adjust[i] = (r << 10) + (g << 5) + (b << 0); + } +} + +auto size(uint& width, uint& height) -> void { + width = width; + height = height * 2; +} + +auto render( + uint32_t* palette, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + initialize(); + + pitch >>= 1; + outpitch >>= 2; + + for(unsigned y = 0; y < height; y++) { + const uint16_t *in = input + y * pitch; + uint32_t *out0 = output + y * outpitch * 2; + uint32_t *out1 = output + y * outpitch * 2 + outpitch; + + for(unsigned x = 0; x < width; x++) { + uint16_t color = *in++; + *out0++ = palette[color]; + *out1++ = palette[adjust[color]]; + } + } +} + +} diff --git a/filter/scanlines-light.cpp b/filter/scanlines-light.cpp new file mode 100644 index 0000000..aefcd3a --- /dev/null +++ b/filter/scanlines-light.cpp @@ -0,0 +1,48 @@ +namespace Filter::ScanlinesLight { + +uint16_t adjust[32768]; + +void initialize() { + static bool initialized = false; + if(initialized == true) return; + initialized = true; + + for(unsigned i = 0; i < 32768; i++) { + uint8_t r = (i >> 10) & 31; + uint8_t g = (i >> 5) & 31; + uint8_t b = (i >> 0) & 31; + r *= 0.666; + g *= 0.666; + b *= 0.666; + adjust[i] = (r << 10) + (g << 5) + (b << 0); + } +} + +auto size(uint& width, uint& height) -> void { + width = width; + height = height * 2; +} + +auto render( + uint32_t* palette, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + initialize(); + + pitch >>= 1; + outpitch >>= 2; + + for(unsigned y = 0; y < height; y++) { + const uint16_t *in = input + y * pitch; + uint32_t *out0 = output + y * outpitch * 2; + uint32_t *out1 = output + y * outpitch * 2 + outpitch; + + for(unsigned x = 0; x < width; x++) { + uint16_t color = *in++; + *out0++ = palette[color]; + *out1++ = palette[adjust[color]]; + } + } +} + +} diff --git a/filter/snes_ntsc/snes_ntsc.c b/filter/snes_ntsc/snes_ntsc.c new file mode 100755 index 0000000..f622baf --- /dev/null +++ b/filter/snes_ntsc/snes_ntsc.c @@ -0,0 +1,251 @@ +/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */ + +#include "snes_ntsc.h" + +/* Copyright (C) 2006-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 */ + +snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 }; +snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }; +snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 }; +snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 }; + +#define alignment_count 3 +#define burst_count 3 +#define rescale_in 8 +#define rescale_out 7 + +#define artifacts_mid 1.0f +#define fringing_mid 1.0f +#define std_decoder_hue 0 + +#define rgb_bits 7 /* half normal range to allow for doubled hires pixels */ +#define gamma_size 32 + +#include "snes_ntsc_impl.h" + +/* 3 input pixels -> 8 composite samples */ +pixel_info_t const snes_ntsc_pixels [alignment_count] = { + { PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } }, + { PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } }, + { PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } }, +}; + +static void merge_kernel_fields( snes_ntsc_rgb_t* io ) +{ + int n; + for ( n = burst_size; n; --n ) + { + snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias; + snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias; + snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias; + /* merge colors without losing precision */ + io [burst_size * 0] = + ((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; + io [burst_size * 1] = + ((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; + io [burst_size * 2] = + ((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; + ++io; + } +} + +static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out ) +{ + int n; + for ( n = burst_count; n; --n ) + { + unsigned i; + for ( i = 0; i < rgb_kernel_size / 2; i++ ) + { + snes_ntsc_rgb_t error = color - + out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] - + out [i + 7] - out [i + 5 +14] - out [i + 3 +28]; + DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 ); + } + out += alignment_count * rgb_kernel_size; + } +} + +void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup ) +{ + int merge_fields; + int entry; + init_t impl; + if ( !setup ) + setup = &snes_ntsc_composite; + init( &impl, setup ); + + merge_fields = setup->merge_fields; + if ( setup->artifacts <= -1 && setup->fringing <= -1 ) + merge_fields = 1; + + for ( entry = 0; entry < snes_ntsc_palette_size; entry++ ) + { + /* Reduce number of significant bits of source color. Clearing the + low bits of R and B were least notictable. Modifying green was too + noticeable. */ + int ir = entry >> 8 & 0x1E; + int ig = entry >> 4 & 0x1F; + int ib = entry << 1 & 0x1E; + + #if SNES_NTSC_BSNES_COLORTBL + if ( setup->bsnes_colortbl ) + { + int bgr15 = (ib << 10) | (ig << 5) | ir; + unsigned long rgb16 = setup->bsnes_colortbl [bgr15]; + ir = rgb16 >> 11 & 0x1E; + ig = rgb16 >> 6 & 0x1F; + ib = rgb16 & 0x1E; + } + #endif + + { + float rr = impl.to_float [ir]; + float gg = impl.to_float [ig]; + float bb = impl.to_float [ib]; + + float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i ); + + int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g ); + snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b ); + + snes_ntsc_rgb_t* out = ntsc->table [entry]; + gen_kernel( &impl, y, i, q, out ); + if ( merge_fields ) + merge_kernel_fields( out ); + correct_errors( rgb, out ); + } + } +} + +#ifndef SNES_NTSC_NO_BLITTERS + +void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, + int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) +{ + int chunk_count = (in_width - 1) / snes_ntsc_in_chunk; + for ( ; in_height; --in_height ) + { + SNES_NTSC_IN_T const* line_in = input; + SNES_NTSC_BEGIN_ROW( ntsc, burst_phase, + snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) ); + snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out; + int n; + ++line_in; + + for ( n = chunk_count; n; --n ) + { + /* order of input and output pixels must not be altered */ + SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); + SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); + SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); + SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); + + line_in += 3; + line_out += 7; + } + + /* finish final pixels */ + SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); + SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); + SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); + SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); + + burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; + input += in_row_width; + rgb_out = (char*) rgb_out + out_pitch; + } +} + +void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, + int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) +{ + int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2); + for ( ; in_height; --in_height ) + { + SNES_NTSC_IN_T const* line_in = input; + SNES_NTSC_HIRES_ROW( ntsc, burst_phase, + snes_ntsc_black, snes_ntsc_black, snes_ntsc_black, + SNES_NTSC_ADJ_IN( line_in [0] ), + SNES_NTSC_ADJ_IN( line_in [1] ) ); + snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out; + int n; + line_in += 2; + + for ( n = chunk_count; n; --n ) + { + /* twice as many input pixels per chunk */ + SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); + SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); + SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); + SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) ); + SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) ); + SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) ); + SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); + + line_in += 6; + line_out += 7; + } + + SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 3, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 4, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 5, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); + + burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; + input += in_row_width; + rgb_out = (char*) rgb_out + out_pitch; + } +} + +#endif diff --git a/filter/snes_ntsc/snes_ntsc.h b/filter/snes_ntsc/snes_ntsc.h new file mode 100755 index 0000000..fff97ec --- /dev/null +++ b/filter/snes_ntsc/snes_ntsc.h @@ -0,0 +1,228 @@ +/* SNES NTSC video filter */ + +/* snes_ntsc 0.2.2 */ +#ifndef SNES_NTSC_H +#define SNES_NTSC_H + +#include "snes_ntsc_config.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown +in parenthesis and should remain fairly stable in future versions. */ +typedef struct snes_ntsc_setup_t +{ + /* Basic parameters */ + double hue; /* -1 = -180 degrees +1 = +180 degrees */ + double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */ + double contrast; /* -1 = dark (0.5) +1 = light (1.5) */ + double brightness; /* -1 = dark (0.5) +1 = light (1.5) */ + double sharpness; /* edge contrast enhancement/blurring */ + + /* Advanced parameters */ + double gamma; /* -1 = dark (1.5) +1 = light (0.5) */ + double resolution; /* image resolution */ + double artifacts; /* artifacts caused by color changes */ + double fringing; /* color artifacts caused by brightness changes */ + double bleed; /* color bleed (color resolution reduction) */ + int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */ + float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */ + + unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */ +} snes_ntsc_setup_t; + +/* Video format presets */ +extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */ +extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */ +extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */ +extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */ + +/* Initializes and adjusts parameters. Can be called multiple times on the same +snes_ntsc_t object. Can pass NULL for either parameter. */ +typedef struct snes_ntsc_t snes_ntsc_t; +void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup ); + +/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT +and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB. +In_row_width is the number of pixels to get to the next input row. Out_pitch +is the number of *bytes* to get to the next output row. */ +void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, + long in_row_width, int burst_phase, int in_width, int in_height, + void* rgb_out, long out_pitch ); + +void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, + long in_row_width, int burst_phase, int in_width, int in_height, + void* rgb_out, long out_pitch ); + +/* Number of output pixels written by low-res blitter for given input width. Width +might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded +value. Guaranteed not to round 256 down at all. */ +#define SNES_NTSC_OUT_WIDTH( in_width ) \ + ((((in_width) - 1) / snes_ntsc_in_chunk + 1) * snes_ntsc_out_chunk) + +/* Number of low-res input pixels that will fit within given output width. Might be +rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded +value. */ +#define SNES_NTSC_IN_WIDTH( out_width ) \ + (((out_width) / snes_ntsc_out_chunk - 1) * snes_ntsc_in_chunk + 1) + + +/* Interface for user-defined custom blitters */ + +enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */ +enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */ +enum { snes_ntsc_black = 0 }; /* palette index for black */ +enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */ + +/* Begins outputting row and starts three pixels. First pixel will be cut off a bit. +Use snes_ntsc_black for unused pixels. Declares variables, so must be before first +statement in a block (unless you're using C++). */ +#define SNES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \ + char const* ktable = \ + (char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\ + SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SNES_NTSC_IN_FORMAT, ktable ) + +/* Begins input pixel */ +#define SNES_NTSC_COLOR_IN( index, color ) \ + SNES_NTSC_COLOR_IN_( index, color, SNES_NTSC_IN_FORMAT, ktable ) + +/* Generates output pixel. Bits can be 24, 16, 15, 14, 32 (treated as 24), or 0: +24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB) +16: RRRRRGGG GGGBBBBB (5-6-5 RGB) +15: RRRRRGG GGGBBBBB (5-5-5 RGB) +14: BBBBBGG GGGRRRRR (5-5-5 BGR, native SNES format) + 0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */ +#define SNES_NTSC_RGB_OUT( index, rgb_out, bits ) \ + SNES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 1 ) + +/* Hires equivalents */ +#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \ + char const* ktable = \ + (char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\ + unsigned const snes_ntsc_pixel1_ = (pixel1);\ + snes_ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel1_ );\ + unsigned const snes_ntsc_pixel2_ = (pixel2);\ + snes_ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel2_ );\ + unsigned const snes_ntsc_pixel3_ = (pixel3);\ + snes_ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel3_ );\ + unsigned const snes_ntsc_pixel4_ = (pixel4);\ + snes_ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel4_ );\ + unsigned const snes_ntsc_pixel5_ = (pixel5);\ + snes_ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel5_ );\ + snes_ntsc_rgb_t const* kernel0 = kernel1;\ + snes_ntsc_rgb_t const* kernelx0;\ + snes_ntsc_rgb_t const* kernelx1 = kernel1;\ + snes_ntsc_rgb_t const* kernelx2 = kernel1;\ + snes_ntsc_rgb_t const* kernelx3 = kernel1;\ + snes_ntsc_rgb_t const* kernelx4 = kernel1;\ + snes_ntsc_rgb_t const* kernelx5 = kernel1 + +#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\ + snes_ntsc_rgb_t raw_ =\ + kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\ + kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\ + kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\ + kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\ + SNES_NTSC_CLAMP_( raw_, 0 );\ + SNES_NTSC_RGB_OUT_( rgb_out, (bits), 0 );\ +} + + +/* private */ +enum { snes_ntsc_entry_size = 128 }; +enum { snes_ntsc_palette_size = 0x2000 }; +typedef unsigned long snes_ntsc_rgb_t; +struct snes_ntsc_t { + snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size]; +}; +enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count }; + +#define SNES_NTSC_RGB16( ktable, n ) \ + (snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \ + (snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t))) + +#define SNES_NTSC_BGR15( ktable, n ) \ + (snes_ntsc_rgb_t const*) (ktable + ((n << 9 & 0x3C00) | (n & 0x03E0) | (n >> 10 & 0x001E)) * \ + (snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t))) + +/* common 3->7 ntsc macros */ +#define SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \ + unsigned const snes_ntsc_pixel0_ = (pixel0);\ + snes_ntsc_rgb_t const* kernel0 = ENTRY( table, snes_ntsc_pixel0_ );\ + unsigned const snes_ntsc_pixel1_ = (pixel1);\ + snes_ntsc_rgb_t const* kernel1 = ENTRY( table, snes_ntsc_pixel1_ );\ + unsigned const snes_ntsc_pixel2_ = (pixel2);\ + snes_ntsc_rgb_t const* kernel2 = ENTRY( table, snes_ntsc_pixel2_ );\ + snes_ntsc_rgb_t const* kernelx0;\ + snes_ntsc_rgb_t const* kernelx1 = kernel0;\ + snes_ntsc_rgb_t const* kernelx2 = kernel0 + +#define SNES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\ + snes_ntsc_rgb_t raw_ =\ + kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\ + kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\ + SNES_NTSC_CLAMP_( raw_, shift );\ + SNES_NTSC_RGB_OUT_( rgb_out, bits, shift );\ +} + +/* common ntsc macros */ +#define snes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1)) +#define snes_ntsc_clamp_mask (snes_ntsc_rgb_builder * 3 / 2) +#define snes_ntsc_clamp_add (snes_ntsc_rgb_builder * 0x101) +#define SNES_NTSC_CLAMP_( io, shift ) {\ + snes_ntsc_rgb_t sub = (io) >> (9-(shift)) & snes_ntsc_clamp_mask;\ + snes_ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\ + io |= clamp;\ + clamp -= sub;\ + io &= clamp;\ +} + +#define SNES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\ + unsigned color_;\ + kernelx##index = kernel##index;\ + kernel##index = (color_ = (color), ENTRY( table, color_ ));\ +} + +/* x is always zero except in snes_ntsc library */ +/* original routine */ +/* +#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\ + if ( bits == 16 )\ + rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\ + if ( bits == 24 || bits == 32 )\ + rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\ + if ( bits == 15 )\ + rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\ + if ( bits == 14 )\ + rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(9-x)&0x03E0)|(raw_<<(6+x)&0x7C00);\ + if ( bits == 0 )\ + rgb_out = raw_ << x;\ +} +*/ + +/* custom bsnes routine -- hooks into bsnes colortable */ +#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\ + if ( bits == 16 ) {\ + rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\ + rgb_out = ((rgb_out&0xf800)>>11)|((rgb_out&0x07c0)>>1)|((rgb_out&0x001f)<<10);\ + rgb_out = colortable[rgb_out];\ + } else if ( bits == 24 || bits == 32 ) {\ + rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\ + rgb_out = ((rgb_out&0xf80000)>>19)|((rgb_out&0x00f800)>>6)|((rgb_out&0x0000f8)<<7);\ + rgb_out = colortable[rgb_out];\ + } else if ( bits == 15 ) {\ + rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\ + rgb_out = ((rgb_out&0x7c00)>>10)|((rgb_out&0x03e0))|((rgb_out&0x001f)<<10);\ + rgb_out = colortable[rgb_out];\ + } else {\ + rgb_out = raw_ << x;\ + }\ +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/filter/snes_ntsc/snes_ntsc_config.h b/filter/snes_ntsc/snes_ntsc_config.h new file mode 100755 index 0000000..7ab94c2 --- /dev/null +++ b/filter/snes_ntsc/snes_ntsc_config.h @@ -0,0 +1,26 @@ +/* Configure library by modifying this file */ + +#ifndef SNES_NTSC_CONFIG_H +#define SNES_NTSC_CONFIG_H + +/* Format of source pixels */ +/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 */ +#define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15 + +/* The following affect the built-in blitter only; a custom blitter can +handle things however it wants. */ + +/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */ +#define SNES_NTSC_OUT_DEPTH 32 + +/* Type of input pixel values */ +#define SNES_NTSC_IN_T unsigned short + +/* Each raw pixel input value is passed through this. You might want to mask +the pixel index if you use the high bits as flags, etc. */ +#define SNES_NTSC_ADJ_IN( in ) in + +/* For each pixel, this is the basic operation: +output_color = SNES_NTSC_ADJ_IN( SNES_NTSC_IN_T ) */ + +#endif diff --git a/filter/snes_ntsc/snes_ntsc_impl.h b/filter/snes_ntsc/snes_ntsc_impl.h new file mode 100755 index 0000000..1d7adc7 --- /dev/null +++ b/filter/snes_ntsc/snes_ntsc_impl.h @@ -0,0 +1,439 @@ +/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */ + +/* Common implementation of NTSC filters */ + +#include +#include + +/* Copyright (C) 2006 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 */ + +#define DISABLE_CORRECTION 0 + +#undef PI +#define PI 3.14159265358979323846f + +#ifndef LUMA_CUTOFF + #define LUMA_CUTOFF 0.20 +#endif +#ifndef gamma_size + #define gamma_size 1 +#endif +#ifndef rgb_bits + #define rgb_bits 8 +#endif +#ifndef artifacts_max + #define artifacts_max (artifacts_mid * 1.5f) +#endif +#ifndef fringing_max + #define fringing_max (fringing_mid * 2) +#endif +#ifndef STD_HUE_CONDITION + #define STD_HUE_CONDITION( setup ) 1 +#endif + +#define ext_decoder_hue (std_decoder_hue + 15) +#define rgb_unit (1 << rgb_bits) +#define rgb_offset (rgb_unit * 2 + 0.5f) + +enum { burst_size = snes_ntsc_entry_size / burst_count }; +enum { kernel_half = 16 }; +enum { kernel_size = kernel_half * 2 + 1 }; + +typedef struct init_t +{ + float to_rgb [burst_count * 6]; + float to_float [gamma_size]; + float contrast; + float brightness; + float artifacts; + float fringing; + float kernel [rescale_out * kernel_size * 2]; +} init_t; + +#define ROTATE_IQ( i, q, sin_b, cos_b ) {\ + float t;\ + t = i * cos_b - q * sin_b;\ + q = i * sin_b + q * cos_b;\ + i = t;\ +} + +static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup ) +{ +#if rescale_out > 1 + float kernels [kernel_size * 2]; +#else + float* const kernels = impl->kernel; +#endif + + /* generate luma (y) filter using sinc kernel */ + { + /* sinc with rolloff (dsf) */ + float const rolloff = 1 + (float) setup->sharpness * (float) 0.032; + float const maxh = 32; + float const pow_a_n = (float) pow( rolloff, maxh ); + float sum; + int i; + /* quadratic mapping to reduce negative (blurring) range */ + float to_angle = (float) setup->resolution + 1; + to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1); + + kernels [kernel_size * 3 / 2] = maxh; /* default center value */ + for ( i = 0; i < kernel_half * 2 + 1; i++ ) + { + int x = i - kernel_half; + float angle = x * to_angle; + /* instability occurs at center point with rolloff very close to 1.0 */ + if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 ) + { + float rolloff_cos_a = rolloff * (float) cos( angle ); + float num = 1 - rolloff_cos_a - + pow_a_n * (float) cos( maxh * angle ) + + pow_a_n * rolloff * (float) cos( (maxh - 1) * angle ); + float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; + float dsf = num / den; + kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5; + } + } + + /* apply blackman window and find sum */ + sum = 0; + for ( i = 0; i < kernel_half * 2 + 1; i++ ) + { + float x = PI * 2 / (kernel_half * 2) * i; + float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 ); + sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman); + } + + /* normalize kernel */ + sum = 1.0f / sum; + for ( i = 0; i < kernel_half * 2 + 1; i++ ) + { + int x = kernel_size * 3 / 2 - kernel_half + i; + kernels [x] *= sum; + assert( kernels [x] == kernels [x] ); /* catch numerical instability */ + } + } + + /* generate chroma (iq) filter using gaussian kernel */ + { + float const cutoff_factor = -0.03125f; + float cutoff = (float) setup->bleed; + int i; + + if ( cutoff < 0 ) + { + /* keep extreme value accessible only near upper end of scale (1.0) */ + cutoff *= cutoff; + cutoff *= cutoff; + cutoff *= cutoff; + cutoff *= -30.0f / 0.65f; + } + cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff; + + for ( i = -kernel_half; i <= kernel_half; i++ ) + kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff ); + + /* normalize even and odd phases separately */ + for ( i = 0; i < 2; i++ ) + { + float sum = 0; + int x; + for ( x = i; x < kernel_size; x += 2 ) + sum += kernels [x]; + + sum = 1.0f / sum; + for ( x = i; x < kernel_size; x += 2 ) + { + kernels [x] *= sum; + assert( kernels [x] == kernels [x] ); /* catch numerical instability */ + } + } + } + + /* + printf( "luma:\n" ); + for ( i = kernel_size; i < kernel_size * 2; i++ ) + printf( "%f\n", kernels [i] ); + printf( "chroma:\n" ); + for ( i = 0; i < kernel_size; i++ ) + printf( "%f\n", kernels [i] ); + */ + + /* generate linear rescale kernels */ + #if rescale_out > 1 + { + float weight = 1.0f; + float* out = impl->kernel; + int n = rescale_out; + do + { + float remain = 0; + int i; + weight -= 1.0f / rescale_in; + for ( i = 0; i < kernel_size * 2; i++ ) + { + float cur = kernels [i]; + float m = cur * weight; + *out++ = m + remain; + remain = cur - m; + } + } + while ( --n ); + } + #endif +} + +static float const default_decoder [6] = + { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f }; + +static void init( init_t* impl, snes_ntsc_setup_t const* setup ) +{ + impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset; + impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit; + #ifdef default_palette_contrast + if ( !setup->palette ) + impl->contrast *= default_palette_contrast; + #endif + + impl->artifacts = (float) setup->artifacts; + if ( impl->artifacts > 0 ) + impl->artifacts *= artifacts_max - artifacts_mid; + impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid; + + impl->fringing = (float) setup->fringing; + if ( impl->fringing > 0 ) + impl->fringing *= fringing_max - fringing_mid; + impl->fringing = impl->fringing * fringing_mid + fringing_mid; + + init_filters( impl, setup ); + + /* generate gamma table */ + if ( gamma_size > 1 ) + { + float const to_float = 1.0f / (gamma_size - (gamma_size > 1)); + float const gamma = 1.1333f - (float) setup->gamma * 0.5f; + /* match common PC's 2.2 gamma to TV's 2.65 gamma */ + int i; + for ( i = 0; i < gamma_size; i++ ) + impl->to_float [i] = + (float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness; + } + + /* setup decoder matricies */ + { + float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue; + float sat = (float) setup->saturation + 1; + float const* decoder = setup->decoder_matrix; + if ( !decoder ) + { + decoder = default_decoder; + if ( STD_HUE_CONDITION( setup ) ) + hue += PI / 180 * (std_decoder_hue - ext_decoder_hue); + } + + { + float s = (float) sin( hue ) * sat; + float c = (float) cos( hue ) * sat; + float* out = impl->to_rgb; + int n; + + n = burst_count; + do + { + float const* in = decoder; + int n = 3; + do + { + float i = *in++; + float q = *in++; + *out++ = i * c - q * s; + *out++ = i * s + q * c; + } + while ( --n ); + if ( burst_count <= 1 ) + break; + ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */ + } + while ( --n ); + } + } +} + +/* kernel generation */ + +#define RGB_TO_YIQ( r, g, b, y, i ) (\ + (y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\ + (i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\ + ((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\ +) + +#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\ + r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\ + g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\ + (type) (y + to_rgb [4] * i + to_rgb [5] * q)\ +) + +#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1) + +enum { rgb_kernel_size = burst_size / alignment_count }; +enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder }; + +typedef struct pixel_info_t +{ + int offset; + float negate; + float kernel [4]; +} pixel_info_t; + +#if rescale_in > 1 + #define PIXEL_OFFSET_( ntsc, scaled ) \ + (kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \ + (kernel_size * 2 * scaled)) + + #define PIXEL_OFFSET( ntsc, scaled ) \ + PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\ + (((scaled) + rescale_out * 10) % rescale_out) ),\ + (1.0f - (((ntsc) + 100) & 2)) +#else + #define PIXEL_OFFSET( ntsc, scaled ) \ + (kernel_size / 2 + (ntsc) - (scaled)),\ + (1.0f - (((ntsc) + 100) & 2)) +#endif + +extern pixel_info_t const snes_ntsc_pixels [alignment_count]; + +/* Generate pixel at all burst phases and column alignments */ +static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out ) +{ + /* generate for each scanline burst phase */ + float const* to_rgb = impl->to_rgb; + int burst_remain = burst_count; + y -= rgb_offset; + do + { + /* Encode yiq into *two* composite signals (to allow control over artifacting). + Convolve these with kernels which: filter respective components, apply + sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack + into integer. Based on algorithm by NewRisingSun. */ + pixel_info_t const* pixel = snes_ntsc_pixels; + int alignment_remain = alignment_count; + do + { + /* negate is -1 when composite starts at odd multiple of 2 */ + float const yy = y * impl->fringing * pixel->negate; + float const ic0 = (i + yy) * pixel->kernel [0]; + float const qc1 = (q + yy) * pixel->kernel [1]; + float const ic2 = (i - yy) * pixel->kernel [2]; + float const qc3 = (q - yy) * pixel->kernel [3]; + + float const factor = impl->artifacts * pixel->negate; + float const ii = i * factor; + float const yc0 = (y + ii) * pixel->kernel [0]; + float const yc2 = (y - ii) * pixel->kernel [2]; + + float const qq = q * factor; + float const yc1 = (y + qq) * pixel->kernel [1]; + float const yc3 = (y - qq) * pixel->kernel [3]; + + float const* k = &impl->kernel [pixel->offset]; + int n; + ++pixel; + for ( n = rgb_kernel_size; n; --n ) + { + float i = k[0]*ic0 + k[2]*ic2; + float q = k[1]*qc1 + k[3]*qc3; + float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 + + k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset; + if ( rescale_out <= 1 ) + k--; + else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] ) + k += kernel_size * 2 - 1; + else + k -= kernel_size * 2 * (rescale_out - 1) + 2; + { + int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g ); + *out++ = PACK_RGB( r, g, b ) - rgb_bias; + } + } + } + while ( alignment_count > 1 && --alignment_remain ); + + if ( burst_count <= 1 ) + break; + + to_rgb += 6; + + ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */ + } + while ( --burst_remain ); +} + +static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out ); + +#if DISABLE_CORRECTION + #define CORRECT_ERROR( a ) { out [i] += rgb_bias; } + #define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; } +#else + #define CORRECT_ERROR( a ) { out [a] += error; } + #define DISTRIBUTE_ERROR( a, b, c ) {\ + snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\ + fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\ + fourth -= rgb_bias >> 2;\ + out [a] += fourth;\ + out [b] += fourth;\ + out [c] += fourth;\ + out [i] += error - (fourth * 3);\ + } +#endif + +#define RGB_PALETTE_OUT( rgb, out_ )\ +{\ + unsigned char* out = (out_);\ + snes_ntsc_rgb_t clamped = (rgb);\ + SNES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\ + out [0] = (unsigned char) (clamped >> 21);\ + out [1] = (unsigned char) (clamped >> 11);\ + out [2] = (unsigned char) (clamped >> 1);\ +} + +/* blitter related */ + +#ifndef restrict + #if defined (__GNUC__) + #define restrict __restrict__ + #elif defined (_MSC_VER) && _MSC_VER > 1300 + #define restrict __restrict + #else + /* no support for restricted pointers */ + #define restrict + #endif +#endif + +#include + +#if SNES_NTSC_OUT_DEPTH <= 16 + #if USHRT_MAX == 0xFFFF + typedef unsigned short snes_ntsc_out_t; + #else + #error "Need 16-bit int type" + #endif + +#else + #if UINT_MAX == 0xFFFFFFFF + typedef unsigned int snes_ntsc_out_t; + #elif ULONG_MAX == 0xFFFFFFFF + typedef unsigned long snes_ntsc_out_t; + #else + #error "Need 32-bit int type" + #endif + +#endif diff --git a/filter/super-2xsai.cpp b/filter/super-2xsai.cpp new file mode 100644 index 0000000..c760f8b --- /dev/null +++ b/filter/super-2xsai.cpp @@ -0,0 +1,25 @@ +namespace Filter::Super2xSaI { + +auto size(uint& width, uint& height) -> void { + width *= 2; + height *= 2; +} + +uint32_t temp[512 * 480]; + +auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + for(unsigned y = 0; y < height; y++) { + const uint16_t *line_in = (const uint16_t*)(((const uint8_t*)input) + pitch * y); + uint32_t *line_out = temp + y * width; + for(unsigned x = 0; x < width; x++) { + line_out[x] = colortable[line_in[x]]; + } + } + + Super2xSaI32((unsigned char*)temp, width * sizeof(uint32_t), 0, (unsigned char*)output, outpitch, width, height); +} + +} diff --git a/filter/super-eagle.cpp b/filter/super-eagle.cpp new file mode 100644 index 0000000..90eb875 --- /dev/null +++ b/filter/super-eagle.cpp @@ -0,0 +1,25 @@ +namespace Filter::SuperEagle { + +auto size(uint& width, uint& height) -> void { + width *= 2; + height *= 2; +} + +uint32_t temp[512 * 480]; + +auto render( + uint32_t* colortable, uint32_t* output, uint outpitch, + const uint16_t* input, uint pitch, uint width, uint height +) -> void { + for(unsigned y = 0; y < height; y++) { + const uint16_t *line_in = (const uint16_t*)(((const uint8_t*)input) + pitch * y); + uint32_t *line_out = temp + y * width; + for(unsigned x = 0; x < width; x++) { + line_out[x] = colortable[line_in[x]]; + } + } + + SuperEagle32((unsigned char*)temp, width * sizeof(uint32_t), 0, (unsigned char*)output, outpitch, width, height); +} + +} diff --git a/gb/Core/apu.c b/gb/Core/apu.c new file mode 100644 index 0000000..9afa5c9 --- /dev/null +++ b/gb/Core/apu.c @@ -0,0 +1,1040 @@ +#include +#include +#include +#include +#include "gb.h" + +#define likely(x) __builtin_expect((x), 1) +#define unlikely(x) __builtin_expect((x), 0) + +static const uint8_t duties[] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 0, +}; + +static void refresh_channel(GB_gameboy_t *gb, unsigned index, unsigned cycles_offset) +{ + unsigned multiplier = gb->apu_output.cycles_since_render + cycles_offset - gb->apu_output.last_update[index]; + gb->apu_output.summed_samples[index].left += gb->apu_output.current_sample[index].left * multiplier; + gb->apu_output.summed_samples[index].right += gb->apu_output.current_sample[index].right * multiplier; + gb->apu_output.last_update[index] = gb->apu_output.cycles_since_render + cycles_offset; +} + +bool GB_apu_is_DAC_enabled(GB_gameboy_t *gb, unsigned index) +{ + if (gb->model >= GB_MODEL_AGB) { + /* On the AGB, mixing is done digitally, so there are no per-channel + DACs. Instead, all channels are summed digital regardless of + whatever the DAC state would be on a CGB or earlier model. */ + return true; + } + + switch (index) { + case GB_SQUARE_1: + return gb->io_registers[GB_IO_NR12] & 0xF8; + + case GB_SQUARE_2: + return gb->io_registers[GB_IO_NR22] & 0xF8; + + case GB_WAVE: + return gb->apu.wave_channel.enable; + + case GB_NOISE: + return gb->io_registers[GB_IO_NR42] & 0xF8; + } + + return false; +} + +static uint8_t agb_bias_for_channel(GB_gameboy_t *gb, unsigned index) +{ + if (!gb->apu.is_active[index]) return 0; + + switch (index) { + case GB_SQUARE_1: + return gb->apu.square_channels[GB_SQUARE_1].current_volume; + case GB_SQUARE_2: + return gb->apu.square_channels[GB_SQUARE_2].current_volume; + case GB_WAVE: + return 0; + case GB_NOISE: + return gb->apu.noise_channel.current_volume; + } + return 0; +} + +static void update_sample(GB_gameboy_t *gb, unsigned index, int8_t value, unsigned cycles_offset) +{ + if (gb->model >= GB_MODEL_AGB) { + /* On the AGB, because no analog mixing is done, the behavior of NR51 is a bit different. + A channel that is not connected to a terminal is idenitcal to a connected channel + playing PCM sample 0. */ + gb->apu.samples[index] = value; + + if (gb->apu_output.sample_rate) { + unsigned right_volume = (gb->io_registers[GB_IO_NR50] & 7) + 1; + unsigned left_volume = ((gb->io_registers[GB_IO_NR50] >> 4) & 7) + 1; + + if (index == GB_WAVE) { + /* For some reason, channel 3 is inverted on the AGB */ + value ^= 0xF; + } + + GB_sample_t output; + uint8_t bias = agb_bias_for_channel(gb, index); + + if (gb->io_registers[GB_IO_NR51] & (1 << index)) { + output.right = (0xf - value * 2 + bias) * right_volume; + } + else { + output.right = 0xf * right_volume; + } + + if (gb->io_registers[GB_IO_NR51] & (0x10 << index)) { + output.left = (0xf - value * 2 + bias) * left_volume; + } + else { + output.left = 0xf * left_volume; + } + + if (*(uint32_t *)&(gb->apu_output.current_sample[index]) != *(uint32_t *)&output) { + refresh_channel(gb, index, cycles_offset); + gb->apu_output.current_sample[index] = output; + } + } + + return; + } + + if (!GB_apu_is_DAC_enabled(gb, index)) { + value = gb->apu.samples[index]; + } + else { + gb->apu.samples[index] = value; + } + + if (gb->apu_output.sample_rate) { + unsigned right_volume = 0; + if (gb->io_registers[GB_IO_NR51] & (1 << index)) { + right_volume = (gb->io_registers[GB_IO_NR50] & 7) + 1; + } + unsigned left_volume = 0; + if (gb->io_registers[GB_IO_NR51] & (0x10 << index)) { + left_volume = ((gb->io_registers[GB_IO_NR50] >> 4) & 7) + 1; + } + GB_sample_t output = {(0xf - value * 2) * left_volume, (0xf - value * 2) * right_volume}; + if (*(uint32_t *)&(gb->apu_output.current_sample[index]) != *(uint32_t *)&output) { + refresh_channel(gb, index, cycles_offset); + gb->apu_output.current_sample[index] = output; + } + } +} + +static double smooth(double x) +{ + return 3*x*x - 2*x*x*x; +} + +static void render(GB_gameboy_t *gb) +{ + GB_sample_t output = {0,0}; + + UNROLL + for (unsigned i = 0; i < GB_N_CHANNELS; i++) { + double multiplier = CH_STEP; + + if (gb->model < GB_MODEL_AGB) { + if (!GB_apu_is_DAC_enabled(gb, i)) { + gb->apu_output.dac_discharge[i] -= ((double) DAC_DECAY_SPEED) / gb->apu_output.sample_rate; + if (gb->apu_output.dac_discharge[i] < 0) { + multiplier = 0; + gb->apu_output.dac_discharge[i] = 0; + } + else { + multiplier *= smooth(gb->apu_output.dac_discharge[i]); + } + } + else { + gb->apu_output.dac_discharge[i] += ((double) DAC_ATTACK_SPEED) / gb->apu_output.sample_rate; + if (gb->apu_output.dac_discharge[i] > 1) { + gb->apu_output.dac_discharge[i] = 1; + } + else { + multiplier *= smooth(gb->apu_output.dac_discharge[i]); + } + } + } + + if (likely(gb->apu_output.last_update[i] == 0)) { + output.left += gb->apu_output.current_sample[i].left * multiplier; + output.right += gb->apu_output.current_sample[i].right * multiplier; + } + else { + refresh_channel(gb, i, 0); + output.left += (signed long) gb->apu_output.summed_samples[i].left * multiplier + / gb->apu_output.cycles_since_render; + output.right += (signed long) gb->apu_output.summed_samples[i].right * multiplier + / gb->apu_output.cycles_since_render; + gb->apu_output.summed_samples[i] = (GB_sample_t){0, 0}; + } + gb->apu_output.last_update[i] = 0; + } + gb->apu_output.cycles_since_render = 0; + + GB_sample_t filtered_output = gb->apu_output.highpass_mode? + (GB_sample_t) {output.left - gb->apu_output.highpass_diff.left, + output.right - gb->apu_output.highpass_diff.right} : + output; + + switch (gb->apu_output.highpass_mode) { + case GB_HIGHPASS_OFF: + gb->apu_output.highpass_diff = (GB_double_sample_t) {0, 0}; + break; + case GB_HIGHPASS_ACCURATE: + gb->apu_output.highpass_diff = (GB_double_sample_t) + {output.left - filtered_output.left * gb->apu_output.highpass_rate, + output.right - filtered_output.right * gb->apu_output.highpass_rate}; + break; + case GB_HIGHPASS_REMOVE_DC_OFFSET: { + unsigned mask = gb->io_registers[GB_IO_NR51]; + unsigned left_volume = 0; + unsigned right_volume = 0; + UNROLL + for (unsigned i = GB_N_CHANNELS; i--;) { + if (gb->apu.is_active[i]) { + if (mask & 1) { + left_volume += (gb->io_registers[GB_IO_NR50] & 7) * CH_STEP * 0xF; + } + if (mask & 0x10) { + right_volume += ((gb->io_registers[GB_IO_NR50] >> 4) & 7) * CH_STEP * 0xF; + } + } + else { + left_volume += gb->apu_output.current_sample[i].left * CH_STEP; + right_volume += gb->apu_output.current_sample[i].right * CH_STEP; + } + mask >>= 1; + } + gb->apu_output.highpass_diff = (GB_double_sample_t) + {left_volume * (1 - gb->apu_output.highpass_rate) + gb->apu_output.highpass_diff.left * gb->apu_output.highpass_rate, + right_volume * (1 - gb->apu_output.highpass_rate) + gb->apu_output.highpass_diff.right * gb->apu_output.highpass_rate}; + + case GB_HIGHPASS_MAX:; + } + + } + + assert(gb->apu_output.sample_callback); + gb->apu_output.sample_callback(gb, &filtered_output); +} + +static uint16_t new_sweep_sample_legnth(GB_gameboy_t *gb) +{ + uint16_t delta = gb->apu.shadow_sweep_sample_legnth >> (gb->io_registers[GB_IO_NR10] & 7); + if (gb->io_registers[GB_IO_NR10] & 8) { + return gb->apu.shadow_sweep_sample_legnth - delta; + } + return gb->apu.shadow_sweep_sample_legnth + delta; +} + +static void update_square_sample(GB_gameboy_t *gb, unsigned index) +{ + if (gb->apu.square_channels[index].current_sample_index & 0x80) return; + + uint8_t duty = gb->io_registers[index == GB_SQUARE_1? GB_IO_NR11 :GB_IO_NR21] >> 6; + update_sample(gb, index, + duties[gb->apu.square_channels[index].current_sample_index + duty * 8]? + gb->apu.square_channels[index].current_volume : 0, + 0); +} + + +/* the effects of NRX2 writes on current volume are not well documented and differ + between models and variants. The exact behavior can only be verified on CGB as it + requires the PCM12 register. The behavior implemented here was verified on *my* + CGB, which might behave differently from other CGB revisions, as well as from the + DMG, MGB or SGB/2 */ +static void nrx2_glitch(uint8_t *volume, uint8_t value, uint8_t old_value) +{ + if (value & 8) { + (*volume)++; + } + + if (((value ^ old_value) & 8)) { + *volume = 0x10 - *volume; + } + + if ((value & 7) && !(old_value & 7) && *volume && !(value & 8)) { + (*volume)--; + } + + if ((old_value & 7) && (value & 8)) { + (*volume)--; + } + + (*volume) &= 0xF; +} + +static void tick_square_envelope(GB_gameboy_t *gb, enum GB_CHANNELS index) +{ + uint8_t nrx2 = gb->io_registers[index == GB_SQUARE_1? GB_IO_NR12 : GB_IO_NR22]; + + if (gb->apu.square_channels[index].volume_countdown || (nrx2 & 7)) { + if (!gb->apu.square_channels[index].volume_countdown || !--gb->apu.square_channels[index].volume_countdown) { + if ((nrx2 & 8) && gb->apu.square_channels[index].current_volume < 0xF) { + gb->apu.square_channels[index].current_volume++; + } + + else if (!(nrx2 & 8) && gb->apu.square_channels[index].current_volume > 0) { + gb->apu.square_channels[index].current_volume--; + } + + gb->apu.square_channels[index].volume_countdown = nrx2 & 7; + + if (gb->apu.is_active[index]) { + update_square_sample(gb, index); + } + } + } +} + +static void tick_noise_envelope(GB_gameboy_t *gb) +{ + uint8_t nr42 = gb->io_registers[GB_IO_NR42]; + + if (gb->apu.noise_channel.volume_countdown || (nr42 & 7)) { + if (!--gb->apu.noise_channel.volume_countdown) { + if ((nr42 & 8) && gb->apu.noise_channel.current_volume < 0xF) { + gb->apu.noise_channel.current_volume++; + } + + else if (!(nr42 & 8) && gb->apu.noise_channel.current_volume > 0) { + gb->apu.noise_channel.current_volume--; + } + + gb->apu.noise_channel.volume_countdown = nr42 & 7; + + if (gb->apu.is_active[GB_NOISE]) { + update_sample(gb, GB_NOISE, + (gb->apu.noise_channel.lfsr & 1) ? + gb->apu.noise_channel.current_volume : 0, + 0); + } + } + } +} + +void GB_apu_div_event(GB_gameboy_t *gb) +{ + if (!gb->apu.global_enable) return; + if (gb->apu.skip_div_event) { + gb->apu.skip_div_event = false; + return; + } + gb->apu.div_divider++; + + if ((gb->apu.div_divider & 1) == 0) { + for (unsigned i = GB_SQUARE_2 + 1; i--;) { + uint8_t nrx2 = gb->io_registers[i == GB_SQUARE_1? GB_IO_NR12 : GB_IO_NR22]; + if (gb->apu.is_active[i] && gb->apu.square_channels[i].volume_countdown == 0 && (nrx2 & 7)) { + tick_square_envelope(gb, i); + } + } + + if (gb->apu.is_active[GB_NOISE] && gb->apu.noise_channel.volume_countdown == 0 && (gb->io_registers[GB_IO_NR42] & 7)) { + tick_noise_envelope(gb); + } + } + + if ((gb->apu.div_divider & 7) == 0) { + for (unsigned i = GB_SQUARE_2 + 1; i--;) { + tick_square_envelope(gb, i); + } + + tick_noise_envelope(gb); + } + + if ((gb->apu.div_divider & 1) == 1) { + for (unsigned i = GB_SQUARE_2 + 1; i--;) { + if (gb->apu.square_channels[i].length_enabled) { + if (gb->apu.square_channels[i].pulse_length) { + if (!--gb->apu.square_channels[i].pulse_length) { + gb->apu.is_active[i] = false; + update_sample(gb, i, 0, 0); + } + } + } + } + + if (gb->apu.wave_channel.length_enabled) { + if (gb->apu.wave_channel.pulse_length) { + if (!--gb->apu.wave_channel.pulse_length) { + gb->apu.is_active[GB_WAVE] = false; + update_sample(gb, GB_WAVE, 0, 0); + } + } + } + + if (gb->apu.noise_channel.length_enabled) { + if (gb->apu.noise_channel.pulse_length) { + if (!--gb->apu.noise_channel.pulse_length) { + gb->apu.is_active[GB_NOISE] = false; + update_sample(gb, GB_NOISE, 0, 0); + } + } + } + } + + if ((gb->apu.div_divider & 3) == 3) { + if (!gb->apu.sweep_enabled) { + return; + } + if (gb->apu.square_sweep_countdown) { + if (!--gb->apu.square_sweep_countdown) { + if ((gb->io_registers[GB_IO_NR10] & 0x70) && (gb->io_registers[GB_IO_NR10] & 0x07)) { + gb->apu.square_channels[GB_SQUARE_1].sample_length = + gb->apu.shadow_sweep_sample_legnth = + gb->apu.new_sweep_sample_legnth; + } + + if (gb->io_registers[GB_IO_NR10] & 0x70) { + /* Recalculation and overflow check only occurs after a delay */ + gb->apu.square_sweep_calculate_countdown = 0x13 - gb->apu.lf_div; + } + + gb->apu.square_sweep_countdown = ((gb->io_registers[GB_IO_NR10] >> 4) & 7); + if (!gb->apu.square_sweep_countdown) gb->apu.square_sweep_countdown = 8; + } + } + } +} + + +void GB_apu_run(GB_gameboy_t *gb) +{ + /* Convert 4MHZ to 2MHz. apu_cycles is always divisable by 4. */ + uint8_t cycles = gb->apu.apu_cycles >> 2; + gb->apu.apu_cycles = 0; + if (!cycles) return; + + if (likely(!gb->stopped || GB_is_cgb(gb))) { + /* To align the square signal to 1MHz */ + gb->apu.lf_div ^= cycles & 1; + gb->apu.noise_channel.alignment += cycles; + + if (gb->apu.square_sweep_calculate_countdown) { + if (gb->apu.square_sweep_calculate_countdown > cycles) { + gb->apu.square_sweep_calculate_countdown -= cycles; + } + else { + /* APU bug: sweep frequency is checked after adding the sweep delta twice */ + gb->apu.new_sweep_sample_legnth = new_sweep_sample_legnth(gb); + if (gb->apu.new_sweep_sample_legnth > 0x7ff) { + gb->apu.is_active[GB_SQUARE_1] = false; + update_sample(gb, GB_SQUARE_1, 0, gb->apu.square_sweep_calculate_countdown - cycles); + gb->apu.sweep_enabled = false; + } + gb->apu.sweep_decreasing |= gb->io_registers[GB_IO_NR10] & 8; + gb->apu.square_sweep_calculate_countdown = 0; + } + } + + UNROLL + for (unsigned i = GB_SQUARE_1; i <= GB_SQUARE_2; i++) { + if (gb->apu.is_active[i]) { + uint8_t cycles_left = cycles; + while (unlikely(cycles_left > gb->apu.square_channels[i].sample_countdown)) { + cycles_left -= gb->apu.square_channels[i].sample_countdown + 1; + gb->apu.square_channels[i].sample_countdown = (gb->apu.square_channels[i].sample_length ^ 0x7FF) * 2 + 1; + gb->apu.square_channels[i].current_sample_index++; + gb->apu.square_channels[i].current_sample_index &= 0x7; + + update_square_sample(gb, i); + } + if (cycles_left) { + gb->apu.square_channels[i].sample_countdown -= cycles_left; + } + } + } + + gb->apu.wave_channel.wave_form_just_read = false; + if (gb->apu.is_active[GB_WAVE]) { + uint8_t cycles_left = cycles; + while (unlikely(cycles_left > gb->apu.wave_channel.sample_countdown)) { + cycles_left -= gb->apu.wave_channel.sample_countdown + 1; + gb->apu.wave_channel.sample_countdown = gb->apu.wave_channel.sample_length ^ 0x7FF; + gb->apu.wave_channel.current_sample_index++; + gb->apu.wave_channel.current_sample_index &= 0x1F; + gb->apu.wave_channel.current_sample = + gb->apu.wave_channel.wave_form[gb->apu.wave_channel.current_sample_index]; + update_sample(gb, GB_WAVE, + gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift, + cycles - cycles_left); + gb->apu.wave_channel.wave_form_just_read = true; + } + if (cycles_left) { + gb->apu.wave_channel.sample_countdown -= cycles_left; + gb->apu.wave_channel.wave_form_just_read = false; + } + } + + if (gb->apu.is_active[GB_NOISE]) { + uint8_t cycles_left = cycles; + while (unlikely(cycles_left > gb->apu.noise_channel.sample_countdown)) { + cycles_left -= gb->apu.noise_channel.sample_countdown + 1; + gb->apu.noise_channel.sample_countdown = gb->apu.noise_channel.sample_length * 4 + 3; + + /* Step LFSR */ + unsigned high_bit_mask = gb->apu.noise_channel.narrow ? 0x4040 : 0x4000; + /* Todo: is this formula is different on a GBA? */ + bool new_high_bit = (gb->apu.noise_channel.lfsr ^ (gb->apu.noise_channel.lfsr >> 1) ^ 1) & 1; + gb->apu.noise_channel.lfsr >>= 1; + + if (new_high_bit) { + gb->apu.noise_channel.lfsr |= high_bit_mask; + } + else { + /* This code is not redundent, it's relevant when switching LFSR widths */ + gb->apu.noise_channel.lfsr &= ~high_bit_mask; + } + + gb->apu.current_lfsr_sample = gb->apu.noise_channel.lfsr & 1; + + update_sample(gb, GB_NOISE, + gb->apu.current_lfsr_sample ? + gb->apu.noise_channel.current_volume : 0, + 0); + } + if (cycles_left) { + gb->apu.noise_channel.sample_countdown -= cycles_left; + } + } + } + + if (gb->apu_output.sample_rate) { + gb->apu_output.cycles_since_render += cycles; + + if (gb->apu_output.sample_cycles >= gb->apu_output.cycles_per_sample) { + gb->apu_output.sample_cycles -= gb->apu_output.cycles_per_sample; + render(gb); + } + } +} +void GB_apu_init(GB_gameboy_t *gb) +{ + memset(&gb->apu, 0, sizeof(gb->apu)); + /* Restore the wave form */ + for (unsigned reg = GB_IO_WAV_START; reg <= GB_IO_WAV_END; reg++) { + gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2] = gb->io_registers[reg] >> 4; + gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2 + 1] = gb->io_registers[reg] & 0xF; + } + gb->apu.lf_div = 1; + /* APU glitch: When turning the APU on while DIV's bit 4 (or 5 in double speed mode) is on, + the first DIV/APU event is skipped. */ + if (gb->div_counter & (gb->cgb_double_speed? 0x2000 : 0x1000)) { + gb->apu.skip_div_event = true; + } +} + +uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg) +{ + if (reg == GB_IO_NR52) { + uint8_t value = 0; + for (int i = 0; i < GB_N_CHANNELS; i++) { + value >>= 1; + if (gb->apu.is_active[i]) { + value |= 0x8; + } + } + if (gb->apu.global_enable) { + value |= 0x80; + } + value |= 0x70; + return value; + } + + static const char read_mask[GB_IO_WAV_END - GB_IO_NR10 + 1] = { + /* NRX0 NRX1 NRX2 NRX3 NRX4 */ + 0x80, 0x3F, 0x00, 0xFF, 0xBF, // NR1X + 0xFF, 0x3F, 0x00, 0xFF, 0xBF, // NR2X + 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, // NR3X + 0xFF, 0xFF, 0x00, 0x00, 0xBF, // NR4X + 0x00, 0x00, 0x70, 0xFF, 0xFF, // NR5X + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Unused + // Wave RAM + 0, /* ... */ + }; + + if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END && gb->apu.is_active[GB_WAVE]) { + if (!GB_is_cgb(gb) && !gb->apu.wave_channel.wave_form_just_read) { + return 0xFF; + } + reg = GB_IO_WAV_START + gb->apu.wave_channel.current_sample_index / 2; + } + + return gb->io_registers[reg] | read_mask[reg - GB_IO_NR10]; +} + +void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) +{ + if (!gb->apu.global_enable && reg != GB_IO_NR52 && reg < GB_IO_WAV_START && (GB_is_cgb(gb) || + ( + reg != GB_IO_NR11 && + reg != GB_IO_NR21 && + reg != GB_IO_NR31 && + reg != GB_IO_NR41 + ) + )) { + return; + } + + if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END && gb->apu.is_active[GB_WAVE]) { + if (!GB_is_cgb(gb) && !gb->apu.wave_channel.wave_form_just_read) { + return; + } + reg = GB_IO_WAV_START + gb->apu.wave_channel.current_sample_index / 2; + } + + /* Todo: this can and should be rewritten with a function table. */ + switch (reg) { + /* Globals */ + case GB_IO_NR50: + case GB_IO_NR51: + gb->io_registers[reg] = value; + /* These registers affect the output of all 4 channels (but not the output of the PCM registers).*/ + /* We call update_samples with the current value so the APU output is updated with the new outputs */ + for (unsigned i = GB_N_CHANNELS; i--;) { + update_sample(gb, i, gb->apu.samples[i], 0); + } + break; + case GB_IO_NR52: { + + uint8_t old_nrx1[] = { + gb->io_registers[GB_IO_NR11], + gb->io_registers[GB_IO_NR21], + gb->io_registers[GB_IO_NR31], + gb->io_registers[GB_IO_NR41] + }; + if ((value & 0x80) && !gb->apu.global_enable) { + GB_apu_init(gb); + gb->apu.global_enable = true; + } + else if (!(value & 0x80) && gb->apu.global_enable) { + for (unsigned i = GB_N_CHANNELS; i--;) { + update_sample(gb, i, 0, 0); + } + memset(&gb->apu, 0, sizeof(gb->apu)); + memset(gb->io_registers + GB_IO_NR10, 0, GB_IO_WAV_START - GB_IO_NR10); + old_nrx1[0] &= 0x3F; + old_nrx1[1] &= 0x3F; + + gb->apu.global_enable = false; + } + + if (!GB_is_cgb(gb) && (value & 0x80)) { + GB_apu_write(gb, GB_IO_NR11, old_nrx1[0]); + GB_apu_write(gb, GB_IO_NR21, old_nrx1[1]); + GB_apu_write(gb, GB_IO_NR31, old_nrx1[2]); + GB_apu_write(gb, GB_IO_NR41, old_nrx1[3]); + } + } + break; + + /* Square channels */ + case GB_IO_NR10: + if (gb->apu.sweep_decreasing && !(value & 8)) { + gb->apu.is_active[GB_SQUARE_1] = false; + update_sample(gb, GB_SQUARE_1, 0, 0); + gb->apu.sweep_enabled = false; + gb->apu.square_sweep_calculate_countdown = 0; + } + if ((value & 0x70) == 0) { + /* Todo: what happens if we set period to 0 while a calculate event is scheduled, and then + re-set it to non-zero? */ + gb->apu.square_sweep_calculate_countdown = 0; + } + break; + + case GB_IO_NR11: + case GB_IO_NR21: { + unsigned index = reg == GB_IO_NR21? GB_SQUARE_2: GB_SQUARE_1; + gb->apu.square_channels[index].pulse_length = (0x40 - (value & 0x3f)); + if (!gb->apu.global_enable) { + value &= 0x3f; + } + break; + } + + case GB_IO_NR12: + case GB_IO_NR22: { + unsigned index = reg == GB_IO_NR22? GB_SQUARE_2: GB_SQUARE_1; + if (((value & 0x7) == 0) && ((gb->io_registers[reg] & 0x7) != 0)) { + /* Envelope disabled */ + gb->apu.square_channels[index].volume_countdown = 0; + } + if ((value & 0xF8) == 0) { + /* This disables the DAC */ + gb->io_registers[reg] = value; + gb->apu.is_active[index] = false; + update_sample(gb, index, 0, 0); + } + else if (gb->apu.is_active[index]) { + nrx2_glitch(&gb->apu.square_channels[index].current_volume, value, gb->io_registers[reg]); + update_square_sample(gb, index); + } + + break; + } + + case GB_IO_NR13: + case GB_IO_NR23: { + unsigned index = reg == GB_IO_NR23? GB_SQUARE_2: GB_SQUARE_1; + gb->apu.square_channels[index].sample_length &= ~0xFF; + gb->apu.square_channels[index].sample_length |= value & 0xFF; + break; + } + + case GB_IO_NR14: + case GB_IO_NR24: { + unsigned index = reg == GB_IO_NR24? GB_SQUARE_2: GB_SQUARE_1; + + /* TODO: When the sample length changes right before being updated, the countdown should change to the + old length, but the current sample should not change. Because our write timing isn't accurate to + the T-cycle, we hack around it by stepping the sample index backwards. */ + if ((value & 0x80) == 0 && gb->apu.is_active[index]) { + /* On an AGB, as well as on CGB C and earlier (TODO: Tested: 0, B and C), it behaves slightly different on + double speed. */ + if (gb->model == GB_MODEL_CGB_E /* || gb->model == GB_MODEL_CGB_D */ || gb->apu.square_channels[index].sample_countdown & 1) { + if (gb->apu.square_channels[index].sample_countdown >> 1 == (gb->apu.square_channels[index].sample_length ^ 0x7FF)) { + gb->apu.square_channels[index].current_sample_index--; + gb->apu.square_channels[index].current_sample_index &= 7; + } + } + } + + gb->apu.square_channels[index].sample_length &= 0xFF; + gb->apu.square_channels[index].sample_length |= (value & 7) << 8; + if (index == GB_SQUARE_1) { + gb->apu.shadow_sweep_sample_legnth = + gb->apu.new_sweep_sample_legnth = + gb->apu.square_channels[0].sample_length; + } + if (value & 0x80) { + /* Current sample index remains unchanged when restarting channels 1 or 2. It is only reset by + turning the APU off. */ + if (!gb->apu.is_active[index]) { + gb->apu.square_channels[index].sample_countdown = (gb->apu.square_channels[index].sample_length ^ 0x7FF) * 2 + 6 - gb->apu.lf_div; + } + else { + /* Timing quirk: if already active, sound starts 2 (2MHz) ticks earlier.*/ + gb->apu.square_channels[index].sample_countdown = (gb->apu.square_channels[index].sample_length ^ 0x7FF) * 2 + 4 - gb->apu.lf_div; + } + gb->apu.square_channels[index].current_volume = gb->io_registers[index == GB_SQUARE_1 ? GB_IO_NR12 : GB_IO_NR22] >> 4; + + /* The volume changes caused by NRX4 sound start take effect instantly (i.e. the effect the previously + started sound). The playback itself is not instant which is why we don't update the sample for other + cases. */ + if (gb->apu.is_active[index]) { + update_square_sample(gb, index); + } + + gb->apu.square_channels[index].volume_countdown = gb->io_registers[index == GB_SQUARE_1 ? GB_IO_NR12 : GB_IO_NR22] & 7; + + if ((gb->io_registers[index == GB_SQUARE_1 ? GB_IO_NR12 : GB_IO_NR22] & 0xF8) != 0 && !gb->apu.is_active[index]) { + gb->apu.is_active[index] = true; + update_sample(gb, index, 0, 0); + /* We use the highest bit in current_sample_index to mark this sample is not actually playing yet, */ + gb->apu.square_channels[index].current_sample_index |= 0x80; + } + if (gb->apu.square_channels[index].pulse_length == 0) { + gb->apu.square_channels[index].pulse_length = 0x40; + gb->apu.square_channels[index].length_enabled = false; + } + + if (index == GB_SQUARE_1) { + gb->apu.sweep_decreasing = false; + if (gb->io_registers[GB_IO_NR10] & 7) { + /* APU bug: if shift is nonzero, overflow check also occurs on trigger */ + gb->apu.square_sweep_calculate_countdown = 0x13 - gb->apu.lf_div; + } + else { + gb->apu.square_sweep_calculate_countdown = 0; + } + gb->apu.sweep_enabled = gb->io_registers[GB_IO_NR10] & 0x77; + gb->apu.square_sweep_countdown = ((gb->io_registers[GB_IO_NR10] >> 4) & 7); + if (!gb->apu.square_sweep_countdown) gb->apu.square_sweep_countdown = 8; + } + + } + + /* APU glitch - if length is enabled while the DIV-divider's LSB is 1, tick the length once. */ + if ((value & 0x40) && + !gb->apu.square_channels[index].length_enabled && + (gb->apu.div_divider & 1) && + gb->apu.square_channels[index].pulse_length) { + gb->apu.square_channels[index].pulse_length--; + if (gb->apu.square_channels[index].pulse_length == 0) { + if (value & 0x80) { + gb->apu.square_channels[index].pulse_length = 0x3F; + } + else { + gb->apu.is_active[index] = false; + update_sample(gb, index, 0, 0); + } + } + } + gb->apu.square_channels[index].length_enabled = value & 0x40; + break; + } + + /* Wave channel */ + case GB_IO_NR30: + gb->apu.wave_channel.enable = value & 0x80; + if (!gb->apu.wave_channel.enable) { + gb->apu.is_active[GB_WAVE] = false; + update_sample(gb, GB_WAVE, 0, 0); + } + break; + case GB_IO_NR31: + gb->apu.wave_channel.pulse_length = (0x100 - value); + break; + case GB_IO_NR32: + gb->apu.wave_channel.shift = (uint8_t[]){4, 0, 1, 2}[(value >> 5) & 3]; + if (gb->apu.is_active[GB_WAVE]) { + update_sample(gb, GB_WAVE, gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift, 0); + } + break; + case GB_IO_NR33: + gb->apu.wave_channel.sample_length &= ~0xFF; + gb->apu.wave_channel.sample_length |= value & 0xFF; + break; + case GB_IO_NR34: + gb->apu.wave_channel.sample_length &= 0xFF; + gb->apu.wave_channel.sample_length |= (value & 7) << 8; + if ((value & 0x80)) { + /* DMG bug: wave RAM gets corrupted if the channel is retriggerred 1 cycle before the APU + reads from it. */ + if (!GB_is_cgb(gb) && + gb->apu.is_active[GB_WAVE] && + gb->apu.wave_channel.sample_countdown == 0 && + gb->apu.wave_channel.enable) { + unsigned offset = ((gb->apu.wave_channel.current_sample_index + 1) >> 1) & 0xF; + + /* This glitch varies between models and even specific instances: + DMG-B: Most of them behave as emulated. A few behave differently. + SGB: As far as I know, all tested instances behave as emulated. + MGB, SGB2: Most instances behave non-deterministically, a few behave as emulated. + + Additionally, I believe DMGs, including those we behave differently than emulated, + are all deterministic. */ + if (offset < 4) { + gb->io_registers[GB_IO_WAV_START] = gb->io_registers[GB_IO_WAV_START + offset]; + gb->apu.wave_channel.wave_form[0] = gb->apu.wave_channel.wave_form[offset / 2]; + gb->apu.wave_channel.wave_form[1] = gb->apu.wave_channel.wave_form[offset / 2 + 1]; + } + else { + memcpy(gb->io_registers + GB_IO_WAV_START, + gb->io_registers + GB_IO_WAV_START + (offset & ~3), + 4); + memcpy(gb->apu.wave_channel.wave_form, + gb->apu.wave_channel.wave_form + (offset & ~3) * 2, + 8); + } + } + if (!gb->apu.is_active[GB_WAVE]) { + gb->apu.is_active[GB_WAVE] = true; + update_sample(gb, GB_WAVE, + gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift, + 0); + } + gb->apu.wave_channel.sample_countdown = (gb->apu.wave_channel.sample_length ^ 0x7FF) + 3; + gb->apu.wave_channel.current_sample_index = 0; + if (gb->apu.wave_channel.pulse_length == 0) { + gb->apu.wave_channel.pulse_length = 0x100; + gb->apu.wave_channel.length_enabled = false; + } + /* Note that we don't change the sample just yet! This was verified on hardware. */ + } + + /* APU glitch - if length is enabled while the DIV-divider's LSB is 1, tick the length once. */ + if ((value & 0x40) && + !gb->apu.wave_channel.length_enabled && + (gb->apu.div_divider & 1) && + gb->apu.wave_channel.pulse_length) { + gb->apu.wave_channel.pulse_length--; + if (gb->apu.wave_channel.pulse_length == 0) { + if (value & 0x80) { + gb->apu.wave_channel.pulse_length = 0xFF; + } + else { + gb->apu.is_active[GB_WAVE] = false; + update_sample(gb, GB_WAVE, 0, 0); + } + } + } + gb->apu.wave_channel.length_enabled = value & 0x40; + if (gb->apu.is_active[GB_WAVE] && !gb->apu.wave_channel.enable) { + gb->apu.is_active[GB_WAVE] = false; + update_sample(gb, GB_WAVE, 0, 0); + } + + break; + + /* Noise Channel */ + + case GB_IO_NR41: { + gb->apu.noise_channel.pulse_length = (0x40 - (value & 0x3f)); + break; + } + + case GB_IO_NR42: { + if (((value & 0x7) == 0) && ((gb->io_registers[reg] & 0x7) != 0)) { + /* Envelope disabled */ + gb->apu.noise_channel.volume_countdown = 0; + } + if ((value & 0xF8) == 0) { + /* This disables the DAC */ + gb->io_registers[reg] = value; + gb->apu.is_active[GB_NOISE] = false; + update_sample(gb, GB_NOISE, 0, 0); + } + else if (gb->apu.is_active[GB_NOISE]){ + nrx2_glitch(&gb->apu.noise_channel.current_volume, value, gb->io_registers[reg]); + update_sample(gb, GB_NOISE, + gb->apu.current_lfsr_sample ? + gb->apu.noise_channel.current_volume : 0, + 0); + } + break; + } + + case GB_IO_NR43: { + gb->apu.noise_channel.narrow = value & 8; + unsigned divisor = (value & 0x07) << 1; + if (!divisor) divisor = 1; + gb->apu.noise_channel.sample_length = (divisor << (value >> 4)) - 1; + + /* Todo: changing the frequency sometimes delays the next sample. This is probably + due to how the frequency is actually calculated in the noise channel, which is probably + not by calculating the effective sample length and counting simiarly to the other channels. + This is not emulated correctly. */ + break; + } + + case GB_IO_NR44: { + if (value & 0x80) { + gb->apu.noise_channel.sample_countdown = (gb->apu.noise_channel.sample_length) * 2 + 6 - gb->apu.lf_div; + + /* I'm COMPLETELY unsure about this logic, but it passes all relevant tests. + See comment in NR43. */ + if ((gb->io_registers[GB_IO_NR43] & 7) && (gb->apu.noise_channel.alignment & 2) == 0) { + if ((gb->io_registers[GB_IO_NR43] & 7) == 1) { + gb->apu.noise_channel.sample_countdown += 2; + } + else { + gb->apu.noise_channel.sample_countdown -= 2; + } + } + if (gb->apu.is_active[GB_NOISE]) { + gb->apu.noise_channel.sample_countdown += 2; + } + + gb->apu.noise_channel.current_volume = gb->io_registers[GB_IO_NR42] >> 4; + + /* The volume changes caused by NRX4 sound start take effect instantly (i.e. the effect the previously + started sound). The playback itself is not instant which is why we don't update the sample for other + cases. */ + if (gb->apu.is_active[GB_NOISE]) { + update_sample(gb, GB_NOISE, + gb->apu.current_lfsr_sample ? + gb->apu.noise_channel.current_volume : 0, + 0); + } + gb->apu.noise_channel.lfsr = 0; + gb->apu.current_lfsr_sample = false; + gb->apu.noise_channel.volume_countdown = gb->io_registers[GB_IO_NR42] & 7; + + if (!gb->apu.is_active[GB_NOISE] && (gb->io_registers[GB_IO_NR42] & 0xF8) != 0) { + gb->apu.is_active[GB_NOISE] = true; + update_sample(gb, GB_NOISE, 0, 0); + } + + if (gb->apu.noise_channel.pulse_length == 0) { + gb->apu.noise_channel.pulse_length = 0x40; + gb->apu.noise_channel.length_enabled = false; + } + } + + /* APU glitch - if length is enabled while the DIV-divider's LSB is 1, tick the length once. */ + if ((value & 0x40) && + !gb->apu.noise_channel.length_enabled && + (gb->apu.div_divider & 1) && + gb->apu.noise_channel.pulse_length) { + gb->apu.noise_channel.pulse_length--; + if (gb->apu.noise_channel.pulse_length == 0) { + if (value & 0x80) { + gb->apu.noise_channel.pulse_length = 0x3F; + } + else { + gb->apu.is_active[GB_NOISE] = false; + update_sample(gb, GB_NOISE, 0, 0); + } + } + } + gb->apu.noise_channel.length_enabled = value & 0x40; + break; + } + + default: + if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END) { + gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2] = value >> 4; + gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2 + 1] = value & 0xF; + } + } + gb->io_registers[reg] = value; +} + +void GB_set_sample_rate(GB_gameboy_t *gb, unsigned sample_rate) +{ + + gb->apu_output.sample_rate = sample_rate; + if (sample_rate) { + gb->apu_output.highpass_rate = pow(0.999958, GB_get_clock_rate(gb) / (double)sample_rate); + } + gb->apu_output.rate_set_in_clocks = false; + GB_apu_update_cycles_per_sample(gb); +} + +void GB_set_sample_rate_by_clocks(GB_gameboy_t *gb, double cycles_per_sample) +{ + + if (cycles_per_sample == 0) { + GB_set_sample_rate(gb, 0); + return; + } + gb->apu_output.cycles_per_sample = cycles_per_sample; + gb->apu_output.sample_rate = GB_get_clock_rate(gb) / cycles_per_sample * 2; + gb->apu_output.highpass_rate = pow(0.999958, cycles_per_sample); + gb->apu_output.rate_set_in_clocks = true; +} + +void GB_apu_set_sample_callback(GB_gameboy_t *gb, GB_sample_callback_t callback) +{ + gb->apu_output.sample_callback = callback; +} + +void GB_set_highpass_filter_mode(GB_gameboy_t *gb, GB_highpass_mode_t mode) +{ + gb->apu_output.highpass_mode = mode; +} + +void GB_apu_update_cycles_per_sample(GB_gameboy_t *gb) +{ + if (gb->apu_output.rate_set_in_clocks) return; + if (gb->apu_output.sample_rate) { + gb->apu_output.cycles_per_sample = 2 * GB_get_clock_rate(gb) / (double)gb->apu_output.sample_rate; /* 2 * because we use 8MHz units */ + } +} diff --git a/gb/Core/apu.h b/gb/Core/apu.h new file mode 100644 index 0000000..885e0ce --- /dev/null +++ b/gb/Core/apu.h @@ -0,0 +1,164 @@ +#ifndef apu_h +#define apu_h +#include +#include +#include +#include "gb_struct_def.h" + + +#ifdef GB_INTERNAL +/* Speed = 1 / Length (in seconds) */ +#define DAC_DECAY_SPEED 20000 +#define DAC_ATTACK_SPEED 20000 + + +/* Divides nicely and never overflows with 4 channels and 8 (1-8) volume levels */ +#ifdef WIIU +/* Todo: Remove this hack once https://github.com/libretro/RetroArch/issues/6252 is fixed*/ +#define MAX_CH_AMP (0xFF0 / 2) +#else +#define MAX_CH_AMP 0xFF0 +#endif +#define CH_STEP (MAX_CH_AMP/0xF/8) +#endif + + + +/* APU ticks are 2MHz, triggered by an internal APU clock. */ + +typedef struct +{ + int16_t left; + int16_t right; +} GB_sample_t; + +typedef struct +{ + double left; + double right; +} GB_double_sample_t; + +enum GB_CHANNELS { + GB_SQUARE_1, + GB_SQUARE_2, + GB_WAVE, + GB_NOISE, + GB_N_CHANNELS +}; + +typedef void (*GB_sample_callback_t)(GB_gameboy_t *gb, GB_sample_t *sample); + +typedef struct +{ + bool global_enable; + uint8_t apu_cycles; + + uint8_t samples[GB_N_CHANNELS]; + bool is_active[GB_N_CHANNELS]; + + uint8_t div_divider; // The DIV register ticks the APU at 512Hz, but is then divided + // once more to generate 128Hz and 64Hz clocks + + uint8_t lf_div; // The APU runs in 2MHz, but channels 1, 2 and 4 run in 1MHZ so we divide + // need to divide the signal. + + uint8_t square_sweep_countdown; // In 128Hz + uint8_t square_sweep_calculate_countdown; // In 2 MHz + uint16_t new_sweep_sample_legnth; + uint16_t shadow_sweep_sample_legnth; + bool sweep_enabled; + bool sweep_decreasing; + + struct { + uint16_t pulse_length; // Reloaded from NRX1 (xorred), in 256Hz DIV ticks + uint8_t current_volume; // Reloaded from NRX2 + uint8_t volume_countdown; // Reloaded from NRX2 + uint8_t current_sample_index; /* For save state compatibility, + highest bit is reused (See NR14/NR24's + write code)*/ + + uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length, xorred $7FF) + uint16_t sample_length; // From NRX3, NRX4, in APU ticks + bool length_enabled; // NRX4 + + } square_channels[2]; + + struct { + bool enable; // NR30 + uint16_t pulse_length; // Reloaded from NR31 (xorred), in 256Hz DIV ticks + uint8_t shift; // NR32 + uint16_t sample_length; // NR33, NR34, in APU ticks + bool length_enabled; // NR34 + + uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length, xorred $7FF) + uint8_t current_sample_index; + uint8_t current_sample; // Current sample before shifting. + + int8_t wave_form[32]; + bool wave_form_just_read; + } wave_channel; + + struct { + uint16_t pulse_length; // Reloaded from NR41 (xorred), in 256Hz DIV ticks + uint8_t current_volume; // Reloaded from NR42 + uint8_t volume_countdown; // Reloaded from NR42 + uint16_t lfsr; + bool narrow; + + uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length) + uint16_t sample_length; // From NR43, in APU ticks + bool length_enabled; // NR44 + + uint8_t alignment; // If (NR43 & 7) != 0, samples are aligned to 512KHz clock instead of + // 1MHz. This variable keeps track of the alignment. + + } noise_channel; + + bool skip_div_event; + bool current_lfsr_sample; +} GB_apu_t; + +typedef enum { + GB_HIGHPASS_OFF, // Do not apply any filter, keep DC offset + GB_HIGHPASS_ACCURATE, // Apply a highpass filter similar to the one used on hardware + GB_HIGHPASS_REMOVE_DC_OFFSET, // Remove DC Offset without affecting the waveform + GB_HIGHPASS_MAX +} GB_highpass_mode_t; + +typedef struct { + unsigned sample_rate; + + double sample_cycles; // In 8 MHz units + double cycles_per_sample; + + // Samples are NOT normalized to MAX_CH_AMP * 4 at this stage! + unsigned cycles_since_render; + unsigned last_update[GB_N_CHANNELS]; + GB_sample_t current_sample[GB_N_CHANNELS]; + GB_sample_t summed_samples[GB_N_CHANNELS]; + double dac_discharge[GB_N_CHANNELS]; + + GB_highpass_mode_t highpass_mode; + double highpass_rate; + GB_double_sample_t highpass_diff; + + GB_sample_callback_t sample_callback; + + bool rate_set_in_clocks; +} GB_apu_output_t; + +void GB_set_sample_rate(GB_gameboy_t *gb, unsigned sample_rate); +void GB_set_sample_rate_by_clocks(GB_gameboy_t *gb, double cycles_per_sample); /* Cycles are in 8MHz units */ +void GB_set_highpass_filter_mode(GB_gameboy_t *gb, GB_highpass_mode_t mode); +void GB_apu_set_sample_callback(GB_gameboy_t *gb, GB_sample_callback_t callback); +#ifdef GB_INTERNAL +bool GB_apu_is_DAC_enabled(GB_gameboy_t *gb, unsigned index); +void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value); +uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg); +void GB_apu_div_event(GB_gameboy_t *gb); +void GB_apu_init(GB_gameboy_t *gb); +void GB_apu_run(GB_gameboy_t *gb); +void GB_apu_update_cycles_per_sample(GB_gameboy_t *gb); +#endif + +#endif /* apu_h */ diff --git a/gb/Core/camera.c b/gb/Core/camera.c new file mode 100644 index 0000000..9b34998 --- /dev/null +++ b/gb/Core/camera.c @@ -0,0 +1,149 @@ +#include "gb.h" + +static int noise_seed = 0; + +/* This is not a complete emulation of the camera chip. Only the features used by the GameBoy Camera ROMs are supported. + We also do not emulate the timing of the real cart, as it might be actually faster than the webcam. */ + +static uint8_t generate_noise(uint8_t x, uint8_t y) +{ + int value = (x + y * 128 + noise_seed); + uint8_t *data = (uint8_t *) &value; + unsigned hash = 0; + + while ((int *) data != &value + 1) { + hash ^= (*data << 8); + if (hash & 0x8000) { + hash ^= 0x8a00; + hash ^= *data; + } + data++; + hash <<= 1; + } + return (hash >> 8); +} + +static long get_processed_color(GB_gameboy_t *gb, uint8_t x, uint8_t y) +{ + if (x >= 128) { + x = 0; + } + if (y >= 112) { + y = 0; + } + + long color = gb->camera_get_pixel_callback? gb->camera_get_pixel_callback(gb, x, y) : (generate_noise(x, y)); + + static const double gain_values[] = + {0.8809390, 0.9149149, 0.9457498, 0.9739758, + 1.0000000, 1.0241412, 1.0466537, 1.0677433, + 1.0875793, 1.1240310, 1.1568911, 1.1868043, + 1.2142561, 1.2396208, 1.2743837, 1.3157323, + 1.3525190, 1.3856512, 1.4157897, 1.4434309, + 1.4689574, 1.4926697, 1.5148087, 1.5355703, + 1.5551159, 1.5735801, 1.5910762, 1.6077008, + 1.6235366, 1.6386550, 1.6531183, 1.6669808}; + /* Multiply color by gain value */ + color *= gain_values[gb->camera_registers[GB_CAMERA_GAIN_AND_EDGE_ENHACEMENT_FLAGS] & 0x1F]; + + + /* Color is multiplied by the exposure register to simulate exposure. */ + color = color * ((gb->camera_registers[GB_CAMERA_EXPOSURE_HIGH] << 8) + gb->camera_registers[GB_CAMERA_EXPOSURE_LOW]) / 0x1000; + + return color; +} + +uint8_t GB_camera_read_image(GB_gameboy_t *gb, uint16_t addr) +{ + if (gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] & 1) { + /* Forbid reading the image while the camera is busy. */ + return 0xFF; + } + uint8_t tile_x = addr / 0x10 % 0x10; + uint8_t tile_y = addr / 0x10 / 0x10; + + uint8_t y = ((addr >> 1) & 0x7) + tile_y * 8; + uint8_t bit = addr & 1; + + uint8_t ret = 0; + + for (uint8_t x = tile_x * 8; x < tile_x * 8 + 8; x++) { + + long color = get_processed_color(gb, x, y); + + static const double edge_enhancement_ratios[] = {0.5, 0.75, 1, 1.25, 2, 3, 4, 5}; + double edge_enhancement_ratio = edge_enhancement_ratios[(gb->camera_registers[GB_CAMERA_EDGE_ENHANCEMENT_INVERT_AND_VOLTAGE] >> 4) & 0x7]; + if ((gb->camera_registers[GB_CAMERA_GAIN_AND_EDGE_ENHACEMENT_FLAGS] & 0xE0) == 0xE0) { + color += (color * 4) * edge_enhancement_ratio; + color -= get_processed_color(gb, x - 1, y) * edge_enhancement_ratio; + color -= get_processed_color(gb, x + 1, y) * edge_enhancement_ratio; + color -= get_processed_color(gb, x, y - 1) * edge_enhancement_ratio; + color -= get_processed_color(gb, x, y + 1) * edge_enhancement_ratio; + } + + + /* The camera's registers are used as a threshold pattern, which defines the dithering */ + uint8_t pattern_base = ((x & 3) + (y & 3) * 4) * 3 + GB_CAMERA_DITHERING_PATTERN_START; + + if (color < gb->camera_registers[pattern_base]) { + color = 3; + } + else if (color < gb->camera_registers[pattern_base + 1]) { + color = 2; + } + else if (color < gb->camera_registers[pattern_base + 2]) { + color = 1; + } + else { + color = 0; + } + + ret <<= 1; + ret |= (color >> bit) & 1; + } + + return ret; +} + +void GB_set_camera_get_pixel_callback(GB_gameboy_t *gb, GB_camera_get_pixel_callback_t callback) +{ + gb->camera_get_pixel_callback = callback; +} + +void GB_set_camera_update_request_callback(GB_gameboy_t *gb, GB_camera_update_request_callback_t callback) +{ + gb->camera_update_request_callback = callback; +} + +void GB_camera_updated(GB_gameboy_t *gb) +{ + gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] &= ~1; +} + +void GB_camera_write_register(GB_gameboy_t *gb, uint16_t addr, uint8_t value) +{ + addr &= 0x7F; + if (addr == GB_CAMERA_SHOOT_AND_1D_FLAGS) { + value &= 0x7; + noise_seed = rand(); + if ((value & 1) && !(gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] & 1) && gb->camera_update_request_callback) { + /* If no callback is set, ignore the write as if the camera is instantly done */ + gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS] |= 1; + gb->camera_update_request_callback(gb); + } + } + else { + if (addr >= 0x36) { + GB_log(gb, "Wrote invalid camera register %02x: %2x\n", addr, value); + return; + } + gb->camera_registers[addr] = value; + } +} +uint8_t GB_camera_read_register(GB_gameboy_t *gb, uint16_t addr) +{ + if ((addr & 0x7F) == 0) { + return gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS]; + } + return 0; +} diff --git a/gb/Core/camera.h b/gb/Core/camera.h new file mode 100644 index 0000000..21c69b6 --- /dev/null +++ b/gb/Core/camera.h @@ -0,0 +1,29 @@ +#ifndef camera_h +#define camera_h +#include +#include "gb_struct_def.h" + +typedef uint8_t (*GB_camera_get_pixel_callback_t)(GB_gameboy_t *gb, uint8_t x, uint8_t y); +typedef void (*GB_camera_update_request_callback_t)(GB_gameboy_t *gb); + +enum { + GB_CAMERA_SHOOT_AND_1D_FLAGS = 0, + GB_CAMERA_GAIN_AND_EDGE_ENHACEMENT_FLAGS = 1, + GB_CAMERA_EXPOSURE_HIGH = 2, + GB_CAMERA_EXPOSURE_LOW = 3, + GB_CAMERA_EDGE_ENHANCEMENT_INVERT_AND_VOLTAGE = 4, + GB_CAMERA_DITHERING_PATTERN_START = 6, + GB_CAMERA_DITHERING_PATTERN_END = 0x35, +}; + +uint8_t GB_camera_read_image(GB_gameboy_t *gb, uint16_t addr); + +void GB_set_camera_get_pixel_callback(GB_gameboy_t *gb, GB_camera_get_pixel_callback_t callback); +void GB_set_camera_update_request_callback(GB_gameboy_t *gb, GB_camera_update_request_callback_t callback); + +void GB_camera_updated(GB_gameboy_t *gb); + +void GB_camera_write_register(GB_gameboy_t *gb, uint16_t addr, uint8_t value); +uint8_t GB_camera_read_register(GB_gameboy_t *gb, uint16_t addr); + +#endif diff --git a/gb/Core/debugger.c b/gb/Core/debugger.c new file mode 100644 index 0000000..df480f3 --- /dev/null +++ b/gb/Core/debugger.c @@ -0,0 +1,2459 @@ +#include +#include +#include +#include "gb.h" + +typedef struct { + bool has_bank; + uint16_t bank:9; + uint16_t value; +} value_t; + +typedef struct { + enum { + LVALUE_MEMORY, + LVALUE_MEMORY16, + LVALUE_REG16, + LVALUE_REG_H, + LVALUE_REG_L, + } kind; + union { + uint16_t *register_address; + value_t memory_address; + }; +} lvalue_t; + +#define VALUE_16(x) ((value_t){false, 0, (x)}) + +struct GB_breakpoint_s { + union { + struct { + uint16_t addr; + uint16_t bank; /* -1 = any bank*/ + }; + uint32_t key; /* For sorting and comparing */ + }; + char *condition; + bool is_jump_to; +}; + +#define BP_KEY(x) (((struct GB_breakpoint_s){.addr = ((x).value), .bank = (x).has_bank? (x).bank : -1 }).key) + +#define GB_WATCHPOINT_R (1) +#define GB_WATCHPOINT_W (2) + +struct GB_watchpoint_s { + union { + struct { + uint16_t addr; + uint16_t bank; /* -1 = any bank*/ + }; + uint32_t key; /* For sorting and comparing */ + }; + char *condition; + uint8_t flags; +}; + +#define WP_KEY(x) (((struct GB_watchpoint_s){.addr = ((x).value), .bank = (x).has_bank? (x).bank : -1 }).key) + +static uint16_t bank_for_addr(GB_gameboy_t *gb, uint16_t addr) +{ + if (addr < 0x4000) { + return gb->mbc_rom0_bank; + } + + if (addr < 0x8000) { + return gb->mbc_rom_bank; + } + + if (addr < 0xD000) { + return 0; + } + + if (addr < 0xE000) { + return gb->cgb_ram_bank; + } + + return 0; +} + +typedef struct { + uint16_t rom0_bank; + uint16_t rom_bank; + uint8_t mbc_ram_bank; + bool mbc_ram_enable; + uint8_t ram_bank; + uint8_t vram_bank; +} banking_state_t; + +static inline void save_banking_state(GB_gameboy_t *gb, banking_state_t *state) +{ + state->rom0_bank = gb->mbc_rom0_bank; + state->rom_bank = gb->mbc_rom_bank; + state->mbc_ram_bank = gb->mbc_ram_bank; + state->mbc_ram_enable = gb->mbc_ram_enable; + state->ram_bank = gb->cgb_ram_bank; + state->vram_bank = gb->cgb_vram_bank; +} + +static inline void restore_banking_state(GB_gameboy_t *gb, banking_state_t *state) +{ + + gb->mbc_rom0_bank = state->rom0_bank; + gb->mbc_rom_bank = state->rom_bank; + gb->mbc_ram_bank = state->mbc_ram_bank; + gb->mbc_ram_enable = state->mbc_ram_enable; + gb->cgb_ram_bank = state->ram_bank; + gb->cgb_vram_bank = state->vram_bank; +} + +static inline void switch_banking_state(GB_gameboy_t *gb, uint16_t bank) +{ + gb->mbc_rom0_bank = bank; + gb->mbc_rom_bank = bank; + gb->mbc_ram_bank = bank; + gb->mbc_ram_enable = true; + if (GB_is_cgb(gb)) { + gb->cgb_ram_bank = bank & 7; + gb->cgb_vram_bank = bank & 1; + if (gb->cgb_ram_bank == 0) { + gb->cgb_ram_bank = 1; + } + } +} + +static const char *value_to_string(GB_gameboy_t *gb, uint16_t value, bool prefer_name) +{ + static __thread char output[256]; + const GB_bank_symbol_t *symbol = GB_debugger_find_symbol(gb, value); + + if (symbol && (value - symbol->addr > 0x1000 || symbol->addr == 0) ) { + symbol = NULL; + } + + /* Avoid overflow */ + if (symbol && strlen(symbol->name) > 240) { + symbol = NULL; + } + + if (!symbol) { + sprintf(output, "$%04x", value); + } + + else if (symbol->addr == value) { + if (prefer_name) { + sprintf(output, "%s ($%04x)", symbol->name, value); + } + else { + sprintf(output, "$%04x (%s)", value, symbol->name); + } + } + + else { + if (prefer_name) { + sprintf(output, "%s+$%03x ($%04x)", symbol->name, value - symbol->addr, value); + } + else { + sprintf(output, "$%04x (%s+$%03x)", value, symbol->name, value - symbol->addr); + } + } + return output; +} + +static const char *debugger_value_to_string(GB_gameboy_t *gb, value_t value, bool prefer_name) +{ + if (!value.has_bank) return value_to_string(gb, value.value, prefer_name); + + static __thread char output[256]; + const GB_bank_symbol_t *symbol = GB_map_find_symbol(gb->bank_symbols[value.bank], value.value); + + if (symbol && (value.value - symbol->addr > 0x1000 || symbol->addr == 0) ) { + symbol = NULL; + } + + /* Avoid overflow */ + if (symbol && strlen(symbol->name) > 240) { + symbol = NULL; + } + + if (!symbol) { + sprintf(output, "$%02x:$%04x", value.bank, value.value); + } + + else if (symbol->addr == value.value) { + if (prefer_name) { + sprintf(output, "%s ($%02x:$%04x)", symbol->name, value.bank, value.value); + } + else { + sprintf(output, "$%02x:$%04x (%s)", value.bank, value.value, symbol->name); + } + } + + else { + if (prefer_name) { + sprintf(output, "%s+$%03x ($%02x:$%04x)", symbol->name, value.value - symbol->addr, value.bank, value.value); + } + else { + sprintf(output, "$%02x:$%04x (%s+$%03x)", value.bank, value.value, symbol->name, value.value - symbol->addr); + } + } + return output; +} + +static value_t read_lvalue(GB_gameboy_t *gb, lvalue_t lvalue) +{ + /* Not used until we add support for operators like += */ + switch (lvalue.kind) { + case LVALUE_MEMORY: + if (lvalue.memory_address.has_bank) { + banking_state_t state; + save_banking_state(gb, &state); + switch_banking_state(gb, lvalue.memory_address.bank); + value_t r = VALUE_16(GB_read_memory(gb, lvalue.memory_address.value)); + restore_banking_state(gb, &state); + return r; + } + return VALUE_16(GB_read_memory(gb, lvalue.memory_address.value)); + + case LVALUE_MEMORY16: + if (lvalue.memory_address.has_bank) { + banking_state_t state; + save_banking_state(gb, &state); + switch_banking_state(gb, lvalue.memory_address.bank); + value_t r = VALUE_16(GB_read_memory(gb, lvalue.memory_address.value)); + restore_banking_state(gb, &state); + return r; + } + return VALUE_16(GB_read_memory(gb, lvalue.memory_address.value) | + (GB_read_memory(gb, lvalue.memory_address.value + 1) * 0x100)); + + case LVALUE_REG16: + return VALUE_16(*lvalue.register_address); + + case LVALUE_REG_L: + return VALUE_16(*lvalue.register_address & 0x00FF); + + case LVALUE_REG_H: + return VALUE_16(*lvalue.register_address >> 8); + } + + return VALUE_16(0); +} + +static void write_lvalue(GB_gameboy_t *gb, lvalue_t lvalue, uint16_t value) +{ + switch (lvalue.kind) { + case LVALUE_MEMORY: + if (lvalue.memory_address.has_bank) { + banking_state_t state; + save_banking_state(gb, &state); + switch_banking_state(gb, lvalue.memory_address.bank); + GB_write_memory(gb, lvalue.memory_address.value, value); + restore_banking_state(gb, &state); + return; + } + GB_write_memory(gb, lvalue.memory_address.value, value); + return; + + case LVALUE_MEMORY16: + if (lvalue.memory_address.has_bank) { + banking_state_t state; + save_banking_state(gb, &state); + switch_banking_state(gb, lvalue.memory_address.bank); + GB_write_memory(gb, lvalue.memory_address.value, value); + restore_banking_state(gb, &state); + return; + } + GB_write_memory(gb, lvalue.memory_address.value, value); + GB_write_memory(gb, lvalue.memory_address.value + 1, value >> 8); + return; + + case LVALUE_REG16: + *lvalue.register_address = value; + return; + + case LVALUE_REG_L: + *lvalue.register_address &= 0xFF00; + *lvalue.register_address |= value & 0xFF; + return; + + case LVALUE_REG_H: + *lvalue.register_address &= 0x00FF; + *lvalue.register_address |= value << 8; + return; + } +} + +/* 16 bit value 16 bit value = 16 bit value + 25 bit address 16 bit value = 25 bit address + 16 bit value 25 bit address = 25 bit address + 25 bit address 25 bit address = 16 bit value (since adding pointers, for examples, makes no sense) + + Boolean operators always return a 16-bit value + */ +#define FIX_BANK(x) ((value_t){a.has_bank ^ b.has_bank, a.has_bank? a.bank : b.bank, (x)}) + +static value_t add(value_t a, value_t b) {return FIX_BANK(a.value + b.value);} +static value_t sub(value_t a, value_t b) {return FIX_BANK(a.value - b.value);} +static value_t mul(value_t a, value_t b) {return FIX_BANK(a.value * b.value);} +static value_t _div(value_t a, value_t b) { + if (b.value == 0) { + return FIX_BANK(0); + } + return FIX_BANK(a.value / b.value); +}; +static value_t mod(value_t a, value_t b) { + if (b.value == 0) { + return FIX_BANK(0); + } + return FIX_BANK(a.value % b.value); +}; +static value_t and(value_t a, value_t b) {return FIX_BANK(a.value & b.value);} +static value_t or(value_t a, value_t b) {return FIX_BANK(a.value | b.value);} +static value_t xor(value_t a, value_t b) {return FIX_BANK(a.value ^ b.value);} +static value_t shleft(value_t a, value_t b) {return FIX_BANK(a.value << b.value);} +static value_t shright(value_t a, value_t b) {return FIX_BANK(a.value >> b.value);} +static value_t assign(GB_gameboy_t *gb, lvalue_t a, uint16_t b) +{ + write_lvalue(gb, a, b); + return read_lvalue(gb, a); +} + +static value_t bool_and(value_t a, value_t b) {return VALUE_16(a.value && b.value);} +static value_t bool_or(value_t a, value_t b) {return VALUE_16(a.value || b.value);} +static value_t equals(value_t a, value_t b) {return VALUE_16(a.value == b.value);} +static value_t different(value_t a, value_t b) {return VALUE_16(a.value != b.value);} +static value_t lower(value_t a, value_t b) {return VALUE_16(a.value < b.value);} +static value_t greater(value_t a, value_t b) {return VALUE_16(a.value > b.value);} +static value_t lower_equals(value_t a, value_t b) {return VALUE_16(a.value <= b.value);} +static value_t greater_equals(value_t a, value_t b) {return VALUE_16(a.value >= b.value);} +static value_t bank(value_t a, value_t b) {return (value_t) {true, a.value, b.value};} + + +static struct { + const char *string; + char priority; + value_t (*operator)(value_t, value_t); + value_t (*lvalue_operator)(GB_gameboy_t *, lvalue_t, uint16_t); +} operators[] = +{ + // Yes. This is not C-like. But it makes much more sense. + // Deal with it. + {"+", 0, add}, + {"-", 0, sub}, + {"||", 0, bool_or}, + {"|", 0, or}, + {"*", 1, mul}, + {"/", 1, _div}, + {"%", 1, mod}, + {"&&", 1, bool_and}, + {"&", 1, and}, + {"^", 1, xor}, + {"<<", 2, shleft}, + {"<=", -1, lower_equals}, + {"<", -1, lower}, + {">>", 2, shright}, + {">=", -1, greater_equals}, + {">", -1, greater}, + {"==", -1, equals}, + {"=", -2, NULL, assign}, + {"!=", -1, different}, + {":", 3, bank}, +}; + +value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, + size_t length, bool *error, + uint16_t *watchpoint_address, uint8_t *watchpoint_new_value); + +static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string, + size_t length, bool *error, + uint16_t *watchpoint_address, uint8_t *watchpoint_new_value) +{ + *error = false; + // Strip whitespace + while (length && (string[0] == ' ' || string[0] == '\n' || string[0] == '\r' || string[0] == '\t')) { + string++; + length--; + } + while (length && (string[length-1] == ' ' || string[length-1] == '\n' || string[length-1] == '\r' || string[length-1] == '\t')) { + length--; + } + if (length == 0) + { + GB_log(gb, "Expected expression.\n"); + *error = true; + return (lvalue_t){0,}; + } + if (string[0] == '(' && string[length - 1] == ')') { + // Attempt to strip parentheses + signed int depth = 0; + for (int i = 0; i < length; i++) { + if (string[i] == '(') depth++; + if (depth == 0) { + // First and last are not matching + depth = 1; + break; + } + if (string[i] == ')') depth--; + } + if (depth == 0) return debugger_evaluate_lvalue(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value); + } + else if (string[0] == '[' && string[length - 1] == ']') { + // Attempt to strip square parentheses (memory dereference) + signed int depth = 0; + for (int i = 0; i < length; i++) { + if (string[i] == '[') depth++; + if (depth == 0) { + // First and last are not matching + depth = 1; + break; + } + if (string[i] == ']') depth--; + } + if (depth == 0) { + return (lvalue_t){LVALUE_MEMORY, .memory_address = debugger_evaluate(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value)}; + } + } + else if (string[0] == '{' && string[length - 1] == '}') { + // Attempt to strip curly parentheses (memory dereference) + signed int depth = 0; + for (int i = 0; i < length; i++) { + if (string[i] == '{') depth++; + if (depth == 0) { + // First and last are not matching + depth = 1; + break; + } + if (string[i] == '}') depth--; + } + if (depth == 0) { + return (lvalue_t){LVALUE_MEMORY16, .memory_address = debugger_evaluate(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value)}; + } + } + + // Registers + if (string[0] != '$' && (string[0] < '0' || string[0] > '9')) { + if (length == 1) { + switch (string[0]) { + case 'a': return (lvalue_t){LVALUE_REG_H, .register_address = &gb->registers[GB_REGISTER_AF]}; + case 'f': return (lvalue_t){LVALUE_REG_L, .register_address = &gb->registers[GB_REGISTER_AF]}; + case 'b': return (lvalue_t){LVALUE_REG_H, .register_address = &gb->registers[GB_REGISTER_BC]}; + case 'c': return (lvalue_t){LVALUE_REG_L, .register_address = &gb->registers[GB_REGISTER_BC]}; + case 'd': return (lvalue_t){LVALUE_REG_H, .register_address = &gb->registers[GB_REGISTER_DE]}; + case 'e': return (lvalue_t){LVALUE_REG_L, .register_address = &gb->registers[GB_REGISTER_DE]}; + case 'h': return (lvalue_t){LVALUE_REG_H, .register_address = &gb->registers[GB_REGISTER_HL]}; + case 'l': return (lvalue_t){LVALUE_REG_L, .register_address = &gb->registers[GB_REGISTER_HL]}; + } + } + else if (length == 2) { + switch (string[0]) { + case 'a': if (string[1] == 'f') return (lvalue_t){LVALUE_REG16, .register_address = &gb->registers[GB_REGISTER_AF]}; + case 'b': if (string[1] == 'c') return (lvalue_t){LVALUE_REG16, .register_address = &gb->registers[GB_REGISTER_BC]}; + case 'd': if (string[1] == 'e') return (lvalue_t){LVALUE_REG16, .register_address = &gb->registers[GB_REGISTER_DE]}; + case 'h': if (string[1] == 'l') return (lvalue_t){LVALUE_REG16, .register_address = &gb->registers[GB_REGISTER_HL]}; + case 's': if (string[1] == 'p') return (lvalue_t){LVALUE_REG16, .register_address = &gb->registers[GB_REGISTER_SP]}; + case 'p': if (string[1] == 'c') return (lvalue_t){LVALUE_REG16, .register_address = &gb->pc}; + } + } + GB_log(gb, "Unknown register: %.*s\n", (unsigned) length, string); + *error = true; + return (lvalue_t){0,}; + } + + GB_log(gb, "Expression is not an lvalue: %.*s\n", (unsigned) length, string); + *error = true; + return (lvalue_t){0,}; +} + +#define ERROR ((value_t){0,}) +value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, + size_t length, bool *error, + uint16_t *watchpoint_address, uint8_t *watchpoint_new_value) +{ + /* Disable watchpoints while evaulating expressions */ + uint16_t n_watchpoints = gb->n_watchpoints; + gb->n_watchpoints = 0; + + value_t ret = ERROR; + + *error = false; + // Strip whitespace + while (length && (string[0] == ' ' || string[0] == '\n' || string[0] == '\r' || string[0] == '\t')) { + string++; + length--; + } + while (length && (string[length-1] == ' ' || string[length-1] == '\n' || string[length-1] == '\r' || string[length-1] == '\t')) { + length--; + } + if (length == 0) + { + GB_log(gb, "Expected expression.\n"); + *error = true; + goto exit; + } + if (string[0] == '(' && string[length - 1] == ')') { + // Attempt to strip parentheses + signed int depth = 0; + for (int i = 0; i < length; i++) { + if (string[i] == '(') depth++; + if (depth == 0) { + // First and last are not matching + depth = 1; + break; + } + if (string[i] == ')') depth--; + } + if (depth == 0) { + ret = debugger_evaluate(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value); + goto exit; + } + } + else if (string[0] == '[' && string[length - 1] == ']') { + // Attempt to strip square parentheses (memory dereference) + signed int depth = 0; + for (int i = 0; i < length; i++) { + if (string[i] == '[') depth++; + if (depth == 0) { + // First and last are not matching + depth = 1; + break; + } + if (string[i] == ']') depth--; + } + + if (depth == 0) { + value_t addr = debugger_evaluate(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value); + banking_state_t state; + if (addr.bank) { + save_banking_state(gb, &state); + switch_banking_state(gb, addr.bank); + } + ret = VALUE_16(GB_read_memory(gb, addr.value)); + if (addr.bank) { + restore_banking_state(gb, &state); + } + goto exit; + } + } + else if (string[0] == '{' && string[length - 1] == '}') { + // Attempt to strip curly parentheses (memory dereference) + signed int depth = 0; + for (int i = 0; i < length; i++) { + if (string[i] == '{') depth++; + if (depth == 0) { + // First and last are not matching + depth = 1; + break; + } + if (string[i] == '}') depth--; + } + + if (depth == 0) { + value_t addr = debugger_evaluate(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value); + banking_state_t state; + if (addr.bank) { + save_banking_state(gb, &state); + switch_banking_state(gb, addr.bank); + } + ret = VALUE_16(GB_read_memory(gb, addr.value) | (GB_read_memory(gb, addr.value + 1) * 0x100)); + if (addr.bank) { + restore_banking_state(gb, &state); + } + goto exit; + } + } + // Search for lowest priority operator + signed int depth = 0; + unsigned operator_index = -1; + unsigned operator_pos = 0; + for (int i = 0; i < length; i++) { + if (string[i] == '(') depth++; + else if (string[i] == ')') depth--; + else if (string[i] == '[') depth++; + else if (string[i] == ']') depth--; + else if (depth == 0) { + for (int j = 0; j < sizeof(operators) / sizeof(operators[0]); j++) { + if (strlen(operators[j].string) > length - i) continue; // Operator too big. + // Priority higher than what we already have. + unsigned long operator_length = strlen(operators[j].string); + if (memcmp(string + i, operators[j].string, operator_length) == 0) { + if (operator_index != -1 && operators[operator_index].priority < operators[j].priority) { + /* for supporting = vs ==, etc*/ + i += operator_length - 1; + continue; + } + // Found an operator! + operator_pos = i; + operator_index = j; + /* for supporting = vs ==, etc*/ + i += operator_length - 1; + break; + } + } + } + } + if (operator_index != -1) { + unsigned right_start = (unsigned)(operator_pos + strlen(operators[operator_index].string)); + value_t right = debugger_evaluate(gb, string + right_start, length - right_start, error, watchpoint_address, watchpoint_new_value); + if (*error) goto exit; + if (operators[operator_index].lvalue_operator) { + lvalue_t left = debugger_evaluate_lvalue(gb, string, operator_pos, error, watchpoint_address, watchpoint_new_value); + if (*error) goto exit; + ret = operators[operator_index].lvalue_operator(gb, left, right.value); + goto exit; + } + value_t left = debugger_evaluate(gb, string, operator_pos, error, watchpoint_address, watchpoint_new_value); + if (*error) goto exit; + ret = operators[operator_index].operator(left, right); + goto exit; + } + + // Not an expression - must be a register or a literal + + // Registers + if (string[0] != '$' && (string[0] < '0' || string[0] > '9')) { + if (length == 1) { + switch (string[0]) { + case 'a': ret = VALUE_16(gb->registers[GB_REGISTER_AF] >> 8); goto exit; + case 'f': ret = VALUE_16(gb->registers[GB_REGISTER_AF] & 0xFF); goto exit; + case 'b': ret = VALUE_16(gb->registers[GB_REGISTER_BC] >> 8); goto exit; + case 'c': ret = VALUE_16(gb->registers[GB_REGISTER_BC] & 0xFF); goto exit; + case 'd': ret = VALUE_16(gb->registers[GB_REGISTER_DE] >> 8); goto exit; + case 'e': ret = VALUE_16(gb->registers[GB_REGISTER_DE] & 0xFF); goto exit; + case 'h': ret = VALUE_16(gb->registers[GB_REGISTER_HL] >> 8); goto exit; + case 'l': ret = VALUE_16(gb->registers[GB_REGISTER_HL] & 0xFF); goto exit; + } + } + else if (length == 2) { + switch (string[0]) { + case 'a': if (string[1] == 'f') {ret = VALUE_16(gb->registers[GB_REGISTER_AF]); goto exit;} + case 'b': if (string[1] == 'c') {ret = VALUE_16(gb->registers[GB_REGISTER_BC]); goto exit;} + case 'd': if (string[1] == 'e') {ret = VALUE_16(gb->registers[GB_REGISTER_DE]); goto exit;} + case 'h': if (string[1] == 'l') {ret = VALUE_16(gb->registers[GB_REGISTER_HL]); goto exit;} + case 's': if (string[1] == 'p') {ret = VALUE_16(gb->registers[GB_REGISTER_SP]); goto exit;} + case 'p': if (string[1] == 'c') {ret = (value_t){true, bank_for_addr(gb, gb->pc), gb->pc}; goto exit;} + } + } + else if (length == 3) { + if (watchpoint_address && memcmp(string, "old", 3) == 0) { + ret = VALUE_16(GB_read_memory(gb, *watchpoint_address)); + goto exit; + } + + if (watchpoint_new_value && memcmp(string, "new", 3) == 0) { + ret = VALUE_16(*watchpoint_new_value); + goto exit; + } + + /* $new is identical to $old in read conditions */ + if (watchpoint_address && memcmp(string, "new", 3) == 0) { + ret = VALUE_16(GB_read_memory(gb, *watchpoint_address)); + goto exit; + } + } + + char symbol_name[length + 1]; + memcpy(symbol_name, string, length); + symbol_name[length] = 0; + const GB_symbol_t *symbol = GB_reversed_map_find_symbol(&gb->reversed_symbol_map, symbol_name); + if (symbol) { + ret = (value_t){true, symbol->bank, symbol->addr}; + goto exit; + } + + GB_log(gb, "Unknown register or symbol: %.*s\n", (unsigned) length, string); + *error = true; + goto exit; + } + + char *end; + int base = 10; + if (string[0] == '$') { + string++; + base = 16; + length--; + } + uint16_t literal = (uint16_t) (strtol(string, &end, base)); + if (end != string + length) { + GB_log(gb, "Failed to parse: %.*s\n", (unsigned) length, string); + *error = true; + goto exit; + } + ret = VALUE_16(literal); +exit: + gb->n_watchpoints = n_watchpoints; + return ret; +} + +struct debugger_command_s; +typedef bool debugger_command_imp_t(GB_gameboy_t *gb, char *arguments, char *modifiers, const struct debugger_command_s *command); + +typedef struct debugger_command_s { + const char *command; + uint8_t min_length; + debugger_command_imp_t *implementation; + const char *help_string; // Null if should not appear in help + const char *arguments_format; // For usage message + const char *modifiers_format; // For usage message +} debugger_command_t; + +static const char *lstrip(const char *str) +{ + while (*str == ' ' || *str == '\t') { + str++; + } + return str; +} + +#define STOPPED_ONLY \ +if (!gb->debug_stopped) { \ +GB_log(gb, "Program is running. \n"); \ +return false; \ +} + +#define NO_MODIFIERS \ +if (modifiers) { \ +print_usage(gb, command); \ +return true; \ +} + +static void print_usage(GB_gameboy_t *gb, const debugger_command_t *command) +{ + GB_log(gb, "Usage: %s", command->command); + + if (command->modifiers_format) { + GB_log(gb, "[/%s]", command->modifiers_format); + } + + if (command->arguments_format) { + GB_log(gb, " %s", command->arguments_format); + } + + GB_log(gb, "\n"); +} + +static bool cont(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + STOPPED_ONLY + + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + gb->debug_stopped = false; + return false; +} + +static bool next(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + STOPPED_ONLY + + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + gb->debug_stopped = false; + gb->debug_next_command = true; + gb->debug_call_depth = 0; + return false; +} + +static bool step(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + STOPPED_ONLY + + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + return false; +} + +static bool finish(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + STOPPED_ONLY + + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + gb->debug_stopped = false; + gb->debug_fin_command = true; + gb->debug_call_depth = 0; + return false; +} + +static bool stack_leak_detection(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + STOPPED_ONLY + + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + gb->debug_stopped = false; + gb->stack_leak_detection = true; + gb->debug_call_depth = 0; + return false; +} + +static bool registers(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + + GB_log(gb, "AF = $%04x (%c%c%c%c)\n", gb->registers[GB_REGISTER_AF], /* AF can't really be an address */ + (gb->f & GB_CARRY_FLAG)? 'C' : '-', + (gb->f & GB_HALF_CARRY_FLAG)? 'H' : '-', + (gb->f & GB_SUBSTRACT_FLAG)? 'N' : '-', + (gb->f & GB_ZERO_FLAG)? 'Z' : '-'); + GB_log(gb, "BC = %s\n", value_to_string(gb, gb->registers[GB_REGISTER_BC], false)); + GB_log(gb, "DE = %s\n", value_to_string(gb, gb->registers[GB_REGISTER_DE], false)); + GB_log(gb, "HL = %s\n", value_to_string(gb, gb->registers[GB_REGISTER_HL], false)); + GB_log(gb, "SP = %s\n", value_to_string(gb, gb->registers[GB_REGISTER_SP], false)); + GB_log(gb, "PC = %s\n", value_to_string(gb, gb->pc, false)); + return true; +} + +/* Find the index of the closest breakpoint equal or greater to addr */ +static uint16_t find_breakpoint(GB_gameboy_t *gb, value_t addr) +{ + if (!gb->breakpoints) { + return 0; + } + + uint32_t key = BP_KEY(addr); + + int min = 0; + int max = gb->n_breakpoints; + while (min < max) { + uint16_t pivot = (min + max) / 2; + if (gb->breakpoints[pivot].key == key) return pivot; + if (gb->breakpoints[pivot].key > key) { + max = pivot; + } + else { + min = pivot + 1; + } + } + return (uint16_t) min; +} + +static bool breakpoint(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + bool is_jump_to = true; + if (!modifiers) { + is_jump_to = false; + } + else if (strcmp(modifiers, "j") != 0) { + print_usage(gb, command); + return true; + } + + if (strlen(lstrip(arguments)) == 0) { + print_usage(gb, command); + return true; + } + + if (gb->n_breakpoints == (typeof(gb->n_breakpoints)) -1) { + GB_log(gb, "Too many breakpoints set\n"); + return true; + } + + char *condition = NULL; + if ((condition = strstr(arguments, " if "))) { + *condition = 0; + condition += strlen(" if "); + /* Verify condition is sane (Todo: This might have side effects!) */ + bool error; + debugger_evaluate(gb, condition, (unsigned)strlen(condition), &error, NULL, NULL); + if (error) return true; + + } + + bool error; + value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + uint32_t key = BP_KEY(result); + + if (error) return true; + + uint16_t index = find_breakpoint(gb, result); + if (index < gb->n_breakpoints && gb->breakpoints[index].key == key) { + GB_log(gb, "Breakpoint already set at %s\n", debugger_value_to_string(gb, result, true)); + if (!gb->breakpoints[index].condition && condition) { + GB_log(gb, "Added condition to breakpoint\n"); + gb->breakpoints[index].condition = strdup(condition); + } + else if (gb->breakpoints[index].condition && condition) { + GB_log(gb, "Replaced breakpoint condition\n"); + free(gb->breakpoints[index].condition); + gb->breakpoints[index].condition = strdup(condition); + } + else if (gb->breakpoints[index].condition && !condition) { + GB_log(gb, "Removed breakpoint condition\n"); + free(gb->breakpoints[index].condition); + gb->breakpoints[index].condition = NULL; + } + return true; + } + + gb->breakpoints = realloc(gb->breakpoints, (gb->n_breakpoints + 1) * sizeof(gb->breakpoints[0])); + memmove(&gb->breakpoints[index + 1], &gb->breakpoints[index], (gb->n_breakpoints - index) * sizeof(gb->breakpoints[0])); + gb->breakpoints[index].key = key; + + if (condition) { + gb->breakpoints[index].condition = strdup(condition); + } + else { + gb->breakpoints[index].condition = NULL; + } + gb->n_breakpoints++; + + gb->breakpoints[index].is_jump_to = is_jump_to; + + if (is_jump_to) { + gb->has_jump_to_breakpoints = true; + } + + GB_log(gb, "Breakpoint set at %s\n", debugger_value_to_string(gb, result, true)); + return true; +} + +static bool delete(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + if (strlen(lstrip(arguments)) == 0) { + for (unsigned i = gb->n_breakpoints; i--;) { + if (gb->breakpoints[i].condition) { + free(gb->breakpoints[i].condition); + } + } + free(gb->breakpoints); + gb->breakpoints = NULL; + gb->n_breakpoints = 0; + return true; + } + + bool error; + value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + uint32_t key = BP_KEY(result); + + if (error) return true; + + uint16_t index = 0; + for (unsigned i = 0; i < gb->n_breakpoints; i++) { + if (gb->breakpoints[i].key == key) { + /* Full match */ + index = i; + break; + } + if (gb->breakpoints[i].addr == result.value && result.has_bank != (gb->breakpoints[i].bank != (uint16_t) -1)) { + /* Partial match */ + index = i; + } + } + + if (index >= gb->n_breakpoints) { + GB_log(gb, "No breakpoint set at %s\n", debugger_value_to_string(gb, result, true)); + return true; + } + + result.bank = gb->breakpoints[index].bank; + result.has_bank = gb->breakpoints[index].bank != (uint16_t) -1; + + if (gb->breakpoints[index].condition) { + free(gb->breakpoints[index].condition); + } + + if (gb->breakpoints[index].is_jump_to) { + gb->has_jump_to_breakpoints = false; + for (unsigned i = 0; i < gb->n_breakpoints; i++) { + if (i == index) continue; + if (gb->breakpoints[i].is_jump_to) { + gb->has_jump_to_breakpoints = true; + break; + } + } + } + + memmove(&gb->breakpoints[index], &gb->breakpoints[index + 1], (gb->n_breakpoints - index - 1) * sizeof(gb->breakpoints[0])); + gb->n_breakpoints--; + gb->breakpoints = realloc(gb->breakpoints, gb->n_breakpoints * sizeof(gb->breakpoints[0])); + + GB_log(gb, "Breakpoint removed from %s\n", debugger_value_to_string(gb, result, true)); + return true; +} + +/* Find the index of the closest watchpoint equal or greater to addr */ +static uint16_t find_watchpoint(GB_gameboy_t *gb, value_t addr) +{ + if (!gb->watchpoints) { + return 0; + } + uint32_t key = WP_KEY(addr); + int min = 0; + int max = gb->n_watchpoints; + while (min < max) { + uint16_t pivot = (min + max) / 2; + if (gb->watchpoints[pivot].key == key) return pivot; + if (gb->watchpoints[pivot].key > key) { + max = pivot; + } + else { + min = pivot + 1; + } + } + return (uint16_t) min; +} + +static bool watch(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + if (strlen(lstrip(arguments)) == 0) { +print_usage: + print_usage(gb, command); + return true; + } + + if (gb->n_watchpoints == (typeof(gb->n_watchpoints)) -1) { + GB_log(gb, "Too many watchpoints set\n"); + return true; + } + + if (!modifiers) { + modifiers = "w"; + } + + uint8_t flags = 0; + while (*modifiers) { + switch (*modifiers) { + case 'r': + flags |= GB_WATCHPOINT_R; + break; + case 'w': + flags |= GB_WATCHPOINT_W; + break; + default: + goto print_usage; + } + modifiers++; + } + + if (!flags) { + goto print_usage; + } + + char *condition = NULL; + if ((condition = strstr(arguments, " if "))) { + *condition = 0; + condition += strlen(" if "); + /* Verify condition is sane (Todo: This might have side effects!) */ + bool error; + /* To make $new and $old legal */ + uint16_t dummy = 0; + uint8_t dummy2 = 0; + debugger_evaluate(gb, condition, (unsigned)strlen(condition), &error, &dummy, &dummy2); + if (error) return true; + + } + + bool error; + value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + uint32_t key = WP_KEY(result); + + if (error) return true; + + uint16_t index = find_watchpoint(gb, result); + if (index < gb->n_watchpoints && gb->watchpoints[index].key == key) { + GB_log(gb, "Watchpoint already set at %s\n", debugger_value_to_string(gb, result, true)); + if (gb->watchpoints[index].flags != flags) { + GB_log(gb, "Modified watchpoint type\n"); + gb->watchpoints[index].flags = flags; + } + if (!gb->watchpoints[index].condition && condition) { + GB_log(gb, "Added condition to watchpoint\n"); + gb->watchpoints[index].condition = strdup(condition); + } + else if (gb->watchpoints[index].condition && condition) { + GB_log(gb, "Replaced watchpoint condition\n"); + free(gb->watchpoints[index].condition); + gb->watchpoints[index].condition = strdup(condition); + } + else if (gb->watchpoints[index].condition && !condition) { + GB_log(gb, "Removed watchpoint condition\n"); + free(gb->watchpoints[index].condition); + gb->watchpoints[index].condition = NULL; + } + return true; + } + + gb->watchpoints = realloc(gb->watchpoints, (gb->n_watchpoints + 1) * sizeof(gb->watchpoints[0])); + memmove(&gb->watchpoints[index + 1], &gb->watchpoints[index], (gb->n_watchpoints - index) * sizeof(gb->watchpoints[0])); + gb->watchpoints[index].key = key; + gb->watchpoints[index].flags = flags; + if (condition) { + gb->watchpoints[index].condition = strdup(condition); + } + else { + gb->watchpoints[index].condition = NULL; + } + gb->n_watchpoints++; + + GB_log(gb, "Watchpoint set at %s\n", debugger_value_to_string(gb, result, true)); + return true; +} + +static bool unwatch(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + if (strlen(lstrip(arguments)) == 0) { + for (unsigned i = gb->n_watchpoints; i--;) { + if (gb->watchpoints[i].condition) { + free(gb->watchpoints[i].condition); + } + } + free(gb->watchpoints); + gb->watchpoints = NULL; + gb->n_watchpoints = 0; + return true; + } + + bool error; + value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + uint32_t key = WP_KEY(result); + + if (error) return true; + + uint16_t index = 0; + for (unsigned i = 0; i < gb->n_watchpoints; i++) { + if (gb->watchpoints[i].key == key) { + /* Full match */ + index = i; + break; + } + if (gb->watchpoints[i].addr == result.value && result.has_bank != (gb->watchpoints[i].bank != (uint16_t) -1)) { + /* Partial match */ + index = i; + } + } + + if (index >= gb->n_watchpoints) { + GB_log(gb, "No watchpoint set at %s\n", debugger_value_to_string(gb, result, true)); + return true; + } + + result.bank = gb->watchpoints[index].bank; + result.has_bank = gb->watchpoints[index].bank != (uint16_t) -1; + + if (gb->watchpoints[index].condition) { + free(gb->watchpoints[index].condition); + } + + memmove(&gb->watchpoints[index], &gb->watchpoints[index + 1], (gb->n_watchpoints - index - 1) * sizeof(gb->watchpoints[0])); + gb->n_watchpoints--; + gb->watchpoints = realloc(gb->watchpoints, gb->n_watchpoints* sizeof(gb->watchpoints[0])); + + GB_log(gb, "Watchpoint removed from %s\n", debugger_value_to_string(gb, result, true)); + return true; +} + +static bool list(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + if (gb->n_breakpoints == 0) { + GB_log(gb, "No breakpoints set.\n"); + } + else { + GB_log(gb, "%d breakpoint(s) set:\n", gb->n_breakpoints); + for (uint16_t i = 0; i < gb->n_breakpoints; i++) { + value_t addr = (value_t){gb->breakpoints[i].bank != (uint16_t)-1, gb->breakpoints[i].bank, gb->breakpoints[i].addr}; + if (gb->breakpoints[i].condition) { + GB_log(gb, " %d. %s (%sCondition: %s)\n", i + 1, + debugger_value_to_string(gb, addr, addr.has_bank), + gb->breakpoints[i].is_jump_to? "Jump to, ": "", + gb->breakpoints[i].condition); + } + else { + GB_log(gb, " %d. %s%s\n", i + 1, + debugger_value_to_string(gb, addr, addr.has_bank), + gb->breakpoints[i].is_jump_to? " (Jump to)" : ""); + } + } + } + + if (gb->n_watchpoints == 0) { + GB_log(gb, "No watchpoints set.\n"); + } + else { + GB_log(gb, "%d watchpoint(s) set:\n", gb->n_watchpoints); + for (uint16_t i = 0; i < gb->n_watchpoints; i++) { + value_t addr = (value_t){gb->watchpoints[i].bank != (uint16_t)-1, gb->watchpoints[i].bank, gb->watchpoints[i].addr}; + if (gb->watchpoints[i].condition) { + GB_log(gb, " %d. %s (%c%c, Condition: %s)\n", i + 1, debugger_value_to_string(gb, addr, addr.has_bank), + (gb->watchpoints[i].flags & GB_WATCHPOINT_R)? 'r' : '-', + (gb->watchpoints[i].flags & GB_WATCHPOINT_W)? 'w' : '-', + gb->watchpoints[i].condition); + } + else { + GB_log(gb, " %d. %s (%c%c)\n", i + 1, debugger_value_to_string(gb,addr, addr.has_bank), + (gb->watchpoints[i].flags & GB_WATCHPOINT_R)? 'r' : '-', + (gb->watchpoints[i].flags & GB_WATCHPOINT_W)? 'w' : '-'); + } + } + } + + return true; +} + +static bool _should_break(GB_gameboy_t *gb, value_t addr, bool jump_to) +{ + uint16_t index = find_breakpoint(gb, addr); + uint32_t key = BP_KEY(addr); + + if (index < gb->n_breakpoints && gb->breakpoints[index].key == key && gb->breakpoints[index].is_jump_to == jump_to) { + if (!gb->breakpoints[index].condition) { + return true; + } + bool error; + bool condition = debugger_evaluate(gb, gb->breakpoints[index].condition, + (unsigned)strlen(gb->breakpoints[index].condition), &error, NULL, NULL).value; + if (error) { + /* Should never happen */ + GB_log(gb, "An internal error has occured\n"); + return true; + } + return condition; + } + return false; +} + +static bool should_break(GB_gameboy_t *gb, uint16_t addr, bool jump_to) +{ + /* Try any-bank breakpoint */ + value_t full_addr = (VALUE_16(addr)); + if (_should_break(gb, full_addr, jump_to)) return true; + + /* Try bank-specific breakpoint */ + full_addr.has_bank = true; + full_addr.bank = bank_for_addr(gb, addr); + return _should_break(gb, full_addr, jump_to); +} + +static bool print(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + if (strlen(lstrip(arguments)) == 0) { + print_usage(gb, command); + return true; + } + + if (!modifiers || !modifiers[0]) { + modifiers = "a"; + } + else if (modifiers[1]) { + print_usage(gb, command); + return true; + } + + bool error; + value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + if (!error) { + switch (modifiers[0]) { + case 'a': + GB_log(gb, "=%s\n", debugger_value_to_string(gb, result, false)); + break; + case 'd': + GB_log(gb, "=%d\n", result.value); + break; + case 'x': + GB_log(gb, "=$%x\n", result.value); + break; + case 'o': + GB_log(gb, "=0%o\n", result.value); + break; + case 'b': + { + if (!result.value) { + GB_log(gb, "=%%0\n"); + break; + } + char binary[17]; + binary[16] = 0; + char *ptr = &binary[16]; + while (result.value) { + *(--ptr) = (result.value & 1)? '1' : '0'; + result.value >>= 1; + } + GB_log(gb, "=%%%s\n", ptr); + break; + } + default: + break; + } + } + return true; +} + +static bool examine(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + if (strlen(lstrip(arguments)) == 0) { + print_usage(gb, command); + return true; + } + + bool error; + value_t addr = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + uint16_t count = 32; + + if (modifiers) { + char *end; + count = (uint16_t) (strtol(modifiers, &end, 10)); + if (*end) { + print_usage(gb, command); + return true; + } + } + + if (!error) { + if (addr.has_bank) { + banking_state_t old_state; + save_banking_state(gb, &old_state); + switch_banking_state(gb, addr.bank); + + while (count) { + GB_log(gb, "%02x:%04x: ", addr.bank, addr.value); + for (int i = 0; i < 16 && count; i++) { + GB_log(gb, "%02x ", GB_read_memory(gb, addr.value + i)); + count--; + } + addr.value += 16; + GB_log(gb, "\n"); + } + + restore_banking_state(gb, &old_state); + } + else { + while (count) { + GB_log(gb, "%04x: ", addr.value); + for (int i = 0; i < 16 && count; i++) { + GB_log(gb, "%02x ", GB_read_memory(gb, addr.value + i)); + count--; + } + addr.value += 16; + GB_log(gb, "\n"); + } + } + } + return true; +} + +static bool disassemble(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + if (strlen(lstrip(arguments)) == 0) { + arguments = "pc"; + } + + bool error; + value_t addr = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + uint16_t count = 5; + + if (modifiers) { + char *end; + count = (uint16_t) (strtol(modifiers, &end, 10)); + if (*end) { + print_usage(gb, command); + return true; + } + } + + if (!error) { + if (addr.has_bank) { + banking_state_t old_state; + save_banking_state(gb, &old_state); + switch_banking_state(gb, addr.bank); + + GB_cpu_disassemble(gb, addr.value, count); + + restore_banking_state(gb, &old_state); + } + else { + GB_cpu_disassemble(gb, addr.value, count); + } + } + return true; +} + +static bool mbc(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + const GB_cartridge_t *cartridge = gb->cartridge_type; + + if (cartridge->has_ram) { + GB_log(gb, "Cartrdige includes%s RAM: $%x bytes\n", cartridge->has_battery? " battery-backed": "", gb->mbc_ram_size); + } + else { + GB_log(gb, "No cartridge RAM\n"); + } + + if (cartridge->mbc_type) { + static const char * const mapper_names[] = { + [GB_MBC1] = "MBC1", + [GB_MBC2] = "MBC2", + [GB_MBC3] = "MBC3", + [GB_MBC5] = "MBC5", + [GB_HUC1] = "HUC1", + [GB_HUC3] = "HUC3", + }; + GB_log(gb, "%s\n", mapper_names[cartridge->mbc_type]); + GB_log(gb, "Current mapped ROM bank: %x\n", gb->mbc_rom_bank); + if (cartridge->has_ram) { + GB_log(gb, "Current mapped RAM bank: %x\n", gb->mbc_ram_bank); + GB_log(gb, "RAM is curently %s\n", gb->mbc_ram_enable? "enabled" : "disabled"); + } + if (cartridge->mbc_type == GB_MBC1 && gb->mbc1_wiring == GB_STANDARD_MBC1_WIRING) { + GB_log(gb, "MBC1 banking mode is %s\n", gb->mbc1.mode == 1 ? "RAM" : "ROM"); + } + if (cartridge->mbc_type == GB_MBC1 && gb->mbc1_wiring == GB_MBC1M_WIRING) { + GB_log(gb, "MBC1 uses MBC1M wiring. \n"); + GB_log(gb, "Current mapped ROM0 bank: %x\n", gb->mbc_rom0_bank); + GB_log(gb, "MBC1 multicart banking mode is %s\n", gb->mbc1.mode == 1 ? "enabled" : "disabled"); + } + + } + else { + GB_log(gb, "No MBC\n"); + } + + if (cartridge->has_rumble) { + GB_log(gb, "Cart contains a rumble pak\n"); + } + + if (cartridge->has_rtc) { + GB_log(gb, "Cart contains a real time clock\n"); + } + + return true; +} + +static bool backtrace(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + GB_log(gb, " 1. %s\n", debugger_value_to_string(gb, (value_t){true, bank_for_addr(gb, gb->pc), gb->pc}, true)); + for (unsigned i = gb->backtrace_size; i--;) { + GB_log(gb, "%3d. %s\n", gb->backtrace_size - i + 1, debugger_value_to_string(gb, (value_t){true, gb->backtrace_returns[i].bank, gb->backtrace_returns[i].addr}, true)); + } + + return true; +} + +static bool ticks(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + STOPPED_ONLY + + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + GB_log(gb, "Ticks: %lu. (Resetting)\n", gb->debugger_ticks); + gb->debugger_ticks = 0; + + return true; +} + + +static bool palettes(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + if (!GB_is_cgb(gb)) { + GB_log(gb, "Not available on a DMG.\n"); + return true; + } + + GB_log(gb, "Background palettes: \n"); + for (unsigned i = 0; i < 32; i++) { + GB_log(gb, "%04x ", ((uint16_t *)&gb->background_palettes_data)[i]); + if (i % 4 == 3) { + GB_log(gb, "\n"); + } + } + + GB_log(gb, "Sprites palettes: \n"); + for (unsigned i = 0; i < 32; i++) { + GB_log(gb, "%04x ", ((uint16_t *)&gb->sprite_palettes_data)[i]); + if (i % 4 == 3) { + GB_log(gb, "\n"); + } + } + + return true; +} + +static bool lcd(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + GB_log(gb, "LCDC:\n"); + GB_log(gb, " LCD enabled: %s\n",(gb->io_registers[GB_IO_LCDC] & 128)? "Enabled" : "Disabled"); + GB_log(gb, " %s: %s\n", (gb->cgb_mode? "Sprite priority flags" : "Background and Window"), + (gb->io_registers[GB_IO_LCDC] & 1)? "Enabled" : "Disabled"); + GB_log(gb, " Objects: %s\n", (gb->io_registers[GB_IO_LCDC] & 2)? "Enabled" : "Disabled"); + GB_log(gb, " Object size: %s\n", (gb->io_registers[GB_IO_LCDC] & 4)? "8x16" : "8x8"); + GB_log(gb, " Background tilemap: %s\n", (gb->io_registers[GB_IO_LCDC] & 8)? "$9C00" : "$9800"); + GB_log(gb, " Background and Window Tileset: %s\n", (gb->io_registers[GB_IO_LCDC] & 16)? "$8000" : "$8800"); + GB_log(gb, " Window: %s\n", (gb->io_registers[GB_IO_LCDC] & 32)? "Enabled" : "Disabled"); + GB_log(gb, " Window tilemap: %s\n", (gb->io_registers[GB_IO_LCDC] & 64)? "$9C00" : "$9800"); + + GB_log(gb, "\nSTAT:\n"); + static const char *modes[] = {"Mode 0, H-Blank", "Mode 1, V-Blank", "Mode 2, OAM", "Mode 3, Rendering"}; + GB_log(gb, " Current mode: %s\n", modes[gb->io_registers[GB_IO_STAT] & 3]); + GB_log(gb, " LYC flag: %s\n", (gb->io_registers[GB_IO_STAT] & 4)? "On" : "Off"); + GB_log(gb, " H-Blank interrupt: %s\n", (gb->io_registers[GB_IO_STAT] & 8)? "Enabled" : "Disabled"); + GB_log(gb, " V-Blank interrupt: %s\n", (gb->io_registers[GB_IO_STAT] & 16)? "Enabled" : "Disabled"); + GB_log(gb, " OAM interrupt: %s\n", (gb->io_registers[GB_IO_STAT] & 32)? "Enabled" : "Disabled"); + GB_log(gb, " LYC interrupt: %s\n", (gb->io_registers[GB_IO_STAT] & 64)? "Enabled" : "Disabled"); + + + + GB_log(gb, "\nCurrent line: %d\n", gb->current_line); + GB_log(gb, "Current state: "); + if (!(gb->io_registers[GB_IO_LCDC] & 0x80)) { + GB_log(gb, "Off\n"); + } + else if (gb->display_state == 7 || gb->display_state == 8) { + GB_log(gb, "Reading OAM data (%d/40)\n", gb->display_state == 8? gb->oam_search_index : 0); + } + else if (gb->display_state <= 3 || gb->display_state == 24 || gb->display_state == 31) { + GB_log(gb, "Glitched line 0 OAM mode (%d cycles to next event)\n", -gb->display_cycles / 2); + } + else if (gb->mode_for_interrupt == 3) { + signed pixel = gb->position_in_line > 160? (int8_t) gb->position_in_line : gb->position_in_line; + GB_log(gb, "Rendering pixel (%d/160)\n", pixel); + } + else { + GB_log(gb, "Sleeping (%d cycles to next event)\n", -gb->display_cycles / 2); + } + GB_log(gb, "LY: %d\n", gb->io_registers[GB_IO_LY]); + GB_log(gb, "LYC: %d\n", gb->io_registers[GB_IO_LYC]); + GB_log(gb, "Window position: %d, %d\n", (signed) gb->io_registers[GB_IO_WX] - 7 , gb->io_registers[GB_IO_WY]); + GB_log(gb, "Interrupt line: %s\n", gb->stat_interrupt_line? "On" : "Off"); + + return true; +} + +static bool apu(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + + GB_log(gb, "Current state: "); + if (!gb->apu.global_enable) { + GB_log(gb, "Disabled\n"); + } + else { + GB_log(gb, "Enabled\n"); + for (uint8_t channel = 0; channel < GB_N_CHANNELS; channel++) { + GB_log(gb, "CH%u is %s, DAC %s; current sample = 0x%x\n", channel + 1, + gb->apu.is_active[channel] ? "active " : "inactive", + GB_apu_is_DAC_enabled(gb, channel) ? "active " : "inactive", + gb->apu.samples[channel]); + } + } + + GB_log(gb, "SO1 (left output): volume %u,", gb->io_registers[GB_IO_NR50] & 0x07); + if (gb->io_registers[GB_IO_NR51] & 0x0f) { + for (uint8_t channel = 0, mask = 0x01; channel < GB_N_CHANNELS; channel++, mask <<= 1) { + if (gb->io_registers[GB_IO_NR51] & mask) { + GB_log(gb, " CH%u", channel + 1); + } + } + } + else { + GB_log(gb, " no channels"); + } + GB_log(gb, "%s\n", gb->io_registers[GB_IO_NR50] & 0x80 ? " VIN": ""); + + GB_log(gb, "SO2 (right output): volume %u,", gb->io_registers[GB_IO_NR50] & 0x70 >> 4); + if (gb->io_registers[GB_IO_NR51] & 0xf0) { + for (uint8_t channel = 0, mask = 0x10; channel < GB_N_CHANNELS; channel++, mask <<= 1) { + if (gb->io_registers[GB_IO_NR51] & mask) { + GB_log(gb, " CH%u", channel + 1); + } + } + } + else { + GB_log(gb, " no channels"); + } + GB_log(gb, "%s\n", gb->io_registers[GB_IO_NR50] & 0x80 ? " VIN": ""); + + + for (uint8_t channel = GB_SQUARE_1; channel <= GB_SQUARE_2; channel++) { + GB_log(gb, "\nCH%u:\n", channel + 1); + GB_log(gb, " Current volume: %u, current sample length: %u APU ticks (next in %u ticks)\n", + gb->apu.square_channels[channel].current_volume, + (gb->apu.square_channels[channel].sample_length ^ 0x7FF) * 2 + 1, + gb->apu.square_channels[channel].sample_countdown); + + uint8_t nrx2 = gb->io_registers[channel == GB_SQUARE_1? GB_IO_NR12 : GB_IO_NR22]; + GB_log(gb, " %u 256 Hz ticks till next volume %screase (out of %u)\n", + gb->apu.square_channels[channel].volume_countdown, + nrx2 & 8 ? "in" : "de", + nrx2 & 7); + + uint8_t duty = gb->io_registers[channel == GB_SQUARE_1? GB_IO_NR11 :GB_IO_NR21] >> 6; + GB_log(gb, " Duty cycle %s%% (%s), current index %u/8%s\n", + duty > 3? "" : (const char *[]){"12.5", " 25", " 50", " 75"}[duty], + duty > 3? "" : (const char *[]){"_______-", "-______-", "-____---", "_------_"}[duty], + gb->apu.square_channels[channel].current_sample_index & 0x7f, + gb->apu.square_channels[channel].current_sample_index >> 7 ? " (suppressed)" : ""); + + if (channel == GB_SQUARE_1) { + GB_log(gb, " Frequency sweep %s and %s (next in %u APU ticks)\n", + gb->apu.sweep_enabled? "active" : "inactive", + gb->apu.sweep_decreasing? "decreasing" : "increasing", + gb->apu.square_sweep_calculate_countdown); + } + + if (gb->apu.square_channels[channel].length_enabled) { + GB_log(gb, " Channel will end in %u 256 Hz ticks\n", + gb->apu.square_channels[channel].pulse_length); + } + } + + + GB_log(gb, "\nCH3:\n"); + GB_log(gb, " Wave:"); + for (uint8_t i = 0; i < 32; i++) { + GB_log(gb, "%s%X", i%4?"":" ", gb->apu.wave_channel.wave_form[i]); + } + GB_log(gb, "\n"); + GB_log(gb, " Current position: %u\n", gb->apu.wave_channel.current_sample_index); + + GB_log(gb, " Volume %s (right-shifted %u times)\n", + gb->apu.wave_channel.shift > 4? "" : (const char *[]){"100%", "50%", "25%", "", "muted"}[gb->apu.wave_channel.shift], + gb->apu.wave_channel.shift); + + GB_log(gb, " Current sample length: %u APU ticks (next in %u ticks)\n", + gb->apu.wave_channel.sample_length ^ 0x7ff, + gb->apu.wave_channel.sample_countdown); + + if (gb->apu.wave_channel.length_enabled) { + GB_log(gb, " Channel will end in %u 256 Hz ticks\n", + gb->apu.wave_channel.pulse_length); + } + + + GB_log(gb, "\nCH4:\n"); + GB_log(gb, " Current volume: %u, current sample length: %u APU ticks (next in %u ticks)\n", + gb->apu.noise_channel.current_volume, + gb->apu.noise_channel.sample_length * 4 + 3, + gb->apu.noise_channel.sample_countdown); + + GB_log(gb, " %u 256 Hz ticks till next volume %screase (out of %u)\n", + gb->apu.noise_channel.volume_countdown, + gb->io_registers[GB_IO_NR42] & 8 ? "in" : "de", + gb->io_registers[GB_IO_NR42] & 7); + + GB_log(gb, " LFSR in %u-step mode, current value ", + gb->apu.noise_channel.narrow? 7 : 15); + for (uint16_t lfsr = gb->apu.noise_channel.lfsr, i = 15; i--; lfsr <<= 1) { + GB_log(gb, "%u%s", (lfsr >> 14) & 1, i%4 ? "" : " "); + } + + if (gb->apu.noise_channel.length_enabled) { + GB_log(gb, " Channel will end in %u 256 Hz ticks\n", + gb->apu.noise_channel.pulse_length); + } + + + GB_log(gb, "\n\nReminder: APU ticks are @ 2 MiHz\n"); + + return true; +} + +static bool wave(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + if (strlen(lstrip(arguments)) || (modifiers && !strchr("fcl", modifiers[0]))) { + print_usage(gb, command); + return true; + } + + uint8_t shift_amount = 1, mask; + if (modifiers) { + switch(modifiers[0]) { + case 'c': + shift_amount = 2; + break; + case 'l': + shift_amount = 8; + break; + } + } + mask = (0xf << (shift_amount - 1)) & 0xf; + + for (int8_t cur_val = 0xf & mask; cur_val >= 0; cur_val -= shift_amount) { + for (uint8_t i = 0; i < 32; i++) { + if ((gb->apu.wave_channel.wave_form[i] & mask) == cur_val) { + GB_log(gb, "%X", gb->apu.wave_channel.wave_form[i]); + } + else { + GB_log(gb, "%c", i%4 == 2 ? '-' : ' '); + } + } + GB_log(gb, "\n"); + } + + return true; +} + +static bool help(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command); + +#define HELP_NEWLINE "\n " + +/* Commands without implementations are aliases of the previous non-alias commands */ +static const debugger_command_t commands[] = { + {"continue", 1, cont, "Continue running until next stop"}, + {"next", 1, next, "Run the next instruction, skipping over function calls"}, + {"step", 1, step, "Run the next instruction, stepping into function calls"}, + {"finish", 1, finish, "Run until the current function returns"}, + {"backtrace", 2, backtrace, "Display the current call stack"}, + {"bt", 2, }, /* Alias */ + {"sld", 3, stack_leak_detection, "Like finish, but stops if a stack leak is detected (Experimental)"}, + {"ticks", 2, ticks, "Display the number of CPU ticks since the last time 'ticks' was used"}, + {"registers", 1, registers, "Print values of processor registers and other important registers"}, + {"cartridge", 2, mbc, "Displays information about the MBC and cartridge"}, + {"mbc", 3, }, /* Alias */ + {"apu", 3, apu, "Displays information about the current state of the audio chip"}, + {"wave", 3, wave, "Prints a visual representation of the wave RAM." HELP_NEWLINE + "Modifiers can be used for a (f)ull print (the default)," HELP_NEWLINE + "a more (c)ompact one, or a one-(l)iner", "", "(f|c|l)"}, + {"lcd", 3, lcd, "Displays information about the current state of the LCD controller"}, + {"palettes", 3, palettes, "Displays the current CGB palettes"}, + {"breakpoint", 1, breakpoint, "Add a new breakpoint at the specified address/expression" HELP_NEWLINE + "Can also modify the condition of existing breakpoints." HELP_NEWLINE + "If the j modifier is used, the breakpoint will occur just before" HELP_NEWLINE + "jumping to the target.", + "[ if ]", "j"}, + {"delete", 2, delete, "Delete a breakpoint by its address, or all breakpoints", "[]"}, + {"watch", 1, watch, "Add a new watchpoint at the specified address/expression." HELP_NEWLINE + "Can also modify the condition and type of existing watchpoints." HELP_NEWLINE + "Default watchpoint type is write-only.", + "[ if ]", "(r|w|rw)"}, + {"unwatch", 3, unwatch, "Delete a watchpoint by its address, or all watchpoints", "[]"}, + {"list", 1, list, "List all set breakpoints and watchpoints"}, + {"print", 1, print, "Evaluate and print an expression" HELP_NEWLINE + "Use modifier to format as an address (a, default) or as a number in" HELP_NEWLINE + "decimal (d), hexadecimal (x), octal (o) or binary (b).", + "", "format"}, + {"eval", 2, }, /* Alias */ + {"examine", 2, examine, "Examine values at address", "", "count"}, + {"x", 1, }, /* Alias */ + {"disassemble", 1, disassemble, "Disassemble instructions at address", "", "count"}, + + + {"help", 1, help, "List available commands or show help for the specified command", "[]"}, + {NULL,}, /* Null terminator */ +}; + +static const debugger_command_t *find_command(const char *string) +{ + size_t length = strlen(string); + for (const debugger_command_t *command = commands; command->command; command++) { + if (command->min_length > length) continue; + if (memcmp(command->command, string, length) == 0) { /* Is a substring? */ + /* Aliases */ + while (!command->implementation) { + command--; + } + return command; + } + } + + return NULL; +} + +static void print_command_shortcut(GB_gameboy_t *gb, const debugger_command_t *command) +{ + GB_attributed_log(gb, GB_LOG_BOLD | GB_LOG_UNDERLINE, "%.*s", command->min_length, command->command); + GB_attributed_log(gb, GB_LOG_BOLD , "%s", command->command + command->min_length); +} + +static void print_command_description(GB_gameboy_t *gb, const debugger_command_t *command) +{ + print_command_shortcut(gb, command); + GB_log(gb, ": "); + GB_log(gb, (const char *)&" %s\n" + strlen(command->command), command->help_string); +} + +static bool help(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *ignored) +{ + const debugger_command_t *command = find_command(arguments); + if (command) { + print_command_description(gb, command); + GB_log(gb, "\n"); + print_usage(gb, command); + + command++; + if (command->command && !command->implementation) { /* Command has aliases*/ + GB_log(gb, "\nAliases: "); + do { + print_command_shortcut(gb, command); + GB_log(gb, " "); + command++; + } while (command->command && !command->implementation); + GB_log(gb, "\n"); + } + return true; + } + for (command = commands; command->command; command++) { + if (command->help_string) { + print_command_description(gb, command); + } + } + return true; +} + +void GB_debugger_call_hook(GB_gameboy_t *gb, uint16_t call_addr) +{ + /* Called just after the CPU calls a function/enters an interrupt/etc... */ + + if (gb->stack_leak_detection) { + if (gb->debug_call_depth >= sizeof(gb->sp_for_call_depth) / sizeof(gb->sp_for_call_depth[0])) { + GB_log(gb, "Potential stack overflow detected (Functions nest too much). \n"); + gb->debug_stopped = true; + } + else { + gb->sp_for_call_depth[gb->debug_call_depth] = gb->registers[GB_REGISTER_SP]; + gb->addr_for_call_depth[gb->debug_call_depth] = gb->pc; + } + } + + if (gb->backtrace_size < sizeof(gb->backtrace_sps) / sizeof(gb->backtrace_sps[0])) { + + while (gb->backtrace_size) { + if (gb->backtrace_sps[gb->backtrace_size - 1] < gb->registers[GB_REGISTER_SP]) { + gb->backtrace_size--; + } + else { + break; + } + } + + gb->backtrace_sps[gb->backtrace_size] = gb->registers[GB_REGISTER_SP]; + gb->backtrace_returns[gb->backtrace_size].bank = bank_for_addr(gb, call_addr); + gb->backtrace_returns[gb->backtrace_size].addr = call_addr; + gb->backtrace_size++; + } + + gb->debug_call_depth++; +} + +void GB_debugger_ret_hook(GB_gameboy_t *gb) +{ + /* Called just before the CPU runs ret/reti */ + + gb->debug_call_depth--; + + if (gb->stack_leak_detection) { + if (gb->debug_call_depth < 0) { + GB_log(gb, "Function finished without a stack leak.\n"); + gb->debug_stopped = true; + } + else { + if (gb->registers[GB_REGISTER_SP] != gb->sp_for_call_depth[gb->debug_call_depth]) { + GB_log(gb, "Stack leak detected for function %s!\n", value_to_string(gb, gb->addr_for_call_depth[gb->debug_call_depth], true)); + GB_log(gb, "SP is $%04x, should be $%04x.\n", gb->registers[GB_REGISTER_SP], + gb->sp_for_call_depth[gb->debug_call_depth]); + gb->debug_stopped = true; + } + } + } + + while (gb->backtrace_size) { + if (gb->backtrace_sps[gb->backtrace_size - 1] <= gb->registers[GB_REGISTER_SP]) { + gb->backtrace_size--; + } + else { + break; + } + } +} + +static bool _GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, value_t addr, uint8_t value) +{ + uint16_t index = find_watchpoint(gb, addr); + uint32_t key = WP_KEY(addr); + + if (index < gb->n_watchpoints && gb->watchpoints[index].key == key) { + if (!(gb->watchpoints[index].flags & GB_WATCHPOINT_W)) { + return false; + } + if (!gb->watchpoints[index].condition) { + gb->debug_stopped = true; + GB_log(gb, "Watchpoint: [%s] = $%02x\n", debugger_value_to_string(gb, addr, true), value); + return true; + } + bool error; + bool condition = debugger_evaluate(gb, gb->watchpoints[index].condition, + (unsigned)strlen(gb->watchpoints[index].condition), &error, &addr.value, &value).value; + if (error) { + /* Should never happen */ + GB_log(gb, "An internal error has occured\n"); + return false; + } + if (condition) { + gb->debug_stopped = true; + GB_log(gb, "Watchpoint: [%s] = $%02x\n", debugger_value_to_string(gb, addr, true), value); + return true; + } + } + return false; +} + +void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t value) +{ + if (gb->debug_stopped) return; + + /* Try any-bank breakpoint */ + value_t full_addr = (VALUE_16(addr)); + if (_GB_debugger_test_write_watchpoint(gb, full_addr, value)) return; + + /* Try bank-specific breakpoint */ + full_addr.has_bank = true; + full_addr.bank = bank_for_addr(gb, addr); + _GB_debugger_test_write_watchpoint(gb, full_addr, value); +} + +static bool _GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, value_t addr) +{ + uint16_t index = find_watchpoint(gb, addr); + uint32_t key = WP_KEY(addr); + + if (index < gb->n_watchpoints && gb->watchpoints[index].key == key) { + if (!(gb->watchpoints[index].flags & GB_WATCHPOINT_R)) { + return false; + } + if (!gb->watchpoints[index].condition) { + gb->debug_stopped = true; + GB_log(gb, "Watchpoint: [%s]\n", debugger_value_to_string(gb, addr, true)); + return true; + } + bool error; + bool condition = debugger_evaluate(gb, gb->watchpoints[index].condition, + (unsigned)strlen(gb->watchpoints[index].condition), &error, &addr.value, NULL).value; + if (error) { + /* Should never happen */ + GB_log(gb, "An internal error has occured\n"); + return false; + } + if (condition) { + gb->debug_stopped = true; + GB_log(gb, "Watchpoint: [%s]\n", debugger_value_to_string(gb, addr, true)); + return true; + } + } + return false; +} + +void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr) +{ + if (gb->debug_stopped) return; + + /* Try any-bank breakpoint */ + value_t full_addr = (VALUE_16(addr)); + if (_GB_debugger_test_read_watchpoint(gb, full_addr)) return; + + /* Try bank-specific breakpoint */ + full_addr.has_bank = true; + full_addr.bank = bank_for_addr(gb, addr); + _GB_debugger_test_read_watchpoint(gb, full_addr); +} + +/* Returns true if debugger waits for more commands */ +bool GB_debugger_execute_command(GB_gameboy_t *gb, char *input) +{ + if (!input[0]) { + return true; + } + + char *command_string = input; + char *arguments = strchr(input, ' '); + if (arguments) { + /* Actually "split" the string. */ + arguments[0] = 0; + arguments++; + } + else { + arguments = ""; + } + + char *modifiers = strchr(command_string, '/'); + if (modifiers) { + /* Actually "split" the string. */ + modifiers[0] = 0; + modifiers++; + } + + const debugger_command_t *command = find_command(command_string); + if (command) { + return command->implementation(gb, arguments, modifiers, command); + } + else { + GB_log(gb, "%s: no such command.\n", command_string); + return true; + } +} + +typedef enum { + JUMP_TO_NONE, + JUMP_TO_BREAK, + JUMP_TO_NONTRIVIAL, +} jump_to_return_t; + +static jump_to_return_t test_jump_to_breakpoints(GB_gameboy_t *gb, uint16_t *address); + +void GB_debugger_run(GB_gameboy_t *gb) +{ + if (gb->debug_disable) return; + + char *input = NULL; + if (gb->debug_next_command && gb->debug_call_depth <= 0) { + gb->debug_stopped = true; + } + if (gb->debug_fin_command && gb->debug_call_depth == -1) { + gb->debug_stopped = true; + } + if (gb->debug_stopped) { + GB_cpu_disassemble(gb, gb->pc, 5); + } +next_command: + if (input) { + free(input); + } + if (gb->breakpoints && !gb->debug_stopped && should_break(gb, gb->pc, false)) { + gb->debug_stopped = true; + GB_log(gb, "Breakpoint: PC = %s\n", value_to_string(gb, gb->pc, true)); + GB_cpu_disassemble(gb, gb->pc, 5); + } + + if (gb->breakpoints && !gb->debug_stopped) { + uint16_t address = 0; + jump_to_return_t jump_to_result = test_jump_to_breakpoints(gb, &address); + + bool should_delete_state = true; + if (gb->nontrivial_jump_state && should_break(gb, gb->pc, true)) { + if (gb->non_trivial_jump_breakpoint_occured) { + gb->non_trivial_jump_breakpoint_occured = false; + } + else { + gb->non_trivial_jump_breakpoint_occured = true; + GB_log(gb, "Jumping to breakpoint: PC = %s\n", value_to_string(gb, gb->pc, true)); + GB_cpu_disassemble(gb, gb->pc, 5); + GB_load_state_from_buffer(gb, gb->nontrivial_jump_state, -1); + gb->debug_stopped = true; + } + } + else if (jump_to_result == JUMP_TO_BREAK) { + gb->debug_stopped = true; + GB_log(gb, "Jumping to breakpoint: PC = %s\n", value_to_string(gb, address, true)); + GB_cpu_disassemble(gb, gb->pc, 5); + gb->non_trivial_jump_breakpoint_occured = false; + } + else if (jump_to_result == JUMP_TO_NONTRIVIAL) { + if (!gb->nontrivial_jump_state) { + gb->nontrivial_jump_state = malloc(GB_get_save_state_size(gb)); + } + GB_save_state_to_buffer(gb, gb->nontrivial_jump_state); + gb->non_trivial_jump_breakpoint_occured = false; + should_delete_state = false; + } + else { + gb->non_trivial_jump_breakpoint_occured = false; + } + + if (should_delete_state) { + if (gb->nontrivial_jump_state) { + free(gb->nontrivial_jump_state); + gb->nontrivial_jump_state = NULL; + } + } + } + + if (gb->debug_stopped && !gb->debug_disable) { + gb->debug_next_command = false; + gb->debug_fin_command = false; + gb->stack_leak_detection = false; + input = gb->input_callback(gb); + + if (input == NULL) { + /* Debugging is no currently available, continue running */ + gb->debug_stopped = false; + return; + } + + if (GB_debugger_execute_command(gb, input)) { + goto next_command; + } + + free(input); + } +} + +void GB_debugger_handle_async_commands(GB_gameboy_t *gb) +{ + char *input = NULL; + + while (gb->async_input_callback && (input = gb->async_input_callback(gb))) { + GB_debugger_execute_command(gb, input); + free(input); + } +} + +void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path) +{ + FILE *f = fopen(path, "r"); + if (!f) return; + + char *line = NULL; + size_t size = 0; + size_t length = 0; + while ((length = getline(&line, &size, f)) != -1) { + for (unsigned i = 0; i < length; i++) { + if (line[i] == ';' || line[i] == '\n' || line[i] == '\r') { + line[i] = 0; + length = i; + break; + } + } + if (length == 0) continue; + + unsigned bank, address; + char symbol[length]; + + if (sscanf(line, "%x:%x %s", &bank, &address, symbol) == 3) { + bank &= 0x1FF; + if (!gb->bank_symbols[bank]) { + gb->bank_symbols[bank] = GB_map_alloc(); + } + GB_bank_symbol_t *allocated_symbol = GB_map_add_symbol(gb->bank_symbols[bank], address, symbol); + if (allocated_symbol) { + GB_reversed_map_add_symbol(&gb->reversed_symbol_map, bank, allocated_symbol); + } + } + } + free(line); + fclose(f); +} + +void GB_debugger_clear_symbols(GB_gameboy_t *gb) +{ + for (int i = sizeof(gb->bank_symbols) / sizeof(gb->bank_symbols[0]); i--;) { + if (gb->bank_symbols[i]) { + GB_map_free(gb->bank_symbols[i]); + gb->bank_symbols[i] = 0; + } + } + for (int i = sizeof(gb->reversed_symbol_map.buckets) / sizeof(gb->reversed_symbol_map.buckets[0]); i--;) { + while (gb->reversed_symbol_map.buckets[i]) { + GB_symbol_t *next = gb->reversed_symbol_map.buckets[i]->next; + free(gb->reversed_symbol_map.buckets[i]); + gb->reversed_symbol_map.buckets[i] = next; + } + } +} + +const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr) +{ + uint16_t bank = bank_for_addr(gb, addr); + + const GB_bank_symbol_t *symbol = GB_map_find_symbol(gb->bank_symbols[bank], addr); + if (symbol) return symbol; + if (bank != 0) return GB_map_find_symbol(gb->bank_symbols[0], addr); /* Maybe the symbol incorrectly uses bank 0? */ + + return NULL; +} + +const char *GB_debugger_name_for_address(GB_gameboy_t *gb, uint16_t addr) +{ + const GB_bank_symbol_t *symbol = GB_debugger_find_symbol(gb, addr); + if (symbol && symbol->addr == addr) return symbol->name; + return NULL; +} + +/* The public version of debugger_evaluate */ +bool GB_debugger_evaluate(GB_gameboy_t *gb, const char *string, uint16_t *result, uint16_t *result_bank) +{ + bool error = false; + value_t value = debugger_evaluate(gb, string, strlen(string), &error, NULL, NULL); + if (result) { + *result = value.value; + } + if (result_bank) { + *result_bank = value.has_bank? value.value : -1; + } + return error; +} + +void GB_debugger_break(GB_gameboy_t *gb) +{ + gb->debug_stopped = true; +} + +bool GB_debugger_is_stopped(GB_gameboy_t *gb) +{ + return gb->debug_stopped; +} + +void GB_debugger_set_disabled(GB_gameboy_t *gb, bool disabled) +{ + gb->debug_disable = disabled; +} + +/* Jump-to breakpoints */ + +static bool is_in_trivial_memory(uint16_t addr) +{ + /* ROM */ + if (addr < 0x8000) { + return true; + } + + /* HRAM */ + if (addr >= 0xFF80 && addr < 0xFFFF) { + return true; + } + + /* RAM */ + if (addr >= 0xC000 && addr < 0xE000) { + return true; + } + + return false; +} + +typedef uint16_t GB_opcode_address_getter_t(GB_gameboy_t *gb, uint8_t opcode); + +uint16_t trivial_1(GB_gameboy_t *gb, uint8_t opcode) +{ + return gb->pc + 1; +} + +uint16_t trivial_2(GB_gameboy_t *gb, uint8_t opcode) +{ + return gb->pc + 2; +} + +uint16_t trivial_3(GB_gameboy_t *gb, uint8_t opcode) +{ + return gb->pc + 3; +} + +static uint16_t jr_r8(GB_gameboy_t *gb, uint8_t opcode) +{ + return gb->pc + 2 + (int8_t)GB_read_memory(gb, gb->pc + 1); +} + +static bool condition_code(GB_gameboy_t *gb, uint8_t opcode) +{ + switch ((opcode >> 3) & 0x3) { + case 0: + return !(gb->registers[GB_REGISTER_AF] & GB_ZERO_FLAG); + case 1: + return (gb->registers[GB_REGISTER_AF] & GB_ZERO_FLAG); + case 2: + return !(gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG); + case 3: + return (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG); + } + + return false; +} + +static uint16_t jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode) +{ + if (!condition_code(gb, opcode)) { + return gb->pc + 2; + } + + return gb->pc + 2 + (int8_t)GB_read_memory(gb, gb->pc + 1); +} + +static uint16_t ret(GB_gameboy_t *gb, uint8_t opcode) +{ + return GB_read_memory(gb, gb->registers[GB_REGISTER_SP]) | + (GB_read_memory(gb, gb->registers[GB_REGISTER_SP] + 1) << 8); +} + + +static uint16_t ret_cc(GB_gameboy_t *gb, uint8_t opcode) +{ + if (condition_code(gb, opcode)) { + return ret(gb, opcode); + } + else { + return gb->pc + 1; + } +} + +static uint16_t jp_a16(GB_gameboy_t *gb, uint8_t opcode) +{ + return GB_read_memory(gb, gb->pc + 1) | + (GB_read_memory(gb, gb->pc + 2) << 8); +} + +static uint16_t jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode) +{ + if (condition_code(gb, opcode)) { + return jp_a16(gb, opcode); + } + else { + return gb->pc + 3; + } +} + +static uint16_t rst(GB_gameboy_t *gb, uint8_t opcode) +{ + return opcode ^ 0xC7; +} + +static uint16_t jp_hl(GB_gameboy_t *gb, uint8_t opcode) +{ + return gb->hl; +} + +static GB_opcode_address_getter_t *opcodes[256] = { + /* X0 X1 X2 X3 X4 X5 X6 X7 */ + /* X8 X9 Xa Xb Xc Xd Xe Xf */ + trivial_1, trivial_3, trivial_1, trivial_1, trivial_1, trivial_1, trivial_2, trivial_1, /* 0X */ + trivial_3, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_2, trivial_1, + trivial_2, trivial_3, trivial_1, trivial_1, trivial_1, trivial_1, trivial_2, trivial_1, /* 1X */ + jr_r8, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_2, trivial_1, + jr_cc_r8, trivial_3, trivial_1, trivial_1, trivial_1, trivial_1, trivial_2, trivial_1, /* 2X */ + jr_cc_r8, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_2, trivial_1, + jr_cc_r8, trivial_3, trivial_1, trivial_1, trivial_1, trivial_1, trivial_2, trivial_1, /* 3X */ + jr_cc_r8, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_2, trivial_1, + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, /* 4X */ + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, /* 5X */ + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, /* 6X */ + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, NULL, trivial_1, /* 7X */ + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, /* 8X */ + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, /* 9X */ + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, /* aX */ + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, /* bX */ + trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, trivial_1, + ret_cc, trivial_1, jp_cc_a16, jp_a16, jp_cc_a16, trivial_1, trivial_2, rst, /* cX */ + ret_cc, ret, jp_cc_a16, trivial_2, jp_cc_a16, jp_a16, trivial_2, rst, + ret_cc, trivial_1, jp_cc_a16, NULL, jp_cc_a16, trivial_1, trivial_2, rst, /* dX */ + ret_cc, ret, jp_cc_a16, NULL, jp_cc_a16, NULL, trivial_2, rst, + trivial_2, trivial_1, trivial_1, NULL, NULL, trivial_1, trivial_2, rst, /* eX */ + trivial_2, jp_hl, trivial_3, NULL, NULL, NULL, trivial_2, rst, + trivial_2, trivial_1, trivial_1, trivial_1, NULL, trivial_1, trivial_2, rst, /* fX */ + trivial_2, trivial_1, trivial_3, trivial_1, NULL, NULL, trivial_2, rst, +}; + +static jump_to_return_t test_jump_to_breakpoints(GB_gameboy_t *gb, uint16_t *address) +{ + if (!gb->has_jump_to_breakpoints) return JUMP_TO_NONE; + + if (!is_in_trivial_memory(gb->pc) || !is_in_trivial_memory(gb->pc + 2) || + !is_in_trivial_memory(gb->registers[GB_REGISTER_SP]) || !is_in_trivial_memory(gb->registers[GB_REGISTER_SP] + 1)) { + return JUMP_TO_NONTRIVIAL; + } + + /* Interrupts */ + if (gb->ime) { + for (unsigned i = 0; i < 5; i++) { + if ((gb->interrupt_enable & (1 << i)) && (gb->io_registers[GB_IO_IF] & (1 << i))) { + if (should_break(gb, 0x40 + i * 8, true)) { + if (address) { + *address = 0x40 + i * 8; + } + return JUMP_TO_BREAK; + } + } + } + } + + uint16_t n_watchpoints = gb->n_watchpoints; + gb->n_watchpoints = 0; + + uint8_t opcode = GB_read_memory(gb, gb->pc); + + if (opcode == 0x76) { + gb->n_watchpoints = n_watchpoints; + if (gb->ime) { /* Already handled in above */ + return JUMP_TO_NONE; + } + + if (gb->interrupt_enable & gb->io_registers[GB_IO_IF] & 0x1F) { + return JUMP_TO_NONTRIVIAL; /* HALT bug could occur */ + } + + return JUMP_TO_NONE; + } + + GB_opcode_address_getter_t *getter = opcodes[opcode]; + if (!getter) { + gb->n_watchpoints = n_watchpoints; + return JUMP_TO_NONE; + } + + uint16_t new_pc = getter(gb, opcode); + + gb->n_watchpoints = n_watchpoints; + + if (address) { + *address = new_pc; + } + + return should_break(gb, new_pc, true) ? JUMP_TO_BREAK : JUMP_TO_NONE; +} diff --git a/gb/Core/debugger.h b/gb/Core/debugger.h new file mode 100644 index 0000000..2906ad9 --- /dev/null +++ b/gb/Core/debugger.h @@ -0,0 +1,43 @@ +#ifndef debugger_h +#define debugger_h +#include +#include +#include "gb_struct_def.h" +#include "symbol_hash.h" + + +#ifdef GB_INTERNAL +#ifdef DISABLE_DEBUGGER +#define GB_debugger_run(gb) (void)0 +#define GB_debugger_handle_async_commands(gb) (void)0 +#define GB_debugger_ret_hook(gb) (void)0 +#define GB_debugger_call_hook(gb, addr) (void)addr +#define GB_debugger_test_write_watchpoint(gb, addr, value) ((void)addr, (void)value) +#define GB_debugger_test_read_watchpoint(gb, addr) (void)addr +#else +void GB_debugger_run(GB_gameboy_t *gb); +void GB_debugger_handle_async_commands(GB_gameboy_t *gb); +void GB_debugger_call_hook(GB_gameboy_t *gb, uint16_t call_addr); +void GB_debugger_ret_hook(GB_gameboy_t *gb); +void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t value); +void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr); +const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr); +#endif /* DISABLE_DEBUGGER */ +#endif + +#ifdef GB_INTERNAL +bool /* Returns true if debugger waits for more commands. Not relevant for non-GB_INTERNAL */ +#else +void +#endif +GB_debugger_execute_command(GB_gameboy_t *gb, char *input); /* Destroys input. */ + + +void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path); +const char *GB_debugger_name_for_address(GB_gameboy_t *gb, uint16_t addr); +bool GB_debugger_evaluate(GB_gameboy_t *gb, const char *string, uint16_t *result, uint16_t *result_bank); /* result_bank is -1 if unused. */ +void GB_debugger_break(GB_gameboy_t *gb); +bool GB_debugger_is_stopped(GB_gameboy_t *gb); +void GB_debugger_set_disabled(GB_gameboy_t *gb, bool disabled); +void GB_debugger_clear_symbols(GB_gameboy_t *gb); +#endif /* debugger_h */ diff --git a/gb/Core/display.c b/gb/Core/display.c new file mode 100644 index 0000000..5c1935c --- /dev/null +++ b/gb/Core/display.c @@ -0,0 +1,1227 @@ +#include +#include +#include +#include +#include "gb.h" + +/* FIFO functions */ + +static inline unsigned fifo_size(GB_fifo_t *fifo) +{ + return (fifo->write_end - fifo->read_end) & (GB_FIFO_LENGTH - 1); +} + +static void fifo_clear(GB_fifo_t *fifo) +{ + fifo->read_end = fifo->write_end = 0; +} + +static GB_fifo_item_t *fifo_pop(GB_fifo_t *fifo) +{ + GB_fifo_item_t *ret = &fifo->fifo[fifo->read_end]; + fifo->read_end++; + fifo->read_end &= (GB_FIFO_LENGTH - 1); + return ret; +} + +static void fifo_push_bg_row(GB_fifo_t *fifo, uint8_t lower, uint8_t upper, uint8_t palette, bool bg_priority, bool flip_x) +{ + if (!flip_x) { + UNROLL + for (unsigned i = 8; i--;) { + fifo->fifo[fifo->write_end] = (GB_fifo_item_t) { + (lower >> 7) | ((upper >> 7) << 1), + palette, + 0, + bg_priority, + }; + lower <<= 1; + upper <<= 1; + + fifo->write_end++; + fifo->write_end &= (GB_FIFO_LENGTH - 1); + } + } + else { + UNROLL + for (unsigned i = 8; i--;) { + fifo->fifo[fifo->write_end] = (GB_fifo_item_t) { + (lower & 1) | ((upper & 1) << 1), + palette, + 0, + bg_priority, + }; + lower >>= 1; + upper >>= 1; + + fifo->write_end++; + fifo->write_end &= (GB_FIFO_LENGTH - 1); + } + } +} + +static void fifo_overlay_object_row(GB_fifo_t *fifo, uint8_t lower, uint8_t upper, uint8_t palette, bool bg_priority, uint8_t priority, bool flip_x) +{ + while (fifo_size(fifo) < 8) { + fifo->fifo[fifo->write_end] = (GB_fifo_item_t) {0,}; + fifo->write_end++; + fifo->write_end &= (GB_FIFO_LENGTH - 1); + } + + uint8_t flip_xor = flip_x? 0: 0x7; + + UNROLL + for (unsigned i = 8; i--;) { + uint8_t pixel = (lower >> 7) | ((upper >> 7) << 1); + GB_fifo_item_t *target = &fifo->fifo[(fifo->read_end + (i ^ flip_xor)) & (GB_FIFO_LENGTH - 1)]; + if (pixel != 0 && (target->pixel == 0 || target->priority > priority)) { + target->pixel = pixel; + target->palette = palette; + target->bg_priority = bg_priority; + target->priority = priority; + } + lower <<= 1; + upper <<= 1; + } +} + + +/* + Each line is 456 cycles. Without scrolling, sprites or a window: + Mode 2 - 80 cycles / OAM Transfer + Mode 3 - 172 cycles / Rendering + Mode 0 - 204 cycles / HBlank + + Mode 1 is VBlank + */ + +#define MODE2_LENGTH (80) +#define LINE_LENGTH (456) +#define LINES (144) +#define WIDTH (160) +#define FRAME_LENGTH (LCDC_PERIOD) +#define VIRTUAL_LINES (FRAME_LENGTH / LINE_LENGTH) // = 154 + +typedef struct __attribute__((packed)) { + uint8_t y; + uint8_t x; + uint8_t tile; + uint8_t flags; +} GB_object_t; + +static bool window_enabled(GB_gameboy_t *gb) +{ + if ((gb->io_registers[GB_IO_LCDC] & 0x1) == 0) { + if (!gb->cgb_mode) { + return false; + } + } + return (gb->io_registers[GB_IO_LCDC] & 0x20) && gb->io_registers[GB_IO_WX] < 167; +} + +static void display_vblank(GB_gameboy_t *gb) +{ + gb->vblank_just_occured = true; + + /* TODO: Slow in turbo mode! */ + if (GB_is_hle_sgb(gb)) { + GB_sgb_render(gb); + } + + if (gb->turbo) { + if (GB_timing_sync_turbo(gb)) { + return; + } + } + + if (!gb->disable_rendering && ((!(gb->io_registers[GB_IO_LCDC] & 0x80) || gb->stopped) || gb->frame_skip_state == GB_FRAMESKIP_LCD_TURNED_ON)) { + /* LCD is off, set screen to white or black (if LCD is on in stop mode) */ + if (gb->sgb) { + for (unsigned i = 0; i < WIDTH * LINES; i++) { + gb->sgb->screen_buffer[i] = 0x0; + } + } + else { + uint32_t color = (gb->io_registers[GB_IO_LCDC] & 0x80) && gb->stopped && GB_is_cgb(gb) ? + gb->rgb_encode_callback(gb, 0, 0, 0) : + gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF); + for (unsigned i = 0; i < WIDTH * LINES; i++) { + gb ->screen[i] = color; + } + } + } + + gb->vblank_callback(gb); + GB_timing_sync(gb); +} + +static inline uint8_t scale_channel(uint8_t x) +{ + return (x << 3) | (x >> 2); +} + +static inline uint8_t scale_channel_with_curve(uint8_t x) +{ + return (uint8_t[]){0,2,4,7,12,18,25,34,42,52,62,73,85,97,109,121,134,146,158,170,182,193,203,213,221,230,237,243,248,251,253,255}[x]; +} + +static inline uint8_t scale_channel_with_curve_agb(uint8_t x) +{ + return (uint8_t[]){0,2,5,10,15,20,26,32,38,45,52,60,68,76,84,92,101,110,119,128,138,148,158,168,178,189,199,210,221,232,244,255}[x]; +} + +static inline uint8_t scale_channel_with_curve_sgb(uint8_t x) +{ + return (uint8_t[]){0,2,5,9,15,20,27,34,42,50,58,67,76,85,94,104,114,123,133,143,153,163,173,182,192,202,211,220,229,238,247,255}[x]; +} + + +uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color) +{ + uint8_t r = (color) & 0x1F; + uint8_t g = (color >> 5) & 0x1F; + uint8_t b = (color >> 10) & 0x1F; + + if (gb->color_correction_mode == GB_COLOR_CORRECTION_DISABLED) { + r = scale_channel(r); + g = scale_channel(g); + b = scale_channel(b); + } + else { + if (GB_is_sgb(gb)) { + return gb->rgb_encode_callback(gb, + scale_channel_with_curve_sgb(r), + scale_channel_with_curve_sgb(g), + scale_channel_with_curve_sgb(b)); + } + bool agb = gb->model == GB_MODEL_AGB; + r = agb? scale_channel_with_curve_agb(r) : scale_channel_with_curve(r); + g = agb? scale_channel_with_curve_agb(g) : scale_channel_with_curve(g); + b = agb? scale_channel_with_curve_agb(b) : scale_channel_with_curve(b); + + if (gb->color_correction_mode != GB_COLOR_CORRECTION_CORRECT_CURVES) { + uint8_t new_r, new_g, new_b; + if (agb) { + new_r = (r * 7 + g * 1) / 8; + new_g = (g * 3 + b * 1) / 4; + new_b = (b * 7 + r * 1) / 8; + } + else { + new_g = (g * 3 + b) / 4; + new_r = r; + new_b = b; + } + if (gb->color_correction_mode == GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS) { + uint8_t old_max = MAX(r, MAX(g, b)); + uint8_t new_max = MAX(new_r, MAX(new_g, new_b)); + + if (new_max != 0) { + new_r = new_r * old_max / new_max; + new_g = new_g * old_max / new_max; + new_b = new_b * old_max / new_max; + } + + uint8_t old_min = MIN(r, MIN(g, b)); + uint8_t new_min = MIN(new_r, MIN(new_g, new_b)); + + if (new_min != 0xff) { + new_r = 0xff - (0xff - new_r) * (0xff - old_min) / (0xff - new_min); + new_g = 0xff - (0xff - new_g) * (0xff - old_min) / (0xff - new_min); + new_b = 0xff - (0xff - new_b) * (0xff - old_min) / (0xff - new_min); + } + } + r = new_r; + g = new_g; + b = new_b; + } + } + + return gb->rgb_encode_callback(gb, r, g, b); +} + +void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index) +{ + if (!gb->rgb_encode_callback || !GB_is_cgb(gb)) return; + uint8_t *palette_data = background_palette? gb->background_palettes_data : gb->sprite_palettes_data; + uint16_t color = palette_data[index & ~1] | (palette_data[index | 1] << 8); + + (background_palette? gb->background_palettes_rgb : gb->sprite_palettes_rgb)[index / 2] = GB_convert_rgb15(gb, color); +} + +void GB_set_color_correction_mode(GB_gameboy_t *gb, GB_color_correction_mode_t mode) +{ + gb->color_correction_mode = mode; + if (GB_is_cgb(gb)) { + for (unsigned i = 0; i < 32; i++) { + GB_palette_changed(gb, false, i * 2); + GB_palette_changed(gb, true, i * 2); + } + } +} + +/* + STAT interrupt is implemented based on this finding: + http://board.byuu.org/phpbb3/viewtopic.php?p=25527#p25531 + + General timing is based on GiiBiiAdvance's documents: + https://github.com/AntonioND/giibiiadvance + + */ + +void GB_STAT_update(GB_gameboy_t *gb) +{ + if (!(gb->io_registers[GB_IO_LCDC] & 0x80)) return; + + bool previous_interrupt_line = gb->stat_interrupt_line; + /* Set LY=LYC bit */ + /* TODO: This behavior might not be correct for CGB revisions other than C and E */ + if (gb->ly_for_comparison != (uint16_t)-1 || gb->model <= GB_MODEL_CGB_C) { + if (gb->ly_for_comparison == gb->io_registers[GB_IO_LYC]) { + gb->lyc_interrupt_line = true; + gb->io_registers[GB_IO_STAT] |= 4; + } + else { + if (gb->ly_for_comparison != (uint16_t)-1) { + gb->lyc_interrupt_line = false; + } + gb->io_registers[GB_IO_STAT] &= ~4; + } + } + + switch (gb->mode_for_interrupt) { + case 0: gb->stat_interrupt_line = gb->io_registers[GB_IO_STAT] & 8; break; + case 1: gb->stat_interrupt_line = gb->io_registers[GB_IO_STAT] & 0x10; break; + case 2: gb->stat_interrupt_line = gb->io_registers[GB_IO_STAT] & 0x20; break; + default: gb->stat_interrupt_line = false; + } + + /* User requested a LY=LYC interrupt and the LY=LYC bit is on */ + if ((gb->io_registers[GB_IO_STAT] & 0x40) && gb->lyc_interrupt_line) { + gb->stat_interrupt_line = true; + } + + if (gb->stat_interrupt_line && !previous_interrupt_line) { + gb->io_registers[GB_IO_IF] |= 2; + } +} + +void GB_lcd_off(GB_gameboy_t *gb) +{ + gb->display_state = 0; + gb->display_cycles = 0; + /* When the LCD is disabled, state is constant */ + + /* When the LCD is off, LY is 0 and STAT mode is 0. */ + gb->io_registers[GB_IO_LY] = 0; + gb->io_registers[GB_IO_STAT] &= ~3; + if (gb->hdma_on_hblank) { + gb->hdma_on_hblank = false; + gb->hdma_on = false; + + /* Todo: is this correct? */ + gb->hdma_steps_left = 0xff; + } + + gb->oam_read_blocked = false; + gb->vram_read_blocked = false; + gb->oam_write_blocked = false; + gb->vram_write_blocked = false; + gb->cgb_palettes_blocked = false; + + /* Reset window rendering state */ + gb->wy_diff = 0; + gb->window_disabled_while_active = false; + gb->current_line = 0; + gb->ly_for_comparison = 0; + + gb->accessed_oam_row = -1; +} + +static void add_object_from_index(GB_gameboy_t *gb, unsigned index) +{ + if (gb->n_visible_objs == 10) return; + + /* TODO: It appears that DMA blocks PPU access to OAM, but it needs verification. */ + if (gb->dma_steps_left && (gb->dma_cycles >= 0 || gb->is_dma_restarting)) { + return; + } + + /* This reverse sorts the visible objects by location and priority */ + GB_object_t *objects = (GB_object_t *) &gb->oam; + bool height_16 = (gb->io_registers[GB_IO_LCDC] & 4) != 0; + signed y = objects[index].y - 16; + if (y <= gb->current_line && y + (height_16? 16 : 8) > gb->current_line) { + unsigned j = 0; + for (; j < gb->n_visible_objs; j++) { + if (gb->obj_comparators[j] <= objects[index].x) break; + } + memmove(gb->visible_objs + j + 1, gb->visible_objs + j, gb->n_visible_objs - j); + memmove(gb->obj_comparators + j + 1, gb->obj_comparators + j, gb->n_visible_objs - j); + gb->visible_objs[j] = index; + gb->obj_comparators[j] = objects[index].x; + gb->n_visible_objs++; + } +} + +static void render_pixel_if_possible(GB_gameboy_t *gb) +{ + GB_fifo_item_t *fifo_item = NULL; + GB_fifo_item_t *oam_fifo_item = NULL; + bool draw_oam = false; + bool bg_enabled = true, bg_priority = false; + + if (!gb->bg_fifo_paused) { + fifo_item = fifo_pop(&gb->bg_fifo); + bg_priority = fifo_item->bg_priority; + } + + if (!gb->oam_fifo_paused && fifo_size(&gb->oam_fifo)) { + oam_fifo_item = fifo_pop(&gb->oam_fifo); + /* Todo: Verify access timings */ + if (oam_fifo_item->pixel && (gb->io_registers[GB_IO_LCDC] & 2)) { + draw_oam = true; + bg_priority |= oam_fifo_item->bg_priority; + } + } + + /* Drop pixels for scrollings */ + if (gb->position_in_line >= 160 || gb->disable_rendering) { + gb->position_in_line++; + return; + } + if (gb->bg_fifo_paused) return; + + /* Mixing */ + + /* Todo: Verify access timings */ + if ((gb->io_registers[GB_IO_LCDC] & 0x1) == 0) { + if (gb->cgb_mode) { + bg_priority = false; + } + else { + bg_enabled = false; + } + } + + uint8_t icd_pixel = 0; + { + uint8_t pixel = bg_enabled? fifo_item->pixel : 0; + if (pixel && bg_priority) { + draw_oam = false; + } + if (!gb->cgb_mode) { + pixel = ((gb->io_registers[GB_IO_BGP] >> (pixel << 1)) & 3); + } + if (gb->sgb) { + if (gb->current_lcd_line < LINES) { + gb->sgb->screen_buffer[gb->position_in_line + gb->current_lcd_line * WIDTH] = gb->stopped? 0 : pixel; + } + } + else if (gb->model & GB_MODEL_NO_SFC_BIT) { + if (gb->icd_pixel_callback) { + icd_pixel = pixel; + } + } + else { + gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->background_palettes_rgb[fifo_item->palette * 4 + pixel]; + } + } + + if (draw_oam) { + uint8_t pixel = oam_fifo_item->pixel; + if (!gb->cgb_mode) { + /* Todo: Verify access timings */ + pixel = ((gb->io_registers[oam_fifo_item->palette? GB_IO_OBP1 : GB_IO_OBP0] >> (pixel << 1)) & 3); + } + if (gb->sgb) { + if (gb->current_lcd_line < LINES) { + gb->sgb->screen_buffer[gb->position_in_line + gb->current_lcd_line * WIDTH] = gb->stopped? 0 : pixel; + } + } + else if (gb->model & GB_MODEL_NO_SFC_BIT) { + if (gb->icd_pixel_callback) { + icd_pixel = pixel; + //gb->icd_pixel_callback(gb, pixel); + } + } + else { + gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->sprite_palettes_rgb[oam_fifo_item->palette * 4 + pixel]; + } + } + + if (gb->model & GB_MODEL_NO_SFC_BIT) { + if (gb->icd_pixel_callback) { + gb->icd_pixel_callback(gb, icd_pixel); + } + } + + gb->position_in_line++; +} + +/* All verified CGB timings are based on CGB CPU E. CGB CPUs >= D are known to have + slightly different timings than CPUs <= C. + + Todo: Add support to CPU C and older */ + +static inline uint8_t fetcher_y(GB_gameboy_t *gb) +{ + return gb->current_line + (gb->in_window? - gb->io_registers[GB_IO_WY] - gb->wy_diff : gb->io_registers[GB_IO_SCY]); +} + +static void advance_fetcher_state_machine(GB_gameboy_t *gb) +{ + typedef enum { + GB_FETCHER_GET_TILE, + GB_FETCHER_GET_TILE_DATA_LOWER, + GB_FETCHER_GET_TILE_DATA_HIGH, + GB_FETCHER_PUSH, + GB_FETCHER_SLEEP, + } fetcher_step_t; + + fetcher_step_t fetcher_state_machine [8] = { + GB_FETCHER_SLEEP, + GB_FETCHER_GET_TILE, + GB_FETCHER_SLEEP, + GB_FETCHER_GET_TILE_DATA_LOWER, + GB_FETCHER_SLEEP, + GB_FETCHER_GET_TILE_DATA_HIGH, + GB_FETCHER_SLEEP, + GB_FETCHER_PUSH, + }; + + switch (fetcher_state_machine[gb->fetcher_state]) { + case GB_FETCHER_GET_TILE: { + uint16_t map = 0x1800; + + /* Todo: Verified for DMG (Tested: SGB2), CGB timing is wrong. */ + if (gb->io_registers[GB_IO_LCDC] & 0x08 && !gb->in_window) { + map = 0x1C00; + } + else if (gb->io_registers[GB_IO_LCDC] & 0x40 && gb->in_window) { + map = 0x1C00; + } + + /* Todo: Verified for DMG (Tested: SGB2), CGB timing is wrong. */ + uint8_t y = fetcher_y(gb); + if (gb->model > GB_MODEL_CGB_C) { + /* This value is cached on the CGB-D and newer, so it cannot be used to mix tiles together */ + gb->fetcher_y = y; + } + gb->current_tile = gb->vram[map + gb->fetcher_x + y / 8 * 32]; + if (GB_is_cgb(gb)) { + /* The CGB actually accesses both the tile index AND the attributes in the same T-cycle. + This probably means the CGB has a 16-bit data bus for the VRAM. */ + gb->current_tile_attributes = gb->vram[map + gb->fetcher_x + y / 8 * 32 + 0x2000]; + } + gb->fetcher_x++; + gb->fetcher_x &= 0x1f; + } + gb->fetcher_state++; + break; + + case GB_FETCHER_GET_TILE_DATA_LOWER: { + uint8_t y_flip = 0; + uint16_t tile_address = 0; + uint8_t y = gb->model > GB_MODEL_CGB_C ? gb->fetcher_y : fetcher_y(gb); + + /* Todo: Verified for DMG (Tested: SGB2), CGB timing is wrong. */ + if (gb->io_registers[GB_IO_LCDC] & 0x10) { + tile_address = gb->current_tile * 0x10; + } + else { + tile_address = (int8_t)gb->current_tile * 0x10 + 0x1000; + } + if (gb->current_tile_attributes & 8) { + tile_address += 0x2000; + } + if (gb->current_tile_attributes & 0x40) { + y_flip = 0x7; + } + gb->current_tile_data[0] = + gb->vram[tile_address + ((y & 7) ^ y_flip) * 2]; + } + gb->fetcher_state++; + break; + + case GB_FETCHER_GET_TILE_DATA_HIGH: { + /* Todo: Verified for DMG (Tested: SGB2), CGB timing is wrong. + Additionally, on CGB-D and newer mixing two tiles by changing the tileset + bit mid-fetching causes a glitched mixing of the two, in comparison to the + more logical DMG version. */ + uint16_t tile_address = 0; + uint8_t y = gb->model > GB_MODEL_CGB_C ? gb->fetcher_y : fetcher_y(gb); + + if (gb->io_registers[GB_IO_LCDC] & 0x10) { + tile_address = gb->current_tile * 0x10; + } + else { + tile_address = (int8_t)gb->current_tile * 0x10 + 0x1000; + } + if (gb->current_tile_attributes & 8) { + tile_address += 0x2000; + } + uint8_t y_flip = 0; + if (gb->current_tile_attributes & 0x40) { + y_flip = 0x7; + } + gb->current_tile_data[1] = + gb->vram[tile_address + ((y & 7) ^ y_flip) * 2 + 1]; + } + gb->fetcher_state++; + break; + + case GB_FETCHER_PUSH: { + if (fifo_size(&gb->bg_fifo) > 0) break; + fifo_push_bg_row(&gb->bg_fifo, gb->current_tile_data[0], gb->current_tile_data[1], + gb->current_tile_attributes & 7, gb->current_tile_attributes & 0x80, gb->current_tile_attributes & 0x20); + gb->bg_fifo_paused = false; + gb->oam_fifo_paused = false; + gb->fetcher_state++; + } + break; + + case GB_FETCHER_SLEEP: + { + gb->fetcher_state++; + } + break; + } + + gb->fetcher_state &= 7; +} + +/* + TODO: It seems that the STAT register's mode bits are always "late" by 4 T-cycles. + The PPU logic can be greatly simplified if that delay is simply emulated. + */ +void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) +{ + /* The PPU does not advance while in STOP mode on the DMG */ + if (gb->stopped && !GB_is_cgb(gb)) { + gb->cycles_in_stop_mode += cycles; + if (gb->cycles_in_stop_mode >= LCDC_PERIOD) { + gb->cycles_in_stop_mode -= LCDC_PERIOD; + display_vblank(gb); + } + return; + } + GB_object_t *objects = (GB_object_t *) &gb->oam; + + GB_STATE_MACHINE(gb, display, cycles, 2) { + GB_STATE(gb, display, 1); + GB_STATE(gb, display, 2); + // GB_STATE(gb, display, 3); + // GB_STATE(gb, display, 4); + // GB_STATE(gb, display, 5); + GB_STATE(gb, display, 6); + GB_STATE(gb, display, 7); + GB_STATE(gb, display, 8); + // GB_STATE(gb, display, 9); + GB_STATE(gb, display, 10); + GB_STATE(gb, display, 11); + GB_STATE(gb, display, 12); + GB_STATE(gb, display, 13); + GB_STATE(gb, display, 14); + GB_STATE(gb, display, 15); + GB_STATE(gb, display, 16); + GB_STATE(gb, display, 17); + // GB_STATE(gb, display, 19); + GB_STATE(gb, display, 20); + GB_STATE(gb, display, 21); + GB_STATE(gb, display, 22); + GB_STATE(gb, display, 23); + // GB_STATE(gb, display, 24); + GB_STATE(gb, display, 25); + GB_STATE(gb, display, 26); + GB_STATE(gb, display, 27); + GB_STATE(gb, display, 28); + GB_STATE(gb, display, 29); + GB_STATE(gb, display, 30); + // GB_STATE(gb, display, 31); + GB_STATE(gb, display, 32); + GB_STATE(gb, display, 33); + GB_STATE(gb, display, 34); + GB_STATE(gb, display, 35); + GB_STATE(gb, display, 36); + GB_STATE(gb, display, 37); + GB_STATE(gb, display, 38); + + } + + if (!(gb->io_registers[GB_IO_LCDC] & 0x80)) { + while (true) { + GB_SLEEP(gb, display, 1, LCDC_PERIOD); + display_vblank(gb); + } + return; + } + + if (!GB_is_cgb(gb)) { + GB_SLEEP(gb, display, 23, 1); + } + + /* Handle mode 2 on the very first line 0 */ + gb->current_line = 0; + gb->ly_for_comparison = 0; + gb->io_registers[GB_IO_STAT] &= ~3; + gb->mode_for_interrupt = -1; + gb->oam_read_blocked = false; + gb->vram_read_blocked = false; + gb->oam_write_blocked = false; + gb->vram_write_blocked = false; + gb->cgb_palettes_blocked = false; + gb->cycles_for_line = MODE2_LENGTH - 4; + GB_STAT_update(gb); + GB_SLEEP(gb, display, 2, MODE2_LENGTH - 4); + + gb->oam_write_blocked = true; + gb->cycles_for_line += 2; + GB_STAT_update(gb); + GB_SLEEP(gb, display, 34, 2); + + gb->n_visible_objs = 0; + gb->cycles_for_line += 8; // Mode 0 is shorter on the first line 0, so we augment cycles_for_line by 8 extra cycles. + + gb->io_registers[GB_IO_STAT] &= ~3; + gb->io_registers[GB_IO_STAT] |= 3; + gb->mode_for_interrupt = 3; + + gb->oam_write_blocked = true; + gb->oam_read_blocked = true; + gb->vram_read_blocked = gb->cgb_double_speed; + gb->vram_write_blocked = gb->cgb_double_speed; + if (!GB_is_cgb(gb)) { + gb->vram_read_blocked = true; + gb->vram_write_blocked = true; + } + gb->cycles_for_line += 2; + GB_SLEEP(gb, display, 37, 2); + + gb->cgb_palettes_blocked = true; + gb->cycles_for_line += 2; + GB_SLEEP(gb, display, 38, 2); + + gb->vram_read_blocked = true; + gb->vram_write_blocked = true; + goto mode_3_start; + + + while (true) { + /* Lines 0 - 143 */ + for (; gb->current_line < LINES; gb->current_line++) { + gb->oam_write_blocked = GB_is_cgb(gb) && !gb->cgb_double_speed; + gb->accessed_oam_row = 0; + + GB_SLEEP(gb, display, 35, 2); + gb->oam_write_blocked = GB_is_cgb(gb); + + GB_SLEEP(gb, display, 6, 1); + gb->io_registers[GB_IO_LY] = gb->current_line; + gb->oam_read_blocked = true; + gb->ly_for_comparison = gb->current_line? -1 : 0; + + /* The OAM STAT interrupt occurs 1 T-cycle before STAT actually changes, except on line 0. + PPU glitch? */ + if (gb->current_line != 0) { + gb->mode_for_interrupt = 2; + gb->io_registers[GB_IO_STAT] &= ~3; + } + else if (!GB_is_cgb(gb)) { + gb->io_registers[GB_IO_STAT] &= ~3; + } + GB_STAT_update(gb); + + GB_SLEEP(gb, display, 7, 1); + + gb->io_registers[GB_IO_STAT] &= ~3; + gb->io_registers[GB_IO_STAT] |= 2; + gb->mode_for_interrupt = 2; + gb->oam_write_blocked = true; + gb->ly_for_comparison = gb->current_line; + GB_STAT_update(gb); + gb->mode_for_interrupt = -1; + GB_STAT_update(gb); + gb->n_visible_objs = 0; + + for (gb->oam_search_index = 0; gb->oam_search_index < 40; gb->oam_search_index++) { + if (GB_is_cgb(gb)) { + add_object_from_index(gb, gb->oam_search_index); + /* The CGB does not care about the accessed OAM row as there's no OAM bug */ + } + GB_SLEEP(gb, display, 8, 2); + if (!GB_is_cgb(gb)) { + add_object_from_index(gb, gb->oam_search_index); + gb->accessed_oam_row = (gb->oam_search_index & ~1) * 4 + 8; + } + if (gb->oam_search_index == 37) { + gb->vram_read_blocked = !GB_is_cgb(gb); + gb->vram_write_blocked = false; + gb->cgb_palettes_blocked = false; + gb->oam_write_blocked = GB_is_cgb(gb); + GB_STAT_update(gb); + } + } + gb->cycles_for_line = MODE2_LENGTH + 4; + + gb->accessed_oam_row = -1; + gb->io_registers[GB_IO_STAT] &= ~3; + gb->io_registers[GB_IO_STAT] |= 3; + gb->mode_for_interrupt = 3; + gb->vram_read_blocked = true; + gb->vram_write_blocked = true; + gb->cgb_palettes_blocked = false; + gb->oam_write_blocked = true; + gb->oam_read_blocked = true; + + GB_STAT_update(gb); + + + uint8_t idle_cycles = 3; + if (GB_is_cgb(gb) && gb->model <= GB_MODEL_CGB_C) { + idle_cycles = 2; + } + gb->cycles_for_line += idle_cycles; + GB_SLEEP(gb, display, 10, idle_cycles); + + gb->cgb_palettes_blocked = true; + gb->cycles_for_line += 2; + GB_SLEEP(gb, display, 32, 2); + mode_3_start: + + fifo_clear(&gb->bg_fifo); + fifo_clear(&gb->oam_fifo); + /* Fill the FIFO with 8 pixels of "junk", it's going to be dropped anyway. */ + fifo_push_bg_row(&gb->bg_fifo, 0, 0, 0, false, false); + /* Todo: find out actual access time of SCX */ + gb->position_in_line = - (gb->io_registers[GB_IO_SCX] & 7) - 8; + + gb->fetcher_x = ((gb->io_registers[GB_IO_SCX]) / 8) & 0x1f; + gb->extra_penalty_for_sprite_at_0 = (gb->io_registers[GB_IO_SCX] & 7); + + + /* The actual rendering cycle */ + gb->fetcher_state = 0; + gb->bg_fifo_paused = false; + gb->oam_fifo_paused = false; + gb->in_window = false; + while (true) { + /* Handle objects */ + /* When the sprite enabled bit is off, this proccess is skipped entirely on the DMG, but not on the CGB. + On the CGB, this bit is checked only when the pixel is actually popped from the FIFO. */ + + while (gb->n_visible_objs != 0 && + (gb->position_in_line < 160 || gb->position_in_line >= (uint8_t)(-8)) && + gb->obj_comparators[gb->n_visible_objs - 1] < (uint8_t)(gb->position_in_line + 8)) { + gb->n_visible_objs--; + } + while (gb->n_visible_objs != 0 && + (gb->io_registers[GB_IO_LCDC] & 2 || GB_is_cgb(gb)) && + gb->obj_comparators[gb->n_visible_objs - 1] == (uint8_t)(gb->position_in_line + 8)) { + + while (gb->fetcher_state < 5) { + advance_fetcher_state_machine(gb); + gb->cycles_for_line++; + GB_SLEEP(gb, display, 27, 1); + } + + /* Todo: Measure if penalty occurs before or after waiting for the fetcher. */ + if (gb->extra_penalty_for_sprite_at_0 != 0) { + if (gb->obj_comparators[gb->n_visible_objs - 1] == 0) { + gb->cycles_for_line += gb->extra_penalty_for_sprite_at_0; + GB_SLEEP(gb, display, 28, gb->extra_penalty_for_sprite_at_0); + gb->extra_penalty_for_sprite_at_0 = 0; + } + } + + gb->cycles_for_line += 6; + GB_SLEEP(gb, display, 20, 6); + /* TODO: what does the PPU read if DMA is active? */ + GB_object_t *object = &objects[gb->visible_objs[gb->n_visible_objs - 1]]; + + bool height_16 = (gb->io_registers[GB_IO_LCDC] & 4) != 0; /* Todo: Which T-cycle actually reads this? */ + uint8_t tile_y = (gb->current_line - object->y) & (height_16? 0xF : 7); + + if (object->flags & 0x40) { /* Flip Y */ + tile_y ^= height_16? 0xF : 7; + } + + /* Todo: I'm not 100% sure an access to OAM can't trigger the OAM bug while we're accessing this */ + uint16_t line_address = (height_16? object->tile & 0xFE : object->tile) * 0x10 + tile_y * 2; + + if (gb->cgb_mode && (object->flags & 0x8)) { /* Use VRAM bank 2 */ + line_address += 0x2000; + } + + uint8_t palette = (object->flags & 0x10) ? 1 : 0; + if (gb->cgb_mode) { + palette = object->flags & 0x7; + } + + fifo_overlay_object_row(&gb->oam_fifo, + gb->vram[line_address], + gb->vram[line_address + 1], + palette, + object->flags & 0x80, + gb->cgb_mode? gb->visible_objs[gb->n_visible_objs - 1] : 0, + object->flags & 0x20); + + gb->n_visible_objs--; + } + + /* Handle window */ + /* Todo: Timing (Including penalty and access timings) not verified by test ROM */ + if (!gb->in_window && window_enabled(gb) && + gb->current_line >= gb->io_registers[GB_IO_WY] + gb->wy_diff && + (uint8_t)(gb->position_in_line + 7) == gb->io_registers[GB_IO_WX]) { + gb->in_window = true; + fifo_clear(&gb->bg_fifo); + gb->bg_fifo_paused = true; + gb->oam_fifo_paused = true; + gb->fetcher_x = 0; + gb->fetcher_state = 0; + } + + render_pixel_if_possible(gb); + advance_fetcher_state_machine(gb); + + if (gb->position_in_line == 160) break; + gb->cycles_for_line++; + GB_SLEEP(gb, display, 21, 1); + } + + if (GB_is_cgb(gb) && gb->model <= GB_MODEL_CGB_C) { + gb->cycles_for_line++; + GB_SLEEP(gb, display, 30, 1); + } + + if (!gb->cgb_double_speed) { + gb->io_registers[GB_IO_STAT] &= ~3; + gb->mode_for_interrupt = 0; + gb->oam_read_blocked = false; + gb->vram_read_blocked = false; + gb->oam_write_blocked = false; + gb->vram_write_blocked = false; + } + + gb->cycles_for_line++; + GB_SLEEP(gb, display, 22, 1); + + gb->io_registers[GB_IO_STAT] &= ~3; + gb->mode_for_interrupt = 0; + gb->oam_read_blocked = false; + gb->vram_read_blocked = false; + gb->oam_write_blocked = false; + gb->vram_write_blocked = false; + GB_STAT_update(gb); + + /* Todo: Measure this value */ + gb->cycles_for_line += 2; + GB_SLEEP(gb, display, 33, 2); + gb->cgb_palettes_blocked = !gb->cgb_double_speed; + + gb->cycles_for_line += 2; + GB_SLEEP(gb, display, 36, 2); + gb->cgb_palettes_blocked = false; + + gb->cycles_for_line += 8; + GB_SLEEP(gb, display, 25, 8); + + if (gb->hdma_on_hblank) { + gb->hdma_starting = true; + } + GB_SLEEP(gb, display, 11, LINE_LENGTH - gb->cycles_for_line); + gb->mode_for_interrupt = 2; + + // Todo: unverified timing + gb->current_lcd_line++; + if (gb->current_lcd_line == LINES && GB_is_sgb(gb)) { + display_vblank(gb); + } + + if (gb->icd_hreset_callback) { + gb->icd_hreset_callback(gb); + } + } + + /* Lines 144 - 152 */ + for (; gb->current_line < VIRTUAL_LINES - 1; gb->current_line++) { + gb->io_registers[GB_IO_LY] = gb->current_line; + gb->ly_for_comparison = -1; + GB_SLEEP(gb, display, 26, 2); + if (gb->current_line == LINES) { + gb->mode_for_interrupt = 2; + } + GB_STAT_update(gb); + GB_SLEEP(gb, display, 12, 2); + gb->ly_for_comparison = gb->current_line; + + if (gb->current_line == LINES) { + /* Entering VBlank state triggers the OAM interrupt */ + gb->io_registers[GB_IO_STAT] &= ~3; + gb->io_registers[GB_IO_STAT] |= 1; + gb->io_registers[GB_IO_IF] |= 1; + gb->mode_for_interrupt = 2; + GB_STAT_update(gb); + gb->mode_for_interrupt = 1; + GB_STAT_update(gb); + + if (gb->frame_skip_state == GB_FRAMESKIP_LCD_TURNED_ON) { + if (!GB_is_sgb(gb) || gb->current_lcd_line < LINES) { + display_vblank(gb); + } + gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED; + } + else { + gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED; + if (!GB_is_sgb(gb) || gb->current_lcd_line < LINES) { + display_vblank(gb); + } + } + } + + GB_STAT_update(gb); + GB_SLEEP(gb, display, 13, LINE_LENGTH - 4); + } + + /* TODO: Verified on SGB2 and CGB-E. Actual interrupt timings not tested. */ + /* Lines 153 */ + gb->io_registers[GB_IO_LY] = 153; + gb->ly_for_comparison = -1; + GB_STAT_update(gb); + GB_SLEEP(gb, display, 14, (gb->model > GB_MODEL_CGB_C)? 4: 6); + + if (!GB_is_cgb(gb)) { + gb->io_registers[GB_IO_LY] = 0; + } + gb->ly_for_comparison = 153; + GB_STAT_update(gb); + GB_SLEEP(gb, display, 15, (gb->model > GB_MODEL_CGB_C)? 4: 2); + + gb->io_registers[GB_IO_LY] = 0; + gb->ly_for_comparison = (gb->model > GB_MODEL_CGB_C)? 153 : -1; + GB_STAT_update(gb); + GB_SLEEP(gb, display, 16, 4); + + gb->ly_for_comparison = 0; + GB_STAT_update(gb); + GB_SLEEP(gb, display, 29, 12); /* Writing to LYC during this period on a CGB has side effects */ + GB_SLEEP(gb, display, 17, LINE_LENGTH - 24); + + + /* Reset window rendering state */ + gb->wy_diff = 0; + gb->window_disabled_while_active = false; + gb->current_line = 0; + // TODO: not the correct timing + gb->current_lcd_line = 0; + if (gb->icd_vreset_callback) { + gb->icd_vreset_callback(gb); + } + } +} + +void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index) +{ + uint32_t none_palette[4]; + uint32_t *palette = NULL; + + switch (GB_is_cgb(gb)? palette_type : GB_PALETTE_NONE) { + default: + case GB_PALETTE_NONE: + none_palette[0] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF); + none_palette[1] = gb->rgb_encode_callback(gb, 0xAA, 0xAA, 0xAA); + none_palette[2] = gb->rgb_encode_callback(gb, 0x55, 0x55, 0x55); + none_palette[3] = gb->rgb_encode_callback(gb, 0, 0, 0 ); + palette = none_palette; + break; + case GB_PALETTE_BACKGROUND: + palette = gb->background_palettes_rgb + (4 * (palette_index & 7)); + break; + case GB_PALETTE_OAM: + palette = gb->sprite_palettes_rgb + (4 * (palette_index & 7)); + break; + } + + for (unsigned y = 0; y < 192; y++) { + for (unsigned x = 0; x < 256; x++) { + if (x >= 128 && !GB_is_cgb(gb)) { + *(dest++) = gb->background_palettes_rgb[0]; + continue; + } + uint16_t tile = (x % 128) / 8 + y / 8 * 16; + uint16_t tile_address = tile * 0x10 + (x >= 128? 0x2000 : 0); + uint8_t pixel = (((gb->vram[tile_address + (y & 7) * 2 ] >> ((~x)&7)) & 1 ) | + ((gb->vram[tile_address + (y & 7) * 2 + 1] >> ((~x)&7)) & 1) << 1); + + if (!gb->cgb_mode) { + if (palette_type == GB_PALETTE_BACKGROUND) { + pixel = ((gb->io_registers[GB_IO_BGP] >> (pixel << 1)) & 3); + } + else if (!gb->cgb_mode) { + if (palette_type == GB_PALETTE_OAM) { + pixel = ((gb->io_registers[palette_index == 0? GB_IO_OBP0 : GB_IO_OBP1] >> (pixel << 1)) & 3); + } + } + } + + + *(dest++) = palette[pixel]; + } + } +} + +void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index, GB_map_type_t map_type, GB_tileset_type_t tileset_type) +{ + uint32_t none_palette[4]; + uint32_t *palette = NULL; + uint16_t map = 0x1800; + + switch (GB_is_cgb(gb)? palette_type : GB_PALETTE_NONE) { + case GB_PALETTE_NONE: + none_palette[0] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF); + none_palette[1] = gb->rgb_encode_callback(gb, 0xAA, 0xAA, 0xAA); + none_palette[2] = gb->rgb_encode_callback(gb, 0x55, 0x55, 0x55); + none_palette[3] = gb->rgb_encode_callback(gb, 0, 0, 0 ); + palette = none_palette; + break; + case GB_PALETTE_BACKGROUND: + palette = gb->background_palettes_rgb + (4 * (palette_index & 7)); + break; + case GB_PALETTE_OAM: + palette = gb->sprite_palettes_rgb + (4 * (palette_index & 7)); + break; + case GB_PALETTE_AUTO: + break; + } + + if (map_type == GB_MAP_9C00 || (map_type == GB_MAP_AUTO && gb->io_registers[GB_IO_LCDC] & 0x08)) { + map = 0x1c00; + } + + if (tileset_type == GB_TILESET_AUTO) { + tileset_type = (gb->io_registers[GB_IO_LCDC] & 0x10)? GB_TILESET_8800 : GB_TILESET_8000; + } + + for (unsigned y = 0; y < 256; y++) { + for (unsigned x = 0; x < 256; x++) { + uint8_t tile = gb->vram[map + x/8 + y/8 * 32]; + uint16_t tile_address; + uint8_t attributes = 0; + + if (tileset_type == GB_TILESET_8800) { + tile_address = tile * 0x10; + } + else { + tile_address = (int8_t) tile * 0x10 + 0x1000; + } + + if (gb->cgb_mode) { + attributes = gb->vram[map + x/8 + y/8 * 32 + 0x2000]; + } + + if (attributes & 0x8) { + tile_address += 0x2000; + } + + uint8_t pixel = (((gb->vram[tile_address + (((attributes & 0x40)? ~y : y) & 7) * 2 ] >> (((attributes & 0x20)? x : ~x)&7)) & 1 ) | + ((gb->vram[tile_address + (((attributes & 0x40)? ~y : y) & 7) * 2 + 1] >> (((attributes & 0x20)? x : ~x)&7)) & 1) << 1); + + if (!gb->cgb_mode && (palette_type == GB_PALETTE_BACKGROUND || palette_type == GB_PALETTE_AUTO)) { + pixel = ((gb->io_registers[GB_IO_BGP] >> (pixel << 1)) & 3); + } + + if (palette) { + *(dest++) = palette[pixel]; + } + else { + *(dest++) = gb->background_palettes_rgb[(attributes & 7) * 4 + pixel]; + } + } + } +} + +uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_height) +{ + uint8_t count = 0; + *sprite_height = (gb->io_registers[GB_IO_LCDC] & 4) ? 16:8; + uint8_t oam_to_dest_index[40] = {0,}; + for (unsigned y = 0; y < LINES; y++) { + GB_object_t *sprite = (GB_object_t *) &gb->oam; + uint8_t sprites_in_line = 0; + for (uint8_t i = 0; i < 40; i++, sprite++) { + int sprite_y = sprite->y - 16; + bool obscured = false; + // Is sprite not in this line? + if (sprite_y > y || sprite_y + *sprite_height <= y) continue; + if (++sprites_in_line == 11) obscured = true; + + GB_oam_info_t *info = NULL; + if (!oam_to_dest_index[i]) { + info = dest + count; + oam_to_dest_index[i] = ++count; + info->x = sprite->x; + info->y = sprite->y; + info->tile = *sprite_height == 16? sprite->tile & 0xFE : sprite->tile; + info->flags = sprite->flags; + info->obscured_by_line_limit = false; + info->oam_addr = 0xFE00 + i * sizeof(*sprite); + } + else { + info = dest + oam_to_dest_index[i] - 1; + } + info->obscured_by_line_limit |= obscured; + } + } + + for (unsigned i = 0; i < count; i++) { + uint16_t vram_address = dest[i].tile * 0x10; + uint8_t flags = dest[i].flags; + uint8_t palette = gb->cgb_mode? (flags & 7) : ((flags & 0x10)? 1 : 0); + if (GB_is_cgb(gb) && (flags & 0x8)) { + vram_address += 0x2000; + } + + for (unsigned y = 0; y < *sprite_height; y++) { + UNROLL + for (unsigned x = 0; x < 8; x++) { + uint8_t color = (((gb->vram[vram_address ] >> ((~x)&7)) & 1 ) | + ((gb->vram[vram_address + 1] >> ((~x)&7)) & 1) << 1 ); + + if (!gb->cgb_mode) { + color = (gb->io_registers[palette? GB_IO_OBP1:GB_IO_OBP0] >> (color << 1)) & 3; + } + dest[i].image[((flags & 0x20)?7-x:x) + ((flags & 0x40)?*sprite_height - 1 -y:y) * 8] = gb->sprite_palettes_rgb[palette * 4 + color]; + } + vram_address += 2; + } + } + return count; +} + +/* Called when a write might enable or disable the window */ +void GB_window_related_write(GB_gameboy_t *gb, uint8_t addr, uint8_t value) +{ + bool before = window_enabled(gb); + gb->io_registers[addr] = value; + bool after = window_enabled(gb); + + if (before != after && gb->current_line < LINES) { + /* Window was disabled or enabled outside of vblank */ + if (gb->current_line >= gb->io_registers[GB_IO_WY]) { + if (after) { + if (!gb->window_disabled_while_active) { + /* Window was turned on for the first time this frame while LY > WY, + should start window in the next line */ + gb->wy_diff = gb->current_line + 1 - gb->io_registers[GB_IO_WY]; + } + else { + gb->wy_diff += gb->current_line; + } + } + else { + gb->wy_diff -= gb->current_line; + gb->window_disabled_while_active = true; + } + } + } +} diff --git a/gb/Core/display.h b/gb/Core/display.h new file mode 100644 index 0000000..9d1d1b4 --- /dev/null +++ b/gb/Core/display.h @@ -0,0 +1,54 @@ +#ifndef display_h +#define display_h + +#include "gb.h" +#include +#include + +#ifdef GB_INTERNAL +void GB_display_run(GB_gameboy_t *gb, uint8_t cycles); +void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index); +void GB_window_related_write(GB_gameboy_t *gb, uint8_t addr, uint8_t value); +void GB_STAT_update(GB_gameboy_t *gb); +void GB_lcd_off(GB_gameboy_t *gb); +#endif + +typedef enum { + GB_PALETTE_NONE, + GB_PALETTE_BACKGROUND, + GB_PALETTE_OAM, + GB_PALETTE_AUTO, +} GB_palette_type_t; + +typedef enum { + GB_MAP_AUTO, + GB_MAP_9800, + GB_MAP_9C00, +} GB_map_type_t; + +typedef enum { + GB_TILESET_AUTO, + GB_TILESET_8800, + GB_TILESET_8000, +} GB_tileset_type_t; + +typedef struct { + uint32_t image[128]; + uint8_t x, y, tile, flags; + uint16_t oam_addr; + bool obscured_by_line_limit; +} GB_oam_info_t; + +typedef enum { + GB_COLOR_CORRECTION_DISABLED, + GB_COLOR_CORRECTION_CORRECT_CURVES, + GB_COLOR_CORRECTION_EMULATE_HARDWARE, + GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS, +} GB_color_correction_mode_t; + +void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index); +void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index, GB_map_type_t map_type, GB_tileset_type_t tileset_type); +uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_height); +uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color); +void GB_set_color_correction_mode(GB_gameboy_t *gb, GB_color_correction_mode_t mode); +#endif /* display_h */ diff --git a/gb/Core/gb.c b/gb/Core/gb.c new file mode 100644 index 0000000..f29d400 --- /dev/null +++ b/gb/Core/gb.c @@ -0,0 +1,1084 @@ +#include +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#endif +#include "random.h" +#include "gb.h" + + +#ifdef DISABLE_REWIND +#define GB_rewind_free(...) +#define GB_rewind_push(...) +#endif + + +static inline uint32_t state_magic(void) +{ + if (sizeof(bool) == 1) return 'SAME'; + return 'S4ME'; +} + +void GB_attributed_logv(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, va_list args) +{ + char *string = NULL; + vasprintf(&string, fmt, args); + if (string) { + if (gb->log_callback) { + gb->log_callback(gb, string, attributes); + } + else { + /* Todo: Add ANSI escape sequences for attributed text */ + printf("%s", string); + } + } + free(string); +} + +void GB_attributed_log(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + GB_attributed_logv(gb, attributes, fmt, args); + va_end(args); +} + +void GB_log(GB_gameboy_t *gb, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + GB_attributed_logv(gb, 0, fmt, args); + va_end(args); +} + +#ifndef DISABLE_DEBUGGER +static char *default_input_callback(GB_gameboy_t *gb) +{ + char *expression = NULL; + size_t size = 0; + + if (getline(&expression, &size, stdin) == -1) { + /* The user doesn't have STDIN or used ^D. We make sure the program keeps running. */ + GB_set_async_input_callback(gb, NULL); /* Disable async input */ + return strdup("c"); + } + + if (!expression) { + return strdup(""); + } + + size_t length = strlen(expression); + if (expression[length - 1] == '\n') { + expression[length - 1] = 0; + } + return expression; +} + +static char *default_async_input_callback(GB_gameboy_t *gb) +{ +#ifndef _WIN32 + fd_set set; + FD_ZERO(&set); + FD_SET(STDIN_FILENO, &set); + struct timeval time = {0,}; + if (select(1, &set, NULL, NULL, &time) == 1) { + if (feof(stdin)) { + GB_set_async_input_callback(gb, NULL); /* Disable async input */ + return NULL; + } + return default_input_callback(gb); + } +#endif + return NULL; +} +#endif + +void GB_init(GB_gameboy_t *gb, GB_model_t model) +{ + memset(gb, 0, sizeof(*gb)); + gb->model = model; + if (GB_is_cgb(gb)) { + gb->ram = malloc(gb->ram_size = 0x1000 * 8); + gb->vram = malloc(gb->vram_size = 0x2000 * 2); + } + else { + gb->ram = malloc(gb->ram_size = 0x2000); + gb->vram = malloc(gb->vram_size = 0x2000); + } + +#ifndef DISABLE_DEBUGGER + gb->input_callback = default_input_callback; + gb->async_input_callback = default_async_input_callback; +#endif + gb->cartridge_type = &GB_cart_defs[0]; // Default cartridge type + gb->clock_multiplier = 1.0; + + if (model & GB_MODEL_NO_SFC_BIT) { + /* Disable time syncing. Timing should be done by the SFC emulator. */ + gb->turbo = true; + } + + GB_reset(gb); +} + +GB_model_t GB_get_model(GB_gameboy_t *gb) +{ + return gb->model; +} + +void GB_free(GB_gameboy_t *gb) +{ + gb->magic = 0; + if (gb->ram) { + free(gb->ram); + } + if (gb->vram) { + free(gb->vram); + } + if (gb->mbc_ram) { + free(gb->mbc_ram); + } + if (gb->rom) { + free(gb->rom); + } + if (gb->breakpoints) { + free(gb->breakpoints); + } + if (gb->sgb) { + free(gb->sgb); + } + if (gb->nontrivial_jump_state) { + free(gb->nontrivial_jump_state); + } +#ifndef DISABLE_DEBUGGER + GB_debugger_clear_symbols(gb); +#endif + GB_rewind_free(gb); + memset(gb, 0, sizeof(*gb)); +} + +int GB_load_boot_rom(GB_gameboy_t *gb, const char *path) +{ + FILE *f = fopen(path, "rb"); + if (!f) { + GB_log(gb, "Could not open boot ROM: %s.\n", strerror(errno)); + return errno; + } + fread(gb->boot_rom, sizeof(gb->boot_rom), 1, f); + fclose(f); + return 0; +} + +void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size) +{ + if (size > sizeof(gb->boot_rom)) { + size = sizeof(gb->boot_rom); + } + memset(gb->boot_rom, 0xFF, sizeof(gb->boot_rom)); + memcpy(gb->boot_rom, buffer, size); +} + +int GB_load_rom(GB_gameboy_t *gb, const char *path) +{ + FILE *f = fopen(path, "rb"); + if (!f) { + GB_log(gb, "Could not open ROM: %s.\n", strerror(errno)); + return errno; + } + fseek(f, 0, SEEK_END); + gb->rom_size = (ftell(f) + 0x3FFF) & ~0x3FFF; /* Round to bank */ + /* And then round to a power of two */ + while (gb->rom_size & (gb->rom_size - 1)) { + /* I promise this works. */ + gb->rom_size |= gb->rom_size >> 1; + gb->rom_size++; + } + fseek(f, 0, SEEK_SET); + if (gb->rom) { + free(gb->rom); + } + gb->rom = malloc(gb->rom_size); + memset(gb->rom, 0xFF, gb->rom_size); /* Pad with 0xFFs */ + fread(gb->rom, 1, gb->rom_size, f); + fclose(f); + GB_configure_cart(gb); + + return 0; +} + +void GB_load_rom_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size) +{ + gb->rom_size = (size + 0x3fff) & ~0x3fff; + while (gb->rom_size & (gb->rom_size - 1)) { + gb->rom_size |= gb->rom_size >> 1; + gb->rom_size++; + } + if (gb->rom) { + free(gb->rom); + } + gb->rom = malloc(gb->rom_size); + memset(gb->rom, 0xff, gb->rom_size); + memcpy(gb->rom, buffer, size); + GB_configure_cart(gb); +} + +typedef struct { + uint8_t seconds; + uint8_t padding1[3]; + uint8_t minutes; + uint8_t padding2[3]; + uint8_t hours; + uint8_t padding3[3]; + uint8_t days; + uint8_t padding4[3]; + uint8_t high; + uint8_t padding5[3]; +} GB_vba_rtc_time_t; + +typedef union { + struct __attribute__((packed)) { + GB_rtc_time_t rtc_real; + time_t last_rtc_second; /* Platform specific endianess and size */ + } sameboy_legacy; + struct { + /* Used by VBA versions with 32-bit timestamp*/ + GB_vba_rtc_time_t rtc_real, rtc_latched; + uint32_t last_rtc_second; /* Always little endian */ + } vba32; + struct { + /* Used by BGB and VBA versions with 64-bit timestamp*/ + GB_vba_rtc_time_t rtc_real, rtc_latched; + uint64_t last_rtc_second; /* Always little endian */ + } vba64; +} GB_rtc_save_t; + +int GB_save_battery_size(GB_gameboy_t *gb) +{ + if (!gb->cartridge_type->has_battery) return 0; // Nothing to save. + if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */ + + GB_rtc_save_t rtc_save_size; + return gb->mbc_ram_size + (gb->cartridge_type->has_rtc ? sizeof(rtc_save_size.vba64) : 0); +} + +int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size) +{ + if (!gb->cartridge_type->has_battery) return 0; // Nothing to save. + if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */ + + if (size < GB_save_battery_size(gb)) return EIO; + + memcpy(buffer, gb->mbc_ram, gb->mbc_ram_size); + + if (gb->cartridge_type->has_rtc) { + GB_rtc_save_t rtc_save = {{{{0,}},},}; + rtc_save.vba64.rtc_real.seconds = gb->rtc_real.seconds; + rtc_save.vba64.rtc_real.minutes = gb->rtc_real.minutes; + rtc_save.vba64.rtc_real.hours = gb->rtc_real.hours; + rtc_save.vba64.rtc_real.days = gb->rtc_real.days; + rtc_save.vba64.rtc_real.high = gb->rtc_real.high; + rtc_save.vba64.rtc_latched.seconds = gb->rtc_latched.seconds; + rtc_save.vba64.rtc_latched.minutes = gb->rtc_latched.minutes; + rtc_save.vba64.rtc_latched.hours = gb->rtc_latched.hours; + rtc_save.vba64.rtc_latched.days = gb->rtc_latched.days; + rtc_save.vba64.rtc_latched.high = gb->rtc_latched.high; +#ifdef GB_BIG_ENDIAN + rtc_save.vba64.last_rtc_second = __builtin_bswap64(gb->last_rtc_second); +#else + rtc_save.vba64.last_rtc_second = gb->last_rtc_second; +#endif + memcpy(buffer + gb->mbc_ram_size, &rtc_save.vba64, sizeof(rtc_save.vba64)); + } + + errno = 0; + return errno; +} + +int GB_save_battery(GB_gameboy_t *gb, const char *path) +{ + if (!gb->cartridge_type->has_battery) return 0; // Nothing to save. + if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */ + FILE *f = fopen(path, "wb"); + if (!f) { + GB_log(gb, "Could not open battery save: %s.\n", strerror(errno)); + return errno; + } + + if (fwrite(gb->mbc_ram, 1, gb->mbc_ram_size, f) != gb->mbc_ram_size) { + fclose(f); + return EIO; + } + if (gb->cartridge_type->has_rtc) { + GB_rtc_save_t rtc_save = {{{{0,}},},}; + rtc_save.vba64.rtc_real.seconds = gb->rtc_real.seconds; + rtc_save.vba64.rtc_real.minutes = gb->rtc_real.minutes; + rtc_save.vba64.rtc_real.hours = gb->rtc_real.hours; + rtc_save.vba64.rtc_real.days = gb->rtc_real.days; + rtc_save.vba64.rtc_real.high = gb->rtc_real.high; + rtc_save.vba64.rtc_latched.seconds = gb->rtc_latched.seconds; + rtc_save.vba64.rtc_latched.minutes = gb->rtc_latched.minutes; + rtc_save.vba64.rtc_latched.hours = gb->rtc_latched.hours; + rtc_save.vba64.rtc_latched.days = gb->rtc_latched.days; + rtc_save.vba64.rtc_latched.high = gb->rtc_latched.high; +#ifdef GB_BIG_ENDIAN + rtc_save.vba64.last_rtc_second = __builtin_bswap64(gb->last_rtc_second); +#else + rtc_save.vba64.last_rtc_second = gb->last_rtc_second; +#endif + if (fwrite(&rtc_save.vba64, 1, sizeof(rtc_save.vba64), f) != sizeof(rtc_save.vba64)) { + fclose(f); + return EIO; + } + + } + + errno = 0; + fclose(f); + return errno; +} + +void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size) +{ + memcpy(gb->mbc_ram, buffer, MIN(gb->mbc_ram_size, size)); + if (size <= gb->mbc_ram_size) { + goto reset_rtc; + } + + GB_rtc_save_t rtc_save; + memcpy(&rtc_save, buffer + gb->mbc_ram_size, MIN(sizeof(rtc_save), size)); + switch (size - gb->mbc_ram_size) { + case sizeof(rtc_save.sameboy_legacy): + memcpy(&gb->rtc_real, &rtc_save.sameboy_legacy.rtc_real, sizeof(gb->rtc_real)); + memcpy(&gb->rtc_latched, &rtc_save.sameboy_legacy.rtc_real, sizeof(gb->rtc_real)); + gb->last_rtc_second = rtc_save.sameboy_legacy.last_rtc_second; + break; + + case sizeof(rtc_save.vba32): + gb->rtc_real.seconds = rtc_save.vba32.rtc_real.seconds; + gb->rtc_real.minutes = rtc_save.vba32.rtc_real.minutes; + gb->rtc_real.hours = rtc_save.vba32.rtc_real.hours; + gb->rtc_real.days = rtc_save.vba32.rtc_real.days; + gb->rtc_real.high = rtc_save.vba32.rtc_real.high; + gb->rtc_latched.seconds = rtc_save.vba32.rtc_latched.seconds; + gb->rtc_latched.minutes = rtc_save.vba32.rtc_latched.minutes; + gb->rtc_latched.hours = rtc_save.vba32.rtc_latched.hours; + gb->rtc_latched.days = rtc_save.vba32.rtc_latched.days; + gb->rtc_latched.high = rtc_save.vba32.rtc_latched.high; +#ifdef GB_BIG_ENDIAN + gb->last_rtc_second = __builtin_bswap32(rtc_save.vba32.last_rtc_second); +#else + gb->last_rtc_second = rtc_save.vba32.last_rtc_second; +#endif + break; + + case sizeof(rtc_save.vba64): + gb->rtc_real.seconds = rtc_save.vba64.rtc_real.seconds; + gb->rtc_real.minutes = rtc_save.vba64.rtc_real.minutes; + gb->rtc_real.hours = rtc_save.vba64.rtc_real.hours; + gb->rtc_real.days = rtc_save.vba64.rtc_real.days; + gb->rtc_real.high = rtc_save.vba64.rtc_real.high; + gb->rtc_latched.seconds = rtc_save.vba64.rtc_latched.seconds; + gb->rtc_latched.minutes = rtc_save.vba64.rtc_latched.minutes; + gb->rtc_latched.hours = rtc_save.vba64.rtc_latched.hours; + gb->rtc_latched.days = rtc_save.vba64.rtc_latched.days; + gb->rtc_latched.high = rtc_save.vba64.rtc_latched.high; +#ifdef GB_BIG_ENDIAN + gb->last_rtc_second = __builtin_bswap64(rtc_save.vba64.last_rtc_second); +#else + gb->last_rtc_second = rtc_save.vba64.last_rtc_second; +#endif + break; + + default: + goto reset_rtc; + } + if (gb->last_rtc_second > time(NULL)) { + /* We must reset RTC here, or it will not advance. */ + goto reset_rtc; + } + + if (gb->last_rtc_second < 852076800) { /* 1/1/97. There weren't any RTC games that time, + so if the value we read is lower it means it wasn't + really RTC data. */ + goto reset_rtc; + } + goto exit; +reset_rtc: + gb->last_rtc_second = time(NULL); + gb->rtc_real.high |= 0x80; /* This gives the game a hint that the clock should be reset. */ +exit: + return; +} + +/* Loading will silently stop if the format is incomplete */ +void GB_load_battery(GB_gameboy_t *gb, const char *path) +{ + FILE *f = fopen(path, "rb"); + if (!f) { + return; + } + + if (fread(gb->mbc_ram, 1, gb->mbc_ram_size, f) != gb->mbc_ram_size) { + goto reset_rtc; + } + + GB_rtc_save_t rtc_save; + switch (fread(&rtc_save, 1, sizeof(rtc_save), f)) { + case sizeof(rtc_save.sameboy_legacy): + memcpy(&gb->rtc_real, &rtc_save.sameboy_legacy.rtc_real, sizeof(gb->rtc_real)); + memcpy(&gb->rtc_latched, &rtc_save.sameboy_legacy.rtc_real, sizeof(gb->rtc_real)); + gb->last_rtc_second = rtc_save.sameboy_legacy.last_rtc_second; + break; + + case sizeof(rtc_save.vba32): + gb->rtc_real.seconds = rtc_save.vba32.rtc_real.seconds; + gb->rtc_real.minutes = rtc_save.vba32.rtc_real.minutes; + gb->rtc_real.hours = rtc_save.vba32.rtc_real.hours; + gb->rtc_real.days = rtc_save.vba32.rtc_real.days; + gb->rtc_real.high = rtc_save.vba32.rtc_real.high; + gb->rtc_latched.seconds = rtc_save.vba32.rtc_latched.seconds; + gb->rtc_latched.minutes = rtc_save.vba32.rtc_latched.minutes; + gb->rtc_latched.hours = rtc_save.vba32.rtc_latched.hours; + gb->rtc_latched.days = rtc_save.vba32.rtc_latched.days; + gb->rtc_latched.high = rtc_save.vba32.rtc_latched.high; +#ifdef GB_BIG_ENDIAN + gb->last_rtc_second = __builtin_bswap32(rtc_save.vba32.last_rtc_second); +#else + gb->last_rtc_second = rtc_save.vba32.last_rtc_second; +#endif + break; + + case sizeof(rtc_save.vba64): + gb->rtc_real.seconds = rtc_save.vba64.rtc_real.seconds; + gb->rtc_real.minutes = rtc_save.vba64.rtc_real.minutes; + gb->rtc_real.hours = rtc_save.vba64.rtc_real.hours; + gb->rtc_real.days = rtc_save.vba64.rtc_real.days; + gb->rtc_real.high = rtc_save.vba64.rtc_real.high; + gb->rtc_latched.seconds = rtc_save.vba64.rtc_latched.seconds; + gb->rtc_latched.minutes = rtc_save.vba64.rtc_latched.minutes; + gb->rtc_latched.hours = rtc_save.vba64.rtc_latched.hours; + gb->rtc_latched.days = rtc_save.vba64.rtc_latched.days; + gb->rtc_latched.high = rtc_save.vba64.rtc_latched.high; +#ifdef GB_BIG_ENDIAN + gb->last_rtc_second = __builtin_bswap64(rtc_save.vba64.last_rtc_second); +#else + gb->last_rtc_second = rtc_save.vba64.last_rtc_second; +#endif + break; + + default: + goto reset_rtc; + } + if (gb->last_rtc_second > time(NULL)) { + /* We must reset RTC here, or it will not advance. */ + goto reset_rtc; + } + + if (gb->last_rtc_second < 852076800) { /* 1/1/97. There weren't any RTC games that time, + so if the value we read is lower it means it wasn't + really RTC data. */ + goto reset_rtc; + } + goto exit; +reset_rtc: + gb->last_rtc_second = time(NULL); + gb->rtc_real.high |= 0x80; /* This gives the game a hint that the clock should be reset. */ +exit: + fclose(f); + return; +} + +uint8_t GB_run(GB_gameboy_t *gb) +{ + gb->vblank_just_occured = false; + + if (gb->sgb && gb->sgb->intro_animation < 140) { + /* On the SGB, the GB is halted after finishing the boot ROM. + Then, after the boot animation is almost done, it's reset. + Since the SGB HLE does not perform any header validity checks, + we just halt the CPU (with hacky code) until the correct time. + This ensures the Nintendo logo doesn't flash on screen, and + the game does "run in background" while the animation is playing. */ + GB_display_run(gb, 228); + gb->cycles_since_last_sync += 228; + return 228; + } + + GB_debugger_run(gb); + gb->cycles_since_run = 0; + GB_cpu_run(gb); + if (gb->vblank_just_occured) { + GB_rtc_run(gb); + GB_debugger_handle_async_commands(gb); + GB_rewind_push(gb); + } + return gb->cycles_since_run; +} + +uint64_t GB_run_frame(GB_gameboy_t *gb) +{ + /* Configure turbo temporarily, the user wants to handle FPS capping manually. */ + bool old_turbo = gb->turbo; + bool old_dont_skip = gb->turbo_dont_skip; + gb->turbo = true; + gb->turbo_dont_skip = true; + + gb->cycles_since_last_sync = 0; + while (true) { + GB_run(gb); + if (gb->vblank_just_occured) { + break; + } + } + gb->turbo = old_turbo; + gb->turbo_dont_skip = old_dont_skip; + return gb->cycles_since_last_sync * 1000000000LL / 2 / GB_get_clock_rate(gb); /* / 2 because we use 8MHz units */ +} + +void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output) +{ + gb->screen = output; +} + +void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback) +{ + gb->vblank_callback = callback; +} + +void GB_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback) +{ + gb->log_callback = callback; +} + +void GB_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback) +{ +#ifndef DISABLE_DEBUGGER + if (gb->input_callback == default_input_callback) { + gb->async_input_callback = NULL; + } + gb->input_callback = callback; +#endif +} + +void GB_set_async_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback) +{ +#ifndef DISABLE_DEBUGGER + gb->async_input_callback = callback; +#endif +} + + +void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback) +{ + if (!gb->rgb_encode_callback && !GB_is_cgb(gb)) { + gb->sprite_palettes_rgb[4] = gb->sprite_palettes_rgb[0] = gb->background_palettes_rgb[0] = + callback(gb, 0xFF, 0xFF, 0xFF); + gb->sprite_palettes_rgb[5] = gb->sprite_palettes_rgb[1] = gb->background_palettes_rgb[1] = + callback(gb, 0xAA, 0xAA, 0xAA); + gb->sprite_palettes_rgb[6] = gb->sprite_palettes_rgb[2] = gb->background_palettes_rgb[2] = + callback(gb, 0x55, 0x55, 0x55); + gb->sprite_palettes_rgb[7] = gb->sprite_palettes_rgb[3] = gb->background_palettes_rgb[3] = + callback(gb, 0, 0, 0); + } + + gb->rgb_encode_callback = callback; + + for (unsigned i = 0; i < 32; i++) { + GB_palette_changed(gb, true, i * 2); + GB_palette_changed(gb, false, i * 2); + } +} + +void GB_set_infrared_callback(GB_gameboy_t *gb, GB_infrared_callback_t callback) +{ + gb->infrared_callback = callback; +} + +void GB_set_infrared_input(GB_gameboy_t *gb, bool state) +{ + gb->infrared_input = state; + gb->cycles_since_input_ir_change = 0; + gb->ir_queue_length = 0; +} + +void GB_queue_infrared_input(GB_gameboy_t *gb, bool state, long cycles_after_previous_change) +{ + if (gb->ir_queue_length == GB_MAX_IR_QUEUE) { + GB_log(gb, "IR Queue is full\n"); + return; + } + gb->ir_queue[gb->ir_queue_length++] = (GB_ir_queue_item_t){state, cycles_after_previous_change}; +} + +void GB_set_rumble_callback(GB_gameboy_t *gb, GB_rumble_callback_t callback) +{ + gb->rumble_callback = callback; +} + +void GB_set_serial_transfer_bit_start_callback(GB_gameboy_t *gb, GB_serial_transfer_bit_start_callback_t callback) +{ + gb->serial_transfer_bit_start_callback = callback; +} + +void GB_set_serial_transfer_bit_end_callback(GB_gameboy_t *gb, GB_serial_transfer_bit_end_callback_t callback) +{ + gb->serial_transfer_bit_end_callback = callback; +} + +bool GB_serial_get_data_bit(GB_gameboy_t *gb) +{ + if (gb->io_registers[GB_IO_SC] & 1) { + /* Internal Clock */ + GB_log(gb, "Serial read request while using internal clock. \n"); + return 0xFF; + } + return gb->io_registers[GB_IO_SB] & 0x80; +} +void GB_serial_set_data_bit(GB_gameboy_t *gb, bool data) +{ + if (gb->io_registers[GB_IO_SC] & 1) { + /* Internal Clock */ + GB_log(gb, "Serial write request while using internal clock. \n"); + return; + } + gb->io_registers[GB_IO_SB] <<= 1; + gb->io_registers[GB_IO_SB] |= data; + gb->serial_count++; + if (gb->serial_count == 8) { + gb->io_registers[GB_IO_IF] |= 8; + gb->serial_count = 0; + } +} + +void GB_disconnect_serial(GB_gameboy_t *gb) +{ + gb->serial_transfer_bit_start_callback = NULL; + gb->serial_transfer_bit_end_callback = NULL; + + /* Reset any internally-emulated device. Currently, only the printer. */ + memset(&gb->printer, 0, sizeof(gb->printer)); +} + +bool GB_is_inited(GB_gameboy_t *gb) +{ + return gb->magic == state_magic(); +} + +bool GB_is_cgb(GB_gameboy_t *gb) +{ + return (gb->model & GB_MODEL_FAMILY_MASK) == GB_MODEL_CGB_FAMILY; +} + +bool GB_is_sgb(GB_gameboy_t *gb) +{ + return (gb->model & ~GB_MODEL_PAL_BIT & ~GB_MODEL_NO_SFC_BIT) == GB_MODEL_SGB || (gb->model & ~GB_MODEL_NO_SFC_BIT) == GB_MODEL_SGB2; +} + +bool GB_is_hle_sgb(GB_gameboy_t *gb) +{ + return (gb->model & ~GB_MODEL_PAL_BIT) == GB_MODEL_SGB || gb->model == GB_MODEL_SGB2; +} + +void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip) +{ + gb->turbo = on; + gb->turbo_dont_skip = no_frame_skip; +} + +void GB_set_rendering_disabled(GB_gameboy_t *gb, bool disabled) +{ + gb->disable_rendering = disabled; +} + +void *GB_get_user_data(GB_gameboy_t *gb) +{ + return gb->user_data; +} + +void GB_set_user_data(GB_gameboy_t *gb, void *data) +{ + gb->user_data = data; +} + +static void reset_ram(GB_gameboy_t *gb) +{ + switch (gb->model) { + case GB_MODEL_CGB_E: + case GB_MODEL_AGB: /* Unverified */ + for (unsigned i = 0; i < gb->ram_size; i++) { + gb->ram[i] = GB_random(); + } + break; + + case GB_MODEL_DMG_B: + case GB_MODEL_SGB_NTSC: /* Unverified*/ + case GB_MODEL_SGB_PAL: /* Unverified */ + case GB_MODEL_SGB_NTSC_NO_SFC: /* Unverified */ + case GB_MODEL_SGB_PAL_NO_SFC: /* Unverified */ + for (unsigned i = 0; i < gb->ram_size; i++) { + gb->ram[i] = GB_random(); + if (i & 0x100) { + gb->ram[i] &= GB_random(); + } + else { + gb->ram[i] |= GB_random(); + } + } + break; + + case GB_MODEL_SGB2: + case GB_MODEL_SGB2_NO_SFC: + for (unsigned i = 0; i < gb->ram_size; i++) { + gb->ram[i] = 0x55; + gb->ram[i] ^= GB_random() & GB_random() & GB_random(); + } + break; + + case GB_MODEL_CGB_C: + for (unsigned i = 0; i < gb->ram_size; i++) { + if ((i & 0x808) == 0x800 || (i & 0x808) == 0x008) { + gb->ram[i] = 0; + } + else { + gb->ram[i] = GB_random() | GB_random() | GB_random() | GB_random(); + } + } + break; + } + + /* HRAM */ + switch (gb->model) { + case GB_MODEL_CGB_C: + // case GB_MODEL_CGB_D: + case GB_MODEL_CGB_E: + case GB_MODEL_AGB: + for (unsigned i = 0; i < sizeof(gb->hram); i++) { + gb->hram[i] = GB_random(); + } + break; + + case GB_MODEL_DMG_B: + case GB_MODEL_SGB_NTSC: /* Unverified*/ + case GB_MODEL_SGB_PAL: /* Unverified */ + case GB_MODEL_SGB_NTSC_NO_SFC: /* Unverified */ + case GB_MODEL_SGB_PAL_NO_SFC: /* Unverified */ + case GB_MODEL_SGB2: + case GB_MODEL_SGB2_NO_SFC: + for (unsigned i = 0; i < sizeof(gb->hram); i++) { + if (i & 1) { + gb->hram[i] = GB_random() | GB_random() | GB_random(); + } + else { + gb->hram[i] = GB_random() & GB_random() & GB_random(); + } + } + break; + } + + /* OAM */ + switch (gb->model) { + case GB_MODEL_CGB_C: + case GB_MODEL_CGB_E: + case GB_MODEL_AGB: + /* Zero'd out by boot ROM anyway*/ + break; + + case GB_MODEL_DMG_B: + case GB_MODEL_SGB_NTSC: /* Unverified */ + case GB_MODEL_SGB_PAL: /* Unverified */ + case GB_MODEL_SGB_NTSC_NO_SFC: /* Unverified */ + case GB_MODEL_SGB_PAL_NO_SFC: /* Unverified */ + case GB_MODEL_SGB2: + case GB_MODEL_SGB2_NO_SFC: + for (unsigned i = 0; i < 8; i++) { + if (i & 2) { + gb->oam[i] = GB_random() & GB_random() & GB_random(); + } + else { + gb->oam[i] = GB_random() | GB_random() | GB_random(); + } + } + for (unsigned i = 8; i < sizeof(gb->oam); i++) { + gb->oam[i] = gb->oam[i - 8]; + } + break; + } + + /* Wave RAM */ + switch (gb->model) { + case GB_MODEL_CGB_C: + case GB_MODEL_CGB_E: + case GB_MODEL_AGB: + /* Initialized by CGB-A and newer, 0s in CGB-0*/ + break; + + case GB_MODEL_DMG_B: + case GB_MODEL_SGB_NTSC: /* Unverified*/ + case GB_MODEL_SGB_PAL: /* Unverified */ + case GB_MODEL_SGB_NTSC_NO_SFC: /* Unverified */ + case GB_MODEL_SGB_PAL_NO_SFC: /* Unverified */ + case GB_MODEL_SGB2: + case GB_MODEL_SGB2_NO_SFC: { + uint8_t temp; + for (unsigned i = 0; i < GB_IO_WAV_END - GB_IO_WAV_START; i++) { + if (i & 1) { + temp = GB_random() & GB_random() & GB_random(); + } + else { + temp = GB_random() | GB_random() | GB_random(); + } + gb->apu.wave_channel.wave_form[i * 2] = temp >> 4; + gb->apu.wave_channel.wave_form[i * 2 + 1] = temp & 0xF; + gb->io_registers[GB_IO_WAV_START + i] = temp; + + } + break; + } + } + + for (unsigned i = 0; i < sizeof(gb->extra_oam); i++) { + gb->extra_oam[i] = GB_random(); + } + + if (GB_is_cgb(gb)) { + for (unsigned i = 0; i < 64; i++) { + gb->background_palettes_data[i] = GB_random(); /* Doesn't really matter as the boot ROM overrides it anyway*/ + gb->sprite_palettes_data[i] = GB_random(); + } + for (unsigned i = 0; i < 32; i++) { + GB_palette_changed(gb, true, i * 2); + GB_palette_changed(gb, false, i * 2); + } + } +} + +void GB_reset(GB_gameboy_t *gb) +{ + uint32_t mbc_ram_size = gb->mbc_ram_size; + GB_model_t model = gb->model; + memset(gb, 0, (size_t)GB_GET_SECTION((GB_gameboy_t *) 0, unsaved)); + gb->model = model; + gb->version = GB_STRUCT_VERSION; + + gb->mbc_rom_bank = 1; + gb->last_rtc_second = time(NULL); + gb->cgb_ram_bank = 1; + gb->io_registers[GB_IO_JOYP] = 0xCF; + gb->mbc_ram_size = mbc_ram_size; + if (GB_is_cgb(gb)) { + gb->ram_size = 0x1000 * 8; + gb->vram_size = 0x2000 * 2; + memset(gb->vram, 0, gb->vram_size); + gb->cgb_mode = true; + } + else { + gb->ram_size = 0x2000; + gb->vram_size = 0x2000; + memset(gb->vram, 0, gb->vram_size); + + if (gb->rgb_encode_callback) { + gb->sprite_palettes_rgb[4] = gb->sprite_palettes_rgb[0] = gb->background_palettes_rgb[0] = + gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF); + gb->sprite_palettes_rgb[5] = gb->sprite_palettes_rgb[1] = gb->background_palettes_rgb[1] = + gb->rgb_encode_callback(gb, 0xAA, 0xAA, 0xAA); + gb->sprite_palettes_rgb[6] = gb->sprite_palettes_rgb[2] = gb->background_palettes_rgb[2] = + gb->rgb_encode_callback(gb, 0x55, 0x55, 0x55); + gb->sprite_palettes_rgb[7] = gb->sprite_palettes_rgb[3] = gb->background_palettes_rgb[3] = + gb->rgb_encode_callback(gb, 0, 0, 0); + } + } + reset_ram(gb); + + /* The serial interrupt always occur on the 0xF7th cycle of every 0x100 cycle since boot. */ + gb->serial_cycles = 0x100-0xF7; + gb->io_registers[GB_IO_SC] = 0x7E; + + /* These are not deterministic, but 00 (CGB) and FF (DMG) are the most common initial values by far */ + gb->io_registers[GB_IO_DMA] = gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = GB_is_cgb(gb)? 0x00 : 0xFF; + + gb->accessed_oam_row = -1; + + + if (GB_is_hle_sgb(gb)) { + if (!gb->sgb) { + gb->sgb = malloc(sizeof(*gb->sgb)); + } + memset(gb->sgb, 0, sizeof(*gb->sgb)); + memset(gb->sgb_intro_jingle_phases, 0, sizeof(gb->sgb_intro_jingle_phases)); + gb->sgb_intro_sweep_phase = 0; + gb->sgb_intro_sweep_previous_sample = 0; + gb->sgb->intro_animation = -10; + + gb->sgb->player_count = 1; + GB_sgb_load_default_data(gb); + + } + else { + if (gb->sgb) { + free(gb->sgb); + gb->sgb = NULL; + } + } + + /* Todo: Ugly, fixme, see comment in the timer state machine */ + gb->div_state = 3; + + GB_apu_update_cycles_per_sample(gb); + + if (gb->nontrivial_jump_state) { + free(gb->nontrivial_jump_state); + gb->nontrivial_jump_state = NULL; + } + + gb->magic = state_magic(); +} + +void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model) +{ + gb->model = model; + if (GB_is_cgb(gb)) { + gb->ram = realloc(gb->ram, gb->ram_size = 0x1000 * 8); + gb->vram = realloc(gb->vram, gb->vram_size = 0x2000 * 2); + } + else { + gb->ram = realloc(gb->ram, gb->ram_size = 0x2000); + gb->vram = realloc(gb->vram, gb->vram_size = 0x2000); + } + GB_rewind_free(gb); + GB_reset(gb); +} + +void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *size, uint16_t *bank) +{ + /* Set size and bank to dummy pointers if not set */ + size_t dummy_size; + uint16_t dummy_bank; + if (!size) { + size = &dummy_size; + } + + if (!bank) { + bank = &dummy_bank; + } + + + switch (access) { + case GB_DIRECT_ACCESS_ROM: + *size = gb->rom_size; + *bank = gb->mbc_rom_bank; + return gb->rom; + case GB_DIRECT_ACCESS_RAM: + *size = gb->ram_size; + *bank = gb->cgb_ram_bank; + return gb->ram; + case GB_DIRECT_ACCESS_CART_RAM: + *size = gb->mbc_ram_size; + *bank = gb->mbc_ram_bank; + return gb->mbc_ram; + case GB_DIRECT_ACCESS_VRAM: + *size = gb->vram_size; + *bank = gb->cgb_vram_bank; + return gb->vram; + case GB_DIRECT_ACCESS_HRAM: + *size = sizeof(gb->hram); + *bank = 0; + return &gb->hram; + case GB_DIRECT_ACCESS_IO: + *size = sizeof(gb->io_registers); + *bank = 0; + return &gb->io_registers; + case GB_DIRECT_ACCESS_BOOTROM: + *size = GB_is_cgb(gb)? sizeof(gb->boot_rom) : 0x100; + *bank = 0; + return &gb->boot_rom; + case GB_DIRECT_ACCESS_OAM: + *size = sizeof(gb->oam); + *bank = 0; + return &gb->oam; + case GB_DIRECT_ACCESS_BGP: + *size = sizeof(gb->background_palettes_data); + *bank = 0; + return &gb->background_palettes_data; + case GB_DIRECT_ACCESS_OBP: + *size = sizeof(gb->sprite_palettes_data); + *bank = 0; + return &gb->sprite_palettes_data; + case GB_DIRECT_ACCESS_IE: + *size = sizeof(gb->interrupt_enable); + *bank = 0; + return &gb->interrupt_enable; + default: + *size = 0; + *bank = 0; + return NULL; + } +} + +void GB_set_clock_multiplier(GB_gameboy_t *gb, double multiplier) +{ + gb->clock_multiplier = multiplier; + GB_apu_update_cycles_per_sample(gb); +} + +uint32_t GB_get_clock_rate(GB_gameboy_t *gb) +{ + if (gb->model & GB_MODEL_PAL_BIT) { + return SGB_PAL_FREQUENCY * gb->clock_multiplier; + } + if ((gb->model & ~GB_MODEL_NO_SFC_BIT) == GB_MODEL_SGB) { + return SGB_NTSC_FREQUENCY * gb->clock_multiplier; + } + return CPU_FREQUENCY * gb->clock_multiplier; +} + +unsigned GB_get_screen_width(GB_gameboy_t *gb) +{ + return GB_is_hle_sgb(gb)? 256 : 160; +} + +unsigned GB_get_screen_height(GB_gameboy_t *gb) +{ + return GB_is_hle_sgb(gb)? 224 : 144; +} + +unsigned GB_get_player_count(GB_gameboy_t *gb) +{ + return GB_is_hle_sgb(gb)? gb->sgb->player_count : 1; +} + +void GB_set_update_input_hint_callback(GB_gameboy_t *gb, GB_update_input_hint_callback_t callback) +{ + gb->update_input_hint_callback = callback; +} + +double GB_get_usual_frame_rate(GB_gameboy_t *gb) +{ + return GB_get_clock_rate(gb) / (double)LCDC_PERIOD; +} + +void GB_set_joyp_write_callback(GB_gameboy_t *gb, GB_joyp_write_callback_t callback) +{ + gb->joyp_write_callback = callback; +} + +void GB_set_icd_pixel_callback(GB_gameboy_t *gb, GB_icd_pixel_callback_t callback) +{ + gb->icd_pixel_callback = callback; +} + +void GB_set_icd_hreset_callback(GB_gameboy_t *gb, GB_icd_hreset_callback_t callback) +{ + gb->icd_hreset_callback = callback; +} + + +void GB_set_icd_vreset_callback(GB_gameboy_t *gb, GB_icd_vreset_callback_t callback) +{ + gb->icd_vreset_callback = callback; +} diff --git a/gb/Core/gb.h b/gb/Core/gb.h new file mode 100644 index 0000000..a561111 --- /dev/null +++ b/gb/Core/gb.h @@ -0,0 +1,725 @@ +#ifndef GB_h +#define GB_h +#define typeof __typeof__ +#include +#include +#include + +#include "gb_struct_def.h" +#include "save_state.h" + +#include "apu.h" +#include "camera.h" +#include "debugger.h" +#include "display.h" +#include "joypad.h" +#include "mbc.h" +#include "memory.h" +#include "printer.h" +#include "timing.h" +#include "rewind.h" +#include "sm83_cpu.h" +#include "symbol_hash.h" +#include "sgb.h" + +#define GB_STRUCT_VERSION 13 + +#define GB_MODEL_FAMILY_MASK 0xF00 +#define GB_MODEL_DMG_FAMILY 0x000 +#define GB_MODEL_MGB_FAMILY 0x100 +#define GB_MODEL_CGB_FAMILY 0x200 +#define GB_MODEL_PAL_BIT 0x1000 +#define GB_MODEL_NO_SFC_BIT 0x2000 + +#ifdef GB_INTERNAL +#if __clang__ +#define UNROLL _Pragma("unroll") +#elif __GNUC__ +#define UNROLL _Pragma("GCC unroll 8") +#else +#define UNROLL +#endif + +#endif + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define GB_BIG_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define GB_LITTLE_ENDIAN +#else +#error Unable to detect endianess +#endif + +typedef union { + struct { + uint8_t seconds; + uint8_t minutes; + uint8_t hours; + uint8_t days; + uint8_t high; + }; + uint8_t data[5]; +} GB_rtc_time_t; + + +typedef enum { + // GB_MODEL_DMG_0 = 0x000, + // GB_MODEL_DMG_A = 0x001, + GB_MODEL_DMG_B = 0x002, + // GB_MODEL_DMG_C = 0x003, + GB_MODEL_SGB = 0x004, + GB_MODEL_SGB_NTSC = GB_MODEL_SGB, + GB_MODEL_SGB_PAL = GB_MODEL_SGB | GB_MODEL_PAL_BIT, + GB_MODEL_SGB_NTSC_NO_SFC = GB_MODEL_SGB | GB_MODEL_NO_SFC_BIT, + GB_MODEL_SGB_NO_SFC = GB_MODEL_SGB_NTSC_NO_SFC, + GB_MODEL_SGB_PAL_NO_SFC = GB_MODEL_SGB | GB_MODEL_NO_SFC_BIT | GB_MODEL_PAL_BIT, + // GB_MODEL_MGB = 0x100, + GB_MODEL_SGB2 = 0x101, + GB_MODEL_SGB2_NO_SFC = GB_MODEL_SGB2 | GB_MODEL_NO_SFC_BIT, + // GB_MODEL_CGB_0 = 0x200, + // GB_MODEL_CGB_A = 0x201, + // GB_MODEL_CGB_B = 0x202, + GB_MODEL_CGB_C = 0x203, + // GB_MODEL_CGB_D = 0x204, + GB_MODEL_CGB_E = 0x205, + GB_MODEL_AGB = 0x206, +} GB_model_t; + +enum { + GB_REGISTER_AF, + GB_REGISTER_BC, + GB_REGISTER_DE, + GB_REGISTER_HL, + GB_REGISTER_SP, + GB_REGISTERS_16_BIT /* Count */ +}; + +/* Todo: Actually use these! */ +enum { + GB_CARRY_FLAG = 16, + GB_HALF_CARRY_FLAG = 32, + GB_SUBSTRACT_FLAG = 64, + GB_ZERO_FLAG = 128, +}; + +#define GB_MAX_IR_QUEUE 256 + +enum { + /* Joypad and Serial */ + GB_IO_JOYP = 0x00, // Joypad (R/W) + GB_IO_SB = 0x01, // Serial transfer data (R/W) + GB_IO_SC = 0x02, // Serial Transfer Control (R/W) + + /* Missing */ + + /* Timers */ + GB_IO_DIV = 0x04, // Divider Register (R/W) + GB_IO_TIMA = 0x05, // Timer counter (R/W) + GB_IO_TMA = 0x06, // Timer Modulo (R/W) + GB_IO_TAC = 0x07, // Timer Control (R/W) + + /* Missing */ + + GB_IO_IF = 0x0f, // Interrupt Flag (R/W) + + /* Sound */ + GB_IO_NR10 = 0x10, // Channel 1 Sweep register (R/W) + GB_IO_NR11 = 0x11, // Channel 1 Sound length/Wave pattern duty (R/W) + GB_IO_NR12 = 0x12, // Channel 1 Volume Envelope (R/W) + GB_IO_NR13 = 0x13, // Channel 1 Frequency lo (Write Only) + GB_IO_NR14 = 0x14, // Channel 1 Frequency hi (R/W) + /* NR20 does not exist */ + GB_IO_NR21 = 0x16, // Channel 2 Sound Length/Wave Pattern Duty (R/W) + GB_IO_NR22 = 0x17, // Channel 2 Volume Envelope (R/W) + GB_IO_NR23 = 0x18, // Channel 2 Frequency lo data (W) + GB_IO_NR24 = 0x19, // Channel 2 Frequency hi data (R/W) + GB_IO_NR30 = 0x1a, // Channel 3 Sound on/off (R/W) + GB_IO_NR31 = 0x1b, // Channel 3 Sound Length + GB_IO_NR32 = 0x1c, // Channel 3 Select output level (R/W) + GB_IO_NR33 = 0x1d, // Channel 3 Frequency's lower data (W) + GB_IO_NR34 = 0x1e, // Channel 3 Frequency's higher data (R/W) + /* NR40 does not exist */ + GB_IO_NR41 = 0x20, // Channel 4 Sound Length (R/W) + GB_IO_NR42 = 0x21, // Channel 4 Volume Envelope (R/W) + GB_IO_NR43 = 0x22, // Channel 4 Polynomial Counter (R/W) + GB_IO_NR44 = 0x23, // Channel 4 Counter/consecutive, Inital (R/W) + GB_IO_NR50 = 0x24, // Channel control / ON-OFF / Volume (R/W) + GB_IO_NR51 = 0x25, // Selection of Sound output terminal (R/W) + GB_IO_NR52 = 0x26, // Sound on/off + + /* Missing */ + + GB_IO_WAV_START = 0x30, // Wave pattern start + GB_IO_WAV_END = 0x3f, // Wave pattern end + + /* Graphics */ + GB_IO_LCDC = 0x40, // LCD Control (R/W) + GB_IO_STAT = 0x41, // LCDC Status (R/W) + GB_IO_SCY = 0x42, // Scroll Y (R/W) + GB_IO_SCX = 0x43, // Scroll X (R/W) + GB_IO_LY = 0x44, // LCDC Y-Coordinate (R) + GB_IO_LYC = 0x45, // LY Compare (R/W) + GB_IO_DMA = 0x46, // DMA Transfer and Start Address (W) + GB_IO_BGP = 0x47, // BG Palette Data (R/W) - Non CGB Mode Only + GB_IO_OBP0 = 0x48, // Object Palette 0 Data (R/W) - Non CGB Mode Only + GB_IO_OBP1 = 0x49, // Object Palette 1 Data (R/W) - Non CGB Mode Only + GB_IO_WY = 0x4a, // Window Y Position (R/W) + GB_IO_WX = 0x4b, // Window X Position minus 7 (R/W) + // Has some undocumented compatibility flags written at boot. + // Unfortunately it is not readable or writable after boot has finished, so research of this + // register is quite limited. The value written to this register, however, can be controlled + // in some cases. + GB_IO_DMG_EMULATION = 0x4c, + + /* General CGB features */ + GB_IO_KEY1 = 0x4d, // CGB Mode Only - Prepare Speed Switch + + /* Missing */ + + GB_IO_VBK = 0x4f, // CGB Mode Only - VRAM Bank + GB_IO_BIOS = 0x50, // Write to disable the BIOS mapping + + /* CGB DMA */ + GB_IO_HDMA1 = 0x51, // CGB Mode Only - New DMA Source, High + GB_IO_HDMA2 = 0x52, // CGB Mode Only - New DMA Source, Low + GB_IO_HDMA3 = 0x53, // CGB Mode Only - New DMA Destination, High + GB_IO_HDMA4 = 0x54, // CGB Mode Only - New DMA Destination, Low + GB_IO_HDMA5 = 0x55, // CGB Mode Only - New DMA Length/Mode/Start + + /* IR */ + GB_IO_RP = 0x56, // CGB Mode Only - Infrared Communications Port + + /* Missing */ + + /* CGB Paletts */ + GB_IO_BGPI = 0x68, // CGB Mode Only - Background Palette Index + GB_IO_BGPD = 0x69, // CGB Mode Only - Background Palette Data + GB_IO_OBPI = 0x6a, // CGB Mode Only - Sprite Palette Index + GB_IO_OBPD = 0x6b, // CGB Mode Only - Sprite Palette Data + + // 1 is written for DMG ROMs on a CGB. Does not appear to have an effect. + GB_IO_DMG_EMULATION_INDICATION = 0x6c, // (FEh) Bit 0 (Read/Write) + + /* Missing */ + + GB_IO_SVBK = 0x70, // CGB Mode Only - WRAM Bank + GB_IO_UNKNOWN2 = 0x72, // (00h) - Bit 0-7 (Read/Write) + GB_IO_UNKNOWN3 = 0x73, // (00h) - Bit 0-7 (Read/Write) + GB_IO_UNKNOWN4 = 0x74, // (00h) - Bit 0-7 (Read/Write) - CGB Mode Only + GB_IO_UNKNOWN5 = 0x75, // (8Fh) - Bit 4-6 (Read/Write) + GB_IO_PCM_12 = 0x76, // Channels 1 and 2 amplitudes + GB_IO_PCM_34 = 0x77, // Channels 3 and 4 amplitudes + GB_IO_UNKNOWN8 = 0x7F, // Unknown, write only +}; + +typedef enum { + GB_LOG_BOLD = 1, + GB_LOG_DASHED_UNDERLINE = 2, + GB_LOG_UNDERLINE = 4, + GB_LOG_UNDERLINE_MASK = GB_LOG_DASHED_UNDERLINE | GB_LOG_UNDERLINE +} GB_log_attributes; + +#ifdef GB_INTERNAL +#define LCDC_PERIOD 70224 +#define CPU_FREQUENCY 0x400000 +#define SGB_NTSC_FREQUENCY (21477272 / 5) +#define SGB_PAL_FREQUENCY (21281370 / 5) +#define DIV_CYCLES (0x100) +#define INTERNAL_DIV_CYCLES (0x40000) + +#if !defined(MIN) +#define MIN(A,B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; }) +#endif + +#if !defined(MAX) +#define MAX(A,B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; }) +#endif +#endif + +typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb); +typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes); +typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb); +typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b); +typedef void (*GB_infrared_callback_t)(GB_gameboy_t *gb, bool on, long cycles_since_last_update); +typedef void (*GB_rumble_callback_t)(GB_gameboy_t *gb, bool rumble_on); +typedef void (*GB_serial_transfer_bit_start_callback_t)(GB_gameboy_t *gb, bool bit_to_send); +typedef bool (*GB_serial_transfer_bit_end_callback_t)(GB_gameboy_t *gb); +typedef void (*GB_update_input_hint_callback_t)(GB_gameboy_t *gb); +typedef void (*GB_joyp_write_callback_t)(GB_gameboy_t *gb, uint8_t value); +typedef void (*GB_icd_pixel_callback_t)(GB_gameboy_t *gb, uint8_t row); +typedef void (*GB_icd_hreset_callback_t)(GB_gameboy_t *gb); +typedef void (*GB_icd_vreset_callback_t)(GB_gameboy_t *gb); + +typedef struct { + bool state; + long delay; +} GB_ir_queue_item_t; + +struct GB_breakpoint_s; +struct GB_watchpoint_s; + +typedef struct { + uint8_t pixel; // Color, 0-3 + uint8_t palette; // Palette, 0 - 7 (CGB); 0-1 in DMG (or just 0 for BG) + uint8_t priority; // Sprite priority – 0 in DMG, OAM index in CGB + bool bg_priority; // For sprite FIFO – the BG priority bit. For the BG FIFO – the CGB attributes priority bit +} GB_fifo_item_t; + +#define GB_FIFO_LENGTH 16 +typedef struct { + GB_fifo_item_t fifo[GB_FIFO_LENGTH]; + uint8_t read_end; + uint8_t write_end; +} GB_fifo_t; + +/* When state saving, each section is dumped independently of other sections. + This allows adding data to the end of the section without worrying about future compatibility. + Some other changes might be "safe" as well. + This struct is not packed, but dumped sections exclusively use types that have the same alignment in both 32 and 64 + bit platforms. */ + +#ifdef GB_INTERNAL +struct GB_gameboy_s { +#else +struct GB_gameboy_internal_s { +#endif + GB_SECTION(header, + /* The magic makes sure a state file is: + - Indeed a SameBoy state file. + - Has the same endianess has the current platform. */ + volatile uint32_t magic; + /* The version field makes sure we don't load save state files with a completely different structure. + This happens when struct fields are removed/resized in an backward incompatible manner. */ + uint32_t version; + ); + + GB_SECTION(core_state, + /* Registers */ + uint16_t pc; + union { + uint16_t registers[GB_REGISTERS_16_BIT]; + struct { + uint16_t af, + bc, + de, + hl, + sp; + }; + struct { +#ifdef GB_BIG_ENDIAN + uint8_t a, f, + b, c, + d, e, + h, l; +#else + uint8_t f, a, + c, b, + e, d, + l, h; +#endif + }; + + }; + uint8_t ime; + uint8_t interrupt_enable; + uint8_t cgb_ram_bank; + + /* CPU and General Hardware Flags*/ + GB_model_t model; + bool cgb_mode; + bool cgb_double_speed; + bool halted; + bool stopped; + bool boot_rom_finished; + bool ime_toggle; /* ei has delayed a effect.*/ + bool halt_bug; + bool just_halted; + + /* Misc state */ + bool infrared_input; + GB_printer_t printer; + uint8_t extra_oam[0xff00 - 0xfea0]; + uint32_t ram_size; // Different between CGB and DMG + ); + + /* DMA and HDMA */ + GB_SECTION(dma, + bool hdma_on; + bool hdma_on_hblank; + uint8_t hdma_steps_left; + int16_t hdma_cycles; // in 8MHz units + uint16_t hdma_current_src, hdma_current_dest; + + uint8_t dma_steps_left; + uint8_t dma_current_dest; + uint16_t dma_current_src; + int16_t dma_cycles; + bool is_dma_restarting; + uint8_t last_opcode_read; /* Required to emulte HDMA reads from Exxx */ + bool hdma_starting; + ); + + /* MBC */ + GB_SECTION(mbc, + uint16_t mbc_rom_bank; + uint8_t mbc_ram_bank; + uint32_t mbc_ram_size; + bool mbc_ram_enable; + union { + struct { + uint8_t bank_low:5; + uint8_t bank_high:2; + uint8_t mode:1; + } mbc1; + + struct { + uint8_t rom_bank:4; + } mbc2; + + struct { + uint8_t rom_bank:7; + uint8_t padding:1; + uint8_t ram_bank:4; + } mbc3; + + struct { + uint8_t rom_bank_low; + uint8_t rom_bank_high:1; + uint8_t ram_bank:4; + } mbc5; + + struct { + uint8_t bank_low:6; + uint8_t bank_high:3; + uint8_t mode:1; + } huc1; + + struct { + uint8_t rom_bank; + uint8_t ram_bank; + } huc3; + }; + uint16_t mbc_rom0_bank; /* For some MBC1 wirings. */ + bool camera_registers_mapped; + uint8_t camera_registers[0x36]; + bool rumble_state; + ); + + + /* HRAM and HW Registers */ + GB_SECTION(hram, + uint8_t hram[0xFFFF - 0xFF80]; + uint8_t io_registers[0x80]; + ); + + /* Timing */ + GB_SECTION(timing, + GB_UNIT(display); + GB_UNIT(div); + uint16_t div_counter; + uint8_t tima_reload_state; /* After TIMA overflows, it becomes 0 for 4 cycles before actually reloading. */ + uint16_t serial_cycles; + uint16_t serial_length; + uint8_t double_speed_alignment; + uint8_t serial_count; + ); + + /* APU */ + GB_SECTION(apu, + GB_apu_t apu; + ); + + /* RTC */ + GB_SECTION(rtc, + GB_rtc_time_t rtc_real, rtc_latched; + uint64_t last_rtc_second; + bool rtc_latch; + ); + + /* Video Display */ + GB_SECTION(video, + uint32_t vram_size; // Different between CGB and DMG + uint8_t cgb_vram_bank; + uint8_t oam[0xA0]; + uint8_t background_palettes_data[0x40]; + uint8_t sprite_palettes_data[0x40]; + uint8_t position_in_line; + bool stat_interrupt_line; + uint8_t effective_scx; + uint8_t wy_diff; + /* The LCDC will skip the first frame it renders after turning it on. + On the CGB, a frame is not skipped if the previous frame was skipped as well. + See https://www.reddit.com/r/EmuDev/comments/6exyxu/ */ + + /* TODO: Drop this and properly emulate the dropped vreset signal*/ + enum { + GB_FRAMESKIP_LCD_TURNED_ON, // On a DMG, the LCD renders a blank screen during this state, + // on a CGB, the previous frame is repeated (which might be + // blank if the LCD was off for more than a few cycles) + GB_FRAMESKIP_FIRST_FRAME_SKIPPED, // This state is 'skipped' when emulating a DMG + GB_FRAMESKIP_SECOND_FRAME_RENDERED, + } frame_skip_state; + bool oam_read_blocked; + bool vram_read_blocked; + bool oam_write_blocked; + bool vram_write_blocked; + bool window_disabled_while_active; + uint8_t current_line; + uint16_t ly_for_comparison; + GB_fifo_t bg_fifo, oam_fifo; + uint8_t fetcher_x; + uint8_t fetcher_y; + uint16_t cycles_for_line; + uint8_t current_tile; + uint8_t current_tile_attributes; + uint8_t current_tile_data[2]; + uint8_t fetcher_state; + bool bg_fifo_paused; + bool oam_fifo_paused; + bool in_window; + uint8_t visible_objs[10]; + uint8_t obj_comparators[10]; + uint8_t n_visible_objs; + uint8_t oam_search_index; + uint8_t accessed_oam_row; + uint8_t extra_penalty_for_sprite_at_0; + uint8_t mode_for_interrupt; + bool lyc_interrupt_line; + bool cgb_palettes_blocked; + uint8_t current_lcd_line; // The LCD can go out of sync since the vsync signal is skipped in some cases. + uint32_t cycles_in_stop_mode; + ); + + /* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */ + /* This data is reserved on reset and must come last in the struct */ + GB_SECTION(unsaved, + /* ROM */ + uint8_t *rom; + uint32_t rom_size; + const GB_cartridge_t *cartridge_type; + enum { + GB_STANDARD_MBC1_WIRING, + GB_MBC1M_WIRING, + } mbc1_wiring; + + unsigned pending_cycles; + + /* Various RAMs */ + uint8_t *ram; + uint8_t *vram; + uint8_t *mbc_ram; + + /* I/O */ + uint32_t *screen; + uint32_t background_palettes_rgb[0x20]; + uint32_t sprite_palettes_rgb[0x20]; + GB_color_correction_mode_t color_correction_mode; + bool keys[4][GB_KEY_MAX]; + + /* Timing */ + uint64_t last_sync; + uint64_t cycles_since_last_sync; // In 8MHz units + + /* Audio */ + GB_apu_output_t apu_output; + + /* Callbacks */ + void *user_data; + GB_log_callback_t log_callback; + GB_input_callback_t input_callback; + GB_input_callback_t async_input_callback; + GB_rgb_encode_callback_t rgb_encode_callback; + GB_vblank_callback_t vblank_callback; + GB_infrared_callback_t infrared_callback; + GB_camera_get_pixel_callback_t camera_get_pixel_callback; + GB_camera_update_request_callback_t camera_update_request_callback; + GB_rumble_callback_t rumble_callback; + GB_serial_transfer_bit_start_callback_t serial_transfer_bit_start_callback; + GB_serial_transfer_bit_end_callback_t serial_transfer_bit_end_callback; + GB_update_input_hint_callback_t update_input_hint_callback; + GB_joyp_write_callback_t joyp_write_callback; + GB_icd_pixel_callback_t icd_pixel_callback; + GB_icd_vreset_callback_t icd_hreset_callback; + GB_icd_vreset_callback_t icd_vreset_callback; + GB_read_memory_callback_t read_memory_callback; + + /* IR */ + long cycles_since_ir_change; // In 8MHz units + long cycles_since_input_ir_change; // In 8MHz units + GB_ir_queue_item_t ir_queue[GB_MAX_IR_QUEUE]; + size_t ir_queue_length; + + /*** Debugger ***/ + volatile bool debug_stopped, debug_disable; + bool debug_fin_command, debug_next_command; + + /* Breakpoints */ + uint16_t n_breakpoints; + struct GB_breakpoint_s *breakpoints; + bool has_jump_to_breakpoints; + void *nontrivial_jump_state; + bool non_trivial_jump_breakpoint_occured; + + /* SLD (Todo: merge with backtrace) */ + bool stack_leak_detection; + int debug_call_depth; + uint16_t sp_for_call_depth[0x200]; /* Should be much more than enough */ + uint16_t addr_for_call_depth[0x200]; + + /* Backtrace */ + unsigned backtrace_size; + uint16_t backtrace_sps[0x200]; + struct { + uint16_t bank; + uint16_t addr; + } backtrace_returns[0x200]; + + /* Watchpoints */ + uint16_t n_watchpoints; + struct GB_watchpoint_s *watchpoints; + + /* Symbol tables */ + GB_symbol_map_t *bank_symbols[0x200]; + GB_reversed_symbol_map_t reversed_symbol_map; + + /* Ticks command */ + unsigned long debugger_ticks; + + /* Rewind */ +#define GB_REWIND_FRAMES_PER_KEY 255 + size_t rewind_buffer_length; + struct { + uint8_t *key_state; + uint8_t *compressed_states[GB_REWIND_FRAMES_PER_KEY]; + unsigned pos; + } *rewind_sequences; // lasts about 4 seconds + size_t rewind_pos; + + /* SGB - saved and allocated optionally */ + GB_sgb_t *sgb; + + double sgb_intro_jingle_phases[7]; + double sgb_intro_sweep_phase; + double sgb_intro_sweep_previous_sample; + + /* Misc */ + bool turbo; + bool turbo_dont_skip; + bool disable_rendering; + uint8_t boot_rom[0x900]; + bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank + uint8_t cycles_since_run; // How many cycles have passed since the last call to GB_run(), in 8MHz units + double clock_multiplier; + ); +}; + +#ifndef GB_INTERNAL +struct GB_gameboy_s { + char __internal[sizeof(struct GB_gameboy_internal_s)]; +}; +#endif + + +#ifndef __printflike +/* Missing from Linux headers. */ +#define __printflike(fmtarg, firstvararg) \ +__attribute__((__format__ (__printf__, fmtarg, firstvararg))) +#endif + +void GB_init(GB_gameboy_t *gb, GB_model_t model); +bool GB_is_inited(GB_gameboy_t *gb); +bool GB_is_cgb(GB_gameboy_t *gb); +bool GB_is_sgb(GB_gameboy_t *gb); // Returns true if the model is SGB or SGB2 +bool GB_is_hle_sgb(GB_gameboy_t *gb); // Returns true if the model is SGB or SGB2 and the SFC/SNES side is HLE'd +GB_model_t GB_get_model(GB_gameboy_t *gb); +void GB_free(GB_gameboy_t *gb); +void GB_reset(GB_gameboy_t *gb); +void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model); + +/* Returns the time passed, in 8MHz ticks. */ +uint8_t GB_run(GB_gameboy_t *gb); +/* Returns the time passed since the last frame, in nanoseconds */ +uint64_t GB_run_frame(GB_gameboy_t *gb); + +typedef enum { + GB_DIRECT_ACCESS_ROM, + GB_DIRECT_ACCESS_RAM, + GB_DIRECT_ACCESS_CART_RAM, + GB_DIRECT_ACCESS_VRAM, + GB_DIRECT_ACCESS_HRAM, + GB_DIRECT_ACCESS_IO, /* Warning: Some registers can only be read/written correctly via GB_memory_read/write. */ + GB_DIRECT_ACCESS_BOOTROM, + GB_DIRECT_ACCESS_OAM, + GB_DIRECT_ACCESS_BGP, + GB_DIRECT_ACCESS_OBP, + GB_DIRECT_ACCESS_IE, +} GB_direct_access_t; + +/* Returns a mutable pointer to various hardware memories. If that memory is banked, the current bank + is returned at *bank, even if only a portion of the memory is banked. */ +void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *size, uint16_t *bank); + +void *GB_get_user_data(GB_gameboy_t *gb); +void GB_set_user_data(GB_gameboy_t *gb, void *data); + + + +int GB_load_boot_rom(GB_gameboy_t *gb, const char *path); +void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size); +int GB_load_rom(GB_gameboy_t *gb, const char *path); +void GB_load_rom_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size); + +int GB_save_battery_size(GB_gameboy_t *gb); +int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size); +int GB_save_battery(GB_gameboy_t *gb, const char *path); + +void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size); +void GB_load_battery(GB_gameboy_t *gb, const char *path); + +void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip); +void GB_set_rendering_disabled(GB_gameboy_t *gb, bool disabled); + +void GB_log(GB_gameboy_t *gb, const char *fmt, ...) __printflike(2, 3); +void GB_attributed_log(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, ...) __printflike(3, 4); + +void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output); + +void GB_set_infrared_input(GB_gameboy_t *gb, bool state); +void GB_queue_infrared_input(GB_gameboy_t *gb, bool state, long cycles_after_previous_change); /* In 8MHz units*/ + +void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback); +void GB_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback); +void GB_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback); +void GB_set_async_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback); +void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback); +void GB_set_infrared_callback(GB_gameboy_t *gb, GB_infrared_callback_t callback); +void GB_set_rumble_callback(GB_gameboy_t *gb, GB_rumble_callback_t callback); +void GB_set_update_input_hint_callback(GB_gameboy_t *gb, GB_update_input_hint_callback_t callback); + +/* These APIs are used when using internal clock */ +void GB_set_serial_transfer_bit_start_callback(GB_gameboy_t *gb, GB_serial_transfer_bit_start_callback_t callback); +void GB_set_serial_transfer_bit_end_callback(GB_gameboy_t *gb, GB_serial_transfer_bit_end_callback_t callback); + +/* These APIs are used when using external clock */ +bool GB_serial_get_data_bit(GB_gameboy_t *gb); +void GB_serial_set_data_bit(GB_gameboy_t *gb, bool data); + +void GB_disconnect_serial(GB_gameboy_t *gb); + +/* For integration with SFC/SNES emulators */ +void GB_set_joyp_write_callback(GB_gameboy_t *gb, GB_joyp_write_callback_t callback); +void GB_set_icd_pixel_callback(GB_gameboy_t *gb, GB_icd_pixel_callback_t callback); +void GB_set_icd_hreset_callback(GB_gameboy_t *gb, GB_icd_hreset_callback_t callback); +void GB_set_icd_vreset_callback(GB_gameboy_t *gb, GB_icd_vreset_callback_t callback); + +#ifdef GB_INTERNAL +uint32_t GB_get_clock_rate(GB_gameboy_t *gb); +#endif +void GB_set_clock_multiplier(GB_gameboy_t *gb, double multiplier); + +unsigned GB_get_screen_width(GB_gameboy_t *gb); +unsigned GB_get_screen_height(GB_gameboy_t *gb); +double GB_get_usual_frame_rate(GB_gameboy_t *gb); +unsigned GB_get_player_count(GB_gameboy_t *gb); + +#endif /* GB_h */ diff --git a/gb/Core/gb_struct_def.h b/gb/Core/gb_struct_def.h new file mode 100644 index 0000000..0e0ebd1 --- /dev/null +++ b/gb/Core/gb_struct_def.h @@ -0,0 +1,5 @@ +#ifndef gb_struct_def_h +#define gb_struct_def_h +struct GB_gameboy_s; +typedef struct GB_gameboy_s GB_gameboy_t; +#endif diff --git a/gb/Core/joypad.c b/gb/Core/joypad.c new file mode 100644 index 0000000..b8d4fdb --- /dev/null +++ b/gb/Core/joypad.c @@ -0,0 +1,92 @@ +#include "gb.h" +#include + +void GB_update_joyp(GB_gameboy_t *gb) +{ + if (gb->model & GB_MODEL_NO_SFC_BIT) return; + + uint8_t key_selection = 0; + uint8_t previous_state = 0; + + /* Todo: add delay to key selection */ + previous_state = gb->io_registers[GB_IO_JOYP] & 0xF; + key_selection = (gb->io_registers[GB_IO_JOYP] >> 4) & 3; + gb->io_registers[GB_IO_JOYP] &= 0xF0; + uint8_t current_player = gb->sgb? (gb->sgb->current_player & (gb->sgb->player_count - 1) & 3) : 0; + switch (key_selection) { + case 3: + if (gb->sgb && gb->sgb->player_count > 1) { + gb->io_registers[GB_IO_JOYP] |= 0xF - current_player; + } + else { + /* Nothing is wired, all up */ + gb->io_registers[GB_IO_JOYP] |= 0x0F; + } + break; + + case 2: + /* Direction keys */ + for (uint8_t i = 0; i < 4; i++) { + gb->io_registers[GB_IO_JOYP] |= (!gb->keys[current_player][i]) << i; + } + /* Forbid pressing two opposing keys, this breaks a lot of games; even if it's somewhat possible. */ + if (!(gb->io_registers[GB_IO_JOYP] & 1)) { + gb->io_registers[GB_IO_JOYP] |= 2; + } + if (!(gb->io_registers[GB_IO_JOYP] & 4)) { + gb->io_registers[GB_IO_JOYP] |= 8; + } + break; + + case 1: + /* Other keys */ + for (uint8_t i = 0; i < 4; i++) { + gb->io_registers[GB_IO_JOYP] |= (!gb->keys[current_player][i + 4]) << i; + } + break; + + case 0: + for (uint8_t i = 0; i < 4; i++) { + gb->io_registers[GB_IO_JOYP] |= (!(gb->keys[current_player][i] || gb->keys[current_player][i + 4])) << i; + } + break; + + default: + break; + } + + /* Todo: This assumes the keys *always* bounce, which is incorrect when emulating an SGB */ + if (previous_state != (gb->io_registers[GB_IO_JOYP] & 0xF)) { + /* The joypad interrupt DOES occur on CGB (Tested on CGB-E), unlike what some documents say. */ + gb->io_registers[GB_IO_IF] |= 0x10; + } + + gb->io_registers[GB_IO_JOYP] |= 0xC0; +} + +void GB_icd_set_joyp(GB_gameboy_t *gb, uint8_t value) +{ + uint8_t previous_state = gb->io_registers[GB_IO_JOYP] & 0xF; + gb->io_registers[GB_IO_JOYP] &= 0xF0; + gb->io_registers[GB_IO_JOYP] |= value & 0xF; + + if (previous_state & ~(gb->io_registers[GB_IO_JOYP] & 0xF)) { + gb->io_registers[GB_IO_IF] |= 0x10; + } + gb->io_registers[GB_IO_JOYP] |= 0xC0; +} + +void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed) +{ + assert(index >= 0 && index < GB_KEY_MAX); + gb->keys[0][index] = pressed; + GB_update_joyp(gb); +} + +void GB_set_key_state_for_player(GB_gameboy_t *gb, GB_key_t index, unsigned player, bool pressed) +{ + assert(index >= 0 && index < GB_KEY_MAX); + assert(player < 4); + gb->keys[player][index] = pressed; + GB_update_joyp(gb); +} diff --git a/gb/Core/joypad.h b/gb/Core/joypad.h new file mode 100644 index 0000000..21fad53 --- /dev/null +++ b/gb/Core/joypad.h @@ -0,0 +1,25 @@ +#ifndef joypad_h +#define joypad_h +#include "gb_struct_def.h" +#include + +typedef enum { + GB_KEY_RIGHT, + GB_KEY_LEFT, + GB_KEY_UP, + GB_KEY_DOWN, + GB_KEY_A, + GB_KEY_B, + GB_KEY_SELECT, + GB_KEY_START, + GB_KEY_MAX +} GB_key_t; + +void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed); +void GB_set_key_state_for_player(GB_gameboy_t *gb, GB_key_t index, unsigned player, bool pressed); +void GB_icd_set_joyp(GB_gameboy_t *gb, uint8_t value); + +#ifdef GB_INTERNAL +void GB_update_joyp(GB_gameboy_t *gb); +#endif +#endif /* joypad_h */ diff --git a/gb/Core/mbc.c b/gb/Core/mbc.c new file mode 100644 index 0000000..d3791a1 --- /dev/null +++ b/gb/Core/mbc.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include "gb.h" + +const GB_cartridge_t GB_cart_defs[256] = { + // From http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header#0147_-_Cartridge_Type + /* MBC SUBTYPE RAM BAT. RTC RUMB. */ + { GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 00h ROM ONLY + { GB_MBC1 , GB_STANDARD_MBC, false, false, false, false}, // 01h MBC1 + { GB_MBC1 , GB_STANDARD_MBC, true , false, false, false}, // 02h MBC1+RAM + { GB_MBC1 , GB_STANDARD_MBC, true , true , false, false}, // 03h MBC1+RAM+BATTERY + [5] = + { GB_MBC2 , GB_STANDARD_MBC, true , false, false, false}, // 05h MBC2 + { GB_MBC2 , GB_STANDARD_MBC, true , true , false, false}, // 06h MBC2+BATTERY + [8] = + { GB_NO_MBC, GB_STANDARD_MBC, true , false, false, false}, // 08h ROM+RAM + { GB_NO_MBC, GB_STANDARD_MBC, true , true , false, false}, // 09h ROM+RAM+BATTERY + [0xB] = + /* Todo: Not supported yet */ + { GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 0Bh MMM01 + { GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 0Ch MMM01+RAM + { GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // 0Dh MMM01+RAM+BATTERY + [0xF] = + { GB_MBC3 , GB_STANDARD_MBC, false, true, true , false}, // 0Fh MBC3+TIMER+BATTERY + { GB_MBC3 , GB_STANDARD_MBC, true , true, true , false}, // 10h MBC3+TIMER+RAM+BATTERY + { GB_MBC3 , GB_STANDARD_MBC, false, false, false, false}, // 11h MBC3 + { GB_MBC3 , GB_STANDARD_MBC, true , false, false, false}, // 12h MBC3+RAM + { GB_MBC3 , GB_STANDARD_MBC, true , true , false, false}, // 13h MBC3+RAM+BATTERY + [0x19] = + { GB_MBC5 , GB_STANDARD_MBC, false, false, false, false}, // 19h MBC5 + { GB_MBC5 , GB_STANDARD_MBC, true , false, false, false}, // 1Ah MBC5+RAM + { GB_MBC5 , GB_STANDARD_MBC, true , true , false, false}, // 1Bh MBC5+RAM+BATTERY + { GB_MBC5 , GB_STANDARD_MBC, false, false, false, true }, // 1Ch MBC5+RUMBLE + { GB_MBC5 , GB_STANDARD_MBC, true , false, false, true }, // 1Dh MBC5+RUMBLE+RAM + { GB_MBC5 , GB_STANDARD_MBC, true , true , false, true }, // 1Eh MBC5+RUMBLE+RAM+BATTERY + [0xFC] = + { GB_MBC5 , GB_CAMERA , true , true , false, false}, // FCh POCKET CAMERA + { GB_NO_MBC, GB_STANDARD_MBC, false, false, false, false}, // FDh BANDAI TAMA5 (Todo: Not supported) + { GB_HUC3 , GB_STANDARD_MBC, true , true , false, false}, // FEh HuC3 (Todo: Mapper support only) + { GB_HUC1 , GB_STANDARD_MBC, true , true , false, false}, // FFh HuC1+RAM+BATTERY (Todo: No IR bindings) +}; + +void GB_update_mbc_mappings(GB_gameboy_t *gb) +{ + switch (gb->cartridge_type->mbc_type) { + case GB_NO_MBC: return; + case GB_MBC1: + switch (gb->mbc1_wiring) { + case GB_STANDARD_MBC1_WIRING: + gb->mbc_rom_bank = gb->mbc1.bank_low | (gb->mbc1.bank_high << 5); + if (gb->mbc1.mode == 0) { + gb->mbc_ram_bank = 0; + gb->mbc_rom0_bank = 0; + } + else { + gb->mbc_ram_bank = gb->mbc1.bank_high; + gb->mbc_rom0_bank = gb->mbc1.bank_high << 5; + } + if ((gb->mbc_rom_bank & 0x1F) == 0) { + gb->mbc_rom_bank++; + } + break; + case GB_MBC1M_WIRING: + gb->mbc_rom_bank = (gb->mbc1.bank_low & 0xF) | (gb->mbc1.bank_high << 4); + if (gb->mbc1.mode == 0) { + gb->mbc_ram_bank = 0; + gb->mbc_rom0_bank = 0; + } + else { + gb->mbc_rom0_bank = gb->mbc1.bank_high << 4; + gb->mbc_ram_bank = 0; + } + if ((gb->mbc1.bank_low & 0x1F) == 0) { + gb->mbc_rom_bank++; + } + break; + } + break; + case GB_MBC2: + gb->mbc_rom_bank = gb->mbc2.rom_bank; + if ((gb->mbc_rom_bank & 0xF) == 0) { + gb->mbc_rom_bank = 1; + } + break; + case GB_MBC3: + gb->mbc_rom_bank = gb->mbc3.rom_bank; + gb->mbc_ram_bank = gb->mbc3.ram_bank; + if (gb->mbc_rom_bank == 0) { + gb->mbc_rom_bank = 1; + } + break; + case GB_MBC5: + gb->mbc_rom_bank = gb->mbc5.rom_bank_low | (gb->mbc5.rom_bank_high << 8); + gb->mbc_ram_bank = gb->mbc5.ram_bank; + break; + case GB_HUC1: + if (gb->huc1.mode == 0) { + gb->mbc_rom_bank = gb->huc1.bank_low | (gb->mbc1.bank_high << 6); + gb->mbc_ram_bank = 0; + } + else { + gb->mbc_rom_bank = gb->huc1.bank_low; + gb->mbc_ram_bank = gb->huc1.bank_high; + } + break; + case GB_HUC3: + gb->mbc_rom_bank = gb->huc3.rom_bank; + gb->mbc_ram_bank = gb->huc3.ram_bank; + break; + } +} + +void GB_configure_cart(GB_gameboy_t *gb) +{ + gb->cartridge_type = &GB_cart_defs[gb->rom[0x147]]; + + if (gb->rom[0x147] == 0 && gb->rom_size > 0x8000) { + GB_log(gb, "ROM header reports no MBC, but file size is over 32Kb. Assuming cartridge uses MBC3.\n"); + gb->cartridge_type = &GB_cart_defs[0x11]; + } + else if (gb->rom[0x147] != 0 && memcmp(gb->cartridge_type, &GB_cart_defs[0], sizeof(GB_cart_defs[0])) == 0) { + GB_log(gb, "Cartridge type %02x is not yet supported.\n", gb->rom[0x147]); + } + + if (gb->cartridge_type->has_ram) { + if (gb->cartridge_type->mbc_type == GB_MBC2) { + gb->mbc_ram_size = 0x200; + } + else { + static const int ram_sizes[256] = {0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000}; + gb->mbc_ram_size = ram_sizes[gb->rom[0x149]]; + } + gb->mbc_ram = malloc(gb->mbc_ram_size); + + /* Todo: Some games assume unintialized MBC RAM is 0xFF. It this true for all cartridges types? */ + memset(gb->mbc_ram, 0xFF, gb->mbc_ram_size); + } + + /* MBC1 has at least 3 types of wiring (We currently support two (Standard and 4bit-MBC1M) of these). + See http://forums.nesdev.com/viewtopic.php?f=20&t=14099 */ + + /* Attempt to "guess" wiring */ + if (gb->cartridge_type->mbc_type == GB_MBC1) { + if (gb->rom_size >= 0x44000 && memcmp(gb->rom + 0x104, gb->rom + 0x40104, 0x30) == 0) { + gb->mbc1_wiring = GB_MBC1M_WIRING; + } + } + + /* Set MBC5's bank to 1 correctly */ + if (gb->cartridge_type->mbc_type == GB_MBC5) { + gb->mbc5.rom_bank_low = 1; + } +} diff --git a/gb/Core/mbc.h b/gb/Core/mbc.h new file mode 100644 index 0000000..7e9b47f --- /dev/null +++ b/gb/Core/mbc.h @@ -0,0 +1,32 @@ +#ifndef MBC_h +#define MBC_h +#include "gb_struct_def.h" +#include + +typedef struct { + enum { + GB_NO_MBC, + GB_MBC1, + GB_MBC2, + GB_MBC3, + GB_MBC5, + GB_HUC1, /* Todo: HUC1 features are not emulated. Should be unified with the CGB IR sensor API. */ + GB_HUC3, + } mbc_type; + enum { + GB_STANDARD_MBC, + GB_CAMERA, + } mbc_subtype; + bool has_ram; + bool has_battery; + bool has_rtc; + bool has_rumble; +} GB_cartridge_t; + +#ifdef GB_INTERNAL +extern const GB_cartridge_t GB_cart_defs[256]; +void GB_update_mbc_mappings(GB_gameboy_t *gb); +void GB_configure_cart(GB_gameboy_t *gb); +#endif + +#endif /* MBC_h */ diff --git a/gb/Core/memory.c b/gb/Core/memory.c new file mode 100644 index 0000000..003bb77 --- /dev/null +++ b/gb/Core/memory.c @@ -0,0 +1,1015 @@ +#include +#include +#include "gb.h" + +typedef uint8_t GB_read_function_t(GB_gameboy_t *gb, uint16_t addr); +typedef void GB_write_function_t(GB_gameboy_t *gb, uint16_t addr, uint8_t value); + +typedef enum { + GB_BUS_MAIN, /* In DMG: Cart and RAM. In CGB: Cart only */ + GB_BUS_RAM, /* In CGB only. */ + GB_BUS_VRAM, + GB_BUS_INTERNAL, /* Anything in highram. Might not be the most correct name. */ +} GB_bus_t; + +static GB_bus_t bus_for_addr(GB_gameboy_t *gb, uint16_t addr) +{ + if (addr < 0x8000) { + return GB_BUS_MAIN; + } + if (addr < 0xA000) { + return GB_BUS_VRAM; + } + if (addr < 0xC000) { + return GB_BUS_MAIN; + } + if (addr < 0xFE00) { + return GB_is_cgb(gb)? GB_BUS_RAM : GB_BUS_MAIN; + } + return GB_BUS_INTERNAL; +} + +static uint8_t bitwise_glitch(uint8_t a, uint8_t b, uint8_t c) +{ + return ((a ^ c) & (b ^ c)) ^ c; +} + +static uint8_t bitwise_glitch_read(uint8_t a, uint8_t b, uint8_t c) +{ + return b | (a & c); +} + +static uint8_t bitwise_glitch_read_increase(uint8_t a, uint8_t b, uint8_t c, uint8_t d) +{ + return (b & (a | c | d)) | (a & c & d); +} + +void GB_trigger_oam_bug(GB_gameboy_t *gb, uint16_t address) +{ + if (GB_is_cgb(gb)) return; + + if (address >= 0xFE00 && address < 0xFF00) { + if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 8) { + gb->oam[gb->accessed_oam_row] = bitwise_glitch(gb->oam[gb->accessed_oam_row], + gb->oam[gb->accessed_oam_row - 8], + gb->oam[gb->accessed_oam_row - 4]); + gb->oam[gb->accessed_oam_row + 1] = bitwise_glitch(gb->oam[gb->accessed_oam_row + 1], + gb->oam[gb->accessed_oam_row - 7], + gb->oam[gb->accessed_oam_row - 3]); + for (unsigned i = 2; i < 8; i++) { + gb->oam[gb->accessed_oam_row + i] = gb->oam[gb->accessed_oam_row - 8 + i]; + } + } + } +} + +void GB_trigger_oam_bug_read(GB_gameboy_t *gb, uint16_t address) +{ + if (GB_is_cgb(gb)) return; + + if (address >= 0xFE00 && address < 0xFF00) { + if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 8) { + gb->oam[gb->accessed_oam_row - 8] = + gb->oam[gb->accessed_oam_row] = bitwise_glitch_read(gb->oam[gb->accessed_oam_row], + gb->oam[gb->accessed_oam_row - 8], + gb->oam[gb->accessed_oam_row - 4]); + gb->oam[gb->accessed_oam_row - 7] = + gb->oam[gb->accessed_oam_row + 1] = bitwise_glitch_read(gb->oam[gb->accessed_oam_row + 1], + gb->oam[gb->accessed_oam_row - 7], + gb->oam[gb->accessed_oam_row - 3]); + for (unsigned i = 2; i < 8; i++) { + gb->oam[gb->accessed_oam_row + i] = gb->oam[gb->accessed_oam_row - 8 + i]; + } + } + } +} + +void GB_trigger_oam_bug_read_increase(GB_gameboy_t *gb, uint16_t address) +{ + if (GB_is_cgb(gb)) return; + + if (address >= 0xFE00 && address < 0xFF00) { + if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 0x20 && gb->accessed_oam_row < 0x98) { + gb->oam[gb->accessed_oam_row - 0x8] = bitwise_glitch_read_increase(gb->oam[gb->accessed_oam_row - 0x10], + gb->oam[gb->accessed_oam_row - 0x08], + gb->oam[gb->accessed_oam_row ], + gb->oam[gb->accessed_oam_row - 0x04] + ); + gb->oam[gb->accessed_oam_row - 0x7] = bitwise_glitch_read_increase(gb->oam[gb->accessed_oam_row - 0x0f], + gb->oam[gb->accessed_oam_row - 0x07], + gb->oam[gb->accessed_oam_row + 0x01], + gb->oam[gb->accessed_oam_row - 0x03] + ); + for (unsigned i = 0; i < 8; i++) { + gb->oam[gb->accessed_oam_row + i] = gb->oam[gb->accessed_oam_row - 0x10 + i] = gb->oam[gb->accessed_oam_row - 0x08 + i]; + } + } + } +} + +static bool is_addr_in_dma_use(GB_gameboy_t *gb, uint16_t addr) +{ + if (!gb->dma_steps_left || (gb->dma_cycles < 0 && !gb->is_dma_restarting) || addr >= 0xFE00) return false; + return bus_for_addr(gb, addr) == bus_for_addr(gb, gb->dma_current_src); +} + +static uint8_t read_rom(GB_gameboy_t *gb, uint16_t addr) +{ + if (addr < 0x100 && !gb->boot_rom_finished) { + return gb->boot_rom[addr]; + } + + if (addr >= 0x200 && addr < 0x900 && GB_is_cgb(gb) && !gb->boot_rom_finished) { + return gb->boot_rom[addr]; + } + + if (!gb->rom_size) { + return 0xFF; + } + unsigned effective_address = (addr & 0x3FFF) + gb->mbc_rom0_bank * 0x4000; + return gb->rom[effective_address & (gb->rom_size - 1)]; +} + +static uint8_t read_mbc_rom(GB_gameboy_t *gb, uint16_t addr) +{ + unsigned effective_address = (addr & 0x3FFF) + gb->mbc_rom_bank * 0x4000; + return gb->rom[effective_address & (gb->rom_size - 1)]; +} + +static uint8_t read_vram(GB_gameboy_t *gb, uint16_t addr) +{ + if (gb->vram_read_blocked) { + return 0xFF; + } + return gb->vram[(addr & 0x1FFF) + (uint16_t) gb->cgb_vram_bank * 0x2000]; +} + +static uint8_t read_mbc_ram(GB_gameboy_t *gb, uint16_t addr) +{ + if ((!gb->mbc_ram_enable || !gb->mbc_ram_size) && + gb->cartridge_type->mbc_subtype != GB_CAMERA && + gb->cartridge_type->mbc_type != GB_HUC1) return 0xFF; + + if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) { + /* RTC read */ + gb->rtc_latched.high |= ~0xC1; /* Not all bytes in RTC high are used. */ + return gb->rtc_latched.data[gb->mbc_ram_bank - 8]; + } + + if (gb->camera_registers_mapped) { + return GB_camera_read_register(gb, addr); + } + + if (!gb->mbc_ram) { + return 0xFF; + } + + if (gb->cartridge_type->mbc_subtype == GB_CAMERA && gb->mbc_ram_bank == 0 && addr >= 0xa100 && addr < 0xaf00) { + return GB_camera_read_image(gb, addr - 0xa100); + } + + uint8_t ret = gb->mbc_ram[((addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000) & (gb->mbc_ram_size - 1)]; + if (gb->cartridge_type->mbc_type == GB_MBC2) { + ret |= 0xF0; + } + return ret; +} + +static uint8_t read_ram(GB_gameboy_t *gb, uint16_t addr) +{ + return gb->ram[addr & 0x0FFF]; +} + +static uint8_t read_banked_ram(GB_gameboy_t *gb, uint16_t addr) +{ + return gb->ram[(addr & 0x0FFF) + gb->cgb_ram_bank * 0x1000]; +} + +static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) +{ + + if (gb->hdma_on) { + return gb->last_opcode_read; + } + + if (addr < 0xFE00) { + return read_banked_ram(gb, addr); + } + + if (addr < 0xFF00) { + if (gb->oam_write_blocked && !GB_is_cgb(gb)) { + GB_trigger_oam_bug_read(gb, addr); + return 0xff; + } + + if ((gb->dma_steps_left && (gb->dma_cycles > 0 || gb->is_dma_restarting))) { + /* Todo: Does reading from OAM during DMA causes the OAM bug? */ + return 0xff; + } + + if (gb->oam_read_blocked) { + if (!GB_is_cgb(gb)) { + if (addr < 0xFEA0) { + if (gb->accessed_oam_row == 0) { + gb->oam[(addr & 0xf8)] = + gb->oam[0] = bitwise_glitch_read(gb->oam[0], + gb->oam[(addr & 0xf8)], + gb->oam[(addr & 0xfe)]); + gb->oam[(addr & 0xf8) + 1] = + gb->oam[1] = bitwise_glitch_read(gb->oam[1], + gb->oam[(addr & 0xf8) + 1], + gb->oam[(addr & 0xfe) | 1]); + for (unsigned i = 2; i < 8; i++) { + gb->oam[i] = gb->oam[(addr & 0xf8) + i]; + } + } + else if (gb->accessed_oam_row == 0xa0) { + gb->oam[0x9e] = bitwise_glitch_read(gb->oam[0x9c], + gb->oam[0x9e], + gb->oam[(addr & 0xf8) | 6]); + gb->oam[0x9f] = bitwise_glitch_read(gb->oam[0x9d], + gb->oam[0x9f], + gb->oam[(addr & 0xf8) | 7]); + + for (unsigned i = 0; i < 8; i++) { + gb->oam[(addr & 0xf8) + i] = gb->oam[0x98 + i]; + } + } + } + } + return 0xff; + } + + if (addr < 0xFEA0) { + return gb->oam[addr & 0xFF]; + } + + if (gb->oam_read_blocked) { + return 0xFF; + } + + switch (gb->model) { + case GB_MODEL_CGB_E: + case GB_MODEL_AGB: + return (addr & 0xF0) | ((addr >> 4) & 0xF); + + /* + case GB_MODEL_CGB_D: + if (addr > 0xfec0) { + addr |= 0xf0; + } + return gb->extra_oam[addr - 0xfea0]; + */ + + case GB_MODEL_CGB_C: + /* + case GB_MODEL_CGB_B: + case GB_MODEL_CGB_A: + case GB_MODEL_CGB_0: + */ + addr &= ~0x18; + return gb->extra_oam[addr - 0xfea0]; + + case GB_MODEL_DMG_B: + case GB_MODEL_SGB_NTSC: + case GB_MODEL_SGB_PAL: + case GB_MODEL_SGB_NTSC_NO_SFC: + case GB_MODEL_SGB_PAL_NO_SFC: + case GB_MODEL_SGB2: + case GB_MODEL_SGB2_NO_SFC: + ; + } + } + + if (addr < 0xFF00) { + + return 0; + + } + + if (addr < 0xFF80) { + switch (addr & 0xFF) { + case GB_IO_IF: + return gb->io_registers[GB_IO_IF] | 0xE0; + case GB_IO_TAC: + return gb->io_registers[GB_IO_TAC] | 0xF8; + case GB_IO_STAT: + return gb->io_registers[GB_IO_STAT] | 0x80; + case GB_IO_DMG_EMULATION_INDICATION: + if (!gb->cgb_mode) { + return 0xFF; + } + return gb->io_registers[GB_IO_DMG_EMULATION_INDICATION] | 0xFE; + + case GB_IO_PCM_12: + if (!GB_is_cgb(gb)) return 0xFF; + return (gb->apu.is_active[GB_SQUARE_2] ? (gb->apu.samples[GB_SQUARE_2] << 4) : 0) | + (gb->apu.is_active[GB_SQUARE_1] ? (gb->apu.samples[GB_SQUARE_1]) : 0); + case GB_IO_PCM_34: + if (!GB_is_cgb(gb)) return 0xFF; + return (gb->apu.is_active[GB_NOISE] ? (gb->apu.samples[GB_NOISE] << 4) : 0) | + (gb->apu.is_active[GB_WAVE] ? (gb->apu.samples[GB_WAVE]) : 0); + case GB_IO_JOYP: + GB_timing_sync(gb); + case GB_IO_TMA: + case GB_IO_LCDC: + case GB_IO_SCY: + case GB_IO_SCX: + case GB_IO_LY: + case GB_IO_LYC: + case GB_IO_BGP: + case GB_IO_OBP0: + case GB_IO_OBP1: + case GB_IO_WY: + case GB_IO_WX: + case GB_IO_SC: + case GB_IO_SB: + case GB_IO_DMA: + return gb->io_registers[addr & 0xFF]; + case GB_IO_TIMA: + if (gb->tima_reload_state == GB_TIMA_RELOADING) { + return 0; + } + return gb->io_registers[GB_IO_TIMA]; + case GB_IO_DIV: + return gb->div_counter >> 8; + case GB_IO_HDMA5: + if (!gb->cgb_mode) return 0xFF; + return ((gb->hdma_on || gb->hdma_on_hblank)? 0 : 0x80) | ((gb->hdma_steps_left - 1) & 0x7F); + case GB_IO_SVBK: + if (!gb->cgb_mode) { + return 0xFF; + } + return gb->cgb_ram_bank | ~0x7; + case GB_IO_VBK: + if (!GB_is_cgb(gb)) { + return 0xFF; + } + return gb->cgb_vram_bank | ~0x1; + + /* Todo: It seems that a CGB in DMG mode can access BGPI and OBPI, but not BGPD and OBPD? */ + case GB_IO_BGPI: + case GB_IO_OBPI: + if (!GB_is_cgb(gb)) { + return 0xFF; + } + return gb->io_registers[addr & 0xFF] | 0x40; + + case GB_IO_BGPD: + case GB_IO_OBPD: + { + if (!gb->cgb_mode && gb->boot_rom_finished) { + return 0xFF; + } + if (gb->cgb_palettes_blocked) { + return 0xFF; + } + uint8_t index_reg = (addr & 0xFF) - 1; + return ((addr & 0xFF) == GB_IO_BGPD? + gb->background_palettes_data : + gb->sprite_palettes_data)[gb->io_registers[index_reg] & 0x3F]; + } + + case GB_IO_KEY1: + if (!gb->cgb_mode) { + return 0xFF; + } + return (gb->io_registers[GB_IO_KEY1] & 0x7F) | (gb->cgb_double_speed? 0xFE : 0x7E); + + case GB_IO_RP: { + if (!gb->cgb_mode) return 0xFF; + /* You will read your own IR LED if it's on. */ + bool read_value = gb->infrared_input || (gb->io_registers[GB_IO_RP] & 1); + uint8_t ret = (gb->io_registers[GB_IO_RP] & 0xC1) | 0x3C; + if ((gb->io_registers[GB_IO_RP] & 0xC0) == 0xC0 && read_value) { + ret |= 2; + } + return ret; + } + case GB_IO_UNKNOWN2: + case GB_IO_UNKNOWN3: + return GB_is_cgb(gb)? gb->io_registers[addr & 0xFF] : 0xFF; + case GB_IO_UNKNOWN4: + return gb->cgb_mode? gb->io_registers[addr & 0xFF] : 0xFF; + case GB_IO_UNKNOWN5: + return GB_is_cgb(gb)? gb->io_registers[addr & 0xFF] | 0x8F : 0xFF; + default: + if ((addr & 0xFF) >= GB_IO_NR10 && (addr & 0xFF) <= GB_IO_WAV_END) { + return GB_apu_read(gb, addr & 0xFF); + } + return 0xFF; + } + /* Hardware registers */ + return 0; + } + + if (addr == 0xFFFF) { + /* Interrupt Mask */ + return gb->interrupt_enable; + } + + /* HRAM */ + return gb->hram[addr - 0xFF80]; +} + +static GB_read_function_t * const read_map[] = +{ + read_rom, read_rom, read_rom, read_rom, /* 0XXX, 1XXX, 2XXX, 3XXX */ + read_mbc_rom, read_mbc_rom, read_mbc_rom, read_mbc_rom, /* 4XXX, 5XXX, 6XXX, 7XXX */ + read_vram, read_vram, /* 8XXX, 9XXX */ + read_mbc_ram, read_mbc_ram, /* AXXX, BXXX */ + read_ram, read_banked_ram, /* CXXX, DXXX */ + read_ram, read_high_memory, /* EXXX FXXX */ +}; + +void GB_set_read_memory_callback(GB_gameboy_t *gb, GB_read_memory_callback_t callback) +{ + gb->read_memory_callback = callback; +} + +uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr) +{ + if (gb->n_watchpoints) { + GB_debugger_test_read_watchpoint(gb, addr); + } + if (is_addr_in_dma_use(gb, addr)) { + addr = gb->dma_current_src; + } + if (gb->read_memory_callback) { + uint8_t data = read_map[addr >> 12](gb, addr); + data = gb->read_memory_callback(gb, addr, data); + return data; + } + return read_map[addr >> 12](gb, addr); +} + +static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value) +{ + switch (gb->cartridge_type->mbc_type) { + case GB_NO_MBC: return; + case GB_MBC1: + switch (addr & 0xF000) { + case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break; + case 0x2000: case 0x3000: gb->mbc1.bank_low = value; break; + case 0x4000: case 0x5000: gb->mbc1.bank_high = value; break; + case 0x6000: case 0x7000: gb->mbc1.mode = value; break; + } + break; + case GB_MBC2: + switch (addr & 0xF000) { + case 0x0000: case 0x1000: if (!(addr & 0x100)) gb->mbc_ram_enable = (value & 0xF) == 0xA; break; + case 0x2000: case 0x3000: if ( addr & 0x100) gb->mbc2.rom_bank = value; break; + } + break; + case GB_MBC3: + switch (addr & 0xF000) { + case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break; + case 0x2000: case 0x3000: gb->mbc3.rom_bank = value; break; + case 0x4000: case 0x5000: gb->mbc3.ram_bank = value; break; + case 0x6000: case 0x7000: + if (!gb->rtc_latch && (value & 1)) { /* Todo: verify condition is correct */ + memcpy(&gb->rtc_latched, &gb->rtc_real, sizeof(gb->rtc_real)); + } + gb->rtc_latch = value & 1; + break; + } + break; + case GB_MBC5: + switch (addr & 0xF000) { + case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break; + case 0x2000: gb->mbc5.rom_bank_low = value; break; + case 0x3000: gb->mbc5.rom_bank_high = value; break; + case 0x4000: case 0x5000: + if (gb->cartridge_type->has_rumble) { + if (!!(value & 8) != gb->rumble_state) { + gb->rumble_state = !gb->rumble_state; + if (gb->rumble_callback) { + gb->rumble_callback(gb, gb->rumble_state); + } + } + value &= 7; + } + gb->mbc5.ram_bank = value; + gb->camera_registers_mapped = (value & 0x10) && gb->cartridge_type->mbc_subtype == GB_CAMERA; + break; + } + break; + case GB_HUC1: + switch (addr & 0xF000) { + case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break; + case 0x2000: case 0x3000: gb->huc1.bank_low = value; break; + case 0x4000: case 0x5000: gb->huc1.bank_high = value; break; + case 0x6000: case 0x7000: gb->huc1.mode = value; break; + } + break; + case GB_HUC3: + switch (addr & 0xF000) { + case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break; + case 0x2000: case 0x3000: gb->huc3.rom_bank = value; break; + case 0x4000: case 0x5000: gb->huc3.ram_bank = value; break; + } + break; + } + GB_update_mbc_mappings(gb); +} + +static void write_vram(GB_gameboy_t *gb, uint16_t addr, uint8_t value) +{ + if (gb->vram_write_blocked) { + //GB_log(gb, "Wrote %02x to %04x (VRAM) during mode 3\n", value, addr); + return; + } + gb->vram[(addr & 0x1FFF) + (uint16_t) gb->cgb_vram_bank * 0x2000] = value; +} + +static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value) +{ + if (gb->camera_registers_mapped) { + GB_camera_write_register(gb, addr, value); + return; + } + + if (!gb->mbc_ram_enable || !gb->mbc_ram_size) return; + + if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) { + gb->rtc_latched.data[gb->mbc_ram_bank - 8] = gb->rtc_real.data[gb->mbc_ram_bank - 8] = value; + return; + } + + if (!gb->mbc_ram) { + return; + } + + gb->mbc_ram[((addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000) & (gb->mbc_ram_size - 1)] = value; +} + +static void write_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value) +{ + gb->ram[addr & 0x0FFF] = value; +} + +static void write_banked_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value) +{ + gb->ram[(addr & 0x0FFF) + gb->cgb_ram_bank * 0x1000] = value; +} + +static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) +{ + if (addr < 0xFE00) { + GB_log(gb, "Wrote %02x to %04x (RAM Mirror)\n", value, addr); + write_banked_ram(gb, addr, value); + return; + } + + if (addr < 0xFF00) { + if (gb->oam_write_blocked) { + GB_trigger_oam_bug(gb, addr); + return; + } + + if ((gb->dma_steps_left && (gb->dma_cycles > 0 || gb->is_dma_restarting))) { + /* Todo: Does writing to OAM during DMA causes the OAM bug? */ + return; + } + + if (GB_is_cgb(gb)) { + if (addr < 0xFEA0) { + gb->oam[addr & 0xFF] = value; + } + switch (gb->model) { + /* + case GB_MODEL_CGB_D: + if (addr > 0xfec0) { + addr |= 0xf0; + } + gb->extra_oam[addr - 0xfea0] = value; + break; + */ + case GB_MODEL_CGB_C: + /* + case GB_MODEL_CGB_B: + case GB_MODEL_CGB_A: + case GB_MODEL_CGB_0: + */ + addr &= ~0x18; + gb->extra_oam[addr - 0xfea0] = value; + break; + case GB_MODEL_DMG_B: + case GB_MODEL_SGB_NTSC: + case GB_MODEL_SGB_PAL: + case GB_MODEL_SGB_NTSC_NO_SFC: + case GB_MODEL_SGB_PAL_NO_SFC: + case GB_MODEL_SGB2: + case GB_MODEL_SGB2_NO_SFC: + case GB_MODEL_CGB_E: + case GB_MODEL_AGB: + break; + } + return; + } + + if (addr < 0xFEA0) { + if (gb->accessed_oam_row == 0xa0) { + for (unsigned i = 0; i < 8; i++) { + if ((i & 6) != (addr & 6)) { + gb->oam[(addr & 0xf8) + i] = gb->oam[0x98 + i]; + } + else { + gb->oam[(addr & 0xf8) + i] = bitwise_glitch(gb->oam[(addr & 0xf8) + i], gb->oam[0x9c], gb->oam[0x98 + i]); + } + } + } + + gb->oam[addr & 0xFF] = value; + + if (gb->accessed_oam_row == 0) { + gb->oam[0] = bitwise_glitch(gb->oam[0], + gb->oam[(addr & 0xf8)], + gb->oam[(addr & 0xfe)]); + gb->oam[1] = bitwise_glitch(gb->oam[1], + gb->oam[(addr & 0xf8) + 1], + gb->oam[(addr & 0xfe) | 1]); + for (unsigned i = 2; i < 8; i++) { + gb->oam[i] = gb->oam[(addr & 0xf8) + i]; + } + } + } + else if (gb->accessed_oam_row == 0) { + gb->oam[addr & 0x7] = value; + } + return; + } + + /* Todo: Clean this code up: use a function table and move relevant code to display.c and timing.c + (APU read and writes are already at apu.c) */ + if (addr < 0xFF80) { + /* Hardware registers */ + switch (addr & 0xFF) { + case GB_IO_WX: + GB_window_related_write(gb, addr & 0xFF, value); + break; + case GB_IO_IF: + case GB_IO_SCX: + case GB_IO_SCY: + case GB_IO_BGP: + case GB_IO_OBP0: + case GB_IO_OBP1: + case GB_IO_WY: + case GB_IO_SB: + case GB_IO_DMG_EMULATION_INDICATION: + case GB_IO_UNKNOWN2: + case GB_IO_UNKNOWN3: + case GB_IO_UNKNOWN4: + case GB_IO_UNKNOWN5: + gb->io_registers[addr & 0xFF] = value; + return; + case GB_IO_LYC: + + /* TODO: Probably completely wrong in double speed mode */ + + /* TODO: This hack is disgusting */ + if (gb->display_state == 29 && GB_is_cgb(gb)) { + gb->ly_for_comparison = 153; + GB_STAT_update(gb); + gb->ly_for_comparison = 0; + } + + gb->io_registers[addr & 0xFF] = value; + + /* These are the states when LY changes, let the display routine call GB_STAT_update for use + so it correctly handles T-cycle accurate LYC writes */ + if (!GB_is_cgb(gb) || ( + gb->display_state != 35 && + gb->display_state != 26 && + gb->display_state != 15 && + gb->display_state != 16)) { + + /* More hacks to make LYC write conflicts work */ + if (gb->display_state == 14 && GB_is_cgb(gb)) { + gb->ly_for_comparison = 153; + GB_STAT_update(gb); + gb->ly_for_comparison = -1; + } + else { + GB_STAT_update(gb); + } + } + return; + + case GB_IO_TIMA: + if (gb->tima_reload_state != GB_TIMA_RELOADED) { + gb->io_registers[GB_IO_TIMA] = value; + } + return; + + case GB_IO_TMA: + gb->io_registers[GB_IO_TMA] = value; + if (gb->tima_reload_state != GB_TIMA_RUNNING) { + gb->io_registers[GB_IO_TIMA] = value; + } + return; + + case GB_IO_TAC: + GB_emulate_timer_glitch(gb, gb->io_registers[GB_IO_TAC], value); + gb->io_registers[GB_IO_TAC] = value; + return; + + + case GB_IO_LCDC: + if ((value & 0x80) && !(gb->io_registers[GB_IO_LCDC] & 0x80)) { + gb->display_cycles = 0; + gb->display_state = 0; + if (GB_is_sgb(gb)) { + gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED; + } + else if (gb->frame_skip_state == GB_FRAMESKIP_SECOND_FRAME_RENDERED) { + gb->frame_skip_state = GB_FRAMESKIP_LCD_TURNED_ON; + } + } + else if (!(value & 0x80) && (gb->io_registers[GB_IO_LCDC] & 0x80)) { + /* Sync after turning off LCD */ + GB_timing_sync(gb); + GB_lcd_off(gb); + } + /* Writing to LCDC might enable to disable the window, so we write it via GB_window_related_write */ + GB_window_related_write(gb, addr & 0xFF, value); + return; + + case GB_IO_STAT: + /* Delete previous R/W bits */ + gb->io_registers[GB_IO_STAT] &= 7; + /* Set them by value */ + gb->io_registers[GB_IO_STAT] |= value & ~7; + /* Set unused bit to 1 */ + gb->io_registers[GB_IO_STAT] |= 0x80; + + GB_STAT_update(gb); + return; + + case GB_IO_DIV: + /* Reset the div state machine */ + gb->div_state = 0; + gb->div_cycles = 0; + return; + + case GB_IO_JOYP: + if (gb->joyp_write_callback) { + gb->joyp_write_callback(gb, value); + GB_update_joyp(gb); + } + else if ((gb->io_registers[GB_IO_JOYP] & 0x30) != (value & 0x30)) { + GB_sgb_write(gb, value); + gb->io_registers[GB_IO_JOYP] = value & 0xF0; + GB_update_joyp(gb); + } + return; + + case GB_IO_BIOS: + gb->boot_rom_finished = true; + return; + + case GB_IO_DMG_EMULATION: + if (GB_is_cgb(gb) && !gb->boot_rom_finished) { + gb->cgb_mode = !(value & 0xC); /* The real "contents" of this register aren't quite known yet. */ + } + return; + + case GB_IO_DMA: + if (gb->dma_steps_left) { + /* This is not correct emulation, since we're not really delaying the second DMA. + One write that should have happened in the first DMA will not happen. However, + since that byte will be overwritten by the second DMA before it can actually be + read, it doesn't actually matter. */ + gb->is_dma_restarting = true; + } + gb->dma_cycles = -7; + gb->dma_current_dest = 0; + gb->dma_current_src = value << 8; + gb->dma_steps_left = 0xa0; + gb->io_registers[GB_IO_DMA] = value; + return; + case GB_IO_SVBK: + if (!gb->cgb_mode) { + return; + } + gb->cgb_ram_bank = value & 0x7; + if (!gb->cgb_ram_bank) { + gb->cgb_ram_bank++; + } + return; + case GB_IO_VBK: + if (!gb->cgb_mode) { + return; + } + gb->cgb_vram_bank = value & 0x1; + return; + + case GB_IO_BGPI: + case GB_IO_OBPI: + if (!GB_is_cgb(gb)) { + return; + } + gb->io_registers[addr & 0xFF] = value; + return; + case GB_IO_BGPD: + case GB_IO_OBPD: + if (!gb->cgb_mode && gb->boot_rom_finished) { + /* Todo: Due to the behavior of a broken Game & Watch Gallery 2 ROM on a real CGB. A proper test ROM + is required. */ + return; + } + + uint8_t index_reg = (addr & 0xFF) - 1; + if (gb->cgb_palettes_blocked) { + if (gb->io_registers[index_reg] & 0x80) { + gb->io_registers[index_reg]++; + gb->io_registers[index_reg] |= 0x80; + } + return; + } + ((addr & 0xFF) == GB_IO_BGPD? + gb->background_palettes_data : + gb->sprite_palettes_data)[gb->io_registers[index_reg] & 0x3F] = value; + GB_palette_changed(gb, (addr & 0xFF) == GB_IO_BGPD, gb->io_registers[index_reg] & 0x3F); + if (gb->io_registers[index_reg] & 0x80) { + gb->io_registers[index_reg]++; + gb->io_registers[index_reg] |= 0x80; + } + return; + case GB_IO_KEY1: + if (!gb->cgb_mode) { + return; + } + gb->io_registers[GB_IO_KEY1] = value; + return; + case GB_IO_HDMA1: + if (gb->cgb_mode) { + gb->hdma_current_src &= 0xF0; + gb->hdma_current_src |= value << 8; + } + return; + case GB_IO_HDMA2: + if (gb->cgb_mode) { + gb->hdma_current_src &= 0xFF00; + gb->hdma_current_src |= value & 0xF0; + } + return; + case GB_IO_HDMA3: + if (gb->cgb_mode) { + gb->hdma_current_dest &= 0xF0; + gb->hdma_current_dest |= value << 8; + } + return; + case GB_IO_HDMA4: + if (gb->cgb_mode) { + gb->hdma_current_dest &= 0x1F00; + gb->hdma_current_dest |= value & 0xF0; + } + return; + case GB_IO_HDMA5: + if (!gb->cgb_mode) return; + if ((value & 0x80) == 0 && gb->hdma_on_hblank) { + gb->hdma_on_hblank = false; + return; + } + gb->hdma_on = (value & 0x80) == 0; + gb->hdma_on_hblank = (value & 0x80) != 0; + if (gb->hdma_on_hblank && (gb->io_registers[GB_IO_STAT] & 3) == 0) { + gb->hdma_on = true; + } + gb->io_registers[GB_IO_HDMA5] = value; + gb->hdma_steps_left = (gb->io_registers[GB_IO_HDMA5] & 0x7F) + 1; + /* Todo: Verify this. Gambatte's DMA tests require this. */ + if (gb->hdma_current_dest + (gb->hdma_steps_left << 4) > 0xFFFF) { + gb->hdma_steps_left = (0x10000 - gb->hdma_current_dest) >> 4; + } + gb->hdma_cycles = -12; + return; + + /* Todo: what happens when starting a transfer during a transfer? + What happens when starting a transfer during external clock? + */ + case GB_IO_SC: + if (!gb->cgb_mode) { + value |= 2; + } + gb->io_registers[GB_IO_SC] = value | (~0x83); + if ((value & 0x80) && (value & 0x1) ) { + gb->serial_length = gb->cgb_mode && (value & 2)? 16 : 512; + gb->serial_count = 0; + /* Todo: This is probably incorrect for CGB's faster clock mode. */ + gb->serial_cycles &= 0xFF; + if (gb->serial_transfer_bit_start_callback) { + gb->serial_transfer_bit_start_callback(gb, gb->io_registers[GB_IO_SB] & 0x80); + } + } + else { + gb->serial_length = 0; + } + return; + + case GB_IO_RP: { + if (!GB_is_cgb(gb)) { + return; + } + if ((value & 1) != (gb->io_registers[GB_IO_RP] & 1)) { + if (gb->infrared_callback) { + gb->infrared_callback(gb, value & 1, gb->cycles_since_ir_change); + gb->cycles_since_ir_change = 0; + } + } + gb->io_registers[GB_IO_RP] = value; + return; + } + + default: + if ((addr & 0xFF) >= GB_IO_NR10 && (addr & 0xFF) <= GB_IO_WAV_END) { + GB_apu_write(gb, addr & 0xFF, value); + return; + } + GB_log(gb, "Wrote %02x to %04x (HW Register)\n", value, addr); + return; + } + } + + if (addr == 0xFFFF) { + /* Interrupt mask */ + gb->interrupt_enable = value; + return; + } + + /* HRAM */ + gb->hram[addr - 0xFF80] = value; +} + + + +static GB_write_function_t * const write_map[] = +{ + write_mbc, write_mbc, write_mbc, write_mbc, /* 0XXX, 1XXX, 2XXX, 3XXX */ + write_mbc, write_mbc, write_mbc, write_mbc, /* 4XXX, 5XXX, 6XXX, 7XXX */ + write_vram, write_vram, /* 8XXX, 9XXX */ + write_mbc_ram, write_mbc_ram, /* AXXX, BXXX */ + write_ram, write_banked_ram, /* CXXX, DXXX */ + write_ram, write_high_memory, /* EXXX FXXX */ +}; + +void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) +{ + if (gb->n_watchpoints) { + GB_debugger_test_write_watchpoint(gb, addr, value); + } + if (is_addr_in_dma_use(gb, addr)) { + /* Todo: What should happen? Will this affect DMA? Will data be written? What and where? */ + return; + } + write_map[addr >> 12](gb, addr, value); +} + +void GB_dma_run(GB_gameboy_t *gb) +{ + while (gb->dma_cycles >= 4 && gb->dma_steps_left) { + /* Todo: measure this value */ + gb->dma_cycles -= 4; + gb->dma_steps_left--; + + if (gb->dma_current_src < 0xe000) { + gb->oam[gb->dma_current_dest++] = GB_read_memory(gb, gb->dma_current_src); + } + else { + /* Todo: Not correct on the CGB */ + gb->oam[gb->dma_current_dest++] = GB_read_memory(gb, gb->dma_current_src & ~0x2000); + } + + /* dma_current_src must be the correct value during GB_read_memory */ + gb->dma_current_src++; + if (!gb->dma_steps_left) { + gb->is_dma_restarting = false; + } + } +} + +void GB_hdma_run(GB_gameboy_t *gb) +{ + if (!gb->hdma_on) return; + + while (gb->hdma_cycles >= 0x4) { + gb->hdma_cycles -= 0x4; + + GB_write_memory(gb, 0x8000 | (gb->hdma_current_dest++ & 0x1FFF), GB_read_memory(gb, (gb->hdma_current_src++))); + + if ((gb->hdma_current_dest & 0xf) == 0) { + if (--gb->hdma_steps_left == 0) { + gb->hdma_on = false; + gb->hdma_on_hblank = false; + gb->hdma_starting = false; + gb->io_registers[GB_IO_HDMA5] &= 0x7F; + break; + } + if (gb->hdma_on_hblank) { + gb->hdma_on = false; + break; + } + } + } +} diff --git a/gb/Core/memory.h b/gb/Core/memory.h new file mode 100644 index 0000000..f0d0390 --- /dev/null +++ b/gb/Core/memory.h @@ -0,0 +1,18 @@ +#ifndef memory_h +#define memory_h +#include "gb_struct_def.h" +#include + +typedef uint8_t (*GB_read_memory_callback_t)(GB_gameboy_t *gb, uint16_t addr, uint8_t data); +void GB_set_read_memory_callback(GB_gameboy_t *gb, GB_read_memory_callback_t callback); + +uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr); +void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value); +#ifdef GB_INTERNAL +void GB_dma_run(GB_gameboy_t *gb); +void GB_hdma_run(GB_gameboy_t *gb); +void GB_trigger_oam_bug(GB_gameboy_t *gb, uint16_t address); +void GB_trigger_oam_bug_read_increase(GB_gameboy_t *gb, uint16_t address); +#endif + +#endif /* memory_h */ diff --git a/gb/Core/printer.c b/gb/Core/printer.c new file mode 100644 index 0000000..add1f86 --- /dev/null +++ b/gb/Core/printer.c @@ -0,0 +1,216 @@ +#include "gb.h" + +/* TODO: Emulation is VERY basic and assumes the ROM correctly uses the printer's interface. + Incorrect usage is not correctly emulated, as it's not well documented, nor do I + have my own GB Printer to figure it out myself. + + It also does not currently emulate communication timeout, which means that a bug + might prevent the printer operation until the GameBoy is restarted. + + Also, field mask values are assumed. */ + +static void handle_command(GB_gameboy_t *gb) +{ + + switch (gb->printer.command_id) { + case GB_PRINTER_INIT_COMMAND: + gb->printer.status = 0; + gb->printer.image_offset = 0; + break; + + case GB_PRINTER_START_COMMAND: + if (gb->printer.command_length == 4) { + gb->printer.status = 6; /* Printing */ + uint32_t image[gb->printer.image_offset]; + uint8_t palette = gb->printer.command_data[2]; + uint32_t colors[4] = {gb->rgb_encode_callback(gb, 0xff, 0xff, 0xff), + gb->rgb_encode_callback(gb, 0xaa, 0xaa, 0xaa), + gb->rgb_encode_callback(gb, 0x55, 0x55, 0x55), + gb->rgb_encode_callback(gb, 0x00, 0x00, 0x00)}; + for (unsigned i = 0; i < gb->printer.image_offset; i++) { + image[i] = colors[(palette >> (gb->printer.image[i] * 2)) & 3]; + } + + if (gb->printer.callback) { + gb->printer.callback(gb, image, gb->printer.image_offset / 160, + gb->printer.command_data[1] >> 4, gb->printer.command_data[1] & 7, + gb->printer.command_data[3] & 0x7F); + } + + gb->printer.image_offset = 0; + } + break; + + case GB_PRINTER_DATA_COMMAND: + if (gb->printer.command_length == GB_PRINTER_DATA_SIZE) { + gb->printer.image_offset %= sizeof(gb->printer.image); + gb->printer.status = 8; /* Received 0x280 bytes */ + + uint8_t *byte = gb->printer.command_data; + + for (unsigned row = 2; row--; ) { + for (unsigned tile_x = 0; tile_x < 160 / 8; tile_x++) { + for (unsigned y = 0; y < 8; y++, byte += 2) { + for (unsigned x_pixel = 0; x_pixel < 8; x_pixel++) { + gb->printer.image[gb->printer.image_offset + tile_x * 8 + x_pixel + y * 160] = + ((*byte) >> 7) | (((*(byte + 1)) >> 7) << 1); + (*byte) <<= 1; + (*(byte + 1)) <<= 1; + } + } + } + + gb->printer.image_offset += 8 * 160; + } + } + + case GB_PRINTER_NOP_COMMAND: + default: + break; + } +} + + +static void byte_reieve_completed(GB_gameboy_t *gb, uint8_t byte_received) +{ + gb->printer.byte_to_send = 0; + switch (gb->printer.command_state) { + case GB_PRINTER_COMMAND_MAGIC1: + if (byte_received != 0x88) { + return; + } + gb->printer.status &= ~1; + gb->printer.command_length = 0; + gb->printer.checksum = 0; + break; + + case GB_PRINTER_COMMAND_MAGIC2: + if (byte_received != 0x33) { + if (byte_received != 0x88) { + gb->printer.command_state = GB_PRINTER_COMMAND_MAGIC1; + } + return; + } + break; + + case GB_PRINTER_COMMAND_ID: + gb->printer.command_id = byte_received & 0xF; + break; + + case GB_PRINTER_COMMAND_COMPRESSION: + gb->printer.compression = byte_received & 1; + break; + + case GB_PRINTER_COMMAND_LENGTH_LOW: + gb->printer.length_left = byte_received; + break; + + case GB_PRINTER_COMMAND_LENGTH_HIGH: + gb->printer.length_left |= (byte_received & 3) << 8; + break; + + case GB_PRINTER_COMMAND_DATA: + if (gb->printer.command_length != GB_PRINTER_MAX_COMMAND_LENGTH) { + if (gb->printer.compression) { + if (!gb->printer.compression_run_lenth) { + gb->printer.compression_run_is_compressed = byte_received & 0x80; + gb->printer.compression_run_lenth = (byte_received & 0x7F) + 1 + gb->printer.compression_run_is_compressed; + } + else if (gb->printer.compression_run_is_compressed) { + while (gb->printer.compression_run_lenth) { + gb->printer.command_data[gb->printer.command_length++] = byte_received; + gb->printer.compression_run_lenth--; + if (gb->printer.command_length == GB_PRINTER_MAX_COMMAND_LENGTH) { + gb->printer.compression_run_lenth = 0; + } + } + } + else { + gb->printer.command_data[gb->printer.command_length++] = byte_received; + gb->printer.compression_run_lenth--; + } + } + else { + gb->printer.command_data[gb->printer.command_length++] = byte_received; + } + } + gb->printer.length_left--; + break; + + case GB_PRINTER_COMMAND_CHECKSUM_LOW: + gb->printer.checksum ^= byte_received; + break; + + case GB_PRINTER_COMMAND_CHECKSUM_HIGH: + gb->printer.checksum ^= byte_received << 8; + if (gb->printer.checksum) { + gb->printer.status |= 1; /* Checksum error*/ + gb->printer.command_state = GB_PRINTER_COMMAND_MAGIC1; + return; + } + gb->printer.byte_to_send = 0x81; + + break; + case GB_PRINTER_COMMAND_ACTIVE: + if ((gb->printer.command_id & 0xF) == GB_PRINTER_INIT_COMMAND) { + /* Games expect INIT commands to return 0? */ + gb->printer.byte_to_send = 0; + } + else { + gb->printer.byte_to_send = gb->printer.status; + } + break; + case GB_PRINTER_COMMAND_STATUS: + + /* Printing is done instantly, but let the game recieve a 6 (Printing) status at least once, for compatibility */ + if (gb->printer.status == 6) { + gb->printer.status = 4; /* Done */ + } + + gb->printer.command_state = GB_PRINTER_COMMAND_MAGIC1; + handle_command(gb); + return; + } + + if (gb->printer.command_state >= GB_PRINTER_COMMAND_ID && gb->printer.command_state < GB_PRINTER_COMMAND_CHECKSUM_LOW) { + gb->printer.checksum += byte_received; + } + + if (gb->printer.command_state != GB_PRINTER_COMMAND_DATA) { + gb->printer.command_state++; + } + + if (gb->printer.command_state == GB_PRINTER_COMMAND_DATA) { + if (gb->printer.length_left == 0) { + gb->printer.command_state++; + } + } +} + +static void serial_start(GB_gameboy_t *gb, bool bit_received) +{ + gb->printer.byte_being_recieved <<= 1; + gb->printer.byte_being_recieved |= bit_received; + gb->printer.bits_recieved++; + if (gb->printer.bits_recieved == 8) { + byte_reieve_completed(gb, gb->printer.byte_being_recieved); + gb->printer.bits_recieved = 0; + gb->printer.byte_being_recieved = 0; + } +} + +static bool serial_end(GB_gameboy_t *gb) +{ + bool ret = gb->printer.bit_to_send; + gb->printer.bit_to_send = gb->printer.byte_to_send & 0x80; + gb->printer.byte_to_send <<= 1; + return ret; +} + +void GB_connect_printer(GB_gameboy_t *gb, GB_print_image_callback_t callback) +{ + memset(&gb->printer, 0, sizeof(gb->printer)); + GB_set_serial_transfer_bit_start_callback(gb, serial_start); + GB_set_serial_transfer_bit_end_callback(gb, serial_end); + gb->printer.callback = callback; +} diff --git a/gb/Core/printer.h b/gb/Core/printer.h new file mode 100644 index 0000000..7cf179e --- /dev/null +++ b/gb/Core/printer.h @@ -0,0 +1,63 @@ +#ifndef printer_h +#define printer_h +#include +#include +#include "gb_struct_def.h" +#define GB_PRINTER_MAX_COMMAND_LENGTH 0x280 +#define GB_PRINTER_DATA_SIZE 0x280 + +typedef void (*GB_print_image_callback_t)(GB_gameboy_t *gb, + uint32_t *image, + uint8_t height, + uint8_t top_margin, + uint8_t bottom_margin, + uint8_t exposure); + + +typedef struct +{ + /* Communication state machine */ + + enum { + GB_PRINTER_COMMAND_MAGIC1, + GB_PRINTER_COMMAND_MAGIC2, + GB_PRINTER_COMMAND_ID, + GB_PRINTER_COMMAND_COMPRESSION, + GB_PRINTER_COMMAND_LENGTH_LOW, + GB_PRINTER_COMMAND_LENGTH_HIGH, + GB_PRINTER_COMMAND_DATA, + GB_PRINTER_COMMAND_CHECKSUM_LOW, + GB_PRINTER_COMMAND_CHECKSUM_HIGH, + GB_PRINTER_COMMAND_ACTIVE, + GB_PRINTER_COMMAND_STATUS, + } command_state : 8; + enum { + GB_PRINTER_INIT_COMMAND = 1, + GB_PRINTER_START_COMMAND = 2, + GB_PRINTER_DATA_COMMAND = 4, + GB_PRINTER_NOP_COMMAND = 0xF, + } command_id : 8; + bool compression; + uint16_t length_left; + uint8_t command_data[GB_PRINTER_MAX_COMMAND_LENGTH]; + uint16_t command_length; + uint16_t checksum; + uint8_t status; + uint8_t byte_to_send; + + uint8_t image[160 * 200]; + uint16_t image_offset; + + GB_print_image_callback_t callback; + + uint8_t compression_run_lenth; + bool compression_run_is_compressed; + + uint8_t bits_recieved; + uint8_t byte_being_recieved; + bool bit_to_send; +} GB_printer_t; + + +void GB_connect_printer(GB_gameboy_t *gb, GB_print_image_callback_t callback); +#endif diff --git a/gb/Core/random.c b/gb/Core/random.c new file mode 100644 index 0000000..cc4d4d3 --- /dev/null +++ b/gb/Core/random.c @@ -0,0 +1,38 @@ +#include "random.h" +#include + +static uint64_t seed; +static bool enabled = true; + +uint8_t GB_random(void) +{ + if (!enabled) return 0; + + seed *= 0x27BB2EE687B0B0FDL; + seed += 0xB504F32D; + return seed >> 56; +} + +uint32_t GB_random32(void) +{ + GB_random(); + return seed >> 32; +} + +void GB_random_seed(uint64_t new_seed) +{ + seed = new_seed; +} + +void GB_random_set_enabled(bool enable) +{ + enabled = enable; +} + +static void __attribute__((constructor)) init_seed(void) +{ + seed = time(NULL); + for (unsigned i = 64; i--;) { + GB_random(); + } +} diff --git a/gb/Core/random.h b/gb/Core/random.h new file mode 100644 index 0000000..8ab0e50 --- /dev/null +++ b/gb/Core/random.h @@ -0,0 +1,12 @@ +#ifndef random_h +#define random_h + +#include +#include + +uint8_t GB_random(void); +uint32_t GB_random32(void); +void GB_random_seed(uint64_t seed); +void GB_random_set_enabled(bool enable); + +#endif /* random_h */ diff --git a/gb/Core/rewind.c b/gb/Core/rewind.c new file mode 100644 index 0000000..c3900d6 --- /dev/null +++ b/gb/Core/rewind.c @@ -0,0 +1,208 @@ +#include "gb.h" +#include +#include +#include +#include + +static uint8_t *state_compress(const uint8_t *prev, const uint8_t *data, size_t uncompressed_size) +{ + size_t malloc_size = 0x1000; + uint8_t *compressed = malloc(malloc_size); + size_t counter_pos = 0; + size_t data_pos = sizeof(uint16_t); + bool prev_mode = true; + *(uint16_t *)compressed = 0; +#define COUNTER (*(uint16_t *)&compressed[counter_pos]) +#define DATA (compressed[data_pos]) + + while (uncompressed_size) { + if (prev_mode) { + if (*data == *prev && COUNTER != 0xffff) { + COUNTER++; + data++; + prev++; + uncompressed_size--; + } + else { + prev_mode = false; + counter_pos += sizeof(uint16_t); + data_pos = counter_pos + sizeof(uint16_t); + if (data_pos >= malloc_size) { + malloc_size *= 2; + compressed = realloc(compressed, malloc_size); + } + COUNTER = 0; + } + } + else { + if (*data != *prev && COUNTER != 0xffff) { + COUNTER++; + DATA = *data; + data_pos++; + data++; + prev++; + uncompressed_size--; + if (data_pos >= malloc_size) { + malloc_size *= 2; + compressed = realloc(compressed, malloc_size); + } + } + else { + prev_mode = true; + counter_pos = data_pos; + data_pos = counter_pos + sizeof(uint16_t); + if (counter_pos >= malloc_size - 1) { + malloc_size *= 2; + compressed = realloc(compressed, malloc_size); + } + COUNTER = 0; + } + } + } + + return realloc(compressed, data_pos); +#undef DATA +#undef COUNTER +} + + +static void state_decompress(const uint8_t *prev, uint8_t *data, uint8_t *dest, size_t uncompressed_size) +{ + size_t counter_pos = 0; + size_t data_pos = sizeof(uint16_t); + bool prev_mode = true; +#define COUNTER (*(uint16_t *)&data[counter_pos]) +#define DATA (data[data_pos]) + + while (uncompressed_size) { + if (prev_mode) { + if (COUNTER) { + COUNTER--; + *(dest++) = *(prev++); + uncompressed_size--; + } + else { + prev_mode = false; + counter_pos += sizeof(uint16_t); + data_pos = counter_pos + sizeof(uint16_t); + } + } + else { + if (COUNTER) { + COUNTER--; + *(dest++) = DATA; + data_pos++; + prev++; + uncompressed_size--; + } + else { + prev_mode = true; + counter_pos = data_pos; + data_pos += sizeof(uint16_t); + } + } + } +#undef DATA +#undef COUNTER +} + +void GB_rewind_push(GB_gameboy_t *gb) +{ + const size_t save_size = GB_get_save_state_size(gb); + if (!gb->rewind_sequences) { + if (gb->rewind_buffer_length) { + gb->rewind_sequences = malloc(sizeof(*gb->rewind_sequences) * gb->rewind_buffer_length); + memset(gb->rewind_sequences, 0, sizeof(*gb->rewind_sequences) * gb->rewind_buffer_length); + gb->rewind_pos = 0; + } + else { + return; + } + } + + if (gb->rewind_sequences[gb->rewind_pos].pos == GB_REWIND_FRAMES_PER_KEY) { + gb->rewind_pos++; + if (gb->rewind_pos == gb->rewind_buffer_length) { + gb->rewind_pos = 0; + } + if (gb->rewind_sequences[gb->rewind_pos].key_state) { + free(gb->rewind_sequences[gb->rewind_pos].key_state); + gb->rewind_sequences[gb->rewind_pos].key_state = NULL; + } + for (unsigned i = 0; i < GB_REWIND_FRAMES_PER_KEY; i++) { + if (gb->rewind_sequences[gb->rewind_pos].compressed_states[i]) { + free(gb->rewind_sequences[gb->rewind_pos].compressed_states[i]); + gb->rewind_sequences[gb->rewind_pos].compressed_states[i] = 0; + } + } + gb->rewind_sequences[gb->rewind_pos].pos = 0; + } + + if (!gb->rewind_sequences[gb->rewind_pos].key_state) { + gb->rewind_sequences[gb->rewind_pos].key_state = malloc(save_size); + GB_save_state_to_buffer(gb, gb->rewind_sequences[gb->rewind_pos].key_state); + } + else { + uint8_t *save_state = malloc(save_size); + GB_save_state_to_buffer(gb, save_state); + gb->rewind_sequences[gb->rewind_pos].compressed_states[gb->rewind_sequences[gb->rewind_pos].pos++] = + state_compress(gb->rewind_sequences[gb->rewind_pos].key_state, save_state, save_size); + free(save_state); + } + +} + +bool GB_rewind_pop(GB_gameboy_t *gb) +{ + if (!gb->rewind_sequences || !gb->rewind_sequences[gb->rewind_pos].key_state) { + return false; + } + + const size_t save_size = GB_get_save_state_size(gb); + if (gb->rewind_sequences[gb->rewind_pos].pos == 0) { + GB_load_state_from_buffer(gb, gb->rewind_sequences[gb->rewind_pos].key_state, save_size); + free(gb->rewind_sequences[gb->rewind_pos].key_state); + gb->rewind_sequences[gb->rewind_pos].key_state = NULL; + gb->rewind_pos = gb->rewind_pos == 0? gb->rewind_buffer_length - 1 : gb->rewind_pos - 1; + return true; + } + + uint8_t *save_state = malloc(save_size); + state_decompress(gb->rewind_sequences[gb->rewind_pos].key_state, + gb->rewind_sequences[gb->rewind_pos].compressed_states[--gb->rewind_sequences[gb->rewind_pos].pos], + save_state, + save_size); + free(gb->rewind_sequences[gb->rewind_pos].compressed_states[gb->rewind_sequences[gb->rewind_pos].pos]); + gb->rewind_sequences[gb->rewind_pos].compressed_states[gb->rewind_sequences[gb->rewind_pos].pos] = NULL; + GB_load_state_from_buffer(gb, save_state, save_size); + free(save_state); + return true; +} + +void GB_rewind_free(GB_gameboy_t *gb) +{ + if (!gb->rewind_sequences) return; + for (unsigned i = 0; i < gb->rewind_buffer_length; i++) { + if (gb->rewind_sequences[i].key_state) { + free(gb->rewind_sequences[i].key_state); + } + for (unsigned j = 0; j < GB_REWIND_FRAMES_PER_KEY; j++) { + if (gb->rewind_sequences[i].compressed_states[j]) { + free(gb->rewind_sequences[i].compressed_states[j]); + } + } + } + free(gb->rewind_sequences); + gb->rewind_sequences = NULL; +} + +void GB_set_rewind_length(GB_gameboy_t *gb, double seconds) +{ + GB_rewind_free(gb); + if (seconds == 0) { + gb->rewind_buffer_length = 0; + } + else { + gb->rewind_buffer_length = (size_t) ceil(seconds * CPU_FREQUENCY / LCDC_PERIOD / GB_REWIND_FRAMES_PER_KEY); + } +} diff --git a/gb/Core/rewind.h b/gb/Core/rewind.h new file mode 100644 index 0000000..ad54841 --- /dev/null +++ b/gb/Core/rewind.h @@ -0,0 +1,14 @@ +#ifndef rewind_h +#define rewind_h + +#include +#include "gb_struct_def.h" + +#ifdef GB_INTERNAL +void GB_rewind_push(GB_gameboy_t *gb); +void GB_rewind_free(GB_gameboy_t *gb); +#endif +bool GB_rewind_pop(GB_gameboy_t *gb); +void GB_set_rewind_length(GB_gameboy_t *gb, double seconds); + +#endif diff --git a/gb/Core/save_state.c b/gb/Core/save_state.c new file mode 100644 index 0000000..8ef99ae --- /dev/null +++ b/gb/Core/save_state.c @@ -0,0 +1,377 @@ +#include "gb.h" +#include +#include + +static bool dump_section(FILE *f, const void *src, uint32_t size) +{ + if (fwrite(&size, 1, sizeof(size), f) != sizeof(size)) { + return false; + } + + if (fwrite(src, 1, size, f) != size) { + return false; + } + + return true; +} + +#define DUMP_SECTION(gb, f, section) dump_section(f, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section)) + +/* Todo: we need a sane and protable save state format. */ +int GB_save_state(GB_gameboy_t *gb, const char *path) +{ + FILE *f = fopen(path, "wb"); + if (!f) { + GB_log(gb, "Could not open save state: %s.\n", strerror(errno)); + return errno; + } + + if (fwrite(GB_GET_SECTION(gb, header), 1, GB_SECTION_SIZE(header), f) != GB_SECTION_SIZE(header)) goto error; + if (!DUMP_SECTION(gb, f, core_state)) goto error; + if (!DUMP_SECTION(gb, f, dma )) goto error; + if (!DUMP_SECTION(gb, f, mbc )) goto error; + if (!DUMP_SECTION(gb, f, hram )) goto error; + if (!DUMP_SECTION(gb, f, timing )) goto error; + if (!DUMP_SECTION(gb, f, apu )) goto error; + if (!DUMP_SECTION(gb, f, rtc )) goto error; + if (!DUMP_SECTION(gb, f, video )) goto error; + + if (GB_is_hle_sgb(gb)) { + if (!dump_section(f, gb->sgb, sizeof(*gb->sgb))) goto error; + } + + + if (fwrite(gb->mbc_ram, 1, gb->mbc_ram_size, f) != gb->mbc_ram_size) { + goto error; + } + + if (fwrite(gb->ram, 1, gb->ram_size, f) != gb->ram_size) { + goto error; + } + + if (fwrite(gb->vram, 1, gb->vram_size, f) != gb->vram_size) { + goto error; + } + + errno = 0; + +error: + fclose(f); + return errno; +} + +#undef DUMP_SECTION + +size_t GB_get_save_state_size(GB_gameboy_t *gb) +{ + return GB_SECTION_SIZE(header) + + GB_SECTION_SIZE(core_state) + sizeof(uint32_t) + + GB_SECTION_SIZE(dma ) + sizeof(uint32_t) + + GB_SECTION_SIZE(mbc ) + sizeof(uint32_t) + + GB_SECTION_SIZE(hram ) + sizeof(uint32_t) + + GB_SECTION_SIZE(timing ) + sizeof(uint32_t) + + GB_SECTION_SIZE(apu ) + sizeof(uint32_t) + + GB_SECTION_SIZE(rtc ) + sizeof(uint32_t) + + GB_SECTION_SIZE(video ) + sizeof(uint32_t) + + (GB_is_hle_sgb(gb)? sizeof(*gb->sgb) + sizeof(uint32_t) : 0) + + gb->mbc_ram_size + + gb->ram_size + + gb->vram_size; +} + +/* A write-line function for memory copying */ +static void buffer_write(const void *src, size_t size, uint8_t **dest) +{ + memcpy(*dest, src, size); + *dest += size; +} + +static void buffer_dump_section(uint8_t **buffer, const void *src, uint32_t size) +{ + buffer_write(&size, sizeof(size), buffer); + buffer_write(src, size, buffer); +} + +#define DUMP_SECTION(gb, buffer, section) buffer_dump_section(&buffer, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section)) +void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer) +{ + buffer_write(GB_GET_SECTION(gb, header), GB_SECTION_SIZE(header), &buffer); + DUMP_SECTION(gb, buffer, core_state); + DUMP_SECTION(gb, buffer, dma ); + DUMP_SECTION(gb, buffer, mbc ); + DUMP_SECTION(gb, buffer, hram ); + DUMP_SECTION(gb, buffer, timing ); + DUMP_SECTION(gb, buffer, apu ); + DUMP_SECTION(gb, buffer, rtc ); + DUMP_SECTION(gb, buffer, video ); + + if (GB_is_hle_sgb(gb)) { + buffer_dump_section(&buffer, gb->sgb, sizeof(*gb->sgb)); + } + + + buffer_write(gb->mbc_ram, gb->mbc_ram_size, &buffer); + buffer_write(gb->ram, gb->ram_size, &buffer); + buffer_write(gb->vram, gb->vram_size, &buffer); +} + +/* Best-effort read function for maximum future compatibility. */ +static bool read_section(FILE *f, void *dest, uint32_t size) +{ + uint32_t saved_size = 0; + if (fread(&saved_size, 1, sizeof(size), f) != sizeof(size)) { + return false; + } + + if (saved_size <= size) { + if (fread(dest, 1, saved_size, f) != saved_size) { + return false; + } + } + else { + if (fread(dest, 1, size, f) != size) { + return false; + } + fseek(f, saved_size - size, SEEK_CUR); + } + + return true; +} +#undef DUMP_SECTION + +static bool verify_state_compatibility(GB_gameboy_t *gb, GB_gameboy_t *save) +{ + if (gb->magic != save->magic) { + GB_log(gb, "The file is not a save state, or is from an incompatible operating system.\n"); + return false; + } + + if (gb->version != save->version) { + GB_log(gb, "The save state is for a different version of SameBoy.\n"); + return false; + } + + if (gb->mbc_ram_size < save->mbc_ram_size) { + GB_log(gb, "The save state has non-matching MBC RAM size.\n"); + return false; + } + + if (gb->vram_size != save->vram_size) { + GB_log(gb, "The save state has non-matching VRAM size. Try changing the emulated model.\n"); + return false; + } + + if (GB_is_hle_sgb(gb) != GB_is_hle_sgb(save)) { + GB_log(gb, "The save state is %sfor a Super Game Boy. Try changing the emulated model.\n", GB_is_hle_sgb(save)? "" : "not "); + return false; + } + + if (gb->ram_size != save->ram_size) { + if (gb->ram_size == 0x1000 * 8 && save->ram_size == 0x2000 * 8) { + /* A bug in versions prior to 0.12 made CGB instances allocate twice the ammount of RAM. + Ignore this issue to retain compatibility with older, 0.11, save states. */ + } + else { + GB_log(gb, "The save state has non-matching RAM size. Try changing the emulated model.\n"); + return false; + } + } + + return true; +} + +#define READ_SECTION(gb, f, section) read_section(f, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section)) + +int GB_load_state(GB_gameboy_t *gb, const char *path) +{ + GB_gameboy_t save; + + /* Every unread value should be kept the same. */ + memcpy(&save, gb, sizeof(save)); + /* ...Except ram size, we use it to detect old saves with incorrect ram sizes */ + save.ram_size = 0; + + FILE *f = fopen(path, "rb"); + if (!f) { + GB_log(gb, "Could not open save state: %s.\n", strerror(errno)); + return errno; + } + + if (fread(GB_GET_SECTION(&save, header), 1, GB_SECTION_SIZE(header), f) != GB_SECTION_SIZE(header)) goto error; + if (!READ_SECTION(&save, f, core_state)) goto error; + if (!READ_SECTION(&save, f, dma )) goto error; + if (!READ_SECTION(&save, f, mbc )) goto error; + if (!READ_SECTION(&save, f, hram )) goto error; + if (!READ_SECTION(&save, f, timing )) goto error; + if (!READ_SECTION(&save, f, apu )) goto error; + if (!READ_SECTION(&save, f, rtc )) goto error; + if (!READ_SECTION(&save, f, video )) goto error; + + if (save.ram_size == 0) { + /* Save doesn't have ram size specified, it's a pre 0.12 save state with potentially + incorrect RAM amount if it's a CGB instance */ + if (GB_is_cgb(&save)) { + save.ram_size = 0x2000 * 8; // Incorrect RAM size + } + else { + save.ram_size = gb->ram_size; + } + } + + if (!verify_state_compatibility(gb, &save)) { + errno = -1; + goto error; + } + + if (GB_is_hle_sgb(gb)) { + if (!read_section(f, gb->sgb, sizeof(*gb->sgb))) goto error; + } + + memset(gb->mbc_ram + save.mbc_ram_size, 0xFF, gb->mbc_ram_size - save.mbc_ram_size); + if (fread(gb->mbc_ram, 1, save.mbc_ram_size, f) != save.mbc_ram_size) { + fclose(f); + return EIO; + } + + if (fread(gb->ram, 1, gb->ram_size, f) != gb->ram_size) { + fclose(f); + return EIO; + } + + /* Fix for 0.11 save states that allocate twice the amount of RAM in CGB instances */ + fseek(f, save.ram_size - gb->ram_size, SEEK_CUR); + + if (fread(gb->vram, 1, gb->vram_size, f) != gb->vram_size) { + fclose(f); + return EIO; + } + + size_t orig_ram_size = gb->ram_size; + memcpy(gb, &save, sizeof(save)); + gb->ram_size = orig_ram_size; + + errno = 0; + + if (gb->cartridge_type->has_rumble && gb->rumble_callback) { + gb->rumble_callback(gb, gb->rumble_state); + } + + for (unsigned i = 0; i < 32; i++) { + GB_palette_changed(gb, false, i * 2); + GB_palette_changed(gb, true, i * 2); + } + + gb->bg_fifo.read_end &= 0xF; + gb->bg_fifo.write_end &= 0xF; + gb->oam_fifo.read_end &= 0xF; + gb->oam_fifo.write_end &= 0xF; + +error: + fclose(f); + return errno; +} + +#undef READ_SECTION + +/* An read-like function for buffer-copying */ +static size_t buffer_read(void *dest, size_t length, const uint8_t **buffer, size_t *buffer_length) +{ + if (length > *buffer_length) { + length = *buffer_length; + } + + memcpy(dest, *buffer, length); + *buffer += length; + *buffer_length -= length; + + return length; +} + +static bool buffer_read_section(const uint8_t **buffer, size_t *buffer_length, void *dest, uint32_t size) +{ + uint32_t saved_size = 0; + if (buffer_read(&saved_size, sizeof(size), buffer, buffer_length) != sizeof(size)) { + return false; + } + + if (saved_size > *buffer_length) return false; + + if (saved_size <= size) { + if (buffer_read(dest, saved_size, buffer, buffer_length) != saved_size) { + return false; + } + } + else { + if (buffer_read(dest, size, buffer, buffer_length) != size) { + return false; + } + *buffer += saved_size - size; + *buffer_length -= saved_size - size; + } + + return true; +} + +#define READ_SECTION(gb, buffer, length, section) buffer_read_section(&buffer, &length, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section)) +int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length) +{ + GB_gameboy_t save; + + /* Every unread value should be kept the same. */ + memcpy(&save, gb, sizeof(save)); + + if (buffer_read(GB_GET_SECTION(&save, header), GB_SECTION_SIZE(header), &buffer, &length) != GB_SECTION_SIZE(header)) return -1; + if (!READ_SECTION(&save, buffer, length, core_state)) return -1; + if (!READ_SECTION(&save, buffer, length, dma )) return -1; + if (!READ_SECTION(&save, buffer, length, mbc )) return -1; + if (!READ_SECTION(&save, buffer, length, hram )) return -1; + if (!READ_SECTION(&save, buffer, length, timing )) return -1; + if (!READ_SECTION(&save, buffer, length, apu )) return -1; + if (!READ_SECTION(&save, buffer, length, rtc )) return -1; + if (!READ_SECTION(&save, buffer, length, video )) return -1; + + if (!verify_state_compatibility(gb, &save)) { + return -1; + } + + if (GB_is_hle_sgb(gb)) { + if (!buffer_read_section(&buffer, &length, gb->sgb, sizeof(*gb->sgb))) return -1; + } + + memset(gb->mbc_ram + save.mbc_ram_size, 0xFF, gb->mbc_ram_size - save.mbc_ram_size); + if (buffer_read(gb->mbc_ram, save.mbc_ram_size, &buffer, &length) != save.mbc_ram_size) { + return -1; + } + + if (buffer_read(gb->ram, gb->ram_size, &buffer, &length) != gb->ram_size) { + return -1; + } + + if (buffer_read(gb->vram,gb->vram_size, &buffer, &length) != gb->vram_size) { + return -1; + } + + /* Fix for 0.11 save states that allocate twice the amount of RAM in CGB instances */ + buffer += save.ram_size - gb->ram_size; + length -= save.ram_size - gb->ram_size; + + memcpy(gb, &save, sizeof(save)); + + if (gb->cartridge_type->has_rumble && gb->rumble_callback) { + gb->rumble_callback(gb, gb->rumble_state); + } + + for (unsigned i = 0; i < 32; i++) { + GB_palette_changed(gb, false, i * 2); + GB_palette_changed(gb, true, i * 2); + } + + gb->bg_fifo.read_end &= 0xF; + gb->bg_fifo.write_end &= 0xF; + gb->oam_fifo.read_end &= 0xF; + gb->oam_fifo.write_end &= 0xF; + + return 0; +} + +#undef READ_SECTION diff --git a/gb/Core/save_state.h b/gb/Core/save_state.h new file mode 100644 index 0000000..546ac2d --- /dev/null +++ b/gb/Core/save_state.h @@ -0,0 +1,24 @@ +/* Macros to make the GB_gameboy_t struct more future compatible when state saving */ +#ifndef save_state_h +#define save_state_h +#include + +#define GB_PADDING(type, old_usage) type old_usage##__do_not_use + +#define GB_SECTION(name, ...) __attribute__ ((aligned (8))) struct {} name##_section_start; __VA_ARGS__; struct {} name##_section_end +#define GB_SECTION_OFFSET(name) (offsetof(GB_gameboy_t, name##_section_start)) +#define GB_SECTION_SIZE(name) (offsetof(GB_gameboy_t, name##_section_end) - offsetof(GB_gameboy_t, name##_section_start)) +#define GB_GET_SECTION(gb, name) ((void*)&((gb)->name##_section_start)) + +#define GB_aligned_double __attribute__ ((aligned (8))) double + + +/* Public calls related to save states */ +int GB_save_state(GB_gameboy_t *gb, const char *path); +size_t GB_get_save_state_size(GB_gameboy_t *gb); +/* Assumes buffer is big enough to contain the save state. Use with GB_get_save_state_size(). */ +void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer); + +int GB_load_state(GB_gameboy_t *gb, const char *path); +int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length); +#endif /* save_state_h */ diff --git a/gb/Core/sgb.c b/gb/Core/sgb.c new file mode 100644 index 0000000..7ebeae0 --- /dev/null +++ b/gb/Core/sgb.c @@ -0,0 +1,842 @@ +#include "gb.h" +#include "random.h" +#include +#include + +#ifndef M_PI + #define M_PI 3.14159265358979323846 +#endif + +#define INTRO_ANIMATION_LENGTH 200 + +enum { + PAL01 = 0x00, + PAL23 = 0x01, + PAL03 = 0x02, + PAL12 = 0x03, + ATTR_BLK = 0x04, + ATTR_LIN = 0x05, + ATTR_DIV = 0x06, + PAL_SET = 0x0A, + PAL_TRN = 0x0B, + DATA_SND = 0x0F, + MLT_REQ = 0x11, + CHR_TRN = 0x13, + PCT_TRN = 0x14, + ATTR_TRN = 0x15, + ATTR_SET = 0x16, + MASK_EN = 0x17, +}; + +typedef enum { + MASK_DISABLED, + MASK_FREEZE, + MASK_BLACK, + MASK_COLOR_0, +} mask_mode_t; + +typedef enum { + TRANSFER_LOW_TILES, + TRANSFER_HIGH_TILES, + TRANSFER_BORDER_DATA, + TRANSFER_PALETTES, + TRANSFER_ATTRIBUTES, +} transfer_dest_t; + +#define SGB_PACKET_SIZE 16 +static inline void pal_command(GB_gameboy_t *gb, unsigned first, unsigned second) +{ + gb->sgb->effective_palettes[0] = gb->sgb->effective_palettes[4] = + gb->sgb->effective_palettes[8] = gb->sgb->effective_palettes[12] = + gb->sgb->command[1] | (gb->sgb->command[2] << 8); + + for (unsigned i = 0; i < 3; i++) { + gb->sgb->effective_palettes[first * 4 + i + 1] = gb->sgb->command[3 + i * 2] | (gb->sgb->command[4 + i * 2] << 8); + } + + for (unsigned i = 0; i < 3; i++) { + gb->sgb->effective_palettes[second * 4 + i + 1] = gb->sgb->command[9 + i * 2] | (gb->sgb->command[10 + i * 2] << 8); + } +} + +static inline void load_attribute_file(GB_gameboy_t *gb, unsigned file_index) +{ + if (file_index > 0x2C) return; + uint8_t *output = gb->sgb->attribute_map; + for (unsigned i = 0; i < 90; i++) { + uint8_t byte = gb->sgb->attribute_files[file_index * 90 + i]; + for (unsigned j = 4; j--;) { + *(output++) = byte >> 6; + byte <<= 2; + } + } +} + +static const uint16_t built_in_palettes[] = +{ + 0x67BF, 0x265B, 0x10B5, 0x2866, + 0x637B, 0x3AD9, 0x0956, 0x0000, + 0x7F1F, 0x2A7D, 0x30F3, 0x4CE7, + 0x57FF, 0x2618, 0x001F, 0x006A, + 0x5B7F, 0x3F0F, 0x222D, 0x10EB, + 0x7FBB, 0x2A3C, 0x0015, 0x0900, + 0x2800, 0x7680, 0x01EF, 0x2FFF, + 0x73BF, 0x46FF, 0x0110, 0x0066, + 0x533E, 0x2638, 0x01E5, 0x0000, + 0x7FFF, 0x2BBF, 0x00DF, 0x2C0A, + 0x7F1F, 0x463D, 0x74CF, 0x4CA5, + 0x53FF, 0x03E0, 0x00DF, 0x2800, + 0x433F, 0x72D2, 0x3045, 0x0822, + 0x7FFA, 0x2A5F, 0x0014, 0x0003, + 0x1EED, 0x215C, 0x42FC, 0x0060, + 0x7FFF, 0x5EF7, 0x39CE, 0x0000, + 0x4F5F, 0x630E, 0x159F, 0x3126, + 0x637B, 0x121C, 0x0140, 0x0840, + 0x66BC, 0x3FFF, 0x7EE0, 0x2C84, + 0x5FFE, 0x3EBC, 0x0321, 0x0000, + 0x63FF, 0x36DC, 0x11F6, 0x392A, + 0x65EF, 0x7DBF, 0x035F, 0x2108, + 0x2B6C, 0x7FFF, 0x1CD9, 0x0007, + 0x53FC, 0x1F2F, 0x0E29, 0x0061, + 0x36BE, 0x7EAF, 0x681A, 0x3C00, + 0x7BBE, 0x329D, 0x1DE8, 0x0423, + 0x739F, 0x6A9B, 0x7293, 0x0001, + 0x5FFF, 0x6732, 0x3DA9, 0x2481, + 0x577F, 0x3EBC, 0x456F, 0x1880, + 0x6B57, 0x6E1B, 0x5010, 0x0007, + 0x0F96, 0x2C97, 0x0045, 0x3200, + 0x67FF, 0x2F17, 0x2230, 0x1548, +}; + +static const struct { + char name[16]; + unsigned palette_index; +} palette_assignments[] = +{ + {"ZELDA", 5}, + {"SUPER MARIOLAND", 6}, + {"MARIOLAND2", 0x14}, + {"SUPERMARIOLAND3", 2}, + {"KIRBY DREAM LAND", 0xB}, + {"HOSHINOKA-BI", 0xB}, + {"KIRBY'S PINBALL", 3}, + {"YOSSY NO TAMAGO", 0xC}, + {"MARIO & YOSHI", 0xC}, + {"YOSSY NO COOKIE", 4}, + {"YOSHI'S COOKIE", 4}, + {"DR.MARIO", 0x12}, + {"TETRIS", 0x11}, + {"YAKUMAN", 0x13}, + {"METROID2", 0x1F}, + {"KAERUNOTAMENI", 9}, + {"GOLF", 0x18}, + {"ALLEY WAY", 0x16}, + {"BASEBALL", 0xF}, + {"TENNIS", 0x17}, + {"F1RACE", 0x1E}, + {"KID ICARUS", 0xE}, + {"QIX", 0x19}, + {"SOLARSTRIKER", 7}, + {"X", 0x1C}, + {"GBWARS", 0x15}, +}; + +static void command_ready(GB_gameboy_t *gb) +{ + /* SGB header commands are used to send the contents of the header to the SNES CPU. + A header command looks like this: + Command ID: 0b1111xxx1, where xxx is the packet index. (e.g. F1 for [0x104, 0x112), F3 for [0x112, 0x120)) + Checksum: Simple one byte sum for the following content bytes + 0xE content bytes. The last command, FB, is padded with zeros, so information past the header is not sent. */ + + if ((gb->sgb->command[0] & 0xF1) == 0xF1) { + if(gb->boot_rom_finished) return; + + uint8_t checksum = 0; + for (unsigned i = 2; i < 0x10; i++) { + checksum += gb->sgb->command[i]; + } + if (checksum != gb->sgb->command[1]) { + GB_log(gb, "Failed checksum for SGB header command, disabling SGB features\n"); + gb->sgb->disable_commands = true; + return; + } + unsigned index = (gb->sgb->command[0] >> 1) & 7; + if (index > 5) { + return; + } + memcpy(&gb->sgb->received_header[index * 14], &gb->sgb->command[2], 14); + if (gb->sgb->command[0] == 0xfb) { + if (gb->sgb->received_header[0x42] != 3 || gb->sgb->received_header[0x47] != 0x33) { + gb->sgb->disable_commands = true; + for (unsigned i = 0; i < sizeof(palette_assignments) / sizeof(palette_assignments[0]); i++) { + if (memcmp(palette_assignments[i].name, &gb->sgb->received_header[0x30], sizeof(palette_assignments[i].name)) == 0) { + gb->sgb->effective_palettes[0] = built_in_palettes[palette_assignments[i].palette_index * 4 - 4]; + gb->sgb->effective_palettes[1] = built_in_palettes[palette_assignments[i].palette_index * 4 + 1 - 4]; + gb->sgb->effective_palettes[2] = built_in_palettes[palette_assignments[i].palette_index * 4 + 2 - 4]; + gb->sgb->effective_palettes[3] = built_in_palettes[palette_assignments[i].palette_index * 4 + 3 - 4]; + break; + } + } + } + } + return; + } + + /* Ignore malformed commands (0 length)*/ + if ((gb->sgb->command[0] & 7) == 0) return; + + switch (gb->sgb->command[0] >> 3) { + case PAL01: + pal_command(gb, 0, 1); + break; + case PAL23: + pal_command(gb, 2, 3); + break; + case PAL03: + pal_command(gb, 0, 3); + break; + case PAL12: + pal_command(gb, 1, 2); + break; + case ATTR_BLK: { + struct { + uint8_t count; + struct { + uint8_t control; + uint8_t palettes; + uint8_t left, top, right, bottom; + } data[]; + } *command = (void *)(gb->sgb->command + 1); + if (command->count > 0x12) return; + + for (unsigned i = 0; i < command->count; i++) { + bool inside = command->data[i].control & 1; + bool middle = command->data[i].control & 2; + bool outside = command->data[i].control & 4; + uint8_t inside_palette = command->data[i].palettes & 0x3; + uint8_t middle_palette = (command->data[i].palettes >> 2) & 0x3; + uint8_t outside_palette = (command->data[i].palettes >> 4) & 0x3; + + if (inside && !middle && !outside) { + middle = true; + middle_palette = inside_palette; + } + else if (outside && !middle && !inside) { + middle = true; + middle_palette = outside_palette; + } + + command->data[i].left &= 0x1F; + command->data[i].top &= 0x1F; + command->data[i].right &= 0x1F; + command->data[i].bottom &= 0x1F; + + for (unsigned y = 0; y < 18; y++) { + for (unsigned x = 0; x < 20; x++) { + if (x < command->data[i].left || x > command->data[i].right || + y < command->data[i].top || y > command->data[i].bottom) { + if (outside) { + gb->sgb->attribute_map[x + 20 * y] = outside_palette; + } + } + else if (x > command->data[i].left && x < command->data[i].right && + y > command->data[i].top && y < command->data[i].bottom) { + if (inside) { + gb->sgb->attribute_map[x + 20 * y] = inside_palette; + } + } + else if(middle) { + gb->sgb->attribute_map[x + 20 * y] = middle_palette; + } + } + } + } + break; + } + case ATTR_LIN: { + struct { + uint8_t count; + uint8_t data[]; + } *command = (void *)(gb->sgb->command + 1); + if (command->count > sizeof(gb->sgb->command) - 2) return; + + for (unsigned i = 0; i < command->count; i++) { + bool horizontal = command->data[i] & 0x80; + uint8_t palette = (command->data[i] >> 5) & 0x3; + uint8_t line = (command->data[i]) & 0x1F; + + if (horizontal) { + if (line > 18) continue; + for (unsigned x = 0; x < 20; x++) { + gb->sgb->attribute_map[x + 20 * line] = palette; + } + } + else { + if (line > 20) continue; + for (unsigned y = 0; y < 18; y++) { + gb->sgb->attribute_map[line + 20 * y] = palette; + } + } + } + break; + } + case ATTR_DIV: { + uint8_t high_palette = gb->sgb->command[1] & 3; + uint8_t low_palette = (gb->sgb->command[1] >> 2) & 3; + uint8_t middle_palette = (gb->sgb->command[1] >> 4) & 3; + bool horizontal = gb->sgb->command[1] & 0x40; + uint8_t line = gb->sgb->command[2] & 0x1F; + + for (unsigned y = 0; y < 18; y++) { + for (unsigned x = 0; x < 20; x++) { + if ((horizontal? y : x) < line) { + gb->sgb->attribute_map[x + 20 * y] = low_palette; + } + else if ((horizontal? y : x) == line) { + gb->sgb->attribute_map[x + 20 * y] = middle_palette; + } + else { + gb->sgb->attribute_map[x + 20 * y] = high_palette; + } + } + } + + break; + } + case PAL_SET: + memcpy(&gb->sgb->effective_palettes[0], + &gb->sgb->ram_palettes[4 * (gb->sgb->command[1] + (gb->sgb->command[2] & 1) * 0x100)], + 8); + memcpy(&gb->sgb->effective_palettes[4], + &gb->sgb->ram_palettes[4 * (gb->sgb->command[3] + (gb->sgb->command[4] & 1) * 0x100)], + 8); + memcpy(&gb->sgb->effective_palettes[8], + &gb->sgb->ram_palettes[4 * (gb->sgb->command[5] + (gb->sgb->command[6] & 1) * 0x100)], + 8); + memcpy(&gb->sgb->effective_palettes[12], + &gb->sgb->ram_palettes[4 * (gb->sgb->command[7] + (gb->sgb->command[8] & 1) * 0x100)], + 8); + + gb->sgb->effective_palettes[12] = gb->sgb->effective_palettes[8] = + gb->sgb->effective_palettes[4] = gb->sgb->effective_palettes[0]; + + if (gb->sgb->command[9] & 0x80) { + load_attribute_file(gb, gb->sgb->command[9] & 0x3F); + } + + if (gb->sgb->command[9] & 0x40) { + gb->sgb->mask_mode = MASK_DISABLED; + } + break; + case PAL_TRN: + gb->sgb->vram_transfer_countdown = 2; + gb->sgb->transfer_dest = TRANSFER_PALETTES; + break; + case DATA_SND: + // Not supported, but used by almost all SGB games for hot patching, so let's mute the warning for this + break; + case MLT_REQ: + if (gb->sgb->player_count == 1) { + gb->sgb->current_player = 0; + } + gb->sgb->player_count = (gb->sgb->command[1] & 3) + 1; /* Todo: When breaking save state comaptibility, + fix this to be 0 based. */ + if (gb->sgb->player_count == 3) { + gb->sgb->current_player++; + } + gb->sgb->mlt_lock = true; + break; + case CHR_TRN: + gb->sgb->vram_transfer_countdown = 2; + gb->sgb->transfer_dest = (gb->sgb->command[1] & 1)? TRANSFER_HIGH_TILES : TRANSFER_LOW_TILES; + break; + case PCT_TRN: + gb->sgb->vram_transfer_countdown = 2; + gb->sgb->transfer_dest = TRANSFER_BORDER_DATA; + break; + case ATTR_TRN: + gb->sgb->vram_transfer_countdown = 2; + gb->sgb->transfer_dest = TRANSFER_ATTRIBUTES; + break; + case ATTR_SET: + load_attribute_file(gb, gb->sgb->command[0] & 0x3F); + + if (gb->sgb->command[0] & 0x40) { + gb->sgb->mask_mode = MASK_DISABLED; + } + break; + case MASK_EN: + gb->sgb->mask_mode = gb->sgb->command[1] & 3; + break; + default: + if ((gb->sgb->command[0] >> 3) == 8 && + (gb->sgb->command[1] & ~0x80) == 0 && + (gb->sgb->command[2] & ~0x80) == 0) { + /* Mute/dummy sound commands, ignore this command as it's used by many games at startup */ + break; + } + GB_log(gb, "Unimplemented SGB command %x: ", gb->sgb->command[0] >> 3); + for (unsigned i = 0; i < gb->sgb->command_write_index / 8; i++) { + GB_log(gb, "%02x ", gb->sgb->command[i]); + } + GB_log(gb, "\n"); + } +} + +void GB_sgb_write(GB_gameboy_t *gb, uint8_t value) +{ + if (!GB_is_sgb(gb)) return; + if (!GB_is_hle_sgb(gb)) { + /* Notify via callback */ + return; + } + if (gb->sgb->disable_commands) return; + if (gb->sgb->command_write_index >= sizeof(gb->sgb->command) * 8) { + return; + } + + uint16_t command_size = (gb->sgb->command[0] & 7 ?: 1) * SGB_PACKET_SIZE * 8; + if ((gb->sgb->command[0] & 0xF1) == 0xF1) { + command_size = SGB_PACKET_SIZE * 8; + } + + if ((value & 0x20) == 0 && (gb->io_registers[GB_IO_JOYP] & 0x20) != 0) { + gb->sgb->mlt_lock ^= true; + } + + switch ((value >> 4) & 3) { + case 3: + gb->sgb->ready_for_pulse = true; + if ((gb->sgb->player_count & 1) == 0 && !gb->sgb->mlt_lock) { + gb->sgb->current_player++; + gb->sgb->current_player &= 3; + gb->sgb->mlt_lock = true; + } + break; + + case 2: // Zero + if (!gb->sgb->ready_for_pulse || !gb->sgb->ready_for_write) return; + if (gb->sgb->ready_for_stop) { + if (gb->sgb->command_write_index == command_size) { + command_ready(gb); + gb->sgb->command_write_index = 0; + memset(gb->sgb->command, 0, sizeof(gb->sgb->command)); + } + gb->sgb->ready_for_pulse = false; + gb->sgb->ready_for_write = false; + gb->sgb->ready_for_stop = false; + } + else { + gb->sgb->command_write_index++; + gb->sgb->ready_for_pulse = false; + if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) == 0) { + gb->sgb->ready_for_stop = true; + } + } + break; + case 1: // One + if (!gb->sgb->ready_for_pulse || !gb->sgb->ready_for_write) return; + if (gb->sgb->ready_for_stop) { + GB_log(gb, "Corrupt SGB command.\n"); + gb->sgb->ready_for_pulse = false; + gb->sgb->ready_for_write = false; + gb->sgb->command_write_index = 0; + memset(gb->sgb->command, 0, sizeof(gb->sgb->command)); + } + else { + gb->sgb->command[gb->sgb->command_write_index / 8] |= 1 << (gb->sgb->command_write_index & 7); + gb->sgb->command_write_index++; + gb->sgb->ready_for_pulse = false; + if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) == 0) { + gb->sgb->ready_for_stop = true; + } + } + break; + + case 0: + if (!gb->sgb->ready_for_pulse) return; + gb->sgb->ready_for_write = true; + gb->sgb->ready_for_pulse = false; + if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) != 0 || + gb->sgb->command_write_index == 0 || + gb->sgb->ready_for_stop) { + gb->sgb->command_write_index = 0; + memset(gb->sgb->command, 0, sizeof(gb->sgb->command)); + gb->sgb->ready_for_stop = false; + } + break; + + default: + break; + } +} + +static uint32_t convert_rgb15(GB_gameboy_t *gb, uint16_t color) +{ + return GB_convert_rgb15(gb, color); +} + +static uint32_t convert_rgb15_with_fade(GB_gameboy_t *gb, uint16_t color, uint8_t fade) +{ + uint8_t r = ((color) & 0x1F) - fade; + uint8_t g = ((color >> 5) & 0x1F) - fade; + uint8_t b = ((color >> 10) & 0x1F) - fade; + + if (r >= 0x20) r = 0; + if (g >= 0x20) g = 0; + if (b >= 0x20) b = 0; + + color = r | (g << 5) | (b << 10); + + return GB_convert_rgb15(gb, color); +} + +#include +static void render_boot_animation (GB_gameboy_t *gb) +{ +#include "sgb_animation_logo.inc" + uint32_t *output = &gb->screen[48 + 40 * 256]; + uint8_t *input = animation_logo; + unsigned fade_blue = 0; + unsigned fade_red = 0; + if (gb->sgb->intro_animation < 80 - 32) { + fade_blue = 32; + } + else if (gb->sgb->intro_animation < 80) { + fade_blue = 80 - gb->sgb->intro_animation; + } + else if (gb->sgb->intro_animation > INTRO_ANIMATION_LENGTH - 32) { + fade_red = fade_blue = gb->sgb->intro_animation - INTRO_ANIMATION_LENGTH + 32; + } + uint32_t colors[] = { + convert_rgb15(gb, 0), + convert_rgb15_with_fade(gb, 0x14A5, fade_blue), + convert_rgb15_with_fade(gb, 0x54E0, fade_blue), + convert_rgb15_with_fade(gb, 0x0019, fade_red), + convert_rgb15(gb, 0x0011), + convert_rgb15(gb, 0x0009), + }; + unsigned y_min = (144 - animation_logo_height) / 2; + unsigned y_max = y_min + animation_logo_height; + for (unsigned y = 0; y < 144; y++) { + for (unsigned x = 0; x < 160; x++) { + if (y < y_min || y >= y_max) { + *(output++) = colors[0]; + } + else { + uint8_t color = *input; + if (color >= 3) { + if (color == gb->sgb->intro_animation / 2 - 3) { + color = 5; + } + else if (color == gb->sgb->intro_animation / 2 - 4) { + color = 4; + } + else if (color < gb->sgb->intro_animation / 2 - 4) { + color = 3; + } + else { + color = 0; + } + } + *(output++) = colors[color]; + input++; + } + } + output += 256 - 160; + } +} + +static void render_jingle(GB_gameboy_t *gb, size_t count); +void GB_sgb_render(GB_gameboy_t *gb) +{ + if (gb->apu_output.sample_rate) { + render_jingle(gb, gb->apu_output.sample_rate / GB_get_usual_frame_rate(gb)); + } + + if (gb->sgb->intro_animation < INTRO_ANIMATION_LENGTH) gb->sgb->intro_animation++; + + if (!gb->screen || !gb->rgb_encode_callback) return; + + if (gb->sgb->mask_mode != MASK_FREEZE) { + memcpy(gb->sgb->effective_screen_buffer, + gb->sgb->screen_buffer, + sizeof(gb->sgb->effective_screen_buffer)); + } + + if (gb->sgb->vram_transfer_countdown) { + if (--gb->sgb->vram_transfer_countdown == 0) { + if (gb->sgb->transfer_dest == TRANSFER_LOW_TILES || gb->sgb->transfer_dest == TRANSFER_HIGH_TILES) { + uint8_t *base = &gb->sgb->pending_border.tiles[gb->sgb->transfer_dest == TRANSFER_HIGH_TILES ? 0x80 * 8 * 8 : 0]; + for (unsigned tile = 0; tile < 0x80; tile++) { + unsigned tile_x = (tile % 10) * 16; + unsigned tile_y = (tile / 10) * 8; + for (unsigned y = 0; y < 0x8; y++) { + for (unsigned x = 0; x < 0x8; x++) { + base[tile * 8 * 8 + y * 8 + x] = gb->sgb->screen_buffer[(tile_x + x) + (tile_y + y) * 160] + + gb->sgb->screen_buffer[(tile_x + x + 8) + (tile_y + y) * 160] * 4; + } + } + } + + } + else { + unsigned size = 0; + uint16_t *data = NULL; + + switch (gb->sgb->transfer_dest) { + case TRANSFER_PALETTES: + size = 0x100; + data = gb->sgb->ram_palettes; + break; + case TRANSFER_BORDER_DATA: + size = 0x88; + data = gb->sgb->pending_border.raw_data; + break; + case TRANSFER_ATTRIBUTES: + size = 0xFE; + data = (uint16_t *)gb->sgb->attribute_files; + break; + default: + return; // Corrupt state? + } + + for (unsigned tile = 0; tile < size; tile++) { + unsigned tile_x = (tile % 20) * 8; + unsigned tile_y = (tile / 20) * 8; + for (unsigned y = 0; y < 0x8; y++) { + static const uint16_t pixel_to_bits[4] = {0x0000, 0x0080, 0x8000, 0x8080}; + *data = 0; + for (unsigned x = 0; x < 8; x++) { + *data |= pixel_to_bits[gb->sgb->screen_buffer[(tile_x + x) + (tile_y + y) * 160] & 3] >> x; + } +#ifdef GB_BIG_ENDIAN + if (gb->sgb->transfer_dest == TRANSFER_ATTRIBUTES) { + *data = __builtin_bswap16(*data); + } +#endif + data++; + } + } + if (gb->sgb->transfer_dest == TRANSFER_BORDER_DATA) { + gb->sgb->border_animation = 64; + } + } + } + } + + uint32_t colors[4 * 4]; + for (unsigned i = 0; i < 4 * 4; i++) { + colors[i] = convert_rgb15(gb, gb->sgb->effective_palettes[i]); + } + + if (gb->sgb->intro_animation < INTRO_ANIMATION_LENGTH) { + render_boot_animation(gb); + } + else { + uint32_t *output = &gb->screen[48 + 40 * 256]; + uint8_t *input = gb->sgb->effective_screen_buffer; + switch ((mask_mode_t) gb->sgb->mask_mode) { + case MASK_DISABLED: + case MASK_FREEZE: { + for (unsigned y = 0; y < 144; y++) { + for (unsigned x = 0; x < 160; x++) { + uint8_t palette = gb->sgb->attribute_map[x / 8 + y / 8 * 20] & 3; + *(output++) = colors[(*(input++) & 3) + palette * 4]; + } + output += 256 - 160; + } + break; + } + case MASK_BLACK: + { + uint32_t black = convert_rgb15(gb, 0); + for (unsigned y = 0; y < 144; y++) { + for (unsigned x = 0; x < 160; x++) { + *(output++) = black; + } + output += 256 - 160; + } + break; + } + case MASK_COLOR_0: + { + for (unsigned y = 0; y < 144; y++) { + for (unsigned x = 0; x < 160; x++) { + *(output++) = colors[0]; + } + output += 256 - 160; + } + break; + } + } + } + + uint32_t border_colors[16 * 4]; + if (gb->sgb->border_animation == 0 || gb->sgb->intro_animation < INTRO_ANIMATION_LENGTH) { + for (unsigned i = 0; i < 16 * 4; i++) { + border_colors[i] = convert_rgb15(gb, gb->sgb->border.palette[i]); + } + } + else if (gb->sgb->border_animation > 32) { + gb->sgb->border_animation--; + for (unsigned i = 0; i < 16 * 4; i++) { + border_colors[i] = convert_rgb15_with_fade(gb, gb->sgb->border.palette[i], 64 - gb->sgb->border_animation); + } + } + else { + gb->sgb->border_animation--; + for (unsigned i = 0; i < 16 * 4; i++) { + border_colors[i] = convert_rgb15_with_fade(gb, gb->sgb->border.palette[i], gb->sgb->border_animation); + } + } + + + if (gb->sgb->border_animation == 32) { + memcpy(&gb->sgb->border, &gb->sgb->pending_border, sizeof(gb->sgb->border)); + } + + for (unsigned tile_y = 0; tile_y < 28; tile_y++) { + for (unsigned tile_x = 0; tile_x < 32; tile_x++) { + bool gb_area = false; + if (tile_x >= 6 && tile_x < 26 && tile_y >= 5 && tile_y < 23) { + gb_area = true; + } + uint16_t tile = gb->sgb->border.map[tile_x + tile_y * 32]; + uint8_t flip_x = (tile & 0x4000)? 0x7 : 0; + uint8_t flip_y = (tile & 0x8000)? 0x7 : 0; + uint8_t palette = (tile >> 10) & 3; + for (unsigned y = 0; y < 8; y++) { + for (unsigned x = 0; x < 8; x++) { + uint8_t color = gb->sgb->border.tiles[(tile & 0xFF) * 64 + (x ^ flip_x) + (y ^ flip_y) * 8] & 0xF; + if (color == 0) { + if (gb_area) continue; + gb->screen[tile_x * 8 + x + (tile_y * 8 + y) * 0x100] = colors[0]; + } + else { + gb->screen[tile_x * 8 + x + (tile_y * 8 + y) * 0x100] = border_colors[color + palette * 16]; + } + } + } + } + } +} + +void GB_sgb_load_default_data(GB_gameboy_t *gb) +{ + +#include "sgb_border.inc" + + memcpy(gb->sgb->border.map, tilemap, sizeof(tilemap)); + memcpy(gb->sgb->border.palette, palette, sizeof(palette)); + + /* Expend tileset */ + for (unsigned tile = 0; tile < sizeof(tiles) / 32; tile++) { + for (unsigned y = 0; y < 8; y++) { + for (unsigned x = 0; x < 8; x++) { + gb->sgb->border.tiles[tile * 8 * 8 + y * 8 + x] = + (tiles[tile * 32 + y * 2 + 0] & (1 << (7 ^ x)) ? 1 : 0) | + (tiles[tile * 32 + y * 2 + 1] & (1 << (7 ^ x)) ? 2 : 0) | + (tiles[tile * 32 + y * 2 + 16] & (1 << (7 ^ x)) ? 4 : 0) | + (tiles[tile * 32 + y * 2 + 17] & (1 << (7 ^ x)) ? 8 : 0); + } + } + } + + if (gb->model != GB_MODEL_SGB2) { + /* Delete the "2" */ + gb->sgb->border.map[25 * 32 + 25] = gb->sgb->border.map[25 * 32 + 26] = + gb->sgb->border.map[26 * 32 + 25] = gb->sgb->border.map[26 * 32 + 26] = + gb->sgb->border.map[27 * 32 + 25] = gb->sgb->border.map[27 * 32 + 26] = + gb->sgb->border.map[0]; + + /* Re-center */ + memmove(&gb->sgb->border.map[25 * 32 + 1], &gb->sgb->border.map[25 * 32], (32 * 3 - 1) * sizeof(gb->sgb->border.map[0])); + } + gb->sgb->effective_palettes[0] = built_in_palettes[0]; + gb->sgb->effective_palettes[1] = built_in_palettes[1]; + gb->sgb->effective_palettes[2] = built_in_palettes[2]; + gb->sgb->effective_palettes[3] = built_in_palettes[3]; +} + +static double fm_synth(double phase) +{ + return (sin(phase * M_PI * 2) + + sin(phase * M_PI * 2 + sin(phase * M_PI * 2)) + + sin(phase * M_PI * 2 + sin(phase * M_PI * 3)) + + sin(phase * M_PI * 2 + sin(phase * M_PI * 4))) / 4; +} + +static double fm_sweep(double phase) +{ + double ret = 0; + for (unsigned i = 0; i < 8; i++) { + ret += sin((phase * M_PI * 2 + sin(phase * M_PI * 8) / 4) * pow(1.25, i)) * (8 - i) / 36; + } + return ret; +} +static double random_double(void) +{ + return ((signed)(GB_random32() % 0x10001) - 0x8000) / (double) 0x8000; +} + +static void render_jingle(GB_gameboy_t *gb, size_t count) +{ + const double frequencies[7] = { + 466.16, // Bb4 + 587.33, // D5 + 698.46, // F5 + 830.61, // Ab5 + 1046.50, // C6 + 1244.51, // Eb6 + 1567.98, // G6 + }; + + assert(gb->apu_output.sample_callback); + + if (gb->sgb->intro_animation < 0) { + GB_sample_t sample = {0, 0}; + for (unsigned i = 0; i < count; i++) { + gb->apu_output.sample_callback(gb, &sample); + } + return; + } + + if (gb->sgb->intro_animation >= INTRO_ANIMATION_LENGTH) return; + + signed jingle_stage = (gb->sgb->intro_animation - 64) / 3; + double sweep_cutoff_ratio = 2000.0 * pow(2, gb->sgb->intro_animation / 20.0) / gb->apu_output.sample_rate; + double sweep_phase_shift = 1000.0 * pow(2, gb->sgb->intro_animation / 40.0) / gb->apu_output.sample_rate; + if (sweep_cutoff_ratio > 1) { + sweep_cutoff_ratio = 1; + } + + GB_sample_t stereo; + for (unsigned i = 0; i < count; i++) { + double sample = 0; + for (signed f = 0; f < 7 && f < jingle_stage; f++) { + sample += fm_synth(gb->sgb_intro_jingle_phases[f]) * + (0.75 * pow(0.5, jingle_stage - f) + 0.25) / 5.0; + gb->sgb_intro_jingle_phases[f] += frequencies[f] / gb->apu_output.sample_rate; + } + if (gb->sgb->intro_animation > 100) { + sample *= pow((INTRO_ANIMATION_LENGTH - gb->sgb->intro_animation) / (INTRO_ANIMATION_LENGTH - 100.0), 3); + } + + if (gb->sgb->intro_animation < 120) { + double next = fm_sweep(gb->sgb_intro_sweep_phase) * 0.3 + random_double() * 0.7; + gb->sgb_intro_sweep_phase += sweep_phase_shift; + + gb->sgb_intro_sweep_previous_sample = next * (sweep_cutoff_ratio) + + gb->sgb_intro_sweep_previous_sample * (1 - sweep_cutoff_ratio); + sample += gb->sgb_intro_sweep_previous_sample * pow((120 - gb->sgb->intro_animation) / 120.0, 2) * 0.8; + } + + stereo.left = stereo.right = sample * 0x7000; + gb->apu_output.sample_callback(gb, &stereo); + } + + return; +} + diff --git a/gb/Core/sgb.h b/gb/Core/sgb.h new file mode 100644 index 0000000..df90253 --- /dev/null +++ b/gb/Core/sgb.h @@ -0,0 +1,66 @@ +#ifndef sgb_h +#define sgb_h +#include "gb_struct_def.h" +#include +#include + +typedef struct GB_sgb_s GB_sgb_t; + +#ifdef GB_INTERNAL +struct GB_sgb_s { + uint8_t command[16 * 7]; + uint16_t command_write_index; + bool ready_for_pulse; + bool ready_for_write; + bool ready_for_stop; + bool disable_commands; + + /* Screen buffer */ + uint8_t screen_buffer[160 * 144]; // Live image from the Game Boy + uint8_t effective_screen_buffer[160 * 144]; // Image actually rendered to the screen + + /* Multiplayer Input */ + uint8_t player_count, current_player; + + /* Mask */ + uint8_t mask_mode; + + /* Data Transfer */ + uint8_t vram_transfer_countdown, transfer_dest; + + /* Border */ + struct { + uint8_t tiles[0x100 * 8 * 8]; /* High nibble not used*/ + union { + struct { + uint16_t map[32 * 32]; + uint16_t palette[16 * 4]; + }; + uint16_t raw_data[0x440]; + }; + } border, pending_border; + uint8_t border_animation; + + /* Colorization */ + uint16_t effective_palettes[4 * 4]; + uint16_t ram_palettes[4 * 512]; + uint8_t attribute_map[20 * 18]; + uint8_t attribute_files[0xFE0]; + + /* Intro */ + int16_t intro_animation; + + /* GB Header */ + uint8_t received_header[0x54]; + + /* Multiplayer (cont) */ + bool mlt_lock; +}; + +void GB_sgb_write(GB_gameboy_t *gb, uint8_t value); +void GB_sgb_render(GB_gameboy_t *gb); +void GB_sgb_load_default_data(GB_gameboy_t *gb); + +#endif + +#endif diff --git a/gb/Core/sgb_animation_logo.inc b/gb/Core/sgb_animation_logo.inc new file mode 100644 index 0000000..75075f4 --- /dev/null +++ b/gb/Core/sgb_animation_logo.inc @@ -0,0 +1,563 @@ +static uint8_t animation_logo[] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x1, 0x3, 0x3, 0x1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x1, 0x1, 0x1, 0x1, 0x3, 0x3, 0x1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3, 0x3, 0x3, 0x3, 0x3, 0x1, 0x1, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x3, 0x3, 0x3, 0x3, 0x3, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x3, 0x3, 0x3, 0x1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, + 0x4, 0x4, 0x4, 0x3, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x3, 0x1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xE, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, + 0x4, 0x4, 0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x3, 0x1, 0x1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xE, 0xE, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x4, + 0x4, 0x4, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x3, 0x1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE, 0xE, 0xE, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, + 0x4, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x3, 0x3, 0x1, 0x1, 0x0, 0x1, + 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x7, 0x0, 0x0, 0x1, 0x9, 0x9, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0xC, 0xC, 0xC, 0xC, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE, 0xE, 0xE, 0xE, 0x1, + 0x0, 0x0, 0xE, 0xE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, + 0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x3, 0x1, 0x1, 0x0, 0x0, 0x5, + 0x5, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x7, 0x7, 0x7, 0x9, 0x9, 0x9, 0x9, 0x9, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0x0, 0x0, 0x0, 0x0, 0xE, 0xE, 0xE, 0xE, 0x1, + 0x1, 0xE, 0xE, 0xE, 0xE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x3, 0x1, 0x0, 0x0, 0x5, 0x5, + 0x5, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x7, 0x7, 0x7, 0x9, 0x1, 0x1, 0x1, 0x9, 0x9, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC, + 0xC, 0xC, 0xC, 0xC, 0x1, 0x1, 0xC, 0xC, 0x0, 0x0, 0x0, 0xE, 0xE, 0xE, 0xE, 0xE, + 0xE, 0xE, 0xE, 0xE, 0xE, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x1, 0x1, 0x0, 0x1, 0x5, 0x5, + 0x5, 0x1, 0x0, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x7, + 0x7, 0x7, 0x9, 0x1, 0x1, 0x0, 0x0, 0x9, 0x9, 0x1, 0x0, 0x0, 0x0, 0x0, 0xC, 0xC, + 0xC, 0xC, 0x1, 0x1, 0x0, 0xC, 0xC, 0xC, 0x1, 0x0, 0x0, 0xE, 0xE, 0xE, 0xE, 0xE, + 0xE, 0xE, 0xE, 0xE, 0xE, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x5, 0x5, 0x5, + 0x5, 0x1, 0x0, 0x0, 0x0, 0x1, 0x6, 0x6, 0x6, 0x1, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7, + 0x7, 0x7, 0x1, 0x1, 0x0, 0x0, 0x1, 0x9, 0x9, 0x9, 0x0, 0x0, 0x0, 0x1, 0xC, 0xC, + 0xC, 0x1, 0x1, 0x0, 0x0, 0xC, 0xC, 0xC, 0x1, 0x0, 0x0, 0x1, 0xD, 0x1, 0x1, 0x1, + 0x1, 0xE, 0xE, 0xE, 0xE, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, + 0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5, 0x5, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, + 0x7, 0x1, 0x1, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x1, 0x0, 0x0, 0x0, 0xC, 0xC, 0xC, + 0xC, 0x1, 0x0, 0x0, 0xC, 0xC, 0xC, 0xC, 0x1, 0x0, 0x0, 0xD, 0xD, 0x1, 0x0, 0x0, + 0xE, 0xE, 0xF, 0xF, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, + 0x4, 0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5, 0x5, + 0x1, 0x0, 0x0, 0x0, 0x1, 0x6, 0x6, 0x6, 0x1, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, + 0x7, 0x1, 0x0, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x1, 0x0, 0x0, 0xC, 0xC, 0xC, 0xC, + 0x1, 0x1, 0x0, 0x1, 0xC, 0xC, 0xC, 0x1, 0x1, 0x0, 0x1, 0xD, 0x1, 0x1, 0x0, 0xF, + 0xF, 0xF, 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, + 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x5, 0x5, 0x5, 0x1, + 0x1, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, 0x0, 0x1, 0x7, 0x7, 0x7, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x1, 0x0, 0x0, 0xC, 0xC, 0xC, 0xC, + 0x1, 0x0, 0x1, 0xC, 0xC, 0xC, 0xC, 0x1, 0x0, 0x0, 0xD, 0xD, 0x1, 0x0, 0x1, 0xF, + 0xF, 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x4, 0x4, 0x4, 0x4, 0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x1, 0x1, + 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x9, 0x1, 0x0, 0x1, 0xC, 0xC, 0xB, 0xB, + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0x1, 0x0, 0x0, 0xD, 0xD, 0x1, 0x1, 0x0, 0xF, 0xF, + 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x1, 0x6, 0x6, 0x6, 0x1, 0x0, + 0x0, 0x0, 0x1, 0x6, 0x6, 0x7, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x7, 0x7, 0x7, 0x1, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x1, 0x1, 0x0, 0xC, 0xC, 0xB, 0xB, 0x1, + 0xC, 0xC, 0xC, 0xC, 0x1, 0x1, 0x1, 0x0, 0x1, 0xD, 0x1, 0x1, 0x0, 0x1, 0xF, 0xF, + 0xF, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x6, 0x6, 0x6, 0x1, 0x1, 0x0, + 0x0, 0x0, 0x6, 0x6, 0x7, 0x7, 0x1, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x8, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x9, 0x9, 0x9, 0x9, 0x1, 0x0, 0x0, 0xC, 0xB, 0xB, 0xB, 0x1, + 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0xD, 0xD, 0x1, 0x0, 0x0, 0xF, 0xF, 0xF, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x5, 0x5, 0x5, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x4, 0x4, 0x1, 0x0, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, + 0x0, 0x6, 0x6, 0x7, 0x7, 0x1, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x8, 0x8, 0x1, + 0x0, 0x0, 0x0, 0x1, 0x9, 0x9, 0xA, 0x1, 0x1, 0x0, 0xC, 0xB, 0xB, 0xB, 0x1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xD, 0xD, 0x1, 0x1, 0x0, 0x0, 0xF, 0xF, 0xF, + 0x1, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x5, 0x5, 0x5, 0x1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x4, 0x1, 0x1, 0x6, 0x6, 0x6, 0x1, 0x0, 0x0, + 0x1, 0x6, 0x7, 0x7, 0x7, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x8, 0x8, 0xA, 0x1, + 0x0, 0x0, 0x0, 0x9, 0x9, 0xA, 0xA, 0x1, 0x0, 0x1, 0xB, 0xB, 0xB, 0xD, 0x1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xD, 0xD, 0x1, 0x1, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, + 0x1, 0x0, 0x0, 0x0, 0xF, 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x5, 0x5, 0x5, 0x5, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x4, 0x1, 0x1, 0x6, 0x6, 0x1, 0x1, 0x0, 0x1, + 0x6, 0x1, 0x7, 0x7, 0x7, 0x1, 0x0, 0x0, 0x1, 0x7, 0x7, 0x8, 0x8, 0xA, 0xA, 0x1, + 0x0, 0x0, 0xA, 0xA, 0xA, 0xA, 0x1, 0x1, 0x0, 0xB, 0xB, 0x1, 0xD, 0xD, 0xD, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xD, 0xD, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, + 0x1, 0x0, 0x0, 0x0, 0xF, 0xF, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5, 0x5, 0x5, 0x5, 0x5, + 0x5, 0x1, 0x0, 0x0, 0x1, 0x4, 0x4, 0x1, 0x1, 0x0, 0x6, 0x6, 0x1, 0x0, 0x1, 0x6, + 0x1, 0x1, 0x7, 0x7, 0x7, 0x1, 0x0, 0x1, 0x7, 0x7, 0x8, 0x8, 0x1, 0x1, 0xA, 0xA, + 0x1, 0xA, 0xA, 0xA, 0xA, 0x1, 0x1, 0xB, 0xB, 0xB, 0x1, 0x1, 0x1, 0xD, 0xD, 0x1, + 0x0, 0x0, 0x0, 0x1, 0xD, 0xD, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, + 0x1, 0x0, 0x1, 0xF, 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5, 0x5, + 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, 0x1, 0x1, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x6, 0x1, + 0x1, 0x0, 0x1, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x1, 0x0, 0x1, 0xA, + 0xA, 0xA, 0xA, 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0x1, 0x1, 0x0, 0x0, 0xD, 0xD, 0xD, + 0xD, 0xD, 0xD, 0xD, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0xF, + 0xF, 0xF, 0xF, 0xF, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x5, + 0x5, 0x5, 0x5, 0x5, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6, 0x1, 0x1, 0x1, + 0x0, 0x0, 0x0, 0x1, 0x7, 0x7, 0x7, 0x1, 0x8, 0x8, 0x8, 0x1, 0x1, 0x0, 0x0, 0x0, + 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0xD, + 0xD, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0xF, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x8, 0x8, 0x8, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x8, 0x8, 0x8, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x8, 0x8, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x8, 0x8, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, + 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x8, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, + 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, + 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x1, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, + 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, + 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, + 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x1, 0x0, 0x1, 0x2, 0x2, + 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, + 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, + 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, + 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, + 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, + 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x1, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, + 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, + 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, + 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, + 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, + 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, + 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, + 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x0, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, + 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, + 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}; +static const unsigned animation_logo_height = sizeof(animation_logo) / 160; diff --git a/gb/Core/sgb_border.inc b/gb/Core/sgb_border.inc new file mode 100644 index 0000000..d7d0a5c --- /dev/null +++ b/gb/Core/sgb_border.inc @@ -0,0 +1,658 @@ +static const uint16_t palette[] = { + 0x0000, 0x0011, 0x18C6, 0x001A, 0x318C, 0x39CE, 0x5294, 0x5AD6, + 0x739C, 0x45A8, 0x4520, 0x18A5, 0x4631, 0x2033, 0x20EC, 0x18B7 +}; + +static const uint16_t tilemap[] = { + 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, + 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, + 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, + 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, + 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, + 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, + 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, + 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, + 0x1001, 0x1003, 0x1004, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, + 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, + 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, + 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x5004, 0x5003, 0x1001, + 0x1001, 0x1006, 0x1007, 0x1007, 0x1007, 0x1008, 0x1009, 0x100A, + 0x100B, 0x100C, 0x100D, 0x100E, 0x100F, 0x1010, 0x1011, 0x1012, + 0x1013, 0x1014, 0x1015, 0x100E, 0x1016, 0x1017, 0x1018, 0x1019, + 0x101A, 0x101B, 0x101C, 0x1007, 0x1007, 0x1007, 0x5006, 0x1001, + 0x1001, 0x101D, 0x101E, 0x101E, 0x101E, 0x101F, 0x1020, 0x1021, + 0x1022, 0x1023, 0x1024, 0x1025, 0x5024, 0x1026, 0x1025, 0x1025, + 0x1027, 0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, + 0x102F, 0x1030, 0x1031, 0x101E, 0x101E, 0x101E, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1034, 0x1035, 0x5034, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x8034, 0x1036, 0xC034, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0xC01D, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0x1037, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1032, 0x1038, 0x1001, + 0x1001, 0x101D, 0x1032, 0x1032, 0x1032, 0x1033, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xC033, 0x1032, 0x1032, 0x1039, 0x103A, 0x1001, + 0x1001, 0x103B, 0x103C, 0x1032, 0x1032, 0xC03C, 0x103D, 0x103D, + 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, + 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, 0x103D, + 0x103D, 0x103D, 0x103E, 0x103F, 0x1040, 0x1041, 0x1001, 0x1001, + 0x1001, 0x1042, 0x1043, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, + 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, + 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, 0x1044, + 0x1044, 0x1044, 0x1045, 0x1046, 0x1001, 0x1001, 0x1001, 0x1001, + 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1047, 0x1048, 0x1049, + 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F, 0x1050, 0x1051, + 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, 0x1058, 0x1059, + 0x105A, 0x105B, 0x105C, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, + 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x105D, 0x105E, 0x105F, + 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067, + 0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F, + 0x1070, 0x1071, 0x1072, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, + 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1073, 0x1074, 0x1075, + 0x1076, 0x1077, 0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, + 0x107E, 0x107F, 0x1080, 0x1081, 0x1082, 0x1083, 0x507A, 0x1084, + 0x1001, 0x1085, 0x507A, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, +}; + +const uint8_t tiles[] = { + 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, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x01, 0xFE, 0x06, 0xF9, 0x08, 0xF7, + 0x11, 0xEF, 0x22, 0xDB, 0x20, 0xDB, 0x40, 0xB7, + 0xFF, 0x00, 0xFF, 0x00, 0xFE, 0x00, 0xF8, 0x00, + 0xF1, 0x00, 0xE6, 0x04, 0xE4, 0x00, 0xC8, 0x00, + 0x7F, 0x80, 0x80, 0x7F, 0x00, 0xFF, 0x7F, 0xFF, + 0x80, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0x80, 0x00, 0x00, 0x00, 0x7F, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0xB7, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, + 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, + 0xC8, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x03, 0xFF, 0x02, 0xFF, + 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0xC1, 0xDD, 0x00, 0xC9, + 0x14, 0xFF, 0x14, 0xFF, 0x14, 0xFF, 0x00, 0xC9, + 0x00, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x36, 0x22, + 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x36, 0x22, + 0x00, 0xFF, 0x00, 0xFF, 0xC7, 0xDF, 0x01, 0xCF, + 0x11, 0xFF, 0x11, 0xFF, 0x11, 0xFF, 0x01, 0xCF, + 0x00, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x31, 0x20, + 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x31, 0x20, + 0x00, 0xFF, 0x00, 0xFF, 0xC2, 0xFF, 0x03, 0xFF, + 0x02, 0xFE, 0x02, 0xFE, 0x02, 0xFF, 0x02, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x03, 0x00, + 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x08, 0xFF, 0x18, 0xFF, + 0x08, 0x4E, 0x08, 0x4E, 0x09, 0x1F, 0x08, 0x1C, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, + 0xB9, 0x10, 0xB9, 0xA1, 0xE9, 0xA0, 0xEB, 0x41, + 0x00, 0xFF, 0x00, 0xFF, 0x4F, 0xFF, 0x02, 0x1F, + 0x02, 0x4F, 0x02, 0x4F, 0xF2, 0xFF, 0x02, 0xE7, + 0x00, 0x00, 0x00, 0x00, 0x4F, 0x00, 0xE2, 0xA0, + 0xB2, 0xA0, 0xB2, 0x10, 0xF2, 0x00, 0x1A, 0x10, + 0x00, 0xFF, 0x00, 0xFF, 0xBC, 0xFD, 0x22, 0xFB, + 0x22, 0xFB, 0x3C, 0xFD, 0x24, 0xFF, 0x26, 0xF9, + 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x26, 0x00, + 0x26, 0x00, 0x3E, 0x00, 0x24, 0x00, 0x26, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x50, 0xFF, 0x49, 0xEF, + 0x49, 0xF0, 0x46, 0xFF, 0x49, 0xF0, 0x49, 0xEF, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x59, 0x00, + 0x4F, 0x06, 0x46, 0x00, 0x4F, 0x06, 0x59, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x88, 0xFF, 0x00, 0x72, + 0x00, 0xF2, 0x05, 0xFF, 0x00, 0xF8, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x8D, 0x08, + 0x0D, 0x05, 0x05, 0x00, 0x07, 0x05, 0x87, 0x02, + 0x00, 0xFF, 0x00, 0xFF, 0x8A, 0xFF, 0x02, 0x27, + 0x02, 0x27, 0x52, 0xFF, 0x02, 0x8F, 0x02, 0x8F, + 0x00, 0x00, 0x00, 0x00, 0x8A, 0x00, 0xDA, 0x88, + 0xDA, 0x50, 0x52, 0x00, 0x72, 0x50, 0x72, 0x20, + 0x00, 0xFF, 0x00, 0xFF, 0xFA, 0xFF, 0x22, 0xFF, + 0x22, 0xFF, 0x23, 0xFF, 0x22, 0xFF, 0x22, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x22, 0x00, + 0x22, 0x00, 0x23, 0x00, 0x22, 0x00, 0x22, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x20, 0xFF, 0x20, 0xFF, + 0x20, 0xFF, 0xE0, 0xFF, 0x20, 0xFF, 0x20, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, + 0x20, 0x00, 0xE0, 0x00, 0x20, 0x00, 0x20, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x33, 0x37, 0x00, 0x77, + 0x80, 0xFF, 0x20, 0x27, 0x08, 0xFF, 0x00, 0x77, + 0x00, 0x00, 0x00, 0x00, 0xFB, 0x40, 0x88, 0x88, + 0x80, 0x00, 0xF8, 0x50, 0x08, 0x00, 0x88, 0x88, + 0x00, 0xFF, 0x00, 0xFF, 0xEF, 0xFF, 0x88, 0xFF, + 0x88, 0xFF, 0x8F, 0xFF, 0x88, 0xFF, 0x88, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xEF, 0x00, 0x88, 0x00, + 0x88, 0x00, 0x8F, 0x00, 0x88, 0x00, 0x88, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0xF9, 0xFD, 0x80, 0xF9, + 0x84, 0xFF, 0xF4, 0xFF, 0x84, 0xFF, 0x80, 0xF9, + 0x00, 0x00, 0x00, 0x00, 0xFB, 0x00, 0x86, 0x02, + 0x84, 0x00, 0xF4, 0x00, 0x84, 0x00, 0x86, 0x02, + 0x00, 0xFF, 0x00, 0xFF, 0xC0, 0xDF, 0x00, 0xCF, + 0x10, 0xFF, 0x10, 0xFF, 0x10, 0xFF, 0x00, 0xCF, + 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x30, 0x20, + 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x30, 0x20, + 0x00, 0xFF, 0x00, 0xFF, 0x30, 0x36, 0x00, 0x74, + 0x82, 0xFF, 0x22, 0x27, 0x0A, 0xFF, 0x00, 0x74, + 0x00, 0x00, 0x00, 0x00, 0xF9, 0x40, 0x8B, 0x89, + 0x82, 0x00, 0xFA, 0x50, 0x0A, 0x00, 0x8B, 0x89, + 0x00, 0xFF, 0x00, 0xFF, 0xE2, 0xEF, 0x02, 0xE7, + 0x0A, 0xFF, 0x0A, 0xFF, 0x0A, 0xFF, 0x00, 0xE4, + 0x00, 0x00, 0x00, 0x00, 0xF2, 0x00, 0x1A, 0x10, + 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x1B, 0x12, + 0x00, 0xFF, 0x00, 0xFF, 0x14, 0xFF, 0x16, 0xFF, + 0x14, 0xFC, 0x15, 0xFE, 0x14, 0xFF, 0x04, 0xCF, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x16, 0x00, + 0x17, 0x01, 0x15, 0x00, 0x14, 0x00, 0x34, 0x10, + 0x00, 0xFF, 0x00, 0xFF, 0x2F, 0xFF, 0x28, 0xFF, + 0x28, 0xFF, 0xA8, 0x7F, 0x28, 0x3F, 0x68, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x28, 0x00, + 0x28, 0x00, 0xA8, 0x00, 0xE8, 0x80, 0x68, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x3F, + 0x40, 0xFF, 0x40, 0xFF, 0x40, 0xFF, 0x00, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x80, + 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xC0, 0x80, + 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, + 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFF, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xC1, 0xDD, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xC1, 0xDF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x02, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x4A, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x0A, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x22, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x82, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x20, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x60, 0x67, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xF8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x8F, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x8F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xA2, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xF9, 0xFD, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xC0, 0xDF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x60, 0x66, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xF9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xE0, 0xEE, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xF1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xC4, 0xDF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xE4, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x2F, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0xFF, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, + 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x3C, 0xFF, + 0x7E, 0xFF, 0xE7, 0xE7, 0xFF, 0x7E, 0xFF, 0x7E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, + 0x81, 0xC3, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x7E, 0xFF, 0x3C, 0xFF, 0x00, 0x7E, 0x81, + 0x3C, 0xC3, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0xC3, 0x81, + 0x7E, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF7, 0x00, 0xF7, 0x00, 0xF7, 0x00, 0xF7, + 0x00, 0xF7, 0x00, 0xED, 0x00, 0xED, 0x00, 0xED, + 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, + 0x09, 0x00, 0x11, 0x02, 0x11, 0x02, 0x11, 0x02, + 0x00, 0xED, 0x00, 0xDB, 0x00, 0xDB, 0x00, 0xDB, + 0x00, 0xB7, 0x00, 0xB7, 0x00, 0x6F, 0x00, 0x6F, + 0x11, 0x02, 0x23, 0x04, 0x23, 0x04, 0x23, 0x04, + 0x47, 0x08, 0x47, 0x08, 0x8F, 0x10, 0x8F, 0x10, + 0x00, 0xFE, 0x00, 0xFD, 0x00, 0xFB, 0x00, 0xF7, + 0x00, 0xEE, 0x00, 0xDD, 0x00, 0xBB, 0x00, 0x77, + 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x10, 0x01, 0x21, 0x02, 0x43, 0x04, 0x87, 0x08, + 0x00, 0xDF, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0x7F, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x1F, 0x20, 0x3F, 0x40, 0x3F, 0x40, 0x7F, 0x80, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xEF, 0x00, 0xB7, + 0x00, 0xB7, 0x00, 0xDB, 0x00, 0xDD, 0x00, 0xEE, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x88, 0x40, + 0x88, 0x40, 0xC4, 0x20, 0xC2, 0x20, 0xE1, 0x10, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFC, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFC, 0x00, 0xE3, 0x00, 0x1F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x1C, 0x00, 0xE0, 0x00, + 0x00, 0xFE, 0x00, 0xFD, 0x00, 0xF3, 0x00, 0xEF, + 0x00, 0x1C, 0x00, 0xF3, 0x00, 0xEF, 0x00, 0x1F, + 0x01, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x10, 0x00, + 0xE0, 0x03, 0x03, 0x0C, 0x0F, 0x10, 0x1F, 0xE0, + 0x00, 0xEF, 0x00, 0xDF, 0x00, 0xBF, 0x00, 0x7F, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x0F, 0x10, 0x1F, 0x20, 0x3F, 0x40, 0x7F, 0x80, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0xF7, 0x00, 0xF9, 0x00, 0xFE, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xF0, 0x08, 0xF8, 0x06, 0xFE, 0x01, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0x80, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x80, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x7F, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0x03, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0x03, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFC, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0xFC, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0xFC, 0x00, 0xE3, 0x00, 0x1F, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x03, 0x03, 0x1C, 0x1F, 0xE0, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x01, 0xFF, 0x01, 0xFD, 0x03, 0xFF, 0x03, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x01, 0xFE, 0x02, 0xFE, 0x02, 0xFC, 0x00, + 0x0E, 0xEE, 0x3F, 0xFF, 0x75, 0x71, 0xFB, 0xE7, + 0xE3, 0xCB, 0xC7, 0x9F, 0x07, 0x3E, 0x84, 0x7C, + 0xFB, 0x1B, 0xE6, 0x26, 0x8E, 0x82, 0x3E, 0x22, + 0x7C, 0x54, 0x7D, 0x25, 0xF9, 0x40, 0xFB, 0x01, + 0x00, 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0xFF, + 0x00, 0x7F, 0x80, 0x4F, 0x31, 0x7F, 0x71, 0xFD, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x80, + 0xFF, 0x00, 0xFF, 0x30, 0xFF, 0xB1, 0xDE, 0x52, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0x7B, 0x87, 0xFF, 0x8E, 0xFE, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x84, 0xFA, 0x82, 0xF9, 0x88, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0xC1, 0xFD, 0xE3, 0x7B, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xC3, 0xBC, 0x24, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x01, 0xFF, 0x03, 0xFF, 0xE3, 0xFB, 0xF7, 0xBF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x01, 0xFE, 0x02, 0x7C, 0x64, 0xFC, 0xB4, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x7F, 0x80, 0xFF, 0xA0, 0x2F, 0xF0, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x80, 0xFF, 0x80, 0xFF, 0x70, 0x8F, 0x80, + 0x00, 0xFF, 0x00, 0xFF, 0x02, 0xFD, 0x00, 0xF7, + 0x00, 0xFF, 0x11, 0xEE, 0x11, 0xEE, 0x10, 0xEF, + 0xFF, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF8, 0x0F, + 0xF0, 0x0F, 0xE0, 0x1F, 0xE1, 0x1E, 0xE0, 0x1F, + 0x00, 0xFF, 0x00, 0xFF, 0x10, 0xE7, 0x00, 0xFB, + 0xC4, 0x3B, 0x98, 0x03, 0x00, 0xEF, 0x80, 0x7F, + 0xFF, 0x00, 0xFF, 0x00, 0x0F, 0xF8, 0x07, 0xFC, + 0x07, 0xF8, 0xEF, 0x74, 0xFF, 0x10, 0x7F, 0x80, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xEF, 0x00, 0xFF, 0x22, 0xDD, 0x06, 0xB9, + 0xFF, 0x00, 0xFF, 0x00, 0xF8, 0x07, 0xF0, 0x0F, + 0xF0, 0x1F, 0xE0, 0x1F, 0xC0, 0x3F, 0xC4, 0x7B, + 0x00, 0xFF, 0x00, 0xFF, 0x80, 0x7D, 0x02, 0xFD, + 0x02, 0xBD, 0x40, 0xBF, 0x40, 0xBF, 0x40, 0xBF, + 0xFF, 0x00, 0xFF, 0x00, 0x7E, 0x83, 0x7C, 0x83, + 0x7C, 0xC3, 0x7C, 0x83, 0x3C, 0xC3, 0x3C, 0xC3, + 0x00, 0xFF, 0x00, 0xFF, 0x10, 0xEF, 0x00, 0xFF, + 0x00, 0xF7, 0x00, 0xF7, 0x48, 0xB6, 0x48, 0xB7, + 0xFF, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF8, 0x0F, 0xF8, 0x07, 0xF9, 0x06, 0xF9, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xBF, 0x02, 0xFC, + 0x02, 0x7D, 0x02, 0xFD, 0x02, 0xFD, 0x20, 0xDD, + 0xFF, 0x00, 0xFF, 0x00, 0xC1, 0x7E, 0x81, 0x7F, + 0x81, 0xFE, 0x01, 0xFE, 0x03, 0xFC, 0x03, 0xFE, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xBF, 0x40, 0xBF, + 0x47, 0xB8, 0x08, 0xF0, 0x08, 0xF7, 0x0F, 0xF0, + 0xFF, 0x00, 0xFF, 0x00, 0xC0, 0x7F, 0x80, 0x7F, + 0x80, 0x7F, 0x87, 0x7F, 0x87, 0x78, 0x80, 0x7F, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFB, 0x24, 0xCB, + 0xE4, 0x1B, 0x00, 0x1F, 0x00, 0xFF, 0x80, 0x3F, + 0xFF, 0x00, 0xFF, 0x00, 0x1C, 0xE7, 0x18, 0xF7, + 0x18, 0xE7, 0xF8, 0xE7, 0xF8, 0x07, 0x78, 0xC7, + 0x00, 0xFF, 0x00, 0xFF, 0x04, 0xF9, 0x00, 0xFF, + 0x71, 0x8E, 0x89, 0x06, 0x81, 0x7E, 0xE1, 0x1E, + 0xFF, 0x00, 0xFF, 0x00, 0x03, 0xFE, 0x01, 0xFE, + 0x00, 0xFF, 0x70, 0xFF, 0x70, 0x8F, 0x01, 0xFE, + 0x00, 0xFF, 0x00, 0xFF, 0x02, 0xF9, 0x00, 0xFF, + 0x00, 0xFF, 0x03, 0xFC, 0x06, 0xB9, 0x44, 0xBB, + 0xFF, 0x00, 0xFF, 0x00, 0xFC, 0x07, 0xF0, 0x0F, + 0xE0, 0x1F, 0xC1, 0x3E, 0xC3, 0x7C, 0x87, 0x78, + 0x00, 0xFF, 0x00, 0xFF, 0x08, 0xF7, 0x00, 0xFD, + 0xC0, 0x3F, 0x11, 0x0E, 0x00, 0xFF, 0x08, 0xF7, + 0xFF, 0x00, 0xFF, 0x00, 0x07, 0xF8, 0x03, 0xFE, + 0x01, 0xFE, 0xE0, 0xFF, 0xF0, 0x0F, 0xF0, 0x0F, + 0x00, 0xFF, 0x00, 0xFF, 0x08, 0x77, 0x40, 0xBF, + 0x04, 0xBB, 0x00, 0xFE, 0x00, 0xDD, 0x00, 0x7F, + 0xFF, 0x00, 0xFF, 0x00, 0x87, 0xF8, 0x87, 0x78, + 0xC3, 0x7C, 0xC3, 0x3D, 0xE2, 0x3F, 0xE0, 0x9F, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFD, 0x06, 0xF9, + 0x0C, 0x73, 0x08, 0xF7, 0x10, 0xE7, 0x20, 0xCF, + 0xFF, 0x00, 0xFF, 0x00, 0xC3, 0x3E, 0x83, 0x7C, + 0x87, 0xF8, 0x0F, 0xF0, 0x1F, 0xE8, 0x3F, 0xD0, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xF7, 0x00, 0xFF, + 0x01, 0xDE, 0x06, 0xF8, 0x1C, 0xC3, 0x00, 0xF3, + 0xFF, 0x00, 0xFF, 0x00, 0xF8, 0x0F, 0xE0, 0x1F, + 0xE0, 0x3F, 0xC3, 0x3D, 0xE7, 0x38, 0xFF, 0x0C, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xDF, 0x00, 0xFF, + 0x00, 0xF7, 0x08, 0x77, 0x08, 0xF7, 0x08, 0xF7, + 0xFF, 0x00, 0xFF, 0x00, 0x3F, 0xE0, 0x0F, 0xF0, + 0x0F, 0xF8, 0x87, 0xF8, 0x87, 0x78, 0x07, 0xF8, + 0x03, 0xFF, 0x03, 0xFF, 0x01, 0xFF, 0x00, 0xFE, + 0x18, 0xDF, 0x1C, 0xFD, 0x0F, 0xEF, 0x07, 0xF7, + 0xFC, 0x00, 0xFE, 0x02, 0xFF, 0x01, 0xFF, 0x01, + 0xFF, 0x38, 0xF3, 0x12, 0xF9, 0x19, 0xFC, 0x0C, + 0x02, 0x79, 0x80, 0xFD, 0xC0, 0xDF, 0xF0, 0xFE, + 0x79, 0x3F, 0x19, 0xDB, 0x19, 0xFB, 0xF9, 0xF7, + 0xFF, 0x84, 0xFF, 0x82, 0x7F, 0x60, 0x9F, 0x91, + 0xEF, 0xA9, 0xF6, 0x34, 0xFE, 0x1C, 0x1F, 0x11, + 0x63, 0xEF, 0xF3, 0xEB, 0xC6, 0xCE, 0xEF, 0xDE, + 0x8C, 0x9C, 0xDE, 0xBD, 0x9C, 0x9D, 0xFF, 0xEF, + 0x9E, 0x02, 0xBC, 0xA4, 0x3D, 0x14, 0x7B, 0x4A, + 0x73, 0x21, 0xF7, 0x94, 0xF7, 0xF6, 0xFE, 0xEE, + 0x8D, 0xEC, 0x9E, 0x7D, 0x1C, 0x5B, 0x38, 0xFA, + 0x79, 0xF7, 0x71, 0x75, 0xF3, 0xF3, 0xEF, 0xCF, + 0xF3, 0x90, 0xF7, 0x14, 0xEF, 0xA8, 0xEF, 0x2D, + 0xCF, 0x41, 0x8E, 0x8A, 0x3C, 0x3C, 0x39, 0x19, + 0x67, 0xFF, 0xEF, 0xFE, 0xEC, 0xDC, 0xCF, 0xCF, + 0xDD, 0xDC, 0xDC, 0x9F, 0x2C, 0x2F, 0xD7, 0xC7, + 0xB9, 0x21, 0xBB, 0xAA, 0xB3, 0x81, 0x76, 0x76, + 0x77, 0x76, 0xE7, 0xA4, 0xD7, 0x44, 0xFB, 0xCB, + 0xB3, 0x37, 0x73, 0x72, 0xF4, 0xEC, 0xEF, 0xCD, + 0xCD, 0x09, 0x11, 0xF3, 0x29, 0xA7, 0xF1, 0xCF, + 0xCD, 0x49, 0xDF, 0xDE, 0xBF, 0xA5, 0x7F, 0x5D, + 0xF6, 0x32, 0xFE, 0x14, 0xFE, 0x70, 0xFF, 0xC1, + 0xF0, 0x77, 0xF0, 0x67, 0xE0, 0xCF, 0x80, 0x97, + 0xC8, 0xBB, 0x98, 0xBB, 0x90, 0xD3, 0xE8, 0xE7, + 0xDF, 0x58, 0xBF, 0x28, 0x7F, 0x50, 0x7F, 0x28, + 0xF7, 0x84, 0xFF, 0xDC, 0xEF, 0xA4, 0xDF, 0xC0, + 0x00, 0xFF, 0x04, 0xF3, 0x03, 0xF8, 0x00, 0xFF, + 0x08, 0xF7, 0x03, 0xFC, 0x00, 0xBF, 0x18, 0xC7, + 0xF0, 0x0F, 0xF8, 0x0F, 0xFE, 0x05, 0xFF, 0x00, + 0xE7, 0x18, 0xC0, 0x3F, 0xC0, 0x7F, 0xE0, 0x3F, + 0x00, 0xFF, 0x00, 0xFF, 0x08, 0xF6, 0x08, 0x77, + 0x08, 0xF5, 0x08, 0xF7, 0x10, 0xE7, 0x70, 0x87, + 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF9, 0x86, 0xF9, + 0x86, 0x7B, 0x0C, 0xF3, 0x08, 0xFF, 0x38, 0xCF, + 0x0A, 0xF1, 0x88, 0x77, 0x0E, 0xF1, 0x00, 0xFF, + 0x00, 0xFF, 0x7F, 0x80, 0x41, 0xBE, 0x81, 0x3E, + 0x84, 0x7F, 0x0E, 0xF1, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x3E, 0xC1, 0x7E, 0x81, 0x7E, 0xC1, + 0x04, 0xFB, 0x04, 0xDB, 0x24, 0xDB, 0x20, 0xDF, + 0x20, 0xDF, 0x00, 0xFF, 0x08, 0xE7, 0x19, 0xE6, + 0x38, 0xC7, 0x38, 0xE7, 0x38, 0xC7, 0x18, 0xE7, + 0x18, 0xE7, 0x18, 0xE7, 0x10, 0xFF, 0x10, 0xEF, + 0x48, 0xB5, 0x80, 0x3F, 0x84, 0x7B, 0x80, 0x7F, + 0xA1, 0x5E, 0x21, 0x5E, 0x02, 0x7C, 0x02, 0x7D, + 0x46, 0xBB, 0x44, 0xFB, 0x40, 0xBF, 0x40, 0xBF, + 0xC0, 0x3F, 0xC1, 0xBE, 0xE1, 0x9F, 0xE3, 0x9C, + 0x60, 0x9D, 0x64, 0x99, 0x84, 0x3B, 0x84, 0x7B, + 0x04, 0x7B, 0x40, 0xBB, 0x41, 0xBA, 0x09, 0xF2, + 0x03, 0xFE, 0x43, 0xBE, 0x43, 0xFC, 0xC3, 0x3C, + 0xC7, 0xB8, 0x87, 0x7C, 0x86, 0x7D, 0x86, 0x7D, + 0x80, 0x7F, 0x80, 0x7F, 0x8F, 0x70, 0x10, 0xEF, + 0x10, 0xEF, 0x1F, 0xE0, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x48, 0xB7, 0x48, 0xB7, 0xC0, 0x3F, 0x01, 0xFE, + 0x01, 0xFE, 0x81, 0x2E, 0x50, 0xAF, 0x50, 0xAF, + 0x30, 0xCF, 0x30, 0xCF, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0x70, 0xDF, 0x20, 0xDF, 0x60, 0x9F, + 0x06, 0xF8, 0x00, 0xFD, 0xF0, 0x0F, 0x00, 0x7E, + 0x00, 0xEE, 0xE2, 0x1C, 0x02, 0xFD, 0x0C, 0xF1, + 0x03, 0xFD, 0x03, 0xFE, 0xE1, 0x1E, 0xF1, 0x8F, + 0xF1, 0x1F, 0x01, 0xFF, 0x03, 0xFC, 0x07, 0xFA, + 0x08, 0xF3, 0x08, 0xF7, 0x08, 0xF7, 0x00, 0xFF, + 0x40, 0xBB, 0x01, 0xFE, 0x20, 0xDF, 0x18, 0xE7, + 0x87, 0x7C, 0x87, 0x78, 0x87, 0x78, 0x87, 0x78, + 0x87, 0x7C, 0xC0, 0x3F, 0xE0, 0x1F, 0xF0, 0x0F, + 0x08, 0xF7, 0x08, 0xF7, 0x01, 0xFE, 0x11, 0xEE, + 0x01, 0xDE, 0x82, 0x7C, 0x04, 0xF9, 0x38, 0xC3, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xE0, 0x1F, + 0xE1, 0x3E, 0x03, 0xFD, 0x07, 0xFA, 0x0F, 0xF4, + 0x10, 0x6F, 0x00, 0x7F, 0x01, 0x7E, 0x01, 0xFE, + 0x01, 0xFE, 0x11, 0xEE, 0x10, 0xEE, 0x12, 0xEC, + 0xE0, 0x9F, 0xF0, 0x8F, 0xF0, 0x8F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xE1, 0x1E, 0xE1, 0x1F, 0xE1, 0x1F, + 0x40, 0x9F, 0x80, 0x3F, 0x80, 0x7F, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x7F, 0xA0, 0x7F, 0xC0, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0xFB, 0x08, 0xF7, 0x00, 0xFF, + 0x01, 0xBE, 0x03, 0xFC, 0x00, 0x7F, 0x80, 0x7F, + 0xFE, 0x01, 0xFC, 0x07, 0xF0, 0x0F, 0xE0, 0x1F, + 0xC1, 0x7E, 0x80, 0x7F, 0x80, 0xFF, 0x00, 0xFF, + 0x08, 0xF7, 0x10, 0xE7, 0x60, 0x8F, 0xC0, 0x3F, + 0x80, 0x7F, 0xE0, 0x0F, 0x00, 0xEF, 0x00, 0xEF, + 0x0F, 0xF0, 0x1F, 0xE8, 0x3F, 0xD0, 0x7F, 0x80, + 0xFF, 0x00, 0x1F, 0xF0, 0x1F, 0xF0, 0x1F, 0xF0, + 0x02, 0xF8, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x04, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xD0, 0xC6, 0x00, 0x1F, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0xC9, 0xFF, 0xE0, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xE7, 0x86, 0x01, 0x39, 0x01, 0xFF, 0x03, 0xFF, + 0x03, 0xFF, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0xFF, + 0xFF, 0x9E, 0xFF, 0xC7, 0xFE, 0x00, 0xFE, 0x02, + 0xFF, 0x03, 0xFF, 0x02, 0xFF, 0x01, 0xFF, 0x00, + 0xC3, 0xD3, 0xC0, 0xBC, 0x80, 0xBF, 0x00, 0x7F, + 0x80, 0x7F, 0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, + 0x7F, 0x6B, 0x7F, 0x03, 0xFF, 0xC0, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x00, 0xFF, 0x00, + 0xC7, 0x1B, 0x00, 0x7C, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x23, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xC0, 0x1F, 0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x20, 0xFF, 0x80, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x50, 0x4F, 0x00, 0x9F, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x40, 0xFF, 0x60, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x07, 0xF0, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xC7, 0x18, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x20, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x80, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xF7, 0x08, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x0C, 0xE1, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x12, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x38, 0x87, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x40, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x8F, 0x30, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x40, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xF0, 0x07, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x03, 0xF0, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x0C, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x0E, 0xF1, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x7F, 0x80, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00 +}; diff --git a/gb/Core/sm83_cpu.c b/gb/Core/sm83_cpu.c new file mode 100644 index 0000000..77248b5 --- /dev/null +++ b/gb/Core/sm83_cpu.c @@ -0,0 +1,1521 @@ +#include +#include +#include +#include "gb.h" + + +typedef void GB_opcode_t(GB_gameboy_t *gb, uint8_t opcode); + +typedef enum { + /* Default behavior. If the CPU writes while another component reads, it reads the old value */ + GB_CONFLICT_READ_OLD, + /* If the CPU writes while another component reads, it reads the new value */ + GB_CONFLICT_READ_NEW, + /* If the CPU and another component write at the same time, the CPU's value "wins" */ + GB_CONFLICT_WRITE_CPU, + /* Register specific values */ + GB_CONFLICT_STAT_CGB, + GB_CONFLICT_STAT_DMG, + GB_CONFLICT_PALETTE_DMG, + GB_CONFLICT_PALETTE_CGB, +} GB_conflict_t; + +/* Todo: How does double speed mode affect these? */ +static const GB_conflict_t cgb_conflict_map[0x80] = { + [GB_IO_IF] = GB_CONFLICT_WRITE_CPU, + [GB_IO_LYC] = GB_CONFLICT_WRITE_CPU, + [GB_IO_STAT] = GB_CONFLICT_STAT_CGB, + [GB_IO_BGP] = GB_CONFLICT_PALETTE_CGB, + [GB_IO_OBP0] = GB_CONFLICT_PALETTE_CGB, + [GB_IO_OBP1] = GB_CONFLICT_PALETTE_CGB, + + + /* Todo: most values not verified, and probably differ between revisions */ +}; + +/* Todo: verify on an MGB */ +static const GB_conflict_t dmg_conflict_map[0x80] = { + [GB_IO_IF] = GB_CONFLICT_WRITE_CPU, + [GB_IO_LYC] = GB_CONFLICT_READ_OLD, + [GB_IO_LCDC] = GB_CONFLICT_READ_NEW, + [GB_IO_SCY] = GB_CONFLICT_READ_NEW, + [GB_IO_STAT] = GB_CONFLICT_STAT_DMG, + + [GB_IO_BGP] = GB_CONFLICT_PALETTE_DMG, + [GB_IO_OBP0] = GB_CONFLICT_PALETTE_DMG, + [GB_IO_OBP1] = GB_CONFLICT_PALETTE_DMG, + + /* Todo: these were not verified at all */ + [GB_IO_WY] = GB_CONFLICT_READ_NEW, + [GB_IO_WX] = GB_CONFLICT_READ_NEW, + [GB_IO_SCX] = GB_CONFLICT_READ_NEW, +}; + +/* Todo: Verify on an SGB1 */ +static const GB_conflict_t sgb_conflict_map[0x80] = { + [GB_IO_IF] = GB_CONFLICT_WRITE_CPU, + [GB_IO_LYC] = GB_CONFLICT_READ_OLD, + [GB_IO_LCDC] = GB_CONFLICT_READ_NEW, + [GB_IO_SCY] = GB_CONFLICT_READ_NEW, + [GB_IO_STAT] = GB_CONFLICT_STAT_DMG, + + [GB_IO_BGP] = GB_CONFLICT_READ_NEW, + [GB_IO_OBP0] = GB_CONFLICT_READ_NEW, + [GB_IO_OBP1] = GB_CONFLICT_READ_NEW, + + /* Todo: these were not verified at all */ + [GB_IO_WY] = GB_CONFLICT_READ_NEW, + [GB_IO_WX] = GB_CONFLICT_READ_NEW, + [GB_IO_SCX] = GB_CONFLICT_READ_NEW, +}; + +static uint8_t cycle_read(GB_gameboy_t *gb, uint16_t addr) +{ + if (gb->pending_cycles) { + GB_advance_cycles(gb, gb->pending_cycles); + } + uint8_t ret = GB_read_memory(gb, addr); + gb->pending_cycles = 4; + return ret; +} + +static uint8_t cycle_read_inc_oam_bug(GB_gameboy_t *gb, uint16_t addr) +{ + if (gb->pending_cycles) { + GB_advance_cycles(gb, gb->pending_cycles); + } + GB_trigger_oam_bug_read_increase(gb, addr); /* Todo: test T-cycle timing */ + uint8_t ret = GB_read_memory(gb, addr); + gb->pending_cycles = 4; + return ret; +} + +/* A special case for IF during ISR, returns the old value of IF. */ +/* TODO: Verify the timing, it might be wrong in cases where, in the same M cycle, IF + is both read be the CPU, modified by the ISR, and modified by an actual interrupt. + If this timing proves incorrect, the ISR emulation must be updated so IF reads are + timed correctly. */ +static uint8_t cycle_write_if(GB_gameboy_t *gb, uint8_t value) +{ + assert(gb->pending_cycles); + GB_advance_cycles(gb, gb->pending_cycles); + uint8_t old = (gb->io_registers[GB_IO_IF]) & 0x1F; + GB_write_memory(gb, 0xFF00 + GB_IO_IF, value); + gb->pending_cycles = 4; + return old; +} + +static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) +{ + assert(gb->pending_cycles); + GB_conflict_t conflict = GB_CONFLICT_READ_OLD; + if ((addr & 0xFF80) == 0xFF00) { + const GB_conflict_t *map = NULL; + if (GB_is_cgb(gb)) { + map = cgb_conflict_map; + } + else if (GB_is_sgb(gb)) { + map = sgb_conflict_map; + } + else { + map = dmg_conflict_map; + } + conflict = map[addr & 0x7F]; + } + switch (conflict) { + case GB_CONFLICT_READ_OLD: + GB_advance_cycles(gb, gb->pending_cycles); + GB_write_memory(gb, addr, value); + gb->pending_cycles = 4; + return; + + case GB_CONFLICT_READ_NEW: + GB_advance_cycles(gb, gb->pending_cycles - 1); + GB_write_memory(gb, addr, value); + gb->pending_cycles = 5; + return; + + case GB_CONFLICT_WRITE_CPU: + GB_advance_cycles(gb, gb->pending_cycles + 1); + GB_write_memory(gb, addr, value); + gb->pending_cycles = 3; + return; + + /* The DMG STAT-write bug is basically the STAT register being read as FF for a single T-cycle */ + case GB_CONFLICT_STAT_DMG: + GB_advance_cycles(gb, gb->pending_cycles); + /* State 7 is the edge between HBlank and OAM mode, and it behaves a bit weird. + The OAM interrupt seems to be blocked by HBlank interrupts in that case, despite + the timing not making much sense for that. + This is a hack to simulate this effect */ + if (gb->display_state == 7 && (gb->io_registers[GB_IO_STAT] & 0x28) == 0x08) { + GB_write_memory(gb, addr, ~0x20); + } + else { + GB_write_memory(gb, addr, 0xFF); + } + GB_advance_cycles(gb, 1); + GB_write_memory(gb, addr, value); + gb->pending_cycles = 3; + return; + + case GB_CONFLICT_STAT_CGB: { + /* Todo: Verify this with SCX adjustments */ + /* The LYC bit behaves differently */ + uint8_t old_value = GB_read_memory(gb, addr); + GB_advance_cycles(gb, gb->pending_cycles); + GB_write_memory(gb, addr, (old_value & 0x40) | (value & ~0x40)); + GB_advance_cycles(gb, 1); + GB_write_memory(gb, addr, value); + gb->pending_cycles = 3; + return; + } + + /* There is some "time travel" going on with these two values, as it appears + that there's some off-by-1-T-cycle timing issue in the PPU implementation. + + This is should be accurate for every measureable scenario, though. */ + + case GB_CONFLICT_PALETTE_DMG: { + GB_advance_cycles(gb, gb->pending_cycles - 2); + uint8_t old_value = GB_read_memory(gb, addr); + GB_write_memory(gb, addr, value | old_value); + GB_advance_cycles(gb, 1); + GB_write_memory(gb, addr, value); + gb->pending_cycles = 5; + return; + } + + case GB_CONFLICT_PALETTE_CGB: { + GB_advance_cycles(gb, gb->pending_cycles - 2); + GB_write_memory(gb, addr, value); + gb->pending_cycles = 6; + return; + } + } +} + +static void cycle_no_access(GB_gameboy_t *gb) +{ + gb->pending_cycles += 4; +} + +static void cycle_oam_bug(GB_gameboy_t *gb, uint8_t register_id) +{ + if (GB_is_cgb(gb)) { + /* Slight optimization */ + gb->pending_cycles += 4; + return; + } + if (gb->pending_cycles) { + GB_advance_cycles(gb, gb->pending_cycles); + } + GB_trigger_oam_bug(gb, gb->registers[register_id]); /* Todo: test T-cycle timing */ + gb->pending_cycles = 4; + +} + +static void flush_pending_cycles(GB_gameboy_t *gb) +{ + if (gb->pending_cycles) { + GB_advance_cycles(gb, gb->pending_cycles); + } + gb->pending_cycles = 0; +} + +/* Todo: test if multi-byte opcodes trigger the OAM bug correctly */ + +static void ill(GB_gameboy_t *gb, uint8_t opcode) +{ + GB_log(gb, "Illegal Opcode. Halting.\n"); + gb->interrupt_enable = 0; + gb->halted = true; +} + +static void nop(GB_gameboy_t *gb, uint8_t opcode) +{ +} + +static void stop(GB_gameboy_t *gb, uint8_t opcode) +{ + if (gb->io_registers[GB_IO_KEY1] & 0x1) { + flush_pending_cycles(gb); + bool needs_alignment = false; + + GB_advance_cycles(gb, 0x4); + /* Make sure we keep the CPU ticks aligned correctly when returning from double speed mode */ + if (gb->double_speed_alignment & 7) { + GB_advance_cycles(gb, 0x4); + needs_alignment = true; + } + + gb->cgb_double_speed ^= true; + gb->io_registers[GB_IO_KEY1] = 0; + + for (unsigned i = 0x800; i--;) { + GB_advance_cycles(gb, 0x40); + } + + if (!needs_alignment) { + GB_advance_cycles(gb, 0x4); + } + + } + else { + GB_timing_sync(gb); + if ((gb->io_registers[GB_IO_JOYP] & 0xF) != 0xF) { + /* HW Bug? When STOP is executed while a button is down, the CPU halts forever + yet the other hardware keeps running. */ + gb->interrupt_enable = 0; + gb->halted = true; + } + else { + gb->stopped = true; + } + } + + /* Todo: is PC being actually read? */ + gb->pc++; +} + +/* Operand naming conventions for functions: + r = 8-bit register + lr = low 8-bit register + hr = high 8-bit register + rr = 16-bit register + d8 = 8-bit imm + d16 = 16-bit imm + d.. = [..] + cc = condition code (z, nz, c, nc) + */ + +static void ld_rr_d16(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + uint16_t value; + register_id = (opcode >> 4) + 1; + value = cycle_read_inc_oam_bug(gb, gb->pc++); + value |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8; + gb->registers[register_id] = value; +} + +static void ld_drr_a(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + register_id = (opcode >> 4) + 1; + cycle_write(gb, gb->registers[register_id], gb->registers[GB_REGISTER_AF] >> 8); +} + +static void inc_rr(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id = (opcode >> 4) + 1; + cycle_oam_bug(gb, register_id); + gb->registers[register_id]++; +} + +static void inc_hr(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + register_id = ((opcode >> 4) + 1) & 0x03; + gb->registers[register_id] += 0x100; + gb->registers[GB_REGISTER_AF] &= ~(GB_SUBSTRACT_FLAG | GB_ZERO_FLAG | GB_HALF_CARRY_FLAG); + + if ((gb->registers[register_id] & 0x0F00) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + + if ((gb->registers[register_id] & 0xFF00) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} +static void dec_hr(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + register_id = ((opcode >> 4) + 1) & 0x03; + gb->registers[register_id] -= 0x100; + gb->registers[GB_REGISTER_AF] &= ~(GB_ZERO_FLAG | GB_HALF_CARRY_FLAG); + gb->registers[GB_REGISTER_AF] |= GB_SUBSTRACT_FLAG; + + if ((gb->registers[register_id] & 0x0F00) == 0xF00) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + + if ((gb->registers[register_id] & 0xFF00) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void ld_hr_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + register_id = ((opcode >> 4) + 1) & 0x03; + gb->registers[register_id] &= 0xFF; + gb->registers[register_id] |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8; +} + +static void rlca(GB_gameboy_t *gb, uint8_t opcode) +{ + bool carry = (gb->registers[GB_REGISTER_AF] & 0x8000) != 0; + + gb->registers[GB_REGISTER_AF] = (gb->registers[GB_REGISTER_AF] & 0xFF00) << 1; + if (carry) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG | 0x0100; + } +} + +static void rla(GB_gameboy_t *gb, uint8_t opcode) +{ + bool bit7 = (gb->registers[GB_REGISTER_AF] & 0x8000) != 0; + bool carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; + + gb->registers[GB_REGISTER_AF] = (gb->registers[GB_REGISTER_AF] & 0xFF00) << 1; + if (carry) { + gb->registers[GB_REGISTER_AF] |= 0x0100; + } + if (bit7) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode) +{ + /* Todo: Verify order is correct */ + uint16_t addr; + addr = cycle_read_inc_oam_bug(gb, gb->pc++); + addr |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8; + cycle_write(gb, addr, gb->registers[GB_REGISTER_SP] & 0xFF); + cycle_write(gb, addr+1, gb->registers[GB_REGISTER_SP] >> 8); +} + +static void add_hl_rr(GB_gameboy_t *gb, uint8_t opcode) +{ + uint16_t hl = gb->registers[GB_REGISTER_HL]; + uint16_t rr; + uint8_t register_id; + cycle_no_access(gb); + register_id = (opcode >> 4) + 1; + rr = gb->registers[register_id]; + gb->registers[GB_REGISTER_HL] = hl + rr; + gb->registers[GB_REGISTER_AF] &= ~(GB_SUBSTRACT_FLAG | GB_CARRY_FLAG | GB_HALF_CARRY_FLAG); + + /* The meaning of the Half Carry flag is really hard to track -_- */ + if (((hl & 0xFFF) + (rr & 0xFFF)) & 0x1000) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + + if ( ((unsigned long) hl + (unsigned long) rr) & 0x10000) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void ld_a_drr(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + register_id = (opcode >> 4) + 1; + gb->registers[GB_REGISTER_AF] &= 0xFF; + gb->registers[GB_REGISTER_AF] |= cycle_read(gb, gb->registers[register_id]) << 8; +} + +static void dec_rr(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id = (opcode >> 4) + 1; + cycle_oam_bug(gb, register_id); + gb->registers[register_id]--; +} + +static void inc_lr(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + uint8_t value; + register_id = (opcode >> 4) + 1; + + value = (gb->registers[register_id] & 0xFF) + 1; + gb->registers[register_id] = (gb->registers[register_id] & 0xFF00) | value; + + gb->registers[GB_REGISTER_AF] &= ~(GB_SUBSTRACT_FLAG | GB_ZERO_FLAG | GB_HALF_CARRY_FLAG); + + if ((gb->registers[register_id] & 0x0F) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + + if ((gb->registers[register_id] & 0xFF) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} +static void dec_lr(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + uint8_t value; + register_id = (opcode >> 4) + 1; + + value = (gb->registers[register_id] & 0xFF) - 1; + gb->registers[register_id] = (gb->registers[register_id] & 0xFF00) | value; + + gb->registers[GB_REGISTER_AF] &= ~(GB_ZERO_FLAG | GB_HALF_CARRY_FLAG); + gb->registers[GB_REGISTER_AF] |= GB_SUBSTRACT_FLAG; + + if ((gb->registers[register_id] & 0x0F) == 0xF) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + + if ((gb->registers[register_id] & 0xFF) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void ld_lr_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + register_id = (opcode >> 4) + 1; + gb->registers[register_id] &= 0xFF00; + gb->registers[register_id] |= cycle_read_inc_oam_bug(gb, gb->pc++); +} + +static void rrca(GB_gameboy_t *gb, uint8_t opcode) +{ + bool carry = (gb->registers[GB_REGISTER_AF] & 0x100) != 0; + + gb->registers[GB_REGISTER_AF] = (gb->registers[GB_REGISTER_AF] >> 1) & 0xFF00; + if (carry) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG | 0x8000; + } +} + +static void rra(GB_gameboy_t *gb, uint8_t opcode) +{ + bool bit1 = (gb->registers[GB_REGISTER_AF] & 0x0100) != 0; + bool carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; + + gb->registers[GB_REGISTER_AF] = (gb->registers[GB_REGISTER_AF] >> 1) & 0xFF00; + if (carry) { + gb->registers[GB_REGISTER_AF] |= 0x8000; + } + if (bit1) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void jr_r8(GB_gameboy_t *gb, uint8_t opcode) +{ + /* Todo: Verify timing */ + gb->pc += (int8_t)cycle_read_inc_oam_bug(gb, gb->pc) + 1; + cycle_no_access(gb); +} + +static bool condition_code(GB_gameboy_t *gb, uint8_t opcode) +{ + switch ((opcode >> 3) & 0x3) { + case 0: + return !(gb->registers[GB_REGISTER_AF] & GB_ZERO_FLAG); + case 1: + return (gb->registers[GB_REGISTER_AF] & GB_ZERO_FLAG); + case 2: + return !(gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG); + case 3: + return (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG); + } + + return false; +} + +static void jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode) +{ + int8_t offset = cycle_read_inc_oam_bug(gb, gb->pc++); + if (condition_code(gb, opcode)) { + gb->pc += offset; + cycle_no_access(gb); + } +} + +static void daa(GB_gameboy_t *gb, uint8_t opcode) +{ + int16_t result = gb->registers[GB_REGISTER_AF] >> 8; + + gb->registers[GB_REGISTER_AF] &= ~(0xFF00 | GB_ZERO_FLAG); + + if (gb->registers[GB_REGISTER_AF] & GB_SUBSTRACT_FLAG) { + if (gb->registers[GB_REGISTER_AF] & GB_HALF_CARRY_FLAG) { + result = (result - 0x06) & 0xFF; + } + + if (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) { + result -= 0x60; + } + } + else { + if ((gb->registers[GB_REGISTER_AF] & GB_HALF_CARRY_FLAG) || (result & 0x0F) > 0x09) { + result += 0x06; + } + + if ((gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) || result > 0x9F) { + result += 0x60; + } + } + + if ((result & 0xFF) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + + if ((result & 0x100) == 0x100) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } + + gb->registers[GB_REGISTER_AF] &= ~GB_HALF_CARRY_FLAG; + gb->registers[GB_REGISTER_AF] |= result << 8; +} + +static void cpl(GB_gameboy_t *gb, uint8_t opcode) +{ + gb->registers[GB_REGISTER_AF] ^= 0xFF00; + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG | GB_SUBSTRACT_FLAG; +} + +static void scf(GB_gameboy_t *gb, uint8_t opcode) +{ + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + gb->registers[GB_REGISTER_AF] &= ~(GB_HALF_CARRY_FLAG | GB_SUBSTRACT_FLAG); +} + +static void ccf(GB_gameboy_t *gb, uint8_t opcode) +{ + gb->registers[GB_REGISTER_AF] ^= GB_CARRY_FLAG; + gb->registers[GB_REGISTER_AF] &= ~(GB_HALF_CARRY_FLAG | GB_SUBSTRACT_FLAG); +} + +static void ld_dhli_a(GB_gameboy_t *gb, uint8_t opcode) +{ + cycle_write(gb, gb->registers[GB_REGISTER_HL]++, gb->registers[GB_REGISTER_AF] >> 8); +} + +static void ld_dhld_a(GB_gameboy_t *gb, uint8_t opcode) +{ + cycle_write(gb, gb->registers[GB_REGISTER_HL]--, gb->registers[GB_REGISTER_AF] >> 8); +} + +static void ld_a_dhli(GB_gameboy_t *gb, uint8_t opcode) +{ + gb->registers[GB_REGISTER_AF] &= 0xFF; + gb->registers[GB_REGISTER_AF] |= cycle_read_inc_oam_bug(gb, gb->registers[GB_REGISTER_HL]++) << 8; +} + +static void ld_a_dhld(GB_gameboy_t *gb, uint8_t opcode) +{ + gb->registers[GB_REGISTER_AF] &= 0xFF; + gb->registers[GB_REGISTER_AF] |= cycle_read_inc_oam_bug(gb, gb->registers[GB_REGISTER_HL]--) << 8; +} + +static void inc_dhl(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value; + value = cycle_read(gb, gb->registers[GB_REGISTER_HL]) + 1; + cycle_write(gb, gb->registers[GB_REGISTER_HL], value); + + gb->registers[GB_REGISTER_AF] &= ~(GB_SUBSTRACT_FLAG | GB_ZERO_FLAG | GB_HALF_CARRY_FLAG); + if ((value & 0x0F) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + + if ((value & 0xFF) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void dec_dhl(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value; + value = cycle_read(gb, gb->registers[GB_REGISTER_HL]) - 1; + cycle_write(gb, gb->registers[GB_REGISTER_HL], value); + + gb->registers[GB_REGISTER_AF] &= ~( GB_ZERO_FLAG | GB_HALF_CARRY_FLAG); + gb->registers[GB_REGISTER_AF] |= GB_SUBSTRACT_FLAG; + if ((value & 0x0F) == 0x0F) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + + if ((value & 0xFF) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t data = cycle_read_inc_oam_bug(gb, gb->pc++); + cycle_write(gb, gb->registers[GB_REGISTER_HL], data); +} + +static uint8_t get_src_value(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t src_register_id; + uint8_t src_low; + src_register_id = ((opcode >> 1) + 1) & 3; + src_low = opcode & 1; + if (src_register_id == GB_REGISTER_AF) { + if (src_low) { + return gb->registers[GB_REGISTER_AF] >> 8; + } + return cycle_read(gb, gb->registers[GB_REGISTER_HL]); + } + if (src_low) { + return gb->registers[src_register_id] & 0xFF; + } + return gb->registers[src_register_id] >> 8; +} + +static void set_src_value(GB_gameboy_t *gb, uint8_t opcode, uint8_t value) +{ + uint8_t src_register_id; + uint8_t src_low; + src_register_id = ((opcode >> 1) + 1) & 3; + src_low = opcode & 1; + + if (src_register_id == GB_REGISTER_AF) { + if (src_low) { + gb->registers[GB_REGISTER_AF] &= 0xFF; + gb->registers[GB_REGISTER_AF] |= value << 8; + } + else { + cycle_write(gb, gb->registers[GB_REGISTER_HL], value); + } + } + else { + if (src_low) { + gb->registers[src_register_id] &= 0xFF00; + gb->registers[src_register_id] |= value; + } + else { + gb->registers[src_register_id] &= 0xFF; + gb->registers[src_register_id] |= value << 8; + } + } +} + +/* The LD r,r instruction is extremely common and extremely simple. Decoding this opcode at runtime is a significent + performance hit, so we generate functions for every ld x,y couple (including [hl]) at compile time using macros. */ + +/* Todo: It's probably wise to do the same to all opcodes. */ + +#define LD_X_Y(x, y) \ +static void ld_##x##_##y(GB_gameboy_t *gb, uint8_t opcode) \ +{ \ + gb->x = gb->y;\ +} + +#define LD_X_DHL(x) \ +static void ld_##x##_##dhl(GB_gameboy_t *gb, uint8_t opcode) \ +{ \ +gb->x = cycle_read(gb, gb->registers[GB_REGISTER_HL]); \ +} + +#define LD_DHL_Y(y) \ +static void ld_##dhl##_##y(GB_gameboy_t *gb, uint8_t opcode) \ +{ \ +cycle_write(gb, gb->registers[GB_REGISTER_HL], gb->y); \ +} + +LD_X_Y(b,c) LD_X_Y(b,d) LD_X_Y(b,e) LD_X_Y(b,h) LD_X_Y(b,l) LD_X_DHL(b) LD_X_Y(b,a) +LD_X_Y(c,b) LD_X_Y(c,d) LD_X_Y(c,e) LD_X_Y(c,h) LD_X_Y(c,l) LD_X_DHL(c) LD_X_Y(c,a) +LD_X_Y(d,b) LD_X_Y(d,c) LD_X_Y(d,e) LD_X_Y(d,h) LD_X_Y(d,l) LD_X_DHL(d) LD_X_Y(d,a) +LD_X_Y(e,b) LD_X_Y(e,c) LD_X_Y(e,d) LD_X_Y(e,h) LD_X_Y(e,l) LD_X_DHL(e) LD_X_Y(e,a) +LD_X_Y(h,b) LD_X_Y(h,c) LD_X_Y(h,d) LD_X_Y(h,e) LD_X_Y(h,l) LD_X_DHL(h) LD_X_Y(h,a) +LD_X_Y(l,b) LD_X_Y(l,c) LD_X_Y(l,d) LD_X_Y(l,e) LD_X_Y(l,h) LD_X_DHL(l) LD_X_Y(l,a) +LD_DHL_Y(b) LD_DHL_Y(c) LD_DHL_Y(d) LD_DHL_Y(e) LD_DHL_Y(h) LD_DHL_Y(l) LD_DHL_Y(a) +LD_X_Y(a,b) LD_X_Y(a,c) LD_X_Y(a,d) LD_X_Y(a,e) LD_X_Y(a,h) LD_X_Y(a,l) LD_X_DHL(a) + + +static void add_a_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = get_src_value(gb, opcode); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] = (a + value) << 8; + if ((uint8_t)(a + value) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + if ((a & 0xF) + (value & 0xF) > 0x0F) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + if (((unsigned long) a) + ((unsigned long) value) > 0xFF) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void adc_a_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a, carry; + value = get_src_value(gb, opcode); + a = gb->registers[GB_REGISTER_AF] >> 8; + carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; + gb->registers[GB_REGISTER_AF] = (a + value + carry) << 8; + + if ((uint8_t)(a + value + carry) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + if ((a & 0xF) + (value & 0xF) + carry > 0x0F) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + if (((unsigned long) a) + ((unsigned long) value) + carry > 0xFF) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void sub_a_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = get_src_value(gb, opcode); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] = ((a - value) << 8) | GB_SUBSTRACT_FLAG; + if (a == value) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + if ((a & 0xF) < (value & 0xF)) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + if (a < value) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void sbc_a_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a, carry; + value = get_src_value(gb, opcode); + a = gb->registers[GB_REGISTER_AF] >> 8; + carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; + gb->registers[GB_REGISTER_AF] = ((a - value - carry) << 8) | GB_SUBSTRACT_FLAG; + + if ((uint8_t) (a - value - carry) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + if ((a & 0xF) < (value & 0xF) + carry) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + if (((unsigned long) a) - ((unsigned long) value) - carry > 0xFF) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void and_a_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = get_src_value(gb, opcode); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] = ((a & value) << 8) | GB_HALF_CARRY_FLAG; + if ((a & value) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void xor_a_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = get_src_value(gb, opcode); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] = (a ^ value) << 8; + if ((a ^ value) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void or_a_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = get_src_value(gb, opcode); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] = (a | value) << 8; + if ((a | value) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void cp_a_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = get_src_value(gb, opcode); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] &= 0xFF00; + gb->registers[GB_REGISTER_AF] |= GB_SUBSTRACT_FLAG; + if (a == value) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + if ((a & 0xF) < (value & 0xF)) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + if (a < value) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void halt(GB_gameboy_t *gb, uint8_t opcode) +{ + assert(gb->pending_cycles == 4); + gb->pending_cycles = 0; + GB_advance_cycles(gb, 1); + GB_advance_cycles(gb, 1); + GB_advance_cycles(gb, 1); + GB_advance_cycles(gb, 1); + + gb->halted = true; + /* Despite what some online documentations say, the HALT bug also happens on a CGB, in both CGB and DMG modes. */ + if (((gb->interrupt_enable & gb->io_registers[GB_IO_IF] & 0x1F) != 0)) { + if (gb->ime) { + gb->halted = false; + gb->pc--; + } + else { + gb->halted = false; + gb->halt_bug = true; + } + } + gb->just_halted = true; +} + +static void pop_rr(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + register_id = ((opcode >> 4) + 1) & 3; + gb->registers[register_id] = cycle_read_inc_oam_bug(gb, gb->registers[GB_REGISTER_SP]++); + gb->registers[register_id] |= cycle_read(gb, gb->registers[GB_REGISTER_SP]++) << 8; + gb->registers[GB_REGISTER_AF] &= 0xFFF0; // Make sure we don't set impossible flags on F! See Blargg's PUSH AF test. +} + +static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode) +{ + uint16_t addr = cycle_read_inc_oam_bug(gb, gb->pc++); + addr |= (cycle_read_inc_oam_bug(gb, gb->pc++) << 8); + if (condition_code(gb, opcode)) { + cycle_no_access(gb); + gb->pc = addr; + } +} + +static void jp_a16(GB_gameboy_t *gb, uint8_t opcode) +{ + uint16_t addr = cycle_read_inc_oam_bug(gb, gb->pc); + addr |= (cycle_read_inc_oam_bug(gb, gb->pc + 1) << 8); + cycle_no_access(gb); + gb->pc = addr; + +} + +static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode) +{ + uint16_t call_addr = gb->pc - 1; + uint16_t addr = cycle_read_inc_oam_bug(gb, gb->pc++); + addr |= (cycle_read_inc_oam_bug(gb, gb->pc++) << 8); + if (condition_code(gb, opcode)) { + cycle_oam_bug(gb, GB_REGISTER_SP); + cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) >> 8); + cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF); + gb->pc = addr; + + GB_debugger_call_hook(gb, call_addr); + } +} + +static void push_rr(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t register_id; + cycle_oam_bug(gb, GB_REGISTER_SP); + register_id = ((opcode >> 4) + 1) & 3; + cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->registers[register_id]) >> 8); + cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->registers[register_id]) & 0xFF); +} + +static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = cycle_read_inc_oam_bug(gb, gb->pc++); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] = (a + value) << 8; + if ((uint8_t) (a + value) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + if ((a & 0xF) + (value & 0xF) > 0x0F) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + if (((unsigned long) a) + ((unsigned long) value) > 0xFF) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void adc_a_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a, carry; + value = cycle_read_inc_oam_bug(gb, gb->pc++); + a = gb->registers[GB_REGISTER_AF] >> 8; + carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; + gb->registers[GB_REGISTER_AF] = (a + value + carry) << 8; + + if (gb->registers[GB_REGISTER_AF] == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + if ((a & 0xF) + (value & 0xF) + carry > 0x0F) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + if (((unsigned long) a) + ((unsigned long) value) + carry > 0xFF) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void sub_a_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = cycle_read_inc_oam_bug(gb, gb->pc++); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] = ((a - value) << 8) | GB_SUBSTRACT_FLAG; + if (a == value) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + if ((a & 0xF) < (value & 0xF)) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + if (a < value) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void sbc_a_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a, carry; + value = cycle_read_inc_oam_bug(gb, gb->pc++); + a = gb->registers[GB_REGISTER_AF] >> 8; + carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; + gb->registers[GB_REGISTER_AF] = ((a - value - carry) << 8) | GB_SUBSTRACT_FLAG; + + if ((uint8_t) (a - value - carry) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + if ((a & 0xF) < (value & 0xF) + carry) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + if (((unsigned long) a) - ((unsigned long) value) - carry > 0xFF) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void and_a_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = cycle_read_inc_oam_bug(gb, gb->pc++); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] = ((a & value) << 8) | GB_HALF_CARRY_FLAG; + if ((a & value) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void xor_a_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = cycle_read_inc_oam_bug(gb, gb->pc++); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] = (a ^ value) << 8; + if ((a ^ value) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void or_a_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = cycle_read_inc_oam_bug(gb, gb->pc++); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] = (a | value) << 8; + if ((a | value) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value, a; + value = cycle_read_inc_oam_bug(gb, gb->pc++); + a = gb->registers[GB_REGISTER_AF] >> 8; + gb->registers[GB_REGISTER_AF] &= 0xFF00; + gb->registers[GB_REGISTER_AF] |= GB_SUBSTRACT_FLAG; + if (a == value) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + if ((a & 0xF) < (value & 0xF)) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + if (a < value) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void rst(GB_gameboy_t *gb, uint8_t opcode) +{ + uint16_t call_addr = gb->pc - 1; + cycle_oam_bug(gb, GB_REGISTER_SP); + cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) >> 8); + cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF); + gb->pc = opcode ^ 0xC7; + GB_debugger_call_hook(gb, call_addr); +} + +static void ret(GB_gameboy_t *gb, uint8_t opcode) +{ + GB_debugger_ret_hook(gb); + gb->pc = cycle_read_inc_oam_bug(gb, gb->registers[GB_REGISTER_SP]++); + gb->pc |= cycle_read(gb, gb->registers[GB_REGISTER_SP]++) << 8; + cycle_no_access(gb); +} + +static void reti(GB_gameboy_t *gb, uint8_t opcode) +{ + ret(gb, opcode); + gb->ime = true; +} + +static void ret_cc(GB_gameboy_t *gb, uint8_t opcode) +{ + if (condition_code(gb, opcode)) { + cycle_no_access(gb); + ret(gb, opcode); + } + else { + cycle_no_access(gb); + } +} + +static void call_a16(GB_gameboy_t *gb, uint8_t opcode) +{ + uint16_t call_addr = gb->pc - 1; + uint16_t addr = cycle_read_inc_oam_bug(gb, gb->pc++); + addr |= (cycle_read_inc_oam_bug(gb, gb->pc++) << 8); + cycle_oam_bug(gb, GB_REGISTER_SP); + cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) >> 8); + cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF); + gb->pc = addr; + GB_debugger_call_hook(gb, call_addr); +} + +static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t temp = cycle_read_inc_oam_bug(gb, gb->pc++); + cycle_write(gb, 0xFF00 + temp, gb->registers[GB_REGISTER_AF] >> 8); +} + +static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode) +{ + gb->registers[GB_REGISTER_AF] &= 0xFF; + uint8_t temp = cycle_read_inc_oam_bug(gb, gb->pc++); + gb->registers[GB_REGISTER_AF] |= cycle_read(gb, 0xFF00 + temp) << 8; +} + +static void ld_dc_a(GB_gameboy_t *gb, uint8_t opcode) +{ + cycle_write(gb, 0xFF00 + (gb->registers[GB_REGISTER_BC] & 0xFF), gb->registers[GB_REGISTER_AF] >> 8); +} + +static void ld_a_dc(GB_gameboy_t *gb, uint8_t opcode) +{ + gb->registers[GB_REGISTER_AF] &= 0xFF; + gb->registers[GB_REGISTER_AF] |= cycle_read(gb, 0xFF00 + (gb->registers[GB_REGISTER_BC] & 0xFF)) << 8; +} + +static void add_sp_r8(GB_gameboy_t *gb, uint8_t opcode) +{ + int16_t offset; + uint16_t sp = gb->registers[GB_REGISTER_SP]; + offset = (int8_t) cycle_read_inc_oam_bug(gb, gb->pc++); + cycle_no_access(gb); + cycle_no_access(gb); + gb->registers[GB_REGISTER_SP] += offset; + + gb->registers[GB_REGISTER_AF] &= 0xFF00; + + /* A new instruction, a new meaning for Half Carry! */ + if ((sp & 0xF) + (offset & 0xF) > 0xF) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + + if ((sp & 0xFF) + (offset & 0xFF) > 0xFF) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void jp_hl(GB_gameboy_t *gb, uint8_t opcode) +{ + gb->pc = gb->registers[GB_REGISTER_HL]; +} + +static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode) +{ + uint16_t addr; + addr = cycle_read_inc_oam_bug(gb, gb->pc++); + addr |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8; + cycle_write(gb, addr, gb->registers[GB_REGISTER_AF] >> 8); +} + +static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode) +{ + uint16_t addr; + gb->registers[GB_REGISTER_AF] &= 0xFF; + addr = cycle_read_inc_oam_bug(gb, gb->pc++); + addr |= cycle_read_inc_oam_bug(gb, gb->pc++) << 8 ; + gb->registers[GB_REGISTER_AF] |= cycle_read(gb, addr) << 8; +} + +static void di(GB_gameboy_t *gb, uint8_t opcode) +{ + /* DI is NOT delayed, not even on a CGB. Mooneye's di_timing-GS test fails on a CGB + for different reasons. */ + gb->ime = false; +} + +static void ei(GB_gameboy_t *gb, uint8_t opcode) +{ + /* ei is actually "disable interrupts for one instruction, then enable them". */ + if (!gb->ime && !gb->ime_toggle) { + gb->ime_toggle = true; + } +} + +static void ld_hl_sp_r8(GB_gameboy_t *gb, uint8_t opcode) +{ + int16_t offset; + gb->registers[GB_REGISTER_AF] &= 0xFF00; + offset = (int8_t) cycle_read_inc_oam_bug(gb, gb->pc++); + cycle_no_access(gb); + gb->registers[GB_REGISTER_HL] = gb->registers[GB_REGISTER_SP] + offset; + + if ((gb->registers[GB_REGISTER_SP] & 0xF) + (offset & 0xF) > 0xF) { + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + } + + if ((gb->registers[GB_REGISTER_SP] & 0xFF) + (offset & 0xFF) > 0xFF) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } +} + +static void ld_sp_hl(GB_gameboy_t *gb, uint8_t opcode) +{ + gb->registers[GB_REGISTER_SP] = gb->registers[GB_REGISTER_HL]; + cycle_no_access(gb); +} + +static void rlc_r(GB_gameboy_t *gb, uint8_t opcode) +{ + bool carry; + uint8_t value; + value = get_src_value(gb, opcode); + carry = (value & 0x80) != 0; + gb->registers[GB_REGISTER_AF] &= 0xFF00; + set_src_value(gb, opcode, (value << 1) | carry); + if (carry) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } + if (!(value << 1)) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void rrc_r(GB_gameboy_t *gb, uint8_t opcode) +{ + bool carry; + uint8_t value; + value = get_src_value(gb, opcode); + carry = (value & 0x01) != 0; + gb->registers[GB_REGISTER_AF] &= 0xFF00; + value = (value >> 1) | (carry << 7); + set_src_value(gb, opcode, value); + if (carry) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } + if (value == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void rl_r(GB_gameboy_t *gb, uint8_t opcode) +{ + bool carry; + uint8_t value; + bool bit7; + value = get_src_value(gb, opcode); + carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; + bit7 = (value & 0x80) != 0; + + gb->registers[GB_REGISTER_AF] &= 0xFF00; + value = (value << 1) | carry; + set_src_value(gb, opcode, value); + if (bit7) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } + if (value == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void rr_r(GB_gameboy_t *gb, uint8_t opcode) +{ + bool carry; + uint8_t value; + bool bit1; + + value = get_src_value(gb, opcode); + carry = (gb->registers[GB_REGISTER_AF] & GB_CARRY_FLAG) != 0; + bit1 = (value & 0x1) != 0; + + gb->registers[GB_REGISTER_AF] &= 0xFF00; + value = (value >> 1) | (carry << 7); + set_src_value(gb, opcode, value); + if (bit1) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } + if (value == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void sla_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value; + bool carry; + value = get_src_value(gb, opcode); + carry = (value & 0x80) != 0; + gb->registers[GB_REGISTER_AF] &= 0xFF00; + set_src_value(gb, opcode, (value << 1)); + if (carry) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } + if ((value & 0x7F) == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void sra_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t bit7; + uint8_t value; + value = get_src_value(gb, opcode); + bit7 = value & 0x80; + gb->registers[GB_REGISTER_AF] &= 0xFF00; + if (value & 1) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } + value = (value >> 1) | bit7; + set_src_value(gb, opcode, value); + if (value == 0) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void srl_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value; + value = get_src_value(gb, opcode); + gb->registers[GB_REGISTER_AF] &= 0xFF00; + set_src_value(gb, opcode, (value >> 1)); + if (value & 1) { + gb->registers[GB_REGISTER_AF] |= GB_CARRY_FLAG; + } + if (!(value >> 1)) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void swap_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value; + value = get_src_value(gb, opcode); + gb->registers[GB_REGISTER_AF] &= 0xFF00; + set_src_value(gb, opcode, (value >> 4) | (value << 4)); + if (!value) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } +} + +static void bit_r(GB_gameboy_t *gb, uint8_t opcode) +{ + uint8_t value; + uint8_t bit; + value = get_src_value(gb, opcode); + bit = 1 << ((opcode >> 3) & 7); + if ((opcode & 0xC0) == 0x40) { /* Bit */ + gb->registers[GB_REGISTER_AF] &= 0xFF00 | GB_CARRY_FLAG; + gb->registers[GB_REGISTER_AF] |= GB_HALF_CARRY_FLAG; + if (!(bit & value)) { + gb->registers[GB_REGISTER_AF] |= GB_ZERO_FLAG; + } + } + else if ((opcode & 0xC0) == 0x80) { /* res */ + set_src_value(gb, opcode, value & ~bit) ; + } + else if ((opcode & 0xC0) == 0xC0) { /* set */ + set_src_value(gb, opcode, value | bit) ; + } +} + +static void cb_prefix(GB_gameboy_t *gb, uint8_t opcode) +{ + opcode = cycle_read_inc_oam_bug(gb, gb->pc++); + switch (opcode >> 3) { + case 0: + rlc_r(gb, opcode); + break; + case 1: + rrc_r(gb, opcode); + break; + case 2: + rl_r(gb, opcode); + break; + case 3: + rr_r(gb, opcode); + break; + case 4: + sla_r(gb, opcode); + break; + case 5: + sra_r(gb, opcode); + break; + case 6: + swap_r(gb, opcode); + break; + case 7: + srl_r(gb, opcode); + break; + default: + bit_r(gb, opcode); + break; + } +} + +static GB_opcode_t *opcodes[256] = { + /* X0 X1 X2 X3 X4 X5 X6 X7 */ + /* X8 X9 Xa Xb Xc Xd Xe Xf */ + nop, ld_rr_d16, ld_drr_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, rlca, /* 0X */ + ld_da16_sp, add_hl_rr, ld_a_drr, dec_rr, inc_lr, dec_lr, ld_lr_d8, rrca, + stop, ld_rr_d16, ld_drr_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, rla, /* 1X */ + jr_r8, add_hl_rr, ld_a_drr, dec_rr, inc_lr, dec_lr, ld_lr_d8, rra, + jr_cc_r8, ld_rr_d16, ld_dhli_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, daa, /* 2X */ + jr_cc_r8, add_hl_rr, ld_a_dhli, dec_rr, inc_lr, dec_lr, ld_lr_d8, cpl, + jr_cc_r8, ld_rr_d16, ld_dhld_a, inc_rr, inc_dhl, dec_dhl, ld_dhl_d8, scf, /* 3X */ + jr_cc_r8, add_hl_rr, ld_a_dhld, dec_rr, inc_hr, dec_hr, ld_hr_d8, ccf, + nop, ld_b_c, ld_b_d, ld_b_e, ld_b_h, ld_b_l, ld_b_dhl, ld_b_a, /* 4X */ + ld_c_b, nop, ld_c_d, ld_c_e, ld_c_h, ld_c_l, ld_c_dhl, ld_c_a, + ld_d_b, ld_d_c, nop, ld_d_e, ld_d_h, ld_d_l, ld_d_dhl, ld_d_a, /* 5X */ + ld_e_b, ld_e_c, ld_e_d, nop, ld_e_h, ld_e_l, ld_e_dhl, ld_e_a, + ld_h_b, ld_h_c, ld_h_d, ld_h_e, nop, ld_h_l, ld_h_dhl, ld_h_a, /* 6X */ + ld_l_b, ld_l_c, ld_l_d, ld_l_e, ld_l_h, nop, ld_l_dhl, ld_l_a, + ld_dhl_b, ld_dhl_c, ld_dhl_d, ld_dhl_e, ld_dhl_h, ld_dhl_l, halt, ld_dhl_a, /* 7X */ + ld_a_b, ld_a_c, ld_a_d, ld_a_e, ld_a_h, ld_a_l, ld_a_dhl, nop, + add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, /* 8X */ + adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, + sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, /* 9X */ + sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, + and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, /* aX */ + xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, + or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, /* bX */ + cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, + ret_cc, pop_rr, jp_cc_a16, jp_a16, call_cc_a16,push_rr, add_a_d8, rst, /* cX */ + ret_cc, ret, jp_cc_a16, cb_prefix, call_cc_a16,call_a16, adc_a_d8, rst, + ret_cc, pop_rr, jp_cc_a16, ill, call_cc_a16,push_rr, sub_a_d8, rst, /* dX */ + ret_cc, reti, jp_cc_a16, ill, call_cc_a16,ill, sbc_a_d8, rst, + ld_da8_a, pop_rr, ld_dc_a, ill, ill, push_rr, and_a_d8, rst, /* eX */ + add_sp_r8, jp_hl, ld_da16_a, ill, ill, ill, xor_a_d8, rst, + ld_a_da8, pop_rr, ld_a_dc, di, ill, push_rr, or_a_d8, rst, /* fX */ + ld_hl_sp_r8,ld_sp_hl, ld_a_da16, ei, ill, ill, cp_a_d8, rst, +}; +void GB_cpu_run(GB_gameboy_t *gb) +{ + if (gb->hdma_on) { + GB_advance_cycles(gb, 4); + return; + } + if (gb->stopped) { + GB_timing_sync(gb); + GB_advance_cycles(gb, 4); + if ((gb->io_registers[GB_IO_JOYP] & 0xF) != 0xF) { + gb->stopped = false; + /* The CPU takes more time to wake up then the other components */ + for (unsigned i = 0x800; i--;) { + GB_advance_cycles(gb, 0x40); + } + GB_advance_cycles(gb, 8); + } + return; + } + + if ((gb->interrupt_enable & 0x10) && (gb->ime || gb->halted)) { + GB_timing_sync(gb); + } + + if (gb->halted && !GB_is_cgb(gb) && !gb->just_halted) { + GB_advance_cycles(gb, 2); + } + + uint8_t interrupt_queue = gb->interrupt_enable & gb->io_registers[GB_IO_IF] & 0x1F; + + if (gb->halted) { + GB_advance_cycles(gb, (GB_is_cgb(gb) || gb->just_halted) ? 4 : 2); + } + gb->just_halted = false; + + bool effecitve_ime = gb->ime; + if (gb->ime_toggle) { + gb->ime = !gb->ime; + gb->ime_toggle = false; + } + + /* Wake up from HALT mode without calling interrupt code. */ + if (gb->halted && !effecitve_ime && interrupt_queue) { + gb->halted = false; + } + + /* Call interrupt */ + else if (effecitve_ime && interrupt_queue) { + gb->halted = false; + uint16_t call_addr = gb->pc; + + cycle_no_access(gb); + cycle_no_access(gb); + GB_trigger_oam_bug(gb, gb->registers[GB_REGISTER_SP]); /* Todo: test T-cycle timing */ + cycle_no_access(gb); + + cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) >> 8); + interrupt_queue = gb->interrupt_enable; + + if (gb->registers[GB_REGISTER_SP] == GB_IO_IF + 0xFF00 + 1) { + gb->registers[GB_REGISTER_SP]--; + interrupt_queue &= cycle_write_if(gb, (gb->pc) & 0xFF); + } + else { + cycle_write(gb, --gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF); + interrupt_queue &= (gb->io_registers[GB_IO_IF]) & 0x1F; + } + + if (interrupt_queue) { + uint8_t interrupt_bit = 0; + while (!(interrupt_queue & 1)) { + interrupt_queue >>= 1; + interrupt_bit++; + } + gb->io_registers[GB_IO_IF] &= ~(1 << interrupt_bit); + gb->pc = interrupt_bit * 8 + 0x40; + } + else { + gb->pc = 0; + } + gb->ime = false; + GB_debugger_call_hook(gb, call_addr); + } + /* Run mode */ + else if(!gb->halted) { + gb->last_opcode_read = cycle_read_inc_oam_bug(gb, gb->pc++); + if (gb->halt_bug) { + gb->pc--; + gb->halt_bug = false; + } + opcodes[gb->last_opcode_read](gb, gb->last_opcode_read); + } + + if (gb->hdma_starting) { + gb->hdma_starting = false; + gb->hdma_on = true; + gb->hdma_cycles = -8; + } + flush_pending_cycles(gb); +} diff --git a/gb/Core/sm83_cpu.h b/gb/Core/sm83_cpu.h new file mode 100644 index 0000000..49fa80b --- /dev/null +++ b/gb/Core/sm83_cpu.h @@ -0,0 +1,11 @@ +#ifndef sm83_cpu_h +#define sm83_cpu_h +#include "gb_struct_def.h" +#include + +void GB_cpu_disassemble(GB_gameboy_t *gb, uint16_t pc, uint16_t count); +#ifdef GB_INTERNAL +void GB_cpu_run(GB_gameboy_t *gb); +#endif + +#endif /* sm83_cpu_h */ diff --git a/gb/Core/sm83_disassembler.c b/gb/Core/sm83_disassembler.c new file mode 100644 index 0000000..96aec00 --- /dev/null +++ b/gb/Core/sm83_disassembler.c @@ -0,0 +1,788 @@ +#include +#include +#include "gb.h" + + +typedef void GB_opcode_t(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc); + +static void ill(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, ".BYTE $%02x\n", opcode); + (*pc)++; +} + +static void nop(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "NOP\n"); + (*pc)++; +} + +static void stop(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint8_t next = GB_read_memory(gb, (*pc)++); + if (next) { + GB_log(gb, "CORRUPTED STOP (%02x)\n", next); + } + else { + GB_log(gb, "STOP\n"); + } +} + +static char *register_names[] = {"af", "bc", "de", "hl", "sp"}; + +static void ld_rr_d16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + uint16_t value; + register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1; + value = GB_read_memory(gb, (*pc)++); + value |= GB_read_memory(gb, (*pc)++) << 8; + const char *symbol = GB_debugger_name_for_address(gb, value); + if (symbol) { + GB_log(gb, "LD %s, %s ; =$%04x\n", register_names[register_id], symbol, value); + } + else { + GB_log(gb, "LD %s, $%04x\n", register_names[register_id], value); + } +} + +static void ld_drr_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1; + GB_log(gb, "LD [%s], a\n", register_names[register_id]); +} + +static void inc_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1; + GB_log(gb, "INC %s\n", register_names[register_id]); +} + +static void inc_hr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + (*pc)++; + register_id = ((opcode >> 4) + 1) & 0x03; + GB_log(gb, "INC %c\n", register_names[register_id][0]); + +} +static void dec_hr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + (*pc)++; + register_id = ((opcode >> 4) + 1) & 0x03; + GB_log(gb, "DEC %c\n", register_names[register_id][0]); +} + +static void ld_hr_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + (*pc)++; + register_id = ((opcode >> 4) + 1) & 0x03; + GB_log(gb, "LD %c, $%02x\n", register_names[register_id][0], GB_read_memory(gb, (*pc)++)); +} + +static void rlca(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "RLCA\n"); +} + +static void rla(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "RLA\n"); +} + +static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc){ + uint16_t addr; + (*pc)++; + addr = GB_read_memory(gb, (*pc)++); + addr |= GB_read_memory(gb, (*pc)++) << 8; + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "LD [%s], sp ; =$%04x\n", symbol, addr); + } + else { + GB_log(gb, "LD [$%04x], sp\n", addr); + } +} + +static void add_hl_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + (*pc)++; + register_id = (opcode >> 4) + 1; + GB_log(gb, "ADD hl, %s\n", register_names[register_id]); +} + +static void ld_a_drr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1; + GB_log(gb, "LD a, [%s]\n", register_names[register_id]); +} + +static void dec_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1; + GB_log(gb, "DEC %s\n", register_names[register_id]); +} + +static void inc_lr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1; + + GB_log(gb, "INC %c\n", register_names[register_id][1]); +} +static void dec_lr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1; + + GB_log(gb, "DEC %c\n", register_names[register_id][1]); +} + +static void ld_lr_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1; + + GB_log(gb, "LD %c, $%02x\n", register_names[register_id][1], GB_read_memory(gb, (*pc)++)); +} + +static void rrca(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "RRCA\n"); + (*pc)++; +} + +static void rra(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "RRA\n"); + (*pc)++; +} + +static void jr_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint16_t addr = *pc + (int8_t) GB_read_memory(gb, (*pc)) + 1; + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_attributed_log(gb, GB_LOG_UNDERLINE, "JR %s ; =$%04x\n", symbol, addr); + } + else { + GB_attributed_log(gb, GB_LOG_UNDERLINE, "JR $%04x\n", addr); + } + (*pc)++; +} + +static const char *condition_code(uint8_t opcode) +{ + switch ((opcode >> 3) & 0x3) { + case 0: + return "nz"; + case 1: + return "z"; + case 2: + return "nc"; + case 3: + return "c"; + } + + return NULL; +} + +static void jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint16_t addr = *pc + (int8_t) GB_read_memory(gb, (*pc)) + 1; + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr); + } + else { + GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, $%04x\n", condition_code(opcode), addr); + } + (*pc)++; +} + +static void daa(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "DAA\n"); + (*pc)++; +} + +static void cpl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "CPL\n"); + (*pc)++; +} + +static void scf(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "SCF\n"); + (*pc)++; +} + +static void ccf(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "CCF\n"); + (*pc)++; +} + +static void ld_dhli_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "LD [hli], a\n"); + (*pc)++; +} + +static void ld_dhld_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "LD [hld], a\n"); + (*pc)++; +} + +static void ld_a_dhli(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "LD a, [hli]\n"); + (*pc)++; +} + +static void ld_a_dhld(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "LD a, [hld]\n"); + (*pc)++; +} + +static void inc_dhl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "INC [hl]\n"); + (*pc)++; +} + +static void dec_dhl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + GB_log(gb, "DEC [hl]\n"); + (*pc)++; +} + +static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "LD [hl], $%02x\n", GB_read_memory(gb, (*pc)++)); +} + +static const char *get_src_name(uint8_t opcode) +{ + uint8_t src_register_id; + uint8_t src_low; + src_register_id = ((opcode >> 1) + 1) & 3; + src_low = (opcode & 1); + if (src_register_id == GB_REGISTER_AF) { + return src_low? "a": "[hl]"; + } + if (src_low) { + return register_names[src_register_id] + 1; + } + static const char *high_register_names[] = {"a", "b", "d", "h"}; + return high_register_names[src_register_id]; +} + +static const char *get_dst_name(uint8_t opcode) +{ + uint8_t dst_register_id; + uint8_t dst_low; + dst_register_id = ((opcode >> 4) + 1) & 3; + dst_low = opcode & 8; + if (dst_register_id == GB_REGISTER_AF) { + return dst_low? "a": "[hl]"; + } + if (dst_low) { + return register_names[dst_register_id] + 1; + } + static const char *high_register_names[] = {"a", "b", "d", "h"}; + return high_register_names[dst_register_id]; +} + +static void ld_r_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "LD %s, %s\n", get_dst_name(opcode), get_src_name(opcode)); +} + +static void add_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "ADD %s\n", get_src_name(opcode)); +} + +static void adc_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "ADC %s\n", get_src_name(opcode)); +} + +static void sub_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "SUB %s\n", get_src_name(opcode)); +} + +static void sbc_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "SBC %s\n", get_src_name(opcode)); +} + +static void and_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "AND %s\n", get_src_name(opcode)); +} + +static void xor_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "XOR %s\n", get_src_name(opcode)); +} + +static void or_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "OR %s\n", get_src_name(opcode)); +} + +static void cp_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "CP %s\n", get_src_name(opcode)); +} + +static void halt(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "HALT\n"); +} + +static void ret_cc(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "RET %s\n", condition_code(opcode)); +} + +static void pop_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + register_id = ((GB_read_memory(gb, (*pc)++) >> 4) + 1) & 3; + GB_log(gb, "POP %s\n", register_names[register_id]); +} + +static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr); + } + else { + GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, $%04x\n", condition_code(opcode), addr); + } + (*pc) += 2; +} + +static void jp_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "JP %s ; =$%04x\n", symbol, addr); + } + else { + GB_log(gb, "JP $%04x\n", addr); + } + (*pc) += 2; +} + +static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "CALL %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr); + } + else { + GB_log(gb, "CALL %s, $%04x\n", condition_code(opcode), addr); + } + (*pc) += 2; +} + +static void push_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t register_id; + register_id = ((GB_read_memory(gb, (*pc)++) >> 4) + 1) & 3; + GB_log(gb, "PUSH %s\n", register_names[register_id]); +} + +static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "ADD $%02x\n", GB_read_memory(gb, (*pc)++)); +} + +static void adc_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "ADC $%02x\n", GB_read_memory(gb, (*pc)++)); +} + +static void sub_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "SUB $%02x\n", GB_read_memory(gb, (*pc)++)); +} + +static void sbc_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "SBC $%02x\n", GB_read_memory(gb, (*pc)++)); +} + +static void and_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "AND $%02x\n", GB_read_memory(gb, (*pc)++)); +} + +static void xor_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "XOR $%02x\n", GB_read_memory(gb, (*pc)++)); +} + +static void or_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "OR $%02x\n", GB_read_memory(gb, (*pc)++)); +} + +static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "CP $%02x\n", GB_read_memory(gb, (*pc)++)); +} + +static void rst(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "RST $%02x\n", opcode ^ 0xC7); + +} + +static void ret(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_attributed_log(gb, GB_LOG_UNDERLINE, "RET\n"); +} + +static void reti(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_attributed_log(gb, GB_LOG_UNDERLINE, "RETI\n"); +} + +static void call_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "CALL %s ; =$%04x\n", symbol, addr); + } + else { + GB_log(gb, "CALL $%04x\n", addr); + } + (*pc) += 2; +} + +static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint8_t addr = GB_read_memory(gb, (*pc)++); + const char *symbol = GB_debugger_name_for_address(gb, 0xff00 + addr); + if (symbol) { + GB_log(gb, "LDH [%s & $FF], a ; =$%02x\n", symbol, addr); + } + else { + GB_log(gb, "LDH [$%02x], a\n", addr); + } +} + +static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint8_t addr = GB_read_memory(gb, (*pc)++); + const char *symbol = GB_debugger_name_for_address(gb, 0xff00 + addr); + if (symbol) { + GB_log(gb, "LDH a, [%s & $FF] ; =$%02x\n", symbol, addr); + } + else { + GB_log(gb, "LDH a, [$%02x]\n", addr); + } +} + +static void ld_dc_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "LDH [c], a\n"); +} + +static void ld_a_dc(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "LDH a, [c]\n"); +} + +static void add_sp_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + int8_t temp = GB_read_memory(gb, (*pc)++); + GB_log(gb, "ADD SP, %s$%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp); +} + +static void jp_hl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "JP hl\n"); +} + +static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "LD [%s], a ; =$%04x\n", symbol, addr); + } + else { + GB_log(gb, "LD [$%04x], a\n", addr); + } + (*pc) += 2; +} + +static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "LD a, [%s] ; =$%04x\n", symbol, addr); + } + else { + GB_log(gb, "LD a, [$%04x]\n", addr); + } + (*pc) += 2; +} + +static void di(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "DI\n"); +} + +static void ei(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "EI\n"); +} + +static void ld_hl_sp_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + int8_t temp = GB_read_memory(gb, (*pc)++); + GB_log(gb, "LD hl, sp, %s$%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp); +} + +static void ld_sp_hl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "LD sp, hl\n"); +} + +static void rlc_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "RLC %s\n", get_src_name(opcode)); +} + +static void rrc_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "RRC %s\n", get_src_name(opcode)); +} + +static void rl_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "RL %s\n", get_src_name(opcode)); +} + +static void rr_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "RR %s\n", get_src_name(opcode)); +} + +static void sla_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "SLA %s\n", get_src_name(opcode)); +} + +static void sra_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "SRA %s\n", get_src_name(opcode)); +} + +static void srl_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "SRL %s\n", get_src_name(opcode)); +} + +static void swap_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + (*pc)++; + GB_log(gb, "SWAP %s\n", get_src_name(opcode)); +} + +static void bit_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + uint8_t bit; + (*pc)++; + bit = ((opcode >> 3) & 7); + if ((opcode & 0xC0) == 0x40) { /* Bit */ + GB_log(gb, "BIT %s, %d\n", get_src_name(opcode), bit); + } + else if ((opcode & 0xC0) == 0x80) { /* res */ + GB_log(gb, "RES %s, %d\n", get_src_name(opcode), bit); + } + else if ((opcode & 0xC0) == 0xC0) { /* set */ + GB_log(gb, "SET %s, %d\n", get_src_name(opcode), bit); + } +} + +static void cb_prefix(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) +{ + opcode = GB_read_memory(gb, ++*pc); + switch (opcode >> 3) { + case 0: + rlc_r(gb, opcode, pc); + break; + case 1: + rrc_r(gb, opcode, pc); + break; + case 2: + rl_r(gb, opcode, pc); + break; + case 3: + rr_r(gb, opcode, pc); + break; + case 4: + sla_r(gb, opcode, pc); + break; + case 5: + sra_r(gb, opcode, pc); + break; + case 6: + swap_r(gb, opcode, pc); + break; + case 7: + srl_r(gb, opcode, pc); + break; + default: + bit_r(gb, opcode, pc); + break; + } +} + +static GB_opcode_t *opcodes[256] = { + /* X0 X1 X2 X3 X4 X5 X6 X7 */ + /* X8 X9 Xa Xb Xc Xd Xe Xf */ + nop, ld_rr_d16, ld_drr_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, rlca, /* 0X */ + ld_da16_sp, add_hl_rr, ld_a_drr, dec_rr, inc_lr, dec_lr, ld_lr_d8, rrca, + stop, ld_rr_d16, ld_drr_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, rla, /* 1X */ + jr_r8, add_hl_rr, ld_a_drr, dec_rr, inc_lr, dec_lr, ld_lr_d8, rra, + jr_cc_r8, ld_rr_d16, ld_dhli_a, inc_rr, inc_hr, dec_hr, ld_hr_d8, daa, /* 2X */ + jr_cc_r8, add_hl_rr, ld_a_dhli, dec_rr, inc_lr, dec_lr, ld_lr_d8, cpl, + jr_cc_r8, ld_rr_d16, ld_dhld_a, inc_rr, inc_dhl, dec_dhl, ld_dhl_d8, scf, /* 3X */ + jr_cc_r8, add_hl_rr, ld_a_dhld, dec_rr, inc_hr, dec_hr, ld_hr_d8, ccf, + ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 4X */ + ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, + ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 5X */ + ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, + ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, /* 6X */ + ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, + ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, halt, ld_r_r, /* 7X */ + ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, ld_r_r, + add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, add_a_r, /* 8X */ + adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, adc_a_r, + sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, sub_a_r, /* 9X */ + sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, sbc_a_r, + and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, and_a_r, /* aX */ + xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, xor_a_r, + or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, or_a_r, /* bX */ + cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, cp_a_r, + ret_cc, pop_rr, jp_cc_a16, jp_a16, call_cc_a16,push_rr, add_a_d8, rst, /* cX */ + ret_cc, ret, jp_cc_a16, cb_prefix, call_cc_a16,call_a16, adc_a_d8, rst, + ret_cc, pop_rr, jp_cc_a16, ill, call_cc_a16,push_rr, sub_a_d8, rst, /* dX */ + ret_cc, reti, jp_cc_a16, ill, call_cc_a16,ill, sbc_a_d8, rst, + ld_da8_a, pop_rr, ld_dc_a, ill, ill, push_rr, and_a_d8, rst, /* eX */ + add_sp_r8, jp_hl, ld_da16_a, ill, ill, ill, xor_a_d8, rst, + ld_a_da8, pop_rr, ld_a_dc, di, ill, push_rr, or_a_d8, rst, /* fX */ + ld_hl_sp_r8,ld_sp_hl, ld_a_da16, ei, ill, ill, cp_a_d8, rst, +}; + + + +void GB_cpu_disassemble(GB_gameboy_t *gb, uint16_t pc, uint16_t count) +{ + const GB_bank_symbol_t *function_symbol = GB_debugger_find_symbol(gb, pc); + + if (function_symbol && pc - function_symbol->addr > 0x1000) { + function_symbol = NULL; + } + + if (function_symbol && pc != function_symbol->addr) { + GB_log(gb, "%s:\n", function_symbol->name); + } + + uint16_t current_function = function_symbol? function_symbol->addr : 0; + + while (count--) { + function_symbol = GB_debugger_find_symbol(gb, pc); + if (function_symbol && function_symbol->addr == pc) { + if (current_function != function_symbol->addr) { + GB_log(gb, "\n"); + } + GB_log(gb, "%s:\n", function_symbol->name); + } + if (function_symbol) { + GB_log(gb, "%s%04x <+%03x>: ", pc == gb->pc? " ->": " ", pc, pc - function_symbol->addr); + } + else { + GB_log(gb, "%s%04x: ", pc == gb->pc? " ->": " ", pc); + } + uint8_t opcode = GB_read_memory(gb, pc); + opcodes[opcode](gb, opcode, &pc); + } +} diff --git a/gb/Core/symbol_hash.c b/gb/Core/symbol_hash.c new file mode 100644 index 0000000..208e72d --- /dev/null +++ b/gb/Core/symbol_hash.c @@ -0,0 +1,110 @@ +#include "gb.h" +#include +#include +#include +#include + +static size_t GB_map_find_symbol_index(GB_symbol_map_t *map, uint16_t addr) +{ + if (!map->symbols) { + return 0; + } + ssize_t min = 0; + ssize_t max = map->n_symbols; + while (min < max) { + size_t pivot = (min + max) / 2; + if (map->symbols[pivot].addr == addr) return pivot; + if (map->symbols[pivot].addr > addr) { + max = pivot; + } + else { + min = pivot + 1; + } + } + return (size_t) min; +} + +GB_bank_symbol_t *GB_map_add_symbol(GB_symbol_map_t *map, uint16_t addr, const char *name) +{ + size_t index = GB_map_find_symbol_index(map, addr); + + if (index < map->n_symbols && map->symbols[index].addr == addr) return NULL; + + map->symbols = realloc(map->symbols, (map->n_symbols + 1) * sizeof(map->symbols[0])); + memmove(&map->symbols[index + 1], &map->symbols[index], (map->n_symbols - index) * sizeof(map->symbols[0])); + map->symbols[index].addr = addr; + map->symbols[index].name = strdup(name); + map->n_symbols++; + return &map->symbols[index]; +} + +const GB_bank_symbol_t *GB_map_find_symbol(GB_symbol_map_t *map, uint16_t addr) +{ + if (!map) return NULL; + size_t index = GB_map_find_symbol_index(map, addr); + if (index < map->n_symbols && map->symbols[index].addr != addr) { + index--; + } + if (index < map->n_symbols) { + return &map->symbols[index]; + } + return NULL; +} + +GB_symbol_map_t *GB_map_alloc(void) +{ + GB_symbol_map_t *map = malloc(sizeof(*map)); + memset(map, 0, sizeof(*map)); + return map; +} + +void GB_map_free(GB_symbol_map_t *map) +{ + for (unsigned i = 0; i < map->n_symbols; i++) { + free(map->symbols[i].name); + } + + if (map->symbols) { + free(map->symbols); + } + + free(map); +} + +static int hash_name(const char *name) +{ + int r = 0; + while (*name) { + r <<= 1; + if (r & 0x400) { + r ^= 0x401; + } + r += (unsigned char)*(name++); + } + + return r & 0x3FF; +} + +void GB_reversed_map_add_symbol(GB_reversed_symbol_map_t *map, uint16_t bank, GB_bank_symbol_t *bank_symbol) +{ + int hash = hash_name(bank_symbol->name); + GB_symbol_t *symbol = malloc(sizeof(*symbol)); + symbol->name = bank_symbol->name; + symbol->addr = bank_symbol->addr; + symbol->bank = bank; + symbol->next = map->buckets[hash]; + map->buckets[hash] = symbol; +} + +const GB_symbol_t *GB_reversed_map_find_symbol(GB_reversed_symbol_map_t *map, const char *name) +{ + int hash = hash_name(name); + GB_symbol_t *symbol = map->buckets[hash]; + + while (symbol) { + if (strcmp(symbol->name, name) == 0) return symbol; + symbol = symbol->next; + } + + return NULL; +} diff --git a/gb/Core/symbol_hash.h b/gb/Core/symbol_hash.h new file mode 100644 index 0000000..2a03c96 --- /dev/null +++ b/gb/Core/symbol_hash.h @@ -0,0 +1,38 @@ +#ifndef symbol_hash_h +#define symbol_hash_h + +#include +#include +#include + +typedef struct { + char *name; + uint16_t addr; +} GB_bank_symbol_t; + +typedef struct GB_symbol_s { + struct GB_symbol_s *next; + const char *name; + uint16_t bank; + uint16_t addr; +} GB_symbol_t; + +typedef struct { + GB_bank_symbol_t *symbols; + size_t n_symbols; +} GB_symbol_map_t; + +typedef struct { + GB_symbol_t *buckets[0x400]; +} GB_reversed_symbol_map_t; + +#ifdef GB_INTERNAL +void GB_reversed_map_add_symbol(GB_reversed_symbol_map_t *map, uint16_t bank, GB_bank_symbol_t *symbol); +const GB_symbol_t *GB_reversed_map_find_symbol(GB_reversed_symbol_map_t *map, const char *name); +GB_bank_symbol_t *GB_map_add_symbol(GB_symbol_map_t *map, uint16_t addr, const char *name); +const GB_bank_symbol_t *GB_map_find_symbol(GB_symbol_map_t *map, uint16_t addr); +GB_symbol_map_t *GB_map_alloc(void); +void GB_map_free(GB_symbol_map_t *map); +#endif + +#endif /* symbol_hash_h */ diff --git a/gb/Core/timing.c b/gb/Core/timing.c new file mode 100644 index 0000000..283558c --- /dev/null +++ b/gb/Core/timing.c @@ -0,0 +1,294 @@ +#include "gb.h" +#ifdef _WIN32 +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif +#include +#else +#include +#endif + +static const unsigned GB_TAC_TRIGGER_BITS[] = {512, 8, 32, 128}; + +#ifndef DISABLE_TIMEKEEPING +static int64_t get_nanoseconds(void) +{ +#ifndef _WIN32 + struct timeval now; + gettimeofday(&now, NULL); + return (now.tv_usec) * 1000 + now.tv_sec * 1000000000L; +#else + FILETIME time; + GetSystemTimeAsFileTime(&time); + return (((int64_t)time.dwHighDateTime << 32) | time.dwLowDateTime) * 100L; +#endif +} + +static void nsleep(uint64_t nanoseconds) +{ +#ifndef _WIN32 + struct timespec sleep = {0, nanoseconds}; + nanosleep(&sleep, NULL); +#else + HANDLE timer; + LARGE_INTEGER time; + timer = CreateWaitableTimer(NULL, true, NULL); + time.QuadPart = -(nanoseconds / 100L); + SetWaitableTimer(timer, &time, 0, NULL, NULL, false); + WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); +#endif +} + +bool GB_timing_sync_turbo(GB_gameboy_t *gb) +{ + if (!gb->turbo_dont_skip) { + int64_t nanoseconds = get_nanoseconds(); + if (nanoseconds <= gb->last_sync + (1000000000LL * LCDC_PERIOD / GB_get_clock_rate(gb))) { + return true; + } + gb->last_sync = nanoseconds; + } + return false; +} + +void GB_timing_sync(GB_gameboy_t *gb) +{ + if (gb->turbo) { + gb->cycles_since_last_sync = 0; + return; + } + /* Prevent syncing if not enough time has passed.*/ + if (gb->cycles_since_last_sync < LCDC_PERIOD / 3) return; + + uint64_t target_nanoseconds = gb->cycles_since_last_sync * 1000000000LL / 2 / GB_get_clock_rate(gb); /* / 2 because we use 8MHz units */ + int64_t nanoseconds = get_nanoseconds(); + int64_t time_to_sleep = target_nanoseconds + gb->last_sync - nanoseconds; + if (time_to_sleep > 0 && time_to_sleep < LCDC_PERIOD * 1000000000LL / GB_get_clock_rate(gb)) { + nsleep(time_to_sleep); + gb->last_sync += target_nanoseconds; + } + else { + gb->last_sync = nanoseconds; + } + + gb->cycles_since_last_sync = 0; + if (gb->update_input_hint_callback) { + gb->update_input_hint_callback(gb); + } +} +#else + +bool GB_timing_sync_turbo(GB_gameboy_t *gb) +{ + return false; +} + +void GB_timing_sync(GB_gameboy_t *gb) +{ +} + +#endif +static void GB_ir_run(GB_gameboy_t *gb) +{ + if (gb->ir_queue_length == 0) return; + if (gb->cycles_since_input_ir_change >= gb->ir_queue[0].delay) { + gb->cycles_since_input_ir_change -= gb->ir_queue[0].delay; + gb->infrared_input = gb->ir_queue[0].state; + gb->ir_queue_length--; + memmove(&gb->ir_queue[0], &gb->ir_queue[1], sizeof(gb->ir_queue[0]) * (gb->ir_queue_length)); + } +} + +static void advance_tima_state_machine(GB_gameboy_t *gb) +{ + if (gb->tima_reload_state == GB_TIMA_RELOADED) { + gb->tima_reload_state = GB_TIMA_RUNNING; + } + else if (gb->tima_reload_state == GB_TIMA_RELOADING) { + gb->io_registers[GB_IO_IF] |= 4; + gb->tima_reload_state = GB_TIMA_RELOADED; + } +} + +static void increase_tima(GB_gameboy_t *gb) +{ + gb->io_registers[GB_IO_TIMA]++; + if (gb->io_registers[GB_IO_TIMA] == 0) { + gb->io_registers[GB_IO_TIMA] = gb->io_registers[GB_IO_TMA]; + gb->tima_reload_state = GB_TIMA_RELOADING; + } +} + +static void GB_set_internal_div_counter(GB_gameboy_t *gb, uint32_t value) +{ + /* TIMA increases when a specific high-bit becomes a low-bit. */ + value &= INTERNAL_DIV_CYCLES - 1; + uint32_t triggers = gb->div_counter & ~value; + if ((gb->io_registers[GB_IO_TAC] & 4) && (triggers & GB_TAC_TRIGGER_BITS[gb->io_registers[GB_IO_TAC] & 3])) { + increase_tima(gb); + } + + /* TODO: Can switching to double speed mode trigger an event? */ + if (triggers & (gb->cgb_double_speed? 0x2000 : 0x1000)) { + GB_apu_run(gb); + GB_apu_div_event(gb); + } + gb->div_counter = value; +} + +static void GB_timers_run(GB_gameboy_t *gb, uint8_t cycles) +{ + GB_STATE_MACHINE(gb, div, cycles, 1) { + GB_STATE(gb, div, 1); + GB_STATE(gb, div, 2); + GB_STATE(gb, div, 3); + } + + GB_set_internal_div_counter(gb, 0); +main: + GB_SLEEP(gb, div, 1, 3); + while (true) { + advance_tima_state_machine(gb); + GB_set_internal_div_counter(gb, gb->div_counter + 4); + gb->apu.apu_cycles += 4 << !gb->cgb_double_speed; + GB_SLEEP(gb, div, 2, 4); + } + + /* Todo: This is ugly to allow compatibility with 0.11 save states. Fix me when breaking save compatibility */ + { + div3: + /* Compensate for lack of prefetch emulation, as well as DIV's internal initial value */ + GB_set_internal_div_counter(gb, 8); + goto main; + } +} + +static void advance_serial(GB_gameboy_t *gb, uint8_t cycles) +{ + if (gb->serial_length == 0) { + gb->serial_cycles += cycles; + return; + } + + while (cycles > gb->serial_length) { + advance_serial(gb, gb->serial_length); + cycles -= gb->serial_length; + } + + uint16_t previous_serial_cycles = gb->serial_cycles; + gb->serial_cycles += cycles; + if ((gb->serial_cycles & gb->serial_length) != (previous_serial_cycles & gb->serial_length)) { + gb->serial_count++; + if (gb->serial_count == 8) { + gb->serial_length = 0; + gb->serial_count = 0; + gb->io_registers[GB_IO_SC] &= ~0x80; + gb->io_registers[GB_IO_IF] |= 8; + } + + gb->io_registers[GB_IO_SB] <<= 1; + + if (gb->serial_transfer_bit_end_callback) { + gb->io_registers[GB_IO_SB] |= gb->serial_transfer_bit_end_callback(gb); + } + else { + gb->io_registers[GB_IO_SB] |= 1; + } + + if (gb->serial_length) { + /* Still more bits to send */ + if (gb->serial_transfer_bit_start_callback) { + gb->serial_transfer_bit_start_callback(gb, gb->io_registers[GB_IO_SB] & 0x80); + } + } + + } + return; + +} + +void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) +{ + // Affected by speed boost + gb->dma_cycles += cycles; + + if (!gb->stopped) { + GB_timers_run(gb, cycles); + advance_serial(gb, cycles); // TODO: Verify what happens in STOP mode + } + + gb->debugger_ticks += cycles; + + if (!gb->cgb_double_speed) { + cycles <<= 1; + } + + // Not affected by speed boost + gb->double_speed_alignment += cycles; + gb->hdma_cycles += cycles; + gb->apu_output.sample_cycles += cycles; + gb->cycles_since_ir_change += cycles; + gb->cycles_since_input_ir_change += cycles; + gb->cycles_since_last_sync += cycles; + gb->cycles_since_run += cycles; + if (!gb->stopped) { // TODO: Verify what happens in STOP mode + GB_dma_run(gb); + GB_hdma_run(gb); + } + GB_apu_run(gb); + GB_display_run(gb, cycles); + GB_ir_run(gb); +} + +/* + This glitch is based on the expected results of mooneye-gb rapid_toggle test. + This glitch happens because how TIMA is increased, see GB_set_internal_div_counter. + According to GiiBiiAdvance, GBC's behavior is different, but this was not tested or implemented. +*/ +void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac) +{ + /* Glitch only happens when old_tac is enabled. */ + if (!(old_tac & 4)) return; + + unsigned old_clocks = GB_TAC_TRIGGER_BITS[old_tac & 3]; + unsigned new_clocks = GB_TAC_TRIGGER_BITS[new_tac & 3]; + + /* The bit used for overflow testing must have been 1 */ + if (gb->div_counter & old_clocks) { + /* And now either the timer must be disabled, or the new bit used for overflow testing be 0. */ + if (!(new_tac & 4) || gb->div_counter & new_clocks) { + increase_tima(gb); + } + } +} + +void GB_rtc_run(GB_gameboy_t *gb) +{ + if ((gb->rtc_real.high & 0x40) == 0) { /* is timer running? */ + time_t current_time = time(NULL); + while (gb->last_rtc_second < current_time) { + gb->last_rtc_second++; + if (++gb->rtc_real.seconds == 60) + { + gb->rtc_real.seconds = 0; + if (++gb->rtc_real.minutes == 60) + { + gb->rtc_real.minutes = 0; + if (++gb->rtc_real.hours == 24) + { + gb->rtc_real.hours = 0; + if (++gb->rtc_real.days == 0) + { + if (gb->rtc_real.high & 1) /* Bit 8 of days*/ + { + gb->rtc_real.high |= 0x80; /* Overflow bit */ + } + gb->rtc_real.high ^= 1; + } + } + } + } + } + } +} diff --git a/gb/Core/timing.h b/gb/Core/timing.h new file mode 100644 index 0000000..02ca54c --- /dev/null +++ b/gb/Core/timing.h @@ -0,0 +1,44 @@ +#ifndef timing_h +#define timing_h +#include "gb_struct_def.h" + +#ifdef GB_INTERNAL +void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles); +void GB_rtc_run(GB_gameboy_t *gb); +void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac); +bool GB_timing_sync_turbo(GB_gameboy_t *gb); /* Returns true if should skip frame */ +void GB_timing_sync(GB_gameboy_t *gb); + +enum { + GB_TIMA_RUNNING = 0, + GB_TIMA_RELOADING = 1, + GB_TIMA_RELOADED = 2 +}; + +#define GB_HALT_VALUE (0xFFFF) + +#define GB_SLEEP(gb, unit, state, cycles) do {\ + (gb)->unit##_cycles -= (cycles) * __state_machine_divisor; \ + if ((gb)->unit##_cycles <= 0) {\ + (gb)->unit##_state = state;\ + return;\ + unit##state:; \ + }\ +} while (0) + +#define GB_HALT(gb, unit) (gb)->unit##_cycles = GB_HALT_VALUE + +#define GB_STATE_MACHINE(gb, unit, cycles, divisor) \ +static const int __state_machine_divisor = divisor;\ +(gb)->unit##_cycles += cycles; \ +if ((gb)->unit##_cycles <= 0 || (gb)->unit##_cycles == GB_HALT_VALUE) {\ + return;\ +}\ +switch ((gb)->unit##_state) +#endif + +#define GB_STATE(gb, unit, state) case state: goto unit##state + +#define GB_UNIT(unit) int32_t unit##_cycles, unit##_state + +#endif /* timing_h */ diff --git a/gb/LICENSE b/gb/LICENSE new file mode 100644 index 0000000..94966be --- /dev/null +++ b/gb/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2015-2019 Lior Halphon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/gb/README b/gb/README new file mode 100644 index 0000000..fa08dc0 --- /dev/null +++ b/gb/README @@ -0,0 +1,5 @@ +Core: 2019-10-22 master snapshot +* has issues with SGB2 audio desynchronization + +Core-new: 2019-11-05 master snapshot +* Game Boy inputs are not working diff --git a/heuristics/bs-memory.cpp b/heuristics/bs-memory.cpp new file mode 100644 index 0000000..ffb255c --- /dev/null +++ b/heuristics/bs-memory.cpp @@ -0,0 +1,33 @@ +namespace Heuristics { + +struct BSMemory { + BSMemory(vector& data, string location); + explicit operator bool() const; + auto manifest() const -> string; + +private: + vector& data; + string location; +}; + +BSMemory::BSMemory(vector& data, string location) : data(data), location(location) { +} + +BSMemory::operator bool() const { + return data.size() >= 0x8000; +} + +auto BSMemory::manifest() const -> string { + if(!operator bool()) return {}; + + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" board\n"); + output.append(Memory{}.type("Flash").size(data.size()).content("Program").text()); + return output; +} + +} diff --git a/heuristics/game-boy.cpp b/heuristics/game-boy.cpp new file mode 100644 index 0000000..411a1cc --- /dev/null +++ b/heuristics/game-boy.cpp @@ -0,0 +1,298 @@ +namespace Heuristics { + +struct GameBoy { + GameBoy(vector& data, string location); + explicit operator bool() const; + auto manifest() const -> string; + +private: + auto read(uint offset) const -> uint8_t { return data[headerAddress + offset]; } + + vector& data; + string location; + uint headerAddress = 0; +}; + +GameBoy::GameBoy(vector& data, string location) : data(data), location(location) { + headerAddress = data.size() < 0x8000 ? data.size() : data.size() - 0x8000; + if(read(0x0104) == 0xce && read(0x0105) == 0xed && read(0x0106) == 0x66 && read(0x0107) == 0x66 + && read(0x0108) == 0xcc && read(0x0109) == 0x0d && read(0x0147) >= 0x0b && read(0x0147) <= 0x0d + ) { //MMM01 stores header at bottom of data[] + } else { //all other mappers store header at top of data[] + headerAddress = 0; + } +} + +GameBoy::operator bool() const { + return data.size() >= 0x4000; +} + +auto GameBoy::manifest() const -> string { + if(!operator bool()) return {}; + + bool black = (read(0x0143) & 0xc0) == 0x80; //cartridge works in DMG+CGB mode + bool clear = (read(0x0143) & 0xc0) == 0xc0; //cartridge works in CGB mode only + + bool ram = false; + bool battery = false; + bool eeprom = false; + bool flash = false; + bool rtc = false; + bool accelerometer = false; + bool rumble = false; + + uint romSize = 0; + uint ramSize = 0; + uint eepromSize = 0; + uint flashSize = 0; + uint rtcSize = 0; + + string mapper = "MBC0"; + + switch(read(0x0147)) { + + case 0x00: + mapper = "MBC0"; + break; + + case 0x01: + mapper = "MBC1"; + break; + + case 0x02: + mapper = "MBC1"; + ram = true; + break; + + case 0x03: + mapper = "MBC1"; + battery = true; + ram = true; + break; + + case 0x05: + mapper = "MBC2"; + ram = true; + break; + + case 0x06: + mapper = "MBC2"; + battery = true; + ram = true; + break; + + case 0x08: + mapper = "MBC0"; + ram = true; + break; + + case 0x09: + mapper = "MBC0"; + battery = true; + ram = true; + break; + + case 0x0b: + mapper = "MMM01"; + break; + + case 0x0c: + mapper = "MMM01"; + ram = true; + break; + + case 0x0d: + mapper = "MMM01"; + battery = true; + ram = true; + break; + + case 0x0f: + mapper = "MBC3"; + battery = true; + rtc = true; + break; + + case 0x10: + mapper = "MBC3"; + battery = true; + ram = true; + rtc = true; + break; + + case 0x11: + mapper = "MBC3"; + break; + + case 0x12: + mapper = "MBC3"; + ram = true; + break; + + case 0x13: + mapper = "MBC3"; + battery = true; + ram = true; + break; + + case 0x19: + mapper = "MBC5"; + break; + + case 0x1a: + mapper = "MBC5"; + ram = true; + break; + + case 0x1b: + mapper = "MBC5"; + battery = true; + ram = true; + break; + + case 0x1c: + mapper = "MBC5"; + rumble = true; + break; + + case 0x1d: + mapper = "MBC5"; + ram = true; + rumble = true; + break; + + case 0x1e: + mapper = "MBC5"; + battery = true; + ram = true; + rumble = true; + break; + + case 0x20: + mapper = "MBC6"; + flash = true; + battery = true; + ram = true; + break; + + case 0x22: + mapper = "MBC7"; + battery = true; + eeprom = true; + accelerometer = true; + rumble = true; + break; + + case 0xfc: + mapper = "CAMERA"; + break; + + case 0xfd: + mapper = "TAMA"; + battery = true; + ram = true; + rtc = true; + break; + + case 0xfe: + mapper = "HuC3"; + break; + + case 0xff: + mapper = "HuC1"; + battery = true; + ram = true; + break; + + } + + //Game Boy: title = $0134-0143 + //Game Boy Color (early games): title = $0134-0142; model = $0143 + //Game Boy Color (later games): title = $0134-013e; serial = $013f-0142; model = $0143 + string title; + for(uint n : range(black || clear ? 15 : 16)) { + char byte = read(0x0134 + n); + if(byte < 0x20 || byte > 0x7e) byte = ' '; + title.append(byte); + } + + string serial = title.slice(-4); + if(!black && !clear) serial = ""; + for(auto& byte : serial) { + if(byte >= 'A' && byte <= 'Z') continue; + //invalid serial + serial = ""; + break; + } + title.trimRight(serial, 1L); //remove the serial from the title, if it exists + title.strip(); //remove any excess whitespace from the title + + switch(read(0x0148)) { default: + case 0x00: romSize = 2 * 16 * 1024; break; + case 0x01: romSize = 4 * 16 * 1024; break; + case 0x02: romSize = 8 * 16 * 1024; break; + case 0x03: romSize = 16 * 16 * 1024; break; + case 0x04: romSize = 32 * 16 * 1024; break; + case 0x05: romSize = 64 * 16 * 1024; break; + case 0x06: romSize = 128 * 16 * 1024; break; + case 0x07: romSize = 256 * 16 * 1024; break; + case 0x52: romSize = 72 * 16 * 1024; break; + case 0x53: romSize = 80 * 16 * 1024; break; + case 0x54: romSize = 96 * 16 * 1024; break; + } + + switch(read(0x0149)) { default: + case 0x00: ramSize = 0 * 1024; break; + case 0x01: ramSize = 2 * 1024; break; + case 0x02: ramSize = 8 * 1024; break; + case 0x03: ramSize = 32 * 1024; break; + } + + if(mapper == "MBC2" && ram) ramSize = 256; + if(mapper == "MBC6" && ram) ramSize = 32 * 1024; + if(mapper == "TAMA" && ram) ramSize = 32; + + if(mapper == "MBC6" && flash) flashSize = 1024 * 1024; + + //Game Boy header does not specify EEPROM size: detect via game title instead + //Command Master: EEPROM = 512 bytes + //Kirby Tilt 'n' Tumble: EEPROM = 256 bytes + //Korokoro Kirby: EEPROM = 256 bytes + if(mapper == "MBC7" && eeprom) { + eepromSize = 256; //fallback guess; supported values are 128, 256, 512 + if(title == "CMASTER" && serial == "KCEJ") eepromSize = 512; + if(title == "KIRBY TNT" && serial == "KTNE") eepromSize = 256; + if(title == "KORO2 KIRBY" && serial == "KKKJ") eepromSize = 256; + } + + if(mapper == "MBC3" && rtc) rtcSize = 13; + if(mapper == "TAMA" && rtc) rtcSize = 21; + + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" title: ", title, "\n"); +if(serial) + output.append(" serial: ", serial, "\n"); + output.append(" board: ", mapper, "\n"); + output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); +if(ram && ramSize && battery) + output.append(Memory{}.type("RAM").size(ramSize).content("Save").text()); +if(ram && ramSize && !battery) + output.append(Memory{}.type("RAM").size(ramSize).content("Save").isVolatile().text()); +if(eeprom && eepromSize) + output.append(Memory{}.type("EEPROM").size(eepromSize).content("Save").text()); +if(flash && flashSize) + output.append(Memory{}.type("Flash").size(flashSize).content("Download").text()); +if(rtc && rtcSize) + output.append(Memory{}.type("RTC").size(rtcSize).content("Time").text()); +if(accelerometer) + output.append(" accelerometer\n"); +if(rumble) + output.append(" rumble\n"); + return output; +} + +} diff --git a/heuristics/heuristics.cpp b/heuristics/heuristics.cpp new file mode 100644 index 0000000..c564ac9 --- /dev/null +++ b/heuristics/heuristics.cpp @@ -0,0 +1,34 @@ +namespace Heuristics { + +auto Memory::text() const -> string { + string output; + output.append(" memory\n"); + output.append(" type: ", _type, "\n"); + output.append(" size: 0x", hex(_size), "\n"); + output.append(" content: ", _content, "\n"); +if(_manufacturer) + output.append(" manufacturer: ", _manufacturer, "\n"); +if(_architecture) + output.append(" architecture: ", _architecture, "\n"); +if(_identifier) + output.append(" identifier: ", _identifier, "\n"); +if(_volatile) + output.append(" volatile\n"); + return output; +} + +auto Oscillator::text() const -> string { + string output; + output.append(" oscillator\n"); + output.append(" frequency: ", _frequency, "\n"); + return output; +} + +auto Slot::text() const -> string { + string output; + output.append(" slot\n"); + output.append(" type: ", _type, "\n"); + return output; +} + +} diff --git a/heuristics/heuristics.hpp b/heuristics/heuristics.hpp new file mode 100644 index 0000000..a65dafa --- /dev/null +++ b/heuristics/heuristics.hpp @@ -0,0 +1,37 @@ +namespace Heuristics { + +struct Memory { + auto& type(string type) { _type = type; return *this; } + auto& size(natural size) { _size = size; return *this; } + auto& content(string content) { _content = content; return *this; } + auto& manufacturer(string manufacturer) { _manufacturer = manufacturer; return *this; } + auto& architecture(string architecture) { _architecture = architecture; return *this; } + auto& identifier(string identifier) { _identifier = identifier; return *this; } + auto& isVolatile() { _volatile = true; return *this; } + auto text() const -> string; + + string _type; + boolean _battery; + natural _size; + string _content; + string _manufacturer; + string _architecture; + string _identifier; + boolean _volatile; +}; + +struct Oscillator { + auto& frequency(natural frequency) { _frequency = frequency; return *this; } + auto text() const -> string; + + natural _frequency; +}; + +struct Slot { + auto& type(string type) { _type = type; return *this; } + auto text() const -> string; + + string _type; +}; + +} diff --git a/heuristics/sufami-turbo.cpp b/heuristics/sufami-turbo.cpp new file mode 100644 index 0000000..5e4ea2d --- /dev/null +++ b/heuristics/sufami-turbo.cpp @@ -0,0 +1,39 @@ +namespace Heuristics { + +struct SufamiTurbo { + SufamiTurbo(vector& data, string location); + explicit operator bool() const; + + auto manifest() const -> string; + +private: + vector& data; + string location; +}; + +SufamiTurbo::SufamiTurbo(vector& data, string location) : data(data), location(location) { +} + +SufamiTurbo::operator bool() const { + return data.size() >= 0x20000; +} + +auto SufamiTurbo::manifest() const -> string { + if(!operator bool()) return {}; + + uint romSize = data[0x36] * 0x20000; //128KB + uint ramSize = data[0x37] * 0x800; // 2KB + + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" board\n"); + output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); +if(ramSize) + output.append(Memory{}.type("RAM").size(ramSize).content("Save").text()); + return output; +} + +} diff --git a/heuristics/super-famicom.cpp b/heuristics/super-famicom.cpp new file mode 100644 index 0000000..674196e --- /dev/null +++ b/heuristics/super-famicom.cpp @@ -0,0 +1,605 @@ +namespace Heuristics { + +struct SuperFamicom { + SuperFamicom(vector& data, string location); + explicit operator bool() const; + + auto manifest() const -> string; + auto region() const -> string; + auto videoRegion() const -> string; + auto revision() const -> string; + auto board() const -> string; + auto title() const -> string; + auto serial() const -> string; + auto romSize() const -> uint; + auto programRomSize() const -> uint; + auto dataRomSize() const -> uint; + auto expansionRomSize() const -> uint; + auto firmwareRomSize() const -> uint; + auto ramSize() const -> uint; + auto expansionRamSize() const -> uint; + auto nonVolatile() const -> bool; + +private: + auto size() const -> uint { return data.size(); } + auto scoreHeader(uint address) -> uint; + auto firmwareARM() const -> string; + auto firmwareEXNEC() const -> string; + auto firmwareGB() const -> string; + auto firmwareHITACHI() const -> string; + auto firmwareNEC() const -> string; + + vector& data; + string location; + uint headerAddress = 0; +}; + +SuperFamicom::SuperFamicom(vector& data, string location) : data(data), location(location) { + if((size() & 0x7fff) == 512) { + //remove header if present + memory::move(&data[0], &data[512], size() - 512); + data.resize(size() - 512); + } + + if(size() < 0x8000) return; //ignore images too small to be valid + + uint LoROM = scoreHeader( 0x7fb0); + uint HiROM = scoreHeader( 0xffb0); + uint ExLoROM = scoreHeader(0x407fb0); + uint ExHiROM = scoreHeader(0x40ffb0); + if(ExLoROM) ExLoROM += 4; + if(ExHiROM) ExHiROM += 4; + + if(LoROM >= HiROM && LoROM >= ExLoROM && LoROM >= ExHiROM) headerAddress = 0x7fb0; + else if(HiROM >= ExLoROM && HiROM >= ExHiROM) headerAddress = 0xffb0; + else if(ExLoROM >= ExHiROM) headerAddress = 0x407fb0; + else headerAddress = 0x40ffb0; +} + +SuperFamicom::operator bool() const { + return headerAddress; +} + +auto SuperFamicom::manifest() const -> string { + if(!operator bool()) return {}; + + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" title: ", title(), "\n"); + output.append(" region: ", region(), "\n"); + output.append(" revision: ", revision(), "\n"); + output.append(" board: ", board(), "\n"); + + auto board = this->board().trimRight("#A", 1L).split("-"); + + if(auto size = romSize()) { + if(board(0) == "SPC7110" && size > 0x100000) { + output.append(Memory{}.type("ROM").size(0x100000).content("Program").text()); + output.append(Memory{}.type("ROM").size(size - 0x100000).content("Data").text()); + } else if(board(0) == "EXSPC7110" && size == 0x700000) { + //Tengai Maykou Zero (fan translation) + output.append(Memory{}.type("ROM").size(0x100000).content("Program").text()); + output.append(Memory{}.type("ROM").size(0x500000).content("Data").text()); + output.append(Memory{}.type("ROM").size(0x100000).content("Expansion").text()); + } else { + output.append(Memory{}.type("ROM").size(size).content("Program").text()); + } + } + + if(auto size = ramSize()) { + output.append(Memory{}.type("RAM").size(size).content("Save").text()); + } + + if(auto size = expansionRamSize()) { + output.append(Memory{}.type("RAM").size(size).content("Save").text()); + } + + if(0) { + } else if(board(0) == "ARM") { + output.append(Memory{}.type("ROM").size(0x20000).content("Program").manufacturer("SETA").architecture("ARM6").identifier(firmwareARM()).text()); + output.append(Memory{}.type("ROM").size( 0x8000).content("Data" ).manufacturer("SETA").architecture("ARM6").identifier(firmwareARM()).text()); + output.append(Memory{}.type("RAM").size( 0x4000).content("Data" ).manufacturer("SETA").architecture("ARM6").identifier(firmwareARM()).isVolatile().text()); + output.append(Oscillator{}.frequency(21'440'000).text()); + } else if(board(0) == "BS" && board(1) == "MCC") { + output.append(Memory{}.type("RAM").size(0x80000).content("Download").text()); + } else if(board(0) == "EXNEC") { + output.append(Memory{}.type("ROM").size(0xc000).content("Program").manufacturer("NEC").architecture("uPD96050").identifier(firmwareEXNEC()).text()); + output.append(Memory{}.type("ROM").size(0x1000).content("Data" ).manufacturer("NEC").architecture("uPD96050").identifier(firmwareEXNEC()).text()); + output.append(Memory{}.type("RAM").size(0x1000).content("Data" ).manufacturer("NEC").architecture("uPD96050").identifier(firmwareEXNEC()).text()); + output.append(Oscillator{}.frequency(firmwareEXNEC() == "ST010" ? 11'000'000 : 15'000'000).text()); + } else if(board(0) == "GB") { + output.append(Memory{}.type("ROM").size(0x100).content("Boot").manufacturer("Nintendo").architecture("LR35902").identifier(firmwareGB()).text()); + if(firmwareGB() == "SGB2") + output.append(Oscillator{}.frequency(20'971'520).text()); + } else if(board(0) == "GSU") { + //todo: MARIO CHIP 1 uses CPU oscillator + output.append(Oscillator{}.frequency(21'440'000).text()); + } else if(board(0) == "HITACHI") { + output.append(Memory{}.type("ROM").size(0xc00).content("Data").manufacturer("Hitachi").architecture("HG51BS169").identifier(firmwareHITACHI()).text()); + output.append(Memory{}.type("RAM").size(0xc00).content("Data").manufacturer("Hitachi").architecture("HG51BS169").identifier(firmwareHITACHI()).isVolatile().text()); + output.append(Oscillator{}.frequency(20'000'000).text()); + } else if(board(0) == "NEC") { + output.append(Memory{}.type("ROM").size(0x1800).content("Program").manufacturer("NEC").architecture("uPD7725").identifier(firmwareNEC()).text()); + output.append(Memory{}.type("ROM").size( 0x800).content("Data" ).manufacturer("NEC").architecture("uPD7725").identifier(firmwareNEC()).text()); + output.append(Memory{}.type("RAM").size( 0x200).content("Data" ).manufacturer("NEC").architecture("uPD7725").identifier(firmwareNEC()).isVolatile().text()); + output.append(Oscillator{}.frequency(7'600'000).text()); + } else if(board(0) == "SA1" || board(1) == "SA1") { //SA1-* or BS-SA1-* + output.append(Memory{}.type("RAM").size(0x800).content("Internal").isVolatile().text()); + } + + if(board.right() == "EPSONRTC") { + output.append(Memory{}.type("RTC").size(0x10).content("Time").manufacturer("Epson").text()); + } else if(board.right() == "SHARPRTC") { + output.append(Memory{}.type("RTC").size(0x10).content("Time").manufacturer("Sharp").text()); + } + + return output; +} + +auto SuperFamicom::region() const -> string { + //Unlicensed software (homebrew, ROM hacks, etc) often change the standard region code, + //and then neglect to change the extended header region code. Thanks to that, we can't + //decode and display the full game serial + region code. + return videoRegion(); + + string region; + + char A = data[headerAddress + 0x02]; //game type + char B = data[headerAddress + 0x03]; //game code + char C = data[headerAddress + 0x04]; //game code + char D = data[headerAddress + 0x05]; //region code (new; sometimes ambiguous) + auto E = data[headerAddress + 0x29]; //region code (old) + + auto valid = [](char n) { return (n >= '0' && n <= '9') || (n >= 'A' && n <= 'Z'); }; + if(data[headerAddress + 0x2a] == 0x33 && valid(A) && valid(B) & valid(C) & valid(D)) { + string code{A, B, C, D}; + if(D == 'B') region = {"SNS-", code, "-BRA"}; + if(D == 'C') region = {"SNSN-", code, "-ROC"}; + if(D == 'D') region = {"SNSP-", code, "-NOE"}; + if(D == 'E') region = {"SNS-", code, "-USA"}; + if(D == 'F') region = {"SNSP-", code, "-FRA"}; + if(D == 'H') region = {"SNSP-", code, "-HOL"}; + if(D == 'I') region = {"SNSP-", code, "-ITA"}; + if(D == 'J') region = {"SHVC-", code, "-JPN"}; + if(D == 'K') region = {"SNSN-", code, "-KOR"}; + if(D == 'N') region = {"SNS-", code, "-CAN"}; + if(D == 'P') region = {"SNSP-", code, "-EUR"}; + if(D == 'S') region = {"SNSP-", code, "-ESP"}; + if(D == 'U') region = {"SNSP-", code, "-AUS"}; + if(D == 'X') region = {"SNSP-", code, "-SCN"}; + } + + if(!region) { + if(E == 0x00) region = {"JPN"}; + if(E == 0x01) region = {"USA"}; + if(E == 0x02) region = {"EUR"}; + if(E == 0x03) region = {"SCN"}; + if(E == 0x06) region = {"FRA"}; + if(E == 0x07) region = {"HOL"}; + if(E == 0x08) region = {"ESP"}; + if(E == 0x09) region = {"NOE"}; + if(E == 0x0a) region = {"ITA"}; + if(E == 0x0b) region = {"ROC"}; + if(E == 0x0d) region = {"KOR"}; + if(E == 0x0f) region = {"CAN"}; + if(E == 0x10) region = {"BRA"}; + if(E == 0x11) region = {"AUS"}; + if(E == 0x12) region = {"SCN"}; + } + + return region ? region : "NTSC"; +} + +auto SuperFamicom::videoRegion() const -> string { + auto region = data[headerAddress + 0x29]; + if(region == 0x00) return "NTSC"; //JPN + if(region == 0x01) return "NTSC"; //USA + if(region == 0x0b) return "NTSC"; //ROC + if(region == 0x0d) return "NTSC"; //KOR + if(region == 0x0f) return "NTSC"; //CAN + if(region == 0x10) return "NTSC"; //BRA + return "PAL"; +} + +auto SuperFamicom::revision() const -> string { + string revision; + + char A = data[headerAddress + 0x02]; //game type + char B = data[headerAddress + 0x03]; //game code + char C = data[headerAddress + 0x04]; //game code + char D = data[headerAddress + 0x05]; //region code (new; sometimes ambiguous) + auto E = data[headerAddress + 0x29]; //region code (old) + uint F = data[headerAddress + 0x2b]; //revision code + + auto valid = [](char n) { return (n >= '0' && n <= '9') || (n >= 'A' && n <= 'Z'); }; + if(data[headerAddress + 0x2a] == 0x33 && valid(A) && valid(B) & valid(C) & valid(D)) { + string code{A, B, C, D}; + if(D == 'B') revision = {"SNS-", code, "-", F}; + if(D == 'C') revision = {"SNSN-", code, "-", F}; + if(D == 'D') revision = {"SNSP-", code, "-", F}; + if(D == 'E') revision = {"SNS-", code, "-", F}; + if(D == 'F') revision = {"SNSP-", code, "-", F}; + if(D == 'H') revision = {"SNSP-", code, "-", F}; + if(D == 'I') revision = {"SNSP-", code, "-", F}; + if(D == 'J') revision = {"SHVC-", code, "-", F}; + if(D == 'K') revision = {"SNSN-", code, "-", F}; + if(D == 'N') revision = {"SNS-", code, "-", F}; + if(D == 'P') revision = {"SNSP-", code, "-", F}; + if(D == 'S') revision = {"SNSP-", code, "-", F}; + if(D == 'U') revision = {"SNSP-", code, "-", F}; + if(D == 'X') revision = {"SNSP-", code, "-", F}; + } + + if(!revision) { + revision = {"1.", F}; + } + + return revision ? revision : string{"1.", F}; +} + +//format: [slot]-[coprocessor]-[mapper]-[ram]-[rtc] +auto SuperFamicom::board() const -> string { + string board; + + auto mapMode = data[headerAddress + 0x25]; + auto cartridgeTypeLo = data[headerAddress + 0x26] & 15; + auto cartridgeTypeHi = data[headerAddress + 0x26] >> 4; + auto cartridgeSubType = data[headerAddress + 0x0f]; + + string mode; + if(mapMode == 0x20 || mapMode == 0x30) mode = "LOROM-"; + if(mapMode == 0x21 || mapMode == 0x31) mode = "HIROM-"; + if(mapMode == 0x22 || mapMode == 0x32) mode = "SDD1-"; + if(mapMode == 0x23 || mapMode == 0x33) mode = "SA1-"; + if(mapMode == 0x25 || mapMode == 0x35) mode = "EXHIROM-"; + if(mapMode == 0x2a || mapMode == 0x3a) mode = "SPC7110-"; + + //many games will store an extra title character, overwriting the map mode + //further, ExLoROM mode is unofficial, and lacks a mapping mode value + if(!mode) { + if(headerAddress == 0x7fb0) mode = "LOROM-"; + if(headerAddress == 0xffb0) mode = "HIROM-"; + if(headerAddress == 0x407fb0) mode = "EXLOROM-"; + if(headerAddress == 0x40ffb0) mode = "EXHIROM-"; + } + + //this game's title ovewrites the map mode with '!' (0x21), but is a LOROM game + if(title() == "YUYU NO QUIZ DE GO!GO") mode = "LOROM-"; + + if(mode == "LOROM-" && headerAddress == 0x407fb0) mode = "EXLOROM-"; + + bool epsonRTC = false; + bool sharpRTC = false; + + if(serial() == "A9PJ") { + //Sufami Turbo (JPN) + board.append("ST-", mode); + } else if(serial() == "ZBSJ") { + //BS-X: Sore wa Namae o Nusumareta Machi no Monogatari (JPN) + board.append("BS-MCC-"); + } else if(serial() == "042J") { + //Super Game Boy 2 + board.append("GB-", mode); + } else if(serial().match("Z??J")) { + board.append("BS-", mode); + } else if(cartridgeTypeLo >= 0x3) { + if(cartridgeTypeHi == 0x0) board.append("NEC-", mode); + if(cartridgeTypeHi == 0x1) board.append("GSU-"); + if(cartridgeTypeHi == 0x2) board.append("OBC1-", mode); + if(cartridgeTypeHi == 0x3) board.append("SA1-"); + if(cartridgeTypeHi == 0x4) board.append("SDD1-"); + if(cartridgeTypeHi == 0x5) board.append(mode), sharpRTC = true; + if(cartridgeTypeHi == 0xe && cartridgeTypeLo == 0x3) board.append("GB-", mode); + if(cartridgeTypeHi == 0xf && cartridgeTypeLo == 0x5 && cartridgeSubType == 0x00) board.append("SPC7110-"); + if(cartridgeTypeHi == 0xf && cartridgeTypeLo == 0x9 && cartridgeSubType == 0x00) board.append("SPC7110-"), epsonRTC = true; + if(cartridgeTypeHi == 0xf && cartridgeSubType == 0x01) board.append("EXNEC-", mode); + if(cartridgeTypeHi == 0xf && cartridgeSubType == 0x02) board.append("ARM-", mode); + if(cartridgeTypeHi == 0xf && cartridgeSubType == 0x10) board.append("HITACHI-", mode); + } + if(!board) board.append(mode); + + if(ramSize() || expansionRamSize()) board.append("RAM-"); + if(epsonRTC) board.append("EPSONRTC-"); + if(sharpRTC) board.append("SHARPRTC-"); + + board.trimRight("-", 1L); + + if(board.beginsWith( "LOROM-RAM") && romSize() <= 0x200000) board.append("#A"); + if(board.beginsWith("NEC-LOROM-RAM") && romSize() <= 0x100000) board.append("#A"); + + //Tengai Makyou Zero (fan translation) + if(board.beginsWith("SPC7110-") && data.size() == 0x700000) board.prepend("EX"); + + return board; +} + +auto SuperFamicom::title() const -> string { + string label; + + for(uint n = 0; n < 0x15; n++) { + auto x = data[headerAddress + 0x10 + n]; + auto y = n == 0x14 ? 0 : data[headerAddress + 0x11 + n]; + + //null terminator (padding) + if(x == 0x00 || x == 0xff); + + //ASCII + else if(x >= 0x20 && x <= 0x7e) label.append((char)x); + + //Shift-JIS (half-width katakana) + else if(x == 0xa1) label.append("。"); + else if(x == 0xa2) label.append("「"); + else if(x == 0xa3) label.append("」"); + else if(x == 0xa4) label.append("、"); + else if(x == 0xa5) label.append("・"); + else if(x == 0xa6) label.append("ヲ"); + else if(x == 0xa7) label.append("ァ"); + else if(x == 0xa8) label.append("ィ"); + else if(x == 0xa9) label.append("ゥ"); + else if(x == 0xaa) label.append("ェ"); + else if(x == 0xab) label.append("ォ"); + else if(x == 0xac) label.append("ャ"); + else if(x == 0xad) label.append("ュ"); + else if(x == 0xae) label.append("ョ"); + else if(x == 0xaf) label.append("ッ"); + else if(x == 0xb0) label.append("ー"); + + else if(x == 0xb1) label.append( "ア"); + else if(x == 0xb2) label.append( "イ"); + else if(x == 0xb3) label.append(y == 0xde ? "ヴ" : "ウ"); + else if(x == 0xb4) label.append( "エ"); + else if(x == 0xb5) label.append( "オ"); + + else if(x == 0xb6) label.append(y == 0xde ? "ガ" : "カ"); + else if(x == 0xb7) label.append(y == 0xde ? "ギ" : "キ"); + else if(x == 0xb8) label.append(y == 0xde ? "グ" : "ク"); + else if(x == 0xb9) label.append(y == 0xde ? "ゲ" : "ケ"); + else if(x == 0xba) label.append(y == 0xde ? "ゴ" : "コ"); + + else if(x == 0xbb) label.append(y == 0xde ? "ザ" : "サ"); + else if(x == 0xbc) label.append(y == 0xde ? "ジ" : "シ"); + else if(x == 0xbd) label.append(y == 0xde ? "ズ" : "ス"); + else if(x == 0xbe) label.append(y == 0xde ? "ゼ" : "セ"); + else if(x == 0xbf) label.append(y == 0xde ? "ゾ" : "ソ"); + + else if(x == 0xc0) label.append(y == 0xde ? "ダ" : "タ"); + else if(x == 0xc1) label.append(y == 0xde ? "ヂ" : "チ"); + else if(x == 0xc2) label.append(y == 0xde ? "ヅ" : "ツ"); + else if(x == 0xc3) label.append(y == 0xde ? "デ" : "テ"); + else if(x == 0xc4) label.append(y == 0xde ? "ド" : "ト"); + + else if(x == 0xc5) label.append("ナ"); + else if(x == 0xc6) label.append("ニ"); + else if(x == 0xc7) label.append("ヌ"); + else if(x == 0xc8) label.append("ネ"); + else if(x == 0xc9) label.append("ノ"); + + else if(x == 0xca) label.append(y == 0xdf ? "パ" : y == 0xde ? "バ" : "ハ"); + else if(x == 0xcb) label.append(y == 0xdf ? "ピ" : y == 0xde ? "ビ" : "ヒ"); + else if(x == 0xcc) label.append(y == 0xdf ? "プ" : y == 0xde ? "ブ" : "フ"); + else if(x == 0xcd) label.append(y == 0xdf ? "ペ" : y == 0xde ? "ベ" : "ヘ"); + else if(x == 0xce) label.append(y == 0xdf ? "ポ" : y == 0xde ? "ボ" : "ホ"); + + else if(x == 0xcf) label.append("マ"); + else if(x == 0xd0) label.append("ミ"); + else if(x == 0xd1) label.append("ム"); + else if(x == 0xd2) label.append("メ"); + else if(x == 0xd3) label.append("モ"); + + else if(x == 0xd4) label.append("ヤ"); + else if(x == 0xd5) label.append("ユ"); + else if(x == 0xd6) label.append("ヨ"); + + else if(x == 0xd7) label.append("ラ"); + else if(x == 0xd8) label.append("リ"); + else if(x == 0xd9) label.append("ル"); + else if(x == 0xda) label.append("レ"); + else if(x == 0xdb) label.append("ロ"); + + else if(x == 0xdc) label.append("ワ"); + else if(x == 0xdd) label.append("ン"); + + else if(x == 0xde) label.append("\xef\xbe\x9e"); //dakuten + else if(x == 0xdf) label.append("\xef\xbe\x9f"); //handakuten + + //unknown + else label.append("?"); + + //(han)dakuten skip + if(y == 0xde && x == 0xb3) n++; + if(y == 0xde && x >= 0xb6 && x <= 0xc4) n++; + if(y == 0xde && x >= 0xca && x <= 0xce) n++; + if(y == 0xdf && x >= 0xca && y <= 0xce) n++; + } + + return label.strip(); +} + +auto SuperFamicom::serial() const -> string { + char A = data[headerAddress + 0x02]; //game type + char B = data[headerAddress + 0x03]; //game code + char C = data[headerAddress + 0x04]; //game code + char D = data[headerAddress + 0x05]; //region code (new; sometimes ambiguous) + + auto valid = [](char n) { return (n >= '0' && n <= '9') || (n >= 'A' && n <= 'Z'); }; + if(data[headerAddress + 0x2a] == 0x33 && valid(A) && valid(B) & valid(C) & valid(D)) { + return {A, B, C, D}; + } + + return ""; +} + +auto SuperFamicom::romSize() const -> uint { + return size() - firmwareRomSize(); +} + +auto SuperFamicom::programRomSize() const -> uint { + if(board().beginsWith("SPC7110-")) return 0x100000; + if(board().beginsWith("EXSPC7110-")) return 0x100000; + return romSize(); +} + +auto SuperFamicom::dataRomSize() const -> uint { + if(board().beginsWith("SPC7110-")) return romSize() - 0x100000; + if(board().beginsWith("EXSPC7110-")) return 0x500000; + return 0; +} + +auto SuperFamicom::expansionRomSize() const -> uint { + if(board().beginsWith("EXSPC7110-")) return 0x100000; + return 0; +} + +//detect if any firmware is appended to the ROM image, and return its size if so +auto SuperFamicom::firmwareRomSize() const -> uint { + auto cartridgeTypeLo = data[headerAddress + 0x26] & 15; + auto cartridgeTypeHi = data[headerAddress + 0x26] >> 4; + auto cartridgeSubType = data[headerAddress + 0x0f]; + + if(serial() == "042J" || (cartridgeTypeLo == 0x3 && cartridgeTypeHi == 0xe)) { + //Game Boy + if((size() & 0x7fff) == 0x100) return 0x100; + } + + if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0xf && cartridgeSubType == 0x10) { + //Hitachi HG51BS169 + if((size() & 0x7fff) == 0xc00) return 0xc00; + } + + if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0x0) { + //NEC uPD7725 + if((size() & 0x7fff) == 0x2000) return 0x2000; + } + + if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0xf && cartridgeSubType == 0x01) { + //NEC uPD96050 + if((size() & 0xffff) == 0xd000) return 0xd000; + } + + if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0xf && cartridgeSubType == 0x02) { + //ARM6 + if((size() & 0x3ffff) == 0x28000) return 0x28000; + } + + return 0; +} + +auto SuperFamicom::ramSize() const -> uint { + auto ramSize = data[headerAddress + 0x28] & 15; + if(ramSize > 8) ramSize = 8; + if(ramSize > 0) return 1024 << ramSize; + return 0; +} + +auto SuperFamicom::expansionRamSize() const -> uint { + if(data[headerAddress + 0x2a] == 0x33) { + auto ramSize = data[headerAddress + 0x0d] & 15; + if(ramSize > 8) ramSize = 8; + if(ramSize > 0) return 1024 << ramSize; + } + if((data[headerAddress + 0x26] >> 4) == 1) { + //GSU: Starfox / Starwing lacks an extended header; but still has expansion RAM + return 0x8000; + } + return 0; +} + +auto SuperFamicom::nonVolatile() const -> bool { + auto cartridgeTypeLo = data[headerAddress + 0x26] & 15; + return cartridgeTypeLo == 0x2 || cartridgeTypeLo == 0x5 || cartridgeTypeLo == 0x6; +} + +auto SuperFamicom::scoreHeader(uint address) -> uint { + int score = 0; + if(size() < address + 0x50) return score; + + uint8_t mapMode = data[address + 0x25] & ~0x10; //ignore FastROM bit + uint16_t complement = data[address + 0x2c] << 0 | data[address + 0x2d] << 8; + uint16_t checksum = data[address + 0x2e] << 0 | data[address + 0x2f] << 8; + uint16_t resetVector = data[address + 0x4c] << 0 | data[address + 0x4d] << 8; + if(resetVector < 0x8000) return score; //$00:0000-7fff is never ROM data + + uint8_t opcode = data[(address & ~0x7fff) | (resetVector & 0x7fff)]; //first instruction executed + + //most likely opcodes + if(opcode == 0x78 //sei + || opcode == 0x18 //clc (clc; xce) + || opcode == 0x38 //sec (sec; xce) + || opcode == 0x9c //stz $nnnn (stz $4200) + || opcode == 0x4c //jmp $nnnn + || opcode == 0x5c //jml $nnnnnn + ) score += 8; + + //plausible opcodes + if(opcode == 0xc2 //rep #$nn + || opcode == 0xe2 //sep #$nn + || opcode == 0xad //lda $nnnn + || opcode == 0xae //ldx $nnnn + || opcode == 0xac //ldy $nnnn + || opcode == 0xaf //lda $nnnnnn + || opcode == 0xa9 //lda #$nn + || opcode == 0xa2 //ldx #$nn + || opcode == 0xa0 //ldy #$nn + || opcode == 0x20 //jsr $nnnn + || opcode == 0x22 //jsl $nnnnnn + ) score += 4; + + //implausible opcodes + if(opcode == 0x40 //rti + || opcode == 0x60 //rts + || opcode == 0x6b //rtl + || opcode == 0xcd //cmp $nnnn + || opcode == 0xec //cpx $nnnn + || opcode == 0xcc //cpy $nnnn + ) score -= 4; + + //least likely opcodes + if(opcode == 0x00 //brk #$nn + || opcode == 0x02 //cop #$nn + || opcode == 0xdb //stp + || opcode == 0x42 //wdm + || opcode == 0xff //sbc $nnnnnn,x + ) score -= 8; + + if(checksum + complement == 0xffff) score += 4; + + if(address == 0x7fb0 && mapMode == 0x20) score += 2; + if(address == 0xffb0 && mapMode == 0x21) score += 2; + + return max(0, score); +} + +auto SuperFamicom::firmwareARM() const -> string { + return "ST018"; +} + +auto SuperFamicom::firmwareEXNEC() const -> string { + if(title() == "EXHAUST HEAT2") return "ST010"; + if(title() == "F1 ROC II") return "ST010"; + if(title() == "2DAN MORITA SHOUGI") return "ST011"; + return "ST010"; +} + +auto SuperFamicom::firmwareGB() const -> string { + if(title() == "Super GAMEBOY") return "SGB1"; + if(title() == "Super GAMEBOY2") return "SGB2"; + return "SGB1"; +} + +auto SuperFamicom::firmwareHITACHI() const -> string { + return "Cx4"; +} + +auto SuperFamicom::firmwareNEC() const -> string { + if(title() == "PILOTWINGS") return "DSP1"; + if(title() == "DUNGEON MASTER") return "DSP2"; + if(title() == "SDガンダムGX") return "DSP3"; + if(title() == "PLANETS CHAMP TG3000") return "DSP4"; + if(title() == "TOP GEAR 3000") return "DSP4"; + return "DSP1B"; +} + +} diff --git a/jg.cpp b/jg.cpp new file mode 100644 index 0000000..75c03d3 --- /dev/null +++ b/jg.cpp @@ -0,0 +1,914 @@ +/* + * bsnes-jg - Super Nintendo emulator + * + * Copyright (C) 2004-2020 byuu + * Copyright (C) 2020 Rupert Carmichael + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, specifically version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +using namespace nall; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SAMPLERATE 48000 +#define FRAMERATE 60 +#define FRAMERATE_PAL 50 +#define CHANNELS 2 +#define NUMINPUTS 2 + +#define ASPECT_NTSC 1.306122 +#define ASPECT_PAL 1.4257812 + +#define TIMING_NTSC 60.098812 +#define TIMING_PAL 50.006979 + +static jg_cb_audio_t jg_cb_audio; +static jg_cb_frametime_t jg_cb_frametime; +static jg_cb_log_t jg_cb_log; +static jg_cb_rumble_t jg_cb_rumble; +static jg_cb_settings_read_t jg_cb_settings_read; + +static jg_coreinfo_t coreinfo = { + "bsnes", "bsnes-jg", "115", "snes", NUMINPUTS, JG_HINT_VIDEO_INTERNAL +}; + +static jg_videoinfo_t vidinfo = { + JG_PIXFMT_RGB1555, // pixfmt + 2304, // wmax + 2160, // hmax + 256, // w + 224, // h + 0, // x + 8, // y + 1024, // p + 8.0/7.0, // aspect + NULL +}; + +static jg_audioinfo_t audinfo = { + JG_SAMPFMT_FLT32, + SAMPLERATE, + CHANNELS, + (SAMPLERATE / FRAMERATE) * CHANNELS, + NULL +}; + +static jg_pathinfo_t pathinfo; +static jg_gameinfo_t gameinfo; +static jg_inputinfo_t inputinfo[NUMINPUTS]; +static jg_inputstate_t *input_device[NUMINPUTS]; + +// Emulator settings +static jg_setting_t settings_bsnes[] = { // name, default, min, max + { "aspect_ratio", 0, 0, 1 }, // 0 = 8:7, 1 = Auto Region +}; + +enum { + ASPECT, +}; + +static uint16_t audio_buffer_index = 0; +static uint16_t audio_buffer_max = audinfo.spf; + +static int vidmult = 1; +static int ss_offset_x = 0; +static int ss_offset_y = 0; + +static const unsigned char iplrom[64] = { + 0xcd, 0xef, 0xbd, 0xe8, 0x00, 0xc6, 0x1d, 0xd0, + 0xfc, 0x8f, 0xaa, 0xf4, 0x8f, 0xbb, 0xf5, 0x78, + 0xcc, 0xf4, 0xd0, 0xfb, 0x2f, 0x19, 0xeb, 0xf4, + 0xd0, 0xfc, 0x7e, 0xf4, 0xd0, 0x0b, 0xe4, 0xf5, + 0xcb, 0xf4, 0xd7, 0x00, 0xfc, 0xd0, 0xf3, 0xab, + 0x01, 0x10, 0xef, 0x7e, 0xf4, 0x10, 0xeb, 0xba, + 0xf6, 0xda, 0x00, 0xba, 0xf4, 0xc4, 0xf4, 0xdd, + 0x5d, 0xd0, 0xdb, 0x1f, 0x00, 0x00, 0xc0, 0xff +}; + +static Emulator::Interface *emulator; + +struct Program : Emulator::Platform { + Program(); + ~Program(); + + auto open(uint id, string name, vfs::file::mode mode, bool required) -> + shared_pointer override; + auto load(uint id, string name, string type, vector options = {}) -> + Emulator::Platform::Load override; + auto videoFrame(const uint16* data, uint pitch, uint width, uint height, + uint scale) -> void override; + auto audioFrame(const double* samples, uint channels) -> void override; + auto inputPoll(uint port, uint device, uint input) -> int16 override; + auto inputRumble(uint port, uint device, uint input, bool enable) -> + void override; + + auto load() -> void; + auto loadFile(string location) -> vector; + auto loadSuperFamicom(string location) -> bool; + auto loadGameBoy(string location) -> bool; + auto loadBSMemory(string location) -> bool; + + auto save() -> void; + + auto openRomSuperFamicom(string name, vfs::file::mode mode) -> + shared_pointer; + auto openRomGameBoy(string name, vfs::file::mode mode) -> + shared_pointer; + auto openRomBSMemory(string name, vfs::file::mode mode) -> + shared_pointer; + + auto hackPatchMemory(vector& data) -> void; + + string base_name; + + bool overscan = true; + +public: + struct Game { + explicit operator bool() const { return (bool)location; } + + string option; + string location; + string manifest; + Markup::Node document; + boolean patched; + boolean verified; + }; + + struct SuperFamicom : Game { + string title; + string region; + vector program; + vector data; + vector expansion; + vector firmware; + } superFamicom; + + struct GameBoy : Game { + vector program; + } gameBoy; + + struct BSMemory : Game { + vector program; + } bsMemory; +}; + +static Program *program = nullptr; + +Program::Program() { + Emulator::platform = this; +} + +Program::~Program() { + delete emulator; +} + +auto Program::save() -> void { + if(!emulator->loaded()) return; + emulator->save(); +} + +auto Program::open(uint id, string name, vfs::file::mode mode, bool required) -> + shared_pointer { + + shared_pointer result; + + if (name == "ipl.rom" && mode == vfs::file::mode::read) { + result = vfs::memory::file::open(iplrom, sizeof(iplrom)); + } + if (name == "boards.bml" && mode == vfs::file::mode::read) { + string boardspath = {pathinfo.core, "/boards.bml"}; + return vfs::fs::file::open(boardspath, mode); + } + + if (id == 1) { //Super Famicom + if (name == "manifest.bml" && mode == vfs::file::mode::read) { + result = vfs::memory::file::open( + superFamicom.manifest.data(), + superFamicom.manifest.size()); + } + else if (name == "program.rom" && mode == vfs::file::mode::read) { + result = vfs::memory::file::open(superFamicom.program.data(), + superFamicom.program.size()); + } + else if (name == "data.rom" && mode == vfs::file::mode::read) { + result = vfs::memory::file::open(superFamicom.data.data(), + superFamicom.data.size()); + } + else if (name == "expansion.rom" && mode == vfs::file::mode::read) { + result = vfs::memory::file::open(superFamicom.expansion.data(), + superFamicom.expansion.size()); + } + else { + result = openRomSuperFamicom(name, mode); + } + } + else if (id == 2) { //Game Boy + if (name == "manifest.bml" && mode == vfs::file::mode::read) { + result = vfs::memory::file::open(gameBoy.manifest.data(), + gameBoy.manifest.size()); + } + else if (name == "program.rom" && mode == vfs::file::mode::read) { + result = vfs::memory::file::open(gameBoy.program.data(), + gameBoy.program.size()); + } + else { + result = openRomGameBoy(name, mode); + } + } + else if (id == 3) { //BS Memory + if (name == "manifest.bml" && mode == vfs::file::mode::read) { + result = vfs::memory::file::open(bsMemory.manifest.data(), + bsMemory.manifest.size()); + } + else if (name == "program.rom" && mode == vfs::file::mode::read) { + result = vfs::memory::file::open(bsMemory.program.data(), + bsMemory.program.size()); + } + else if(name == "program.flash") { + //writes are not flushed to disk in bsnes + result = vfs::memory::file::open(bsMemory.program.data(), + bsMemory.program.size()); + } + else { + result = openRomBSMemory(name, mode); + } + } + + return result; +} + +auto Program::load() -> void { + emulator->unload(); + emulator->load(); + + // per-game hack overrides + auto title = superFamicom.title; + auto region = superFamicom.region; + + //sometimes menu options are skipped over in the main menu with cycle-based + //joypad polling + if (title == "Arcades Greatest Hits") + emulator->configure("Hacks/CPU/FastJoypadPolling", true); + + //the start button doesn't work in this game with cycle-based joypad polling + else if (title == "TAIKYOKU-IGO Goliath") + emulator->configure("Hacks/CPU/FastJoypadPolling", true); + + //holding up or down on the menu quickly cycles through options instead of + //stopping after each button press + else if (title == "WORLD MASTERS GOLF") + emulator->configure("Hacks/CPU/FastJoypadPolling", true); + + //relies on mid-scanline rendering techniques + else if (title == "AIR STRIKE PATROL" || title == "DESERT FIGHTER") + emulator->configure("Hacks/PPU/Fast", false); + + //the dialogue text is blurry due to an issue in the scanline-based + //renderer's color math support + else if (title == "マーヴェラス") + emulator->configure("Hacks/PPU/Fast", false); + + //stage 2 uses pseudo-hires in a way that's not compatible with the + //scanline-based renderer + else if (title == "SFC クレヨンシンチャン") + emulator->configure("Hacks/PPU/Fast", false); + + //title screen game select (after choosing a game) changes OAM tiledata + //address mid-frame. This is only supported by the cycle-based PPU renderer + else if (title == "Winter olympics") + emulator->configure("Hacks/PPU/Fast", false); + + //title screen shows remnants of the flag after choosing a language with the + //scanline-based renderer + else if (title == "WORLD CUP STRIKER") + emulator->configure("Hacks/PPU/Fast", false); + + //relies on cycle-accurate writes to the echo buffer + else if (title == "KOUSHIEN_2") + emulator->configure("Hacks/DSP/Fast", false); + + //will hang immediately + else if (title == "RENDERING RANGER R2") + emulator->configure("Hacks/DSP/Fast", false); + + //will hang sometimes in the "Bach in Time" stage + else if (title == "BUBSY II" && region == "PAL") + emulator->configure("Hacks/DSP/Fast", false); + + //fixes for an errant scanline on the title screen due to writing to PPU + //registers too late + else if (title == "ADVENTURES OF FRANKEN" && region == "PAL") + emulator->configure("Hacks/PPU/RenderCycle", 32); + + else if (title == "FIREPOWER 2000" || title == "SUPER SWIV") + emulator->configure("Hacks/PPU/RenderCycle", 32); + + else if (title == "NHL '94" || title == "NHL PROHOCKEY'94") + emulator->configure("Hacks/PPU/RenderCycle", 32); + + else if (title == "Sugoro Quest++") + emulator->configure("Hacks/PPU/RenderCycle", 128); + + else if (emulator->configuration("Hacks/Hotfixes")) { + //this game transfers uninitialized memory into video RAM: this can + //cause a row of invalid tiles to appear in the background of stage 12. + //this one is a bug in the original game, so only enable it if the + //hotfixes option has been enabled. + if (title == "The Hurricanes") + emulator->configure("Hacks/Entropy", "None"); + + //Frisky Tom attract sequence sometimes hangs when WRAM is initialized + //to pseudo-random patterns + else if (title == "ニチブツ・アーケード・クラシックス") + emulator->configure("Hacks/Entropy", "None"); + } +} + +auto Program::load(uint id, string name, string type, vector options) -> + Emulator::Platform::Load { + + if (id == 1) { + if (loadSuperFamicom(superFamicom.location)) { + return {id, superFamicom.region}; + } + } + else if (id == 2) { + if (loadGameBoy(gameBoy.location)) { + return { id, NULL }; + } + } + else if (id == 3) { + if (loadBSMemory(bsMemory.location)) { + return { id, NULL }; + } + } + return { id, options(0) }; +} + +auto Program::videoFrame(const uint16* data, uint pitch, uint width, + uint height, uint scale) -> void { + + //print("p: ", pitch, " w: ", width, " h: ", height, "\n"); + vidmult = height / 240; + vidinfo.y = 8 * vidmult; + height -= 2 * vidinfo.y; + + vidinfo.w = width; + vidinfo.h = height; + vidinfo.p = pitch / 2; // Divide by pixel size - 16-bit pixels == 2 + vidinfo.buf = (void*)data; +} + +auto Program::audioFrame(const double* samples, uint channels) -> void { + float *abuf = (float*)audinfo.buf; + abuf[audio_buffer_index++] = (float)samples[0]; + abuf[audio_buffer_index++] = (float)samples[1]; +} + +static uint8_t imap[12] = { 0, 1, 2, 3, 7, 6, 9, 8, 10, 11, 4, 5 }; + +auto pollInputDevices(uint port, uint device, uint input) -> int16 { + //print("port: ", port, " device: ", device, " input: ", input, "\n"); + if (device == SuperFamicom::ID::Device::SuperScope) { + switch (input) { + case 0: // X + return (input_device[port]->coord[0] / vidmult) + ss_offset_x; + case 1: // Y + return (input_device[port]->coord[1] / vidmult) + ss_offset_y; + case 2: { // Trigger + int ret = 0; + if (input_device[port]->button[1]) { // Offscreen + input_device[port]->coord[0] = 1026; + ret = 1; + } + else + ret = input_device[port]->button[0]; + return ret; + } + case 3: // Cursor + return input_device[port]->button[2]; + case 4: // Turbo + return input_device[port]->button[3]; + case 5: // Pause + return input_device[port]->button[4]; + default: + return 0; + } + } + /*else if (device == SuperFamicom::ID::Device::Justifier) { + switch (input) { + case 0: // X + return (input_device[port]->coord[0] / vidmult) + ss_offset_x; + case 1: // Y + return (input_device[port]->coord[1] / vidmult) + ss_offset_y; + case 2: {// Trigger + int ret = 0; + if (input_device[port]->button[1]) { // Offscreen + input_device[port]->coord[0] = 1026; + ret = 1; + } + else + ret = input_device[port]->button[0]; + return ret; + } + case 3: // Start + return input_device[port]->button[2]; + default: + return 0; + } + }*/ + + return port > 1 ? 0 : input_device[port]->button[imap[input]]; +} + +auto Program::inputPoll(uint port, uint device, uint input) -> int16 { + return pollInputDevices(port, device, input); +} + +auto Program::inputRumble(uint port, uint device, uint input, bool enable) -> + void { +} + +auto Program::openRomSuperFamicom(string name, vfs::file::mode mode) -> + shared_pointer { + + if (name == "program.rom" && mode == vfs::file::mode::read) { + return vfs::memory::file::open(superFamicom.program.data(), + superFamicom.program.size()); + } + + if (name == "data.rom" && mode == vfs::file::mode::read) { + return vfs::memory::file::open(superFamicom.data.data(), + superFamicom.data.size()); + } + + if (name == "expansion.rom" && mode == vfs::file::mode::read) { + return vfs::memory::file::open(superFamicom.expansion.data(), + superFamicom.expansion.size()); + } + + if (name == "msu1/data.rom") { + return vfs::fs::file::open({Location::notsuffix(superFamicom.location), + ".msu"}, mode); + } + + if (name.match("msu1/track*.pcm")) { + name.trimLeft("msu1/track", 1L); + return vfs::fs::file::open({Location::notsuffix(superFamicom.location), + name}, mode); + } + + if (name == "save.ram") { + string save_path = { pathinfo.save, "/", gameinfo.name, ".srm" }; + const char *save = nullptr; + return vfs::fs::file::open(save_path, mode); + } + + if (name == "download.ram") { + string ram_path = { pathinfo.save, "/", gameinfo.name, ".psr" }; + const char *save = nullptr; + return vfs::fs::file::open(ram_path, mode); + } + + return {}; +} + +auto Program::openRomGameBoy(string name, vfs::file::mode mode) -> + shared_pointer { + + if (name == "program.rom" && mode == vfs::file::mode::read) { + return vfs::memory::file::open(gameBoy.program.data(), + gameBoy.program.size()); + } + + if (name == "save.ram") { + string save_path = { pathinfo.save, "/", gameinfo.name, ".srm" }; + const char *save = nullptr; + return vfs::fs::file::open(save_path, mode); + } + + if (name == "time.rtc") { + string save_path = { pathinfo.save, "/", gameinfo.name, ".rtc" }; + const char *save = nullptr; + return vfs::fs::file::open(save_path, mode); + } + + return {}; +} + +auto Program::openRomBSMemory(string name, vfs::file::mode mode) -> + shared_pointer { + + if (name == "program.rom" && mode == vfs::file::mode::read) { + return vfs::memory::file::open(bsMemory.program.data(), + bsMemory.program.size()); + } + + if (name == "program.flash") { + //writes are not flushed to disk + return vfs::memory::file::open(bsMemory.program.data(), + bsMemory.program.size()); + } + + return {}; +} + +auto Program::loadFile(string location) -> vector { + if(Location::suffix(location).downcase() == ".zip") { + Decode::ZIP archive; + if (archive.open(location)) { + for (auto& file : archive.file) { + auto type = Location::suffix(file.name).downcase(); + if (type == ".sfc" || type == ".smc" || type == ".gb" || + type == ".gbc" || type == ".bs" || type == ".st") { + return archive.extract(file); + } + } + } + return {}; + } + else if(Location::suffix(location).downcase() == ".7z") { + return LZMA::extract(location); + } + else { + return file::read(location); + } +} + +auto Program::loadSuperFamicom(string location) -> bool { + vector rom; + rom = loadFile(location); + + if (rom.size() < 0x8000) return false; + + //assume ROM and IPS agree on whether a copier header is present + //superFamicom.patched = applyPatchIPS(rom, location); + if ((rom.size() & 0x7fff) == 512) { + //remove copier header + memory::move(&rom[0], &rom[512], rom.size() - 512); + rom.resize(rom.size() - 512); + } + + auto heuristics = Heuristics::SuperFamicom(rom, location); + auto sha256 = Hash::SHA256(rom).digest(); + + superFamicom.title = heuristics.title(); + superFamicom.region = heuristics.videoRegion(); + superFamicom.manifest = heuristics.manifest(); + + hackPatchMemory(rom); + superFamicom.document = BML::unserialize(superFamicom.manifest); + superFamicom.location = location; + + uint offset = 0; + if (auto size = heuristics.programRomSize()) { + superFamicom.program.resize(size); + memory::copy(&superFamicom.program[0], &rom[offset], size); + offset += size; + } + if (auto size = heuristics.dataRomSize()) { + superFamicom.data.resize(size); + memory::copy(&superFamicom.data[0], &rom[offset], size); + offset += size; + } + if (auto size = heuristics.expansionRomSize()) { + superFamicom.expansion.resize(size); + memory::copy(&superFamicom.expansion[0], &rom[offset], size); + offset += size; + } + if (auto size = heuristics.firmwareRomSize()) { + superFamicom.firmware.resize(size); + memory::copy(&superFamicom.firmware[0], &rom[offset], size); + offset += size; + } + return true; +} + +auto Program::loadGameBoy(string location) -> bool { + vector rom; + rom = loadFile(location); + + if (rom.size() < 0x4000) return false; + + auto heuristics = Heuristics::GameBoy(rom, location); + auto sha256 = Hash::SHA256(rom).digest(); + + gameBoy.manifest = heuristics.manifest(); + gameBoy.document = BML::unserialize(gameBoy.manifest); + gameBoy.location = location; + gameBoy.program = rom; + + return true; +} + +auto Program::loadBSMemory(string location) -> bool { + string manifest; + vector rom; + rom = loadFile(location); + + if (rom.size() < 0x8000) return false; + + auto heuristics = Heuristics::BSMemory(rom, location); + auto sha256 = Hash::SHA256(rom).digest(); + + bsMemory.manifest = manifest ? manifest : heuristics.manifest(); + bsMemory.document = BML::unserialize(bsMemory.manifest); + bsMemory.location = location; + + bsMemory.program = rom; + return true; +} + +auto Program::hackPatchMemory(vector& data) -> void { + auto title = superFamicom.title; + + if(title == "Satellaview BS-X" && data.size() >= 0x100000) { + //BS-X: Sore wa Namae o Nusumareta Machi no Monogatari (JPN) (1.1) + //disable limited play check for BS Memory flash cartridges + //benefit: allow locked out BS Memory flash games to play without manual + //header patching. + //detriment: BS Memory ROM cartridges will cause the game to hang in the + //load menu + if(data[0x4a9b] == 0x10) data[0x4a9b] = 0x80; + if(data[0x4d6d] == 0x10) data[0x4d6d] = 0x80; + if(data[0x4ded] == 0x10) data[0x4ded] = 0x80; + if(data[0x4e9a] == 0x10) data[0x4e9a] = 0x80; + } +} + +// Jolly Good API Calls +void jg_set_cb_audio(jg_cb_audio_t func) { + jg_cb_audio = func; +} + +void jg_set_cb_frametime(jg_cb_frametime_t func) { + jg_cb_frametime = func; +} + +void jg_set_cb_log(jg_cb_log_t func) { + jg_cb_log = func; +} + +void jg_set_cb_rumble(jg_cb_rumble_t func) { + jg_cb_rumble = func; +} + +void jg_set_cb_settings_read(jg_cb_settings_read_t func) { + jg_cb_settings_read = func; +} + +int jg_init() { + jg_cb_settings_read(settings_bsnes, + sizeof(settings_bsnes) / sizeof(jg_setting_t)); + emulator = new SuperFamicom::Interface; + program = new Program; + return 1; +} + +void jg_deinit() { + delete program; +} + +void jg_reset(int hard) { + emulator->reset(); +} + +void jg_exec_frame() { + emulator->run(); + jg_cb_audio(audio_buffer_index); + audio_buffer_index = 0; +} + +int jg_game_load() { + emulator->configure("Audio/Frequency", SAMPLERATE); + + emulator->configure("Video/BlurEmulation", false); + + emulator->configure("Hacks/Entropy", "Low"); + emulator->configure("Hacks/Hotfixes", false); + + emulator->configure("Hacks/CPU/Overclock", 100); + emulator->configure("Hacks/CPU/FastMath", false); + emulator->configure("Hacks/SA1/Overclock", 100); + emulator->configure("Hacks/SuperFX/Overclock", 100); + + emulator->configure("Hacks/PPU/Fast", false); // default true + emulator->configure("Hacks/PPU/Deinterlace", false); + emulator->configure("Hacks/PPU/NoSpriteLimit", false); + emulator->configure("Hacks/PPU/NoVRAMBlocking", false); + emulator->configure("Hacks/PPU/Mode7/Scale", 4); + emulator->configure("Hacks/PPU/Mode7/Perspective", false); + emulator->configure("Hacks/PPU/Mode7/Supersample", false); + emulator->configure("Hacks/PPU/Mode7/Mosaic", false); + + emulator->configure("Hacks/DSP/Fast", false); // default true + emulator->configure("Hacks/DSP/Cubic", false); + emulator->configure("Hacks/DSP/EchoShadow", false); + emulator->configure("Hacks/Coprocessor/DelayedSync", false); // default true + emulator->configure("Hacks/Coprocessor/PreferHLE", true); + + // Overscan should be drawn because the frontend does the clipping + program->overscan = true; + + // Load the game + if (string(gameinfo.path).endsWith(".gb") || + string(gameinfo.path).endsWith(".gbc")) { + //string sgb_bios = string(pathinfo.bios, "/Super Game Boy (JU).sfc"); + //string sgb_bios = string(pathinfo.bios, "/Super Game Boy (UE).sfc"); + string sgb_bios = string(pathinfo.bios, "/Super Game Boy 2 (J).sfc"); + if (!file::exists(sgb_bios)) { + jg_cb_log(JG_LOG_ERR, + "Missing BIOS file \'Super Game Boy 2 (J).sfc\', exiting...\n"); + return 0; + } + + program->superFamicom.location = sgb_bios; + program->gameBoy.location = string(gameinfo.path); + } + else if (string(gameinfo.path).endsWith(".bs")) { + string bsx_bios = string(pathinfo.bios, "/BsxBios.sfc"); + if (!file::exists(bsx_bios)) { + jg_cb_log(JG_LOG_ERR, + "Missing BIOS file \'BsxBios.sfc\', exiting...\n"); + return 0; + } + program->superFamicom.location = bsx_bios; + program->bsMemory.location = string(gameinfo.path); + } + else { + program->superFamicom.location = string(gameinfo.path); + } + + program->base_name = string(gameinfo.path); + program->load(); + + // Set up inputs + string title = program->superFamicom.title; + bool superscope = false; + + // There must be a better way of doing this. But nall must be killed first. + // The requirement for offsets suggests something broken at deeper levels. + if (title == "BAZOOKA BLITZKRIEG" || title == "SFC DESTRUCTIVE") { + superscope = true; + ss_offset_x = 1; + ss_offset_y = 19; + } + else if(title == "T2 ARCADE") { + superscope = true; + ss_offset_x = 36; + ss_offset_y = -14; + } + else if(title == "X ZONE") { + superscope = true; + ss_offset_x = 40; + ss_offset_y = -7; + } + // Games that do not require an offset + else if (title == "BATTLE CLASH" || title == "Hunt for Red October" || + title == "LAMBORGHINI AMERICAN" || title == "METAL COMBAT" || + title == "OPERATION THUNDERBOLT" || title == "SUPER SCOPE 6" || + title == "TINSTAR" || title == "YOSHI'S SAFARI") { + superscope = true; + } + + // Default input devices are SNES Controllers + inputinfo[0] = (jg_inputinfo_t){JG_INPUT_CONTROLLER, 0, + "pad1", "Controller 1", defs_snespad, 0, NDEFS_SNESPAD}; + emulator->connect(SuperFamicom::ID::Port::Controller1, + SuperFamicom::ID::Device::Gamepad); + + inputinfo[1] = (jg_inputinfo_t){JG_INPUT_CONTROLLER, 1, + "pad2", "Controller 2", defs_snespad, 0, NDEFS_SNESPAD}; + emulator->connect(SuperFamicom::ID::Port::Controller2, + SuperFamicom::ID::Device::Gamepad);//*/ + + /*inputinfo[0] = (jg_inputinfo_t){JG_INPUT_POINTER, 0, + "mouse", "SNES Mouse", defs_snesmouse, 0, NDEFS_SNESMOUSE}; + emulator->connect(SuperFamicom::ID::Port::Controller1, + SuperFamicom::ID::Device::Mouse);//*/ + + // Plug in a Super Scope if the game supports it + if (superscope) { + inputinfo[1] = (jg_inputinfo_t){JG_INPUT_GUN, 1, + "superscope", "Super Scope", defs_superscope, 0, NDEFS_SUPERSCOPE}; + emulator->connect(SuperFamicom::ID::Port::Controller2, + SuperFamicom::ID::Device::SuperScope); + } + + // Justifier support appears fundamentally broken at the core level + /*inputinfo[1] = (jg_inputinfo_t){JG_INPUT_GUN, 1, + "justifier", "Justifier", defs_snesjustifier, 0, NDEFS_SNESJUSTIFIER}; + emulator->connect(SuperFamicom::ID::Port::Controller2, + SuperFamicom::ID::Device::Justifier);*/ + + // Set the aspect ratio + if (settings_bsnes[ASPECT].value) + vidinfo.aspect = program->superFamicom.region == "PAL" ? + ASPECT_PAL : ASPECT_NTSC; + + // Audio and timing adjustments + if (program->superFamicom.region == "PAL") { + audinfo.spf = (SAMPLERATE / FRAMERATE_PAL) * CHANNELS; + jg_cb_frametime(TIMING_PAL); + } + else { + jg_cb_frametime(TIMING_NTSC); + } + + emulator->power(); // Power up! + + return 1; +} + +int jg_game_unload() { + program->save(); + emulator->unload(); + return 1; +} + +int jg_state_load(const char *filename) { + vector memory; + memory = file::read(filename); + auto serializerRLE = Decode::RLE<1>({memory.data() + 3 * sizeof(uint), + memory.size() - 3 * sizeof(uint)}); + serializer s{serializerRLE.data(), (uint)serializerRLE.size()}; + return emulator->unserialize(s); +} + +int jg_state_save(const char *filename) { + serializer s = emulator->serialize(); + if (!s.size()) return 0; + + auto serializerRLE = Encode::RLE<1>({s.data(), s.size()}); + + vector saveState; + saveState.resize(3 * sizeof(uint)); + memory::writel(saveState.data() + 0 * sizeof(uint), + 0x5a22'0000); + memory::writel(saveState.data() + 1 * sizeof(uint), + serializerRLE.size()); + memory::writel(saveState.data() + 2 * sizeof(uint), 0); + saveState.append(serializerRLE); + + return file::write(filename, saveState); +} + +void jg_media_select() { +} + +void jg_media_insert() { +} + +// JG Functions that return values to the frontend +jg_coreinfo_t* jg_get_coreinfo(const char *sys) { return &coreinfo; } +jg_videoinfo_t* jg_get_videoinfo() { return &vidinfo; } +jg_audioinfo_t* jg_get_audioinfo() { return &audinfo; } +jg_inputinfo_t* jg_get_inputinfo(int port) { return &inputinfo[port]; } + +void jg_setup_video() { } +void jg_setup_audio() { } + +void jg_set_inputstate(jg_inputstate_t *ptr, int port) { + input_device[port] = ptr; +} + +void jg_set_gameinfo(jg_gameinfo_t info) { gameinfo = info; } +void jg_set_paths(jg_pathinfo_t paths) { pathinfo = paths; } diff --git a/libco/aarch64.c b/libco/aarch64.c new file mode 100644 index 0000000..2132b4e --- /dev/null +++ b/libco/aarch64.c @@ -0,0 +1,109 @@ +#define LIBCO_C +#include "libco.h" +#include "settings.h" + +#include +#include +#include +#ifdef LIBCO_MPROTECT + #include + #include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static thread_local unsigned long co_active_buffer[64]; +static thread_local cothread_t co_active_handle = 0; +static void (*co_swap)(cothread_t, cothread_t) = 0; + +#ifdef LIBCO_MPROTECT + alignas(4096) +#else + section(text) +#endif +static const uint32_t co_swap_function[1024] = { + 0xa9002428, /* stp x8,x9,[x1] */ + 0xa9012c2a, /* stp x10,x11,[x1,#16] */ + 0xa902342c, /* stp x12,x13,[x1,#32] */ + 0xa9033c2e, /* stp x14,x15,[x1,#48] */ + 0xf9002433, /* str x19,[x1,#72] */ + 0xa9055434, /* stp x20,x21,[x1,#80] */ + 0xa9065c36, /* stp x22,x23,[x1,#96] */ + 0xa9076438, /* stp x24,x25,[x1,#112] */ + 0xa9086c3a, /* stp x26,x27,[x1,#128] */ + 0xa909743c, /* stp x28,x29,[x1,#144] */ + 0x910003f0, /* mov x16,sp */ + 0xa90a7830, /* stp x16,x30,[x1,#160] */ + + 0xa9402408, /* ldp x8,x9,[x0] */ + 0xa9412c0a, /* ldp x10,x11,[x0,#16] */ + 0xa942340c, /* ldp x12,x13,[x0,#32] */ + 0xa9433c0e, /* ldp x14,x15,[x0,#48] */ + 0xf9402413, /* ldr x19,[x0,#72] */ + 0xa9455414, /* ldp x20,x21,[x0,#80] */ + 0xa9465c16, /* ldp x22,x23,[x0,#96] */ + 0xa9476418, /* ldp x24,x25,[x0,#112] */ + 0xa9486c1a, /* ldp x26,x27,[x0,#128] */ + 0xa949741c, /* ldp x28,x29,[x0,#144] */ + 0xa94a4410, /* ldp x16,x17,[x0,#160] */ + 0x9100021f, /* mov sp,x16 */ + 0xd61f0220, /* br x17 */ +}; + +static void co_init() { + #ifdef LIBCO_MPROTECT + 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_EXEC); + #endif +} + +cothread_t co_active() { + if(!co_active_handle) co_active_handle = &co_active_buffer; + return co_active_handle; +} + +cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) { + unsigned long* 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; + + if(handle = (unsigned long*)memory) { + unsigned int offset = (size & ~15); + unsigned long* p = (unsigned long*)((unsigned char*)handle + offset); + handle[19] = (unsigned long)p; /* x29 (frame pointer) */ + handle[20] = (unsigned long)p; /* x30 (stack pointer) */ + handle[21] = (unsigned long)entrypoint; /* x31 (link register) */ + } + + return handle; +} + +cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { + void* memory = malloc(size); + if(!memory) return (cothread_t)0; + return co_derive(memory, size, entrypoint); +} + +void co_delete(cothread_t handle) { + free(handle); +} + +void co_switch(cothread_t handle) { + cothread_t co_previous_handle = co_active_handle; + co_swap(co_active_handle = handle, co_previous_handle); +} + +int co_serializable() { + return 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/amd64.c b/libco/amd64.c new file mode 100755 index 0000000..9d827d3 --- /dev/null +++ b/libco/amd64.c @@ -0,0 +1,165 @@ +#define LIBCO_C +#include "libco.h" +#include "settings.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 LIBCO_MPROTECT + alignas(4096) +#else + section(text) +#endif +#ifdef _WIN32 + /* ABI: Win64 */ + static const unsigned char co_swap_function[4096] = { + 0x48, 0x89, 0x22, /* mov [rdx],rsp */ + 0x48, 0x8b, 0x21, /* mov rsp,[rcx] */ + 0x58, /* pop rax */ + 0x48, 0x89, 0x6a, 0x08, /* mov [rdx+ 8],rbp */ + 0x48, 0x89, 0x72, 0x10, /* mov [rdx+16],rsi */ + 0x48, 0x89, 0x7a, 0x18, /* mov [rdx+24],rdi */ + 0x48, 0x89, 0x5a, 0x20, /* mov [rdx+32],rbx */ + 0x4c, 0x89, 0x62, 0x28, /* mov [rdx+40],r12 */ + 0x4c, 0x89, 0x6a, 0x30, /* mov [rdx+48],r13 */ + 0x4c, 0x89, 0x72, 0x38, /* mov [rdx+56],r14 */ + 0x4c, 0x89, 0x7a, 0x40, /* mov [rdx+64],r15 */ + #if !defined(LIBCO_NO_SSE) + 0x0f, 0x29, 0x72, 0x50, /* movaps [rdx+ 80],xmm6 */ + 0x0f, 0x29, 0x7a, 0x60, /* movaps [rdx+ 96],xmm7 */ + 0x44, 0x0f, 0x29, 0x42, 0x70, /* movaps [rdx+112],xmm8 */ + 0x48, 0x83, 0xc2, 0x70, /* add rdx,112 */ + 0x44, 0x0f, 0x29, 0x4a, 0x10, /* movaps [rdx+ 16],xmm9 */ + 0x44, 0x0f, 0x29, 0x52, 0x20, /* movaps [rdx+ 32],xmm10 */ + 0x44, 0x0f, 0x29, 0x5a, 0x30, /* movaps [rdx+ 48],xmm11 */ + 0x44, 0x0f, 0x29, 0x62, 0x40, /* movaps [rdx+ 64],xmm12 */ + 0x44, 0x0f, 0x29, 0x6a, 0x50, /* movaps [rdx+ 80],xmm13 */ + 0x44, 0x0f, 0x29, 0x72, 0x60, /* movaps [rdx+ 96],xmm14 */ + 0x44, 0x0f, 0x29, 0x7a, 0x70, /* movaps [rdx+112],xmm15 */ + #endif + 0x48, 0x8b, 0x69, 0x08, /* mov rbp,[rcx+ 8] */ + 0x48, 0x8b, 0x71, 0x10, /* mov rsi,[rcx+16] */ + 0x48, 0x8b, 0x79, 0x18, /* mov rdi,[rcx+24] */ + 0x48, 0x8b, 0x59, 0x20, /* mov rbx,[rcx+32] */ + 0x4c, 0x8b, 0x61, 0x28, /* mov r12,[rcx+40] */ + 0x4c, 0x8b, 0x69, 0x30, /* mov r13,[rcx+48] */ + 0x4c, 0x8b, 0x71, 0x38, /* mov r14,[rcx+56] */ + 0x4c, 0x8b, 0x79, 0x40, /* mov r15,[rcx+64] */ + #if !defined(LIBCO_NO_SSE) + 0x0f, 0x28, 0x71, 0x50, /* movaps xmm6, [rcx+ 80] */ + 0x0f, 0x28, 0x79, 0x60, /* movaps xmm7, [rcx+ 96] */ + 0x44, 0x0f, 0x28, 0x41, 0x70, /* movaps xmm8, [rcx+112] */ + 0x48, 0x83, 0xc1, 0x70, /* add rcx,112 */ + 0x44, 0x0f, 0x28, 0x49, 0x10, /* movaps xmm9, [rcx+ 16] */ + 0x44, 0x0f, 0x28, 0x51, 0x20, /* movaps xmm10,[rcx+ 32] */ + 0x44, 0x0f, 0x28, 0x59, 0x30, /* movaps xmm11,[rcx+ 48] */ + 0x44, 0x0f, 0x28, 0x61, 0x40, /* movaps xmm12,[rcx+ 64] */ + 0x44, 0x0f, 0x28, 0x69, 0x50, /* movaps xmm13,[rcx+ 80] */ + 0x44, 0x0f, 0x28, 0x71, 0x60, /* movaps xmm14,[rcx+ 96] */ + 0x44, 0x0f, 0x28, 0x79, 0x70, /* movaps xmm15,[rcx+112] */ + #endif + 0xff, 0xe0, /* jmp rax */ + }; + + #include + + static void co_init() { + #ifdef LIBCO_MPROTECT + DWORD old_privileges; + VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges); + #endif + } +#else + /* ABI: SystemV */ + static const unsigned char co_swap_function[4096] = { + 0x48, 0x89, 0x26, /* mov [rsi],rsp */ + 0x48, 0x8b, 0x27, /* mov rsp,[rdi] */ + 0x58, /* pop rax */ + 0x48, 0x89, 0x6e, 0x08, /* mov [rsi+ 8],rbp */ + 0x48, 0x89, 0x5e, 0x10, /* mov [rsi+16],rbx */ + 0x4c, 0x89, 0x66, 0x18, /* mov [rsi+24],r12 */ + 0x4c, 0x89, 0x6e, 0x20, /* mov [rsi+32],r13 */ + 0x4c, 0x89, 0x76, 0x28, /* mov [rsi+40],r14 */ + 0x4c, 0x89, 0x7e, 0x30, /* mov [rsi+48],r15 */ + 0x48, 0x8b, 0x6f, 0x08, /* mov rbp,[rdi+ 8] */ + 0x48, 0x8b, 0x5f, 0x10, /* mov rbx,[rdi+16] */ + 0x4c, 0x8b, 0x67, 0x18, /* mov r12,[rdi+24] */ + 0x4c, 0x8b, 0x6f, 0x20, /* mov r13,[rdi+32] */ + 0x4c, 0x8b, 0x77, 0x28, /* mov r14,[rdi+40] */ + 0x4c, 0x8b, 0x7f, 0x30, /* mov r15,[rdi+48] */ + 0xff, 0xe0, /* jmp rax */ + }; + + #ifdef LIBCO_MPROTECT + #include + #include + #endif + + static void co_init() { + #ifdef LIBCO_MPROTECT + 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_EXEC); + #endif + } +#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_derive(void* memory, 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; + + if((handle = (cothread_t)memory)) { + unsigned int offset = (size & ~15) - 32; + long long *p = (long long*)((char*)handle + offset); /* 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; +} + +cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { + void* memory = malloc(size); + if(!memory) return (cothread_t)0; + return co_derive(memory, size, entrypoint); +} + +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); +} + +int co_serializable() { + return 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/arm.c b/libco/arm.c new file mode 100644 index 0000000..ce5970e --- /dev/null +++ b/libco/arm.c @@ -0,0 +1,84 @@ +#define LIBCO_C +#include "libco.h" +#include "settings.h" + +#include +#include +#ifdef LIBCO_MPROTECT + #include + #include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static thread_local unsigned long co_active_buffer[64]; +static thread_local cothread_t co_active_handle = 0; +static void (*co_swap)(cothread_t, cothread_t) = 0; + +#ifdef LIBCO_MPROTECT + alignas(4096) +#else + section(text) +#endif +static const unsigned long co_swap_function[1024] = { + 0xe8a16ff0, /* stmia r1!, {r4-r11,sp,lr} */ + 0xe8b0aff0, /* ldmia r0!, {r4-r11,sp,pc} */ + 0xe12fff1e, /* bx lr */ +}; + +static void co_init() { + #ifdef LIBCO_MPROTECT + 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_EXEC); + #endif +} + +cothread_t co_active() { + if(!co_active_handle) co_active_handle = &co_active_buffer; + return co_active_handle; +} + +cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) { + unsigned long* 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; + + if((handle = (unsigned long*)memory)) { + unsigned int offset = (size & ~15); + unsigned long* p = (unsigned long*)((unsigned char*)handle + offset); + handle[8] = (unsigned long)p; + handle[9] = (unsigned long)entrypoint; + } + + return handle; +} + +cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { + void* memory = malloc(size); + if(!memory) return (cothread_t)0; + return co_derive(memory, size, entrypoint); +} + +void co_delete(cothread_t handle) { + free(handle); +} + +void co_switch(cothread_t handle) { + cothread_t co_previous_handle = co_active_handle; + co_swap(co_active_handle = handle, co_previous_handle); +} + +int co_serializable() { + return 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/doc/style.css b/libco/doc/style.css new file mode 100755 index 0000000..ab07025 --- /dev/null +++ b/libco/doc/style.css @@ -0,0 +1,12 @@ +body { + background: #333; + color: #fff; +} + +code { + background: #444; +} + +a { + color: #aaf; +} diff --git a/libco/doc/targets.html b/libco/doc/targets.html new file mode 100755 index 0000000..d6211a1 --- /dev/null +++ b/libco/doc/targets.html @@ -0,0 +1,89 @@ + + + + + + + +Supported targets:

+ +Note that supported targets are only those that have been tested and confirmed +working. It is quite possible that libco will work on more processors, compilers +and operating systems than those listed below. +


+ +libco.x86
+Overhead: ~5x
+Supported processor(s): 32-bit x86
+Supported compiler(s): any
+Supported operating system(s):
    +
  • Windows
  • +
  • Mac OS X
  • +
  • Linux
  • +
  • BSD
  • +
+
+ +libco.amd64
+Overhead: ~10x (Windows), ~6x (all other platforms)
+Supported processor(s): 64-bit amd64
+Supported compiler(s): any
+Supported operating system(s):
    +
  • Windows
  • +
  • Mac OS X
  • +
  • Linux
  • +
  • BSD
  • +
+
+ +libco.ppc
+Overhead: ~20x
+Supported processor(s): 32-bit PowerPC, 64-bit PowerPC
+Supported compiler(s): GNU GCC
+Supported operating system(s):
    +
+
  • Mac OS X
  • +
  • Linux
  • +
  • BSD
  • +
  • Playstation 3
  • + +
    + +Note: this module contains compiler flags to enable/disable FPU and Altivec +support. + +
    + +libco.fiber
    +Overhead: ~15x
    +Supported processor(s): Processor independent
    +Supported compiler(s): any
    +Supported operating system(s):
      +
    • Windows
    • +
    +
    + +libco.sjlj
    +Overhead: ~30x
    +Supported processor(s): Processor independent
    +Supported compiler(s): any
    +Supported operating system(s):
      +
    • Mac OS X
    • +
    • Linux
    • +
    • BSD
    • +
    • Solaris
    • +
    +
    + +libco.ucontext
    +Overhead: ~300x
    +Supported processor(s): Processor independent
    +Supported compiler(s): any
    +Supported operating system(s):
      +
    • Linux
    • +
    • BSD
    • +
    +
    + + + diff --git a/libco/doc/usage.html b/libco/doc/usage.html new file mode 100755 index 0000000..994072f --- /dev/null +++ b/libco/doc/usage.html @@ -0,0 +1,108 @@ + + + + + + + +License:

    +libco is released under the ISC license. +
    + +Foreword:

    +libco is a cross-platform, permissively licensed implementation of +cooperative-multithreading; a feature that is sorely lacking from the ISO C/C++ +standard.
    +The library is designed for maximum speed and portability, and not for safety or +features. If safety or extra functionality is desired, a wrapper API can easily +be written to encapsulate all library functions.
    +Behavior of executing operations that are listed as not permitted below result +in undefined behavior. They may work anyway, they may cause undesired / unknown +behavior, or they may crash the program entirely.
    +The goal of this library was to simplify the base API as much as possible, +implementing only that which cannot be implemented using pure C. Additional +functionality after this would only complicate ports of this library to new +platforms. +
    + +Porting:

    +This document is included as a reference for porting libco. Please submit any +ports you create to me, so that libco can become more useful. Please note that +since libco is permissively licensed, you must submit your code as a work of the +public domain in order for it to be included in the official distribution. +Full credit will be given in the source code of the official release. Please +do not bother submitting code to me under any other license -- including GPL, +LGPL, BSD or CC -- I am not interested in creating a library with multiple +different licenses depending on which targets are used. +
    + +Synopsis:

    + +typedef void* cothread_t;
    +
    +cothread_t co_active();
    +cothread_t co_create(unsigned int heapsize, void (*coentry)(void));
    +void       co_delete(cothread_t cothread);
    +void       co_switch(cothread_t cothread);
    +
    +
    + +Usage: +
    + +typedef void* cothread_t;

    +Handle to cothread.
    +Handle must be of type void*.
    +A value of null (0) indicates an uninitialized or invalid +handle, whereas a non-zero value indicates a valid handle. +
    + +cothread_t co_active();

    +Return handle to current cothread. Always returns a valid handle, even when +called from the main program thread. +
    + +cothread_t co_derive(void* memory, unsigned int heapsize, void (*coentry)(void));

    +Initializes new cothread.
    +This function is identical to co_create, only it attempts to use the provided +memory instead of allocating new memory on the heap. Please note that certain +implementations (currently only Windows Fibers) cannot be created using existing +memory, and as such, this function will fail. +
    + +cothread_t co_create(unsigned int heapsize, void (*coentry)(void));

    +Create new cothread.
    +Heapsize is the amount of memory allocated for the cothread stack, specified +in bytes. This is unfortunately impossible to make fully portable. It is +recommended to specify sizes using `n * sizeof(void*)'. It is better to err +on the side of caution and allocate more memory than will be needed to ensure +compatibility with other platforms, within reason. A typical heapsize for a +32-bit architecture is ~1MB.
    +When the new cothread is first called, program execution jumps to coentry. +This function does not take any arguments, due to portability issues with +passing function arguments. However, arguments can be simulated by the use +of global variables, which can be set before the first call to each cothread.
    +coentry() must not return, and should end with an appropriate co_switch() +statement. Behavior is undefined if entry point returns normally.
    +Library is responsible for allocating cothread stack memory, to free +the user from needing to allocate special memory capable of being used +as program stack memory on platforms where this is required.
    +User is always responsible for deleting cothreads with co_delete().
    +Return value of null (0) indicates cothread creation failed. +
    + +void co_delete(cothread_t cothread);

    +Delete specified cothread.
    +Null (0) or invalid cothread handle is not allowed.
    +Passing handle of active cothread to this function is not allowed.
    +Passing handle of primary cothread is not allowed. +
    + +void co_switch(cothread_t cothread);

    +Switch to specified cothread.
    +Null (0) or invalid cothread handle is not allowed.
    +Passing handle of active cothread to this function is not allowed. +
    + + + diff --git a/libco/fiber.c b/libco/fiber.c new file mode 100755 index 0000000..dd539c3 --- /dev/null +++ b/libco/fiber.c @@ -0,0 +1,55 @@ +#define LIBCO_C +#include "libco.h" +#include "settings.h" + +#define WINVER 0x0400 +#define _WIN32_WINNT 0x0400 +#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_derive(void* memory, unsigned int heapsize, void (*coentry)(void)) { + //Windows fibers do not allow users to supply their own memory + return (cothread_t)0; +} + +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); +} + +int co_serializable() { + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/libco.c b/libco/libco.c new file mode 100755 index 0000000..21fe4ca --- /dev/null +++ b/libco/libco.c @@ -0,0 +1,37 @@ +#if defined(__clang__) + #pragma clang diagnostic ignored "-Wparentheses" + + /* placing code in section(text) does not mark it executable with Clang. */ + #undef LIBCO_MPROTECT + #define LIBCO_MPROTECT +#endif + +#if defined(__clang__) || defined(__GNUC__) + #if defined(__i386__) + #include "x86.c" + #elif defined(__amd64__) + #include "amd64.c" + #elif defined(__arm__) + #include "arm.c" + #elif defined(__aarch64__) + #include "aarch64.c" + #elif defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2 + #include "ppc64v2.c" + #elif defined(_ARCH_PPC) && !defined(__LITTLE_ENDIAN__) + #include "ppc.c" + #elif defined(_WIN32) + #include "fiber.c" + #else + #include "sjlj.c" + #endif +#elif defined(_MSC_VER) + #if defined(_M_IX86) + #include "x86.c" + #elif defined(_M_AMD64) + #include "amd64.c" + #else + #include "fiber.c" + #endif +#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 0000000..88d00a7 --- /dev/null +++ b/libco/libco.h @@ -0,0 +1,28 @@ +/* + libco v20 (2019-10-16) + author: byuu + license: ISC +*/ + +#ifndef LIBCO_H +#define LIBCO_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* cothread_t; + +cothread_t co_active(); +cothread_t co_derive(void*, unsigned int, void (*)(void)); +cothread_t co_create(unsigned int, void (*)(void)); +void co_delete(cothread_t); +void co_switch(cothread_t); +int co_serializable(); + +#ifdef __cplusplus +} +#endif + +/* ifndef LIBCO_H */ +#endif diff --git a/libco/ppc.c b/libco/ppc.c new file mode 100755 index 0000000..ee6a9a8 --- /dev/null +++ b/libco/ppc.c @@ -0,0 +1,431 @@ +/* ppc64le (ELFv2) is not currently supported */ + +#define LIBCO_C +#include "libco.h" +#include "settings.h" + +#include +#include +#include + +#ifdef 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 registers + 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 && (!defined(_CALL_ELF) || _CALL_ELF == 1))) + #define LIBCO_PPCDESC 1 + #endif +#endif + +#ifdef LIBCO_MPROTECT + alignas(4096) +#else + section(text) +#endif +static const uint32_t libco_ppc_code[1024] = { + #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 + +static uint32_t* co_derive_(void* memory, unsigned size, uintptr_t entry) { + (void)entry; + + uint32_t* t = (uint32_t*)memory; + + #if LIBCO_PPCDESC + if(t) { + memcpy(t, (void*)entry, sizeof(void*) * 3); /* copy entry's descriptor */ + *(const void**)t = libco_ppc_code; /* set function pointer to swap routine */ + } + #endif + + return t; +} + +cothread_t co_derive(void* memory, unsigned int size, void (*entry_)(void)) { + uintptr_t entry = (uintptr_t)entry_; + uint32_t* t = 0; + + /* be sure main thread was successfully allocated */ + if(co_active()) { + t = co_derive_(memory, 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 + entry = (uintptr_t)*(void**)entry; /* get real address */ + #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; +} + +static uint32_t* co_create_(unsigned size, uintptr_t entry) { + (void)entry; + + uint32_t* t = (uint32_t*)malloc(size); + + #if LIBCO_PPCDESC + if(t) { + memcpy(t, (void*)entry, sizeof(void*) * 3); /* copy entry's descriptor */ + *(const void**)t = libco_ppc_code; /* set function pointer to swap routine */ + } + #endif + + return t; +} + +cothread_t co_create(unsigned int size, void (*entry_)(void)) { + uintptr_t entry = (uintptr_t)entry_; + uint32_t* t = 0; + + /* 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 + entry = (uintptr_t)*(void**)entry; /* get real address */ + #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 + 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_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); +} + +int co_serializable() { + return 0; +} diff --git a/libco/ppc64v2.c b/libco/ppc64v2.c new file mode 100644 index 0000000..3c29695 --- /dev/null +++ b/libco/ppc64v2.c @@ -0,0 +1,279 @@ +/* author: Shawn Anastasio */ + +#define LIBCO_C +#include "libco.h" +#include "settings.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ppc64_context { + //GPRs + uint64_t gprs[32]; + uint64_t lr; + uint64_t ccr; + + //FPRs + uint64_t fprs[32]; + + #ifdef __ALTIVEC__ + //Altivec (VMX) + uint64_t vmx[12 * 2]; + uint32_t vrsave; + #endif +}; + +static thread_local struct ppc64_context* co_active_handle = 0; + +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ALIGN(p, x) ((void*)((uintptr_t)(p) & ~((x) - 1))) + +#define MIN_STACK 0x10000lu +#define MIN_STACK_FRAME 0x20lu +#define STACK_ALIGN 0x10lu + +void swap_context(struct ppc64_context* read, struct ppc64_context* write); +__asm__( + ".text\n" + ".align 4\n" + ".type swap_context @function\n" + "swap_context:\n" + ".cfi_startproc\n" + + //save GPRs + "std 1, 8(4)\n" + "std 2, 16(4)\n" + "std 12, 96(4)\n" + "std 13, 104(4)\n" + "std 14, 112(4)\n" + "std 15, 120(4)\n" + "std 16, 128(4)\n" + "std 17, 136(4)\n" + "std 18, 144(4)\n" + "std 19, 152(4)\n" + "std 20, 160(4)\n" + "std 21, 168(4)\n" + "std 22, 176(4)\n" + "std 23, 184(4)\n" + "std 24, 192(4)\n" + "std 25, 200(4)\n" + "std 26, 208(4)\n" + "std 27, 216(4)\n" + "std 28, 224(4)\n" + "std 29, 232(4)\n" + "std 30, 240(4)\n" + "std 31, 248(4)\n" + + //save LR + "mflr 5\n" + "std 5, 256(4)\n" + + //save CCR + "mfcr 5\n" + "std 5, 264(4)\n" + + //save FPRs + "stfd 14, 384(4)\n" + "stfd 15, 392(4)\n" + "stfd 16, 400(4)\n" + "stfd 17, 408(4)\n" + "stfd 18, 416(4)\n" + "stfd 19, 424(4)\n" + "stfd 20, 432(4)\n" + "stfd 21, 440(4)\n" + "stfd 22, 448(4)\n" + "stfd 23, 456(4)\n" + "stfd 24, 464(4)\n" + "stfd 25, 472(4)\n" + "stfd 26, 480(4)\n" + "stfd 27, 488(4)\n" + "stfd 28, 496(4)\n" + "stfd 29, 504(4)\n" + "stfd 30, 512(4)\n" + "stfd 31, 520(4)\n" + + #ifdef __ALTIVEC__ + //save VMX + "li 5, 528\n" + "stvxl 20, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 21, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 22, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 23, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 24, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 25, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 26, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 27, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 28, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 29, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 30, 4, 5\n" + "addi 5, 5, 16\n" + "stvxl 31, 4, 5\n" + "addi 5, 5, 16\n" + + //save VRSAVE + "mfvrsave 5\n" + "stw 5, 736(4)\n" + #endif + + //restore GPRs + "ld 1, 8(3)\n" + "ld 2, 16(3)\n" + "ld 12, 96(3)\n" + "ld 13, 104(3)\n" + "ld 14, 112(3)\n" + "ld 15, 120(3)\n" + "ld 16, 128(3)\n" + "ld 17, 136(3)\n" + "ld 18, 144(3)\n" + "ld 19, 152(3)\n" + "ld 20, 160(3)\n" + "ld 21, 168(3)\n" + "ld 22, 176(3)\n" + "ld 23, 184(3)\n" + "ld 24, 192(3)\n" + "ld 25, 200(3)\n" + "ld 26, 208(3)\n" + "ld 27, 216(3)\n" + "ld 28, 224(3)\n" + "ld 29, 232(3)\n" + "ld 30, 240(3)\n" + "ld 31, 248(3)\n" + + //restore LR + "ld 5, 256(3)\n" + "mtlr 5\n" + + //restore CCR + "ld 5, 264(3)\n" + "mtcr 5\n" + + //restore FPRs + "lfd 14, 384(3)\n" + "lfd 15, 392(3)\n" + "lfd 16, 400(3)\n" + "lfd 17, 408(3)\n" + "lfd 18, 416(3)\n" + "lfd 19, 424(3)\n" + "lfd 20, 432(3)\n" + "lfd 21, 440(3)\n" + "lfd 22, 448(3)\n" + "lfd 23, 456(3)\n" + "lfd 24, 464(3)\n" + "lfd 25, 472(3)\n" + "lfd 26, 480(3)\n" + "lfd 27, 488(3)\n" + "lfd 28, 496(3)\n" + "lfd 29, 504(3)\n" + "lfd 30, 512(3)\n" + "lfd 31, 520(3)\n" + + #ifdef __ALTIVEC__ + //restore VMX + "li 5, 528\n" + "lvxl 20, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 21, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 22, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 23, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 24, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 25, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 26, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 27, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 28, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 29, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 30, 3, 5\n" + "addi 5, 5, 16\n" + "lvxl 31, 3, 5\n" + "addi 5, 5, 16\n" + + //restore VRSAVE + "lwz 5, 720(3)\n" + "mtvrsave 5\n" + #endif + + //branch to LR + "blr\n" + + ".cfi_endproc\n" + ".size swap_context, .-swap_context\n" +); + +cothread_t co_active() { + if(!co_active_handle) { + co_active_handle = (struct ppc64_context*)malloc(MIN_STACK + sizeof(struct ppc64_context)); + } + return (cothread_t)co_active_handle; +} + +cothread_t co_derive(void* memory, unsigned int size, void (*coentry)(void)) { + uint8_t* sp; + struct ppc64_context* context = (struct ppc64_context*)memory; + + //save current context into new context to initialize it + swap_context(context, context); + + //align stack + sp = (uint8_t*)memory + size - STACK_ALIGN; + sp = (uint8_t*)ALIGN(sp, STACK_ALIGN); + + //write 0 for initial backchain + *(uint64_t*)sp = 0; + + //create new frame with backchain + sp -= MIN_STACK_FRAME; + *(uint64_t*)sp = (uint64_t)(sp + MIN_STACK_FRAME); + + //update context with new stack (r1) and entrypoint (r12, lr) + context->gprs[ 1] = (uint64_t)sp; + context->gprs[12] = (uint64_t)coentry; + context->lr = (uint64_t)coentry; + + return (cothread_t)memory; +} + +cothread_t co_create(unsigned int size, void (*coentry)(void)) { + void* memory = malloc(size); + if(!memory) return (cothread_t)0; + return co_derive(memory, size, coentry); +} + +void co_delete(cothread_t handle) { + free(handle); +} + +void co_switch(cothread_t to) { + struct ppc64_context* from = co_active_handle; + co_active_handle = (struct ppc64_context*)to; + swap_context((struct ppc64_context*)to, from); +} + +int co_serializable() { + return 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/settings.h b/libco/settings.h new file mode 100644 index 0000000..d8037bc --- /dev/null +++ b/libco/settings.h @@ -0,0 +1,38 @@ +#if defined(LIBCO_C) + +/*[amd64, arm, ppc, x86]: + by default, co_swap_function is marked as a text (code) section + if not supported, uncomment the below line to use mprotect instead */ +/* #define LIBCO_MPROTECT */ + +/*[amd64]: + Win64 only: provides a substantial speed-up, but will thrash XMM regs + do not use this unless you are certain your application won't use SSE */ +/* #define LIBCO_NO_SSE */ + +#if defined(LIBCO_C) + #if defined(LIBCO_MP) + #define thread_local __thread + #else + #define thread_local + #endif +#endif + +#if __STDC_VERSION__ >= 201112L + #if !defined(_MSC_VER) + #include + #endif +#else + #define alignas(bytes) +#endif + +#if defined(_MSC_VER) + #define section(name) __declspec(allocate("." #name)) +#elif defined(__APPLE__) + #define section(name) __attribute__((section("__TEXT,__" #name))) +#else + #define section(name) __attribute__((section("." #name "#"))) +#endif + +/* if defined(LIBCO_C) */ +#endif diff --git a/libco/sjlj.c b/libco/sjlj.c new file mode 100755 index 0000000..5af1472 --- /dev/null +++ b/libco/sjlj.c @@ -0,0 +1,145 @@ +/* + 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 "settings.h" + +#define _BSD_SOURCE +#define _XOPEN_SOURCE 500 +#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; +static thread_local cothread_struct* 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_derive(void* memory, unsigned int size, void (*coentry)(void)) { + if(!co_running) co_running = &co_primary; + + cothread_struct* thread = (cothread_struct*)memory; + memory = (unsigned char*)memory + sizeof(cothread_struct); + size -= 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 = memory; + 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; +} + +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); + } +} + +int co_serializable() { + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/ucontext.c b/libco/ucontext.c new file mode 100755 index 0000000..5ff76af --- /dev/null +++ b/libco/ucontext.c @@ -0,0 +1,86 @@ +/* + 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 "settings.h" + +#define _BSD_SOURCE +#define _XOPEN_SOURCE 500 +#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_derive(void* memory, unsigned int heapsize, void (*coentry)(void)) { + if(!co_running) co_running = &co_primary; + ucontext_t* thread = (ucontext_t*)memory; + memory = (unsigned char*)memory + sizeof(ucontext_t); + heapsize -= sizeof(ucontext_t); + if(thread) { + if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = memory)) { + thread->uc_link = co_running; + thread->uc_stack.ss_size = heapsize; + makecontext(thread, coentry, 0); + } else { + thread = 0; + } + } + return (cothread_t)thread; +} + +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); +} + +int co_serializable() { + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/x86.c b/libco/x86.c new file mode 100755 index 0000000..217692a --- /dev/null +++ b/libco/x86.c @@ -0,0 +1,119 @@ +#define LIBCO_C +#include "libco.h" +#include "settings.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__clang__) || defined(__GNUC__) + #define fastcall __attribute__((fastcall)) +#elif defined(_MSC_VER) + #define fastcall __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; + +#ifdef LIBCO_MPROTECT + alignas(4096) +#else + section(text) +#endif +/* ABI: fastcall */ +static const unsigned char co_swap_function[4096] = { + 0x89, 0x22, /* mov [edx],esp */ + 0x8b, 0x21, /* mov esp,[ecx] */ + 0x58, /* pop eax */ + 0x89, 0x6a, 0x04, /* mov [edx+ 4],ebp */ + 0x89, 0x72, 0x08, /* mov [edx+ 8],esi */ + 0x89, 0x7a, 0x0c, /* mov [edx+12],edi */ + 0x89, 0x5a, 0x10, /* mov [edx+16],ebx */ + 0x8b, 0x69, 0x04, /* mov ebp,[ecx+ 4] */ + 0x8b, 0x71, 0x08, /* mov esi,[ecx+ 8] */ + 0x8b, 0x79, 0x0c, /* mov edi,[ecx+12] */ + 0x8b, 0x59, 0x10, /* mov ebx,[ecx+16] */ + 0xff, 0xe0, /* jmp eax */ +}; + +#ifdef _WIN32 + #include + + static void co_init() { + #ifdef LIBCO_MPROTECT + DWORD old_privileges; + VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges); + #endif + } +#else + #ifdef LIBCO_MPROTECT + #include + #include + #endif + + static void co_init() { + #ifdef LIBCO_MPROTECT + 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_EXEC); + #endif + } +#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_derive(void* memory, 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; + + if((handle = (cothread_t)memory)) { + unsigned int offset = (size & ~15) - 32; + long *p = (long*)((char*)handle + offset); /* 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; +} + +cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { + void* memory = malloc(size); + if(!memory) return (cothread_t)0; + return co_derive(memory, size, entrypoint); +} + +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); +} + +int co_serializable() { + return 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/lzma/7z.h b/lzma/7z.h new file mode 100644 index 0000000..82813c2 --- /dev/null +++ b/lzma/7z.h @@ -0,0 +1,202 @@ +/* 7z.h -- 7z interface +2017-04-03 : Igor Pavlov : Public domain */ + +#ifndef __7Z_H +#define __7Z_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define k7zStartHeaderSize 0x20 +#define k7zSignatureSize 6 + +extern const Byte k7zSignature[k7zSignatureSize]; + +typedef struct +{ + const Byte *Data; + size_t Size; +} CSzData; + +/* CSzCoderInfo & CSzFolder support only default methods */ + +typedef struct +{ + size_t PropsOffset; + UInt32 MethodID; + Byte NumStreams; + Byte PropsSize; +} CSzCoderInfo; + +typedef struct +{ + UInt32 InIndex; + UInt32 OutIndex; +} CSzBond; + +#define SZ_NUM_CODERS_IN_FOLDER_MAX 4 +#define SZ_NUM_BONDS_IN_FOLDER_MAX 3 +#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4 + +typedef struct +{ + UInt32 NumCoders; + UInt32 NumBonds; + UInt32 NumPackStreams; + UInt32 UnpackStream; + UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX]; + CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX]; + CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX]; +} CSzFolder; + + +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd); + +typedef struct +{ + UInt32 Low; + UInt32 High; +} CNtfsFileTime; + +typedef struct +{ + Byte *Defs; /* MSB 0 bit numbering */ + UInt32 *Vals; +} CSzBitUi32s; + +typedef struct +{ + Byte *Defs; /* MSB 0 bit numbering */ + // UInt64 *Vals; + CNtfsFileTime *Vals; +} CSzBitUi64s; + +#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) + +#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) + +typedef struct +{ + UInt32 NumPackStreams; + UInt32 NumFolders; + + UInt64 *PackPositions; // NumPackStreams + 1 + CSzBitUi32s FolderCRCs; // NumFolders + + size_t *FoCodersOffsets; // NumFolders + 1 + UInt32 *FoStartPackStreamIndex; // NumFolders + 1 + UInt32 *FoToCoderUnpackSizes; // NumFolders + 1 + Byte *FoToMainUnpackSizeIndex; // NumFolders + UInt64 *CoderUnpackSizes; // for all coders in all folders + + Byte *CodersData; +} CSzAr; + +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex); + +SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, + ILookInStream *stream, UInt64 startPos, + Byte *outBuffer, size_t outSize, + ISzAllocPtr allocMain); + +typedef struct +{ + CSzAr db; + + UInt64 startPosAfterHeader; + UInt64 dataPos; + + UInt32 NumFiles; + + UInt64 *UnpackPositions; // NumFiles + 1 + // Byte *IsEmptyFiles; + Byte *IsDirs; + CSzBitUi32s CRCs; + + CSzBitUi32s Attribs; + // CSzBitUi32s Parents; + CSzBitUi64s MTime; + CSzBitUi64s CTime; + + UInt32 *FolderToFile; // NumFolders + 1 + UInt32 *FileToFolder; // NumFiles + + size_t *FileNameOffsets; /* in 2-byte steps */ + Byte *FileNames; /* UTF-16-LE */ +} CSzArEx; + +#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i)) + +#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i]) + +void SzArEx_Init(CSzArEx *p); +void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc); +UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); +int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); + +/* +if dest == NULL, the return value specifies the required size of the buffer, + in 16-bit characters, including the null-terminating character. +if dest != NULL, the return value specifies the number of 16-bit characters that + are written to the dest, including the null-terminating character. */ + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); + +/* +size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex); +UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest); +*/ + + + +/* + SzArEx_Extract extracts file from archive + + *outBuffer must be 0 before first call for each new archive. + + Extracting cache: + If you need to decompress more than one file, you can send + these values from previous call: + *blockIndex, + *outBuffer, + *outBufferSize + You can consider "*outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + If you use external function, you can declare these 3 cache variables + (blockIndex, outBuffer, outBufferSize) as static in that external function. + + Free *outBuffer and set *outBuffer to 0, if you want to flush cache. +*/ + +SRes SzArEx_Extract( + const CSzArEx *db, + ILookInStream *inStream, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp); + + +/* +SzArEx_Open Errors: +SZ_ERROR_NO_ARCHIVE +SZ_ERROR_ARCHIVE +SZ_ERROR_UNSUPPORTED +SZ_ERROR_MEM +SZ_ERROR_CRC +SZ_ERROR_INPUT_EOF +SZ_ERROR_FAIL +*/ + +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, + ISzAllocPtr allocMain, ISzAllocPtr allocTemp); + +EXTERN_C_END + +#endif diff --git a/lzma/7zAlloc.c b/lzma/7zAlloc.c new file mode 100644 index 0000000..ea32809 --- /dev/null +++ b/lzma/7zAlloc.c @@ -0,0 +1,80 @@ +/* 7zAlloc.c -- Allocation functions +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zAlloc.h" + +/* #define _SZ_ALLOC_DEBUG */ +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ + +#ifdef _SZ_ALLOC_DEBUG + +#ifdef _WIN32 +#include +#endif + +#include +int g_allocCount = 0; +int g_allocCountTemp = 0; + +#endif + +void *SzAlloc(ISzAllocPtr p, size_t size) +{ + UNUSED_VAR(p); + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc %10u bytes; count = %10d", (unsigned)size, g_allocCount); + g_allocCount++; + #endif + return malloc(size); +} + +void SzFree(ISzAllocPtr p, void *address) +{ + UNUSED_VAR(p); + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + { + g_allocCount--; + fprintf(stderr, "\nFree; count = %10d", g_allocCount); + } + #endif + free(address); +} + +void *SzAllocTemp(ISzAllocPtr p, size_t size) +{ + UNUSED_VAR(p); + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc_temp %10u bytes; count = %10d", (unsigned)size, g_allocCountTemp); + g_allocCountTemp++; + #ifdef _WIN32 + return HeapAlloc(GetProcessHeap(), 0, size); + #endif + #endif + return malloc(size); +} + +void SzFreeTemp(ISzAllocPtr p, void *address) +{ + UNUSED_VAR(p); + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + { + g_allocCountTemp--; + fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp); + } + #ifdef _WIN32 + HeapFree(GetProcessHeap(), 0, address); + return; + #endif + #endif + free(address); +} diff --git a/lzma/7zAlloc.h b/lzma/7zAlloc.h new file mode 100644 index 0000000..c0f89d7 --- /dev/null +++ b/lzma/7zAlloc.h @@ -0,0 +1,19 @@ +/* 7zAlloc.h -- Allocation functions +2017-04-03 : Igor Pavlov : Public domain */ + +#ifndef __7Z_ALLOC_H +#define __7Z_ALLOC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void *SzAlloc(ISzAllocPtr p, size_t size); +void SzFree(ISzAllocPtr p, void *address); + +void *SzAllocTemp(ISzAllocPtr p, size_t size); +void SzFreeTemp(ISzAllocPtr p, void *address); + +EXTERN_C_END + +#endif diff --git a/lzma/7zArcIn.c b/lzma/7zArcIn.c new file mode 100644 index 0000000..68cc12f --- /dev/null +++ b/lzma/7zArcIn.c @@ -0,0 +1,1771 @@ +/* 7zArcIn.c -- 7z Input functions +2018-12-31 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7z.h" +#include "7zBuf.h" +#include "7zCrc.h" +#include "CpuArch.h" + +#define MY_ALLOC(T, p, size, alloc) { \ + if ((p = (T *)ISzAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; } + +#define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) } + +#define MY_ALLOC_AND_CPY(to, size, from, alloc) \ + { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); } + +#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \ + { if ((size) == 0) to = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } } + +#define k7zMajorVersion 0 + +enum EIdEnum +{ + k7zIdEnd, + k7zIdHeader, + k7zIdArchiveProperties, + k7zIdAdditionalStreamsInfo, + k7zIdMainStreamsInfo, + k7zIdFilesInfo, + k7zIdPackInfo, + k7zIdUnpackInfo, + k7zIdSubStreamsInfo, + k7zIdSize, + k7zIdCRC, + k7zIdFolder, + k7zIdCodersUnpackSize, + k7zIdNumUnpackStream, + k7zIdEmptyStream, + k7zIdEmptyFile, + k7zIdAnti, + k7zIdName, + k7zIdCTime, + k7zIdATime, + k7zIdMTime, + k7zIdWinAttrib, + k7zIdComment, + k7zIdEncodedHeader, + k7zIdStartPos, + k7zIdDummy + // k7zNtSecure, + // k7zParent, + // k7zIsReal +}; + +const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; + +#define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } + +static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAllocPtr alloc) +{ + if (num == 0) + { + p->Defs = NULL; + p->Vals = NULL; + } + else + { + MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc); + MY_ALLOC(UInt32, p->Vals, num, alloc); + } + return SZ_OK; +} + +void SzBitUi32s_Free(CSzBitUi32s *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; + ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; +} + +#define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } + +void SzBitUi64s_Free(CSzBitUi64s *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; + ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; +} + + +static void SzAr_Init(CSzAr *p) +{ + p->NumPackStreams = 0; + p->NumFolders = 0; + + p->PackPositions = NULL; + SzBitUi32s_Init(&p->FolderCRCs); + + p->FoCodersOffsets = NULL; + p->FoStartPackStreamIndex = NULL; + p->FoToCoderUnpackSizes = NULL; + p->FoToMainUnpackSizeIndex = NULL; + p->CoderUnpackSizes = NULL; + + p->CodersData = NULL; +} + +static void SzAr_Free(CSzAr *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->PackPositions); + SzBitUi32s_Free(&p->FolderCRCs, alloc); + + ISzAlloc_Free(alloc, p->FoCodersOffsets); + ISzAlloc_Free(alloc, p->FoStartPackStreamIndex); + ISzAlloc_Free(alloc, p->FoToCoderUnpackSizes); + ISzAlloc_Free(alloc, p->FoToMainUnpackSizeIndex); + ISzAlloc_Free(alloc, p->CoderUnpackSizes); + + ISzAlloc_Free(alloc, p->CodersData); + + SzAr_Init(p); +} + + +void SzArEx_Init(CSzArEx *p) +{ + SzAr_Init(&p->db); + + p->NumFiles = 0; + p->dataPos = 0; + + p->UnpackPositions = NULL; + p->IsDirs = NULL; + + p->FolderToFile = NULL; + p->FileToFolder = NULL; + + p->FileNameOffsets = NULL; + p->FileNames = NULL; + + SzBitUi32s_Init(&p->CRCs); + SzBitUi32s_Init(&p->Attribs); + // SzBitUi32s_Init(&p->Parents); + SzBitUi64s_Init(&p->MTime); + SzBitUi64s_Init(&p->CTime); +} + +void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->UnpackPositions); + ISzAlloc_Free(alloc, p->IsDirs); + + ISzAlloc_Free(alloc, p->FolderToFile); + ISzAlloc_Free(alloc, p->FileToFolder); + + ISzAlloc_Free(alloc, p->FileNameOffsets); + ISzAlloc_Free(alloc, p->FileNames); + + SzBitUi32s_Free(&p->CRCs, alloc); + SzBitUi32s_Free(&p->Attribs, alloc); + // SzBitUi32s_Free(&p->Parents, alloc); + SzBitUi64s_Free(&p->MTime, alloc); + SzBitUi64s_Free(&p->CTime, alloc); + + SzAr_Free(&p->db, alloc); + SzArEx_Init(p); +} + + +static int TestSignatureCandidate(const Byte *testBytes) +{ + unsigned i; + for (i = 0; i < k7zSignatureSize; i++) + if (testBytes[i] != k7zSignature[i]) + return 0; + return 1; +} + +#define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; } + +#define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++; +#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest) +#define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++; + +#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); } +#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); } + +#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \ + dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4); + +static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) +{ + Byte firstByte, mask; + unsigned i; + UInt32 v; + + SZ_READ_BYTE(firstByte); + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + return SZ_OK; + } + SZ_READ_BYTE(v); + if ((firstByte & 0x40) == 0) + { + *value = (((UInt32)firstByte & 0x3F) << 8) | v; + return SZ_OK; + } + SZ_READ_BYTE(mask); + *value = v | ((UInt32)mask << 8); + mask = 0x20; + for (i = 2; i < 8; i++) + { + Byte b; + if ((firstByte & mask) == 0) + { + UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); + *value |= (highPart << (8 * i)); + return SZ_OK; + } + SZ_READ_BYTE(b); + *value |= ((UInt64)b << (8 * i)); + mask >>= 1; + } + return SZ_OK; +} + + +static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) +{ + Byte firstByte; + UInt64 value64; + if (sd->Size == 0) + return SZ_ERROR_ARCHIVE; + firstByte = *sd->Data; + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + sd->Data++; + sd->Size--; + return SZ_OK; + } + RINOK(ReadNumber(sd, &value64)); + if (value64 >= (UInt32)0x80000000 - 1) + return SZ_ERROR_UNSUPPORTED; + if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4))) + return SZ_ERROR_UNSUPPORTED; + *value = (UInt32)value64; + return SZ_OK; +} + +#define ReadID(sd, value) ReadNumber(sd, value) + +static SRes SkipData(CSzData *sd) +{ + UInt64 size; + RINOK(ReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, size); + return SZ_OK; +} + +static SRes WaitId(CSzData *sd, UInt32 id) +{ + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == id) + return SZ_OK; + if (type == k7zIdEnd) + return SZ_ERROR_ARCHIVE; + RINOK(SkipData(sd)); + } +} + +static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v) +{ + UInt32 numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + *v = sd->Data; + SKIP_DATA(sd, numBytes); + return SZ_OK; +} + +static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems) +{ + Byte b = 0; + unsigned m = 0; + UInt32 sum = 0; + for (; numItems != 0; numItems--) + { + if (m == 0) + { + b = *bits++; + m = 8; + } + m--; + sum += ((b >> m) & 1); + } + return sum; +} + +static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc) +{ + Byte allAreDefined; + Byte *v2; + UInt32 numBytes = (numItems + 7) >> 3; + *v = NULL; + SZ_READ_BYTE(allAreDefined); + if (numBytes == 0) + return SZ_OK; + if (allAreDefined == 0) + { + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc); + SKIP_DATA(sd, numBytes); + return SZ_OK; + } + MY_ALLOC(Byte, *v, numBytes, alloc); + v2 = *v; + memset(v2, 0xFF, (size_t)numBytes); + { + unsigned numBits = (unsigned)numItems & 7; + if (numBits != 0) + v2[(size_t)numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits)); + } + return SZ_OK; +} + +static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) +{ + UInt32 i; + CSzData sd; + UInt32 *vals; + const Byte *defs; + MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc); + sd = *sd2; + defs = crcs->Defs; + vals = crcs->Vals; + for (i = 0; i < numItems; i++) + if (SzBitArray_Check(defs, i)) + { + SZ_READ_32(vals[i]); + } + else + vals[i] = 0; + *sd2 = sd; + return SZ_OK; +} + +static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) +{ + SzBitUi32s_Free(crcs, alloc); + RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)); + return ReadUi32s(sd, numItems, crcs, alloc); +} + +static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems) +{ + Byte allAreDefined; + UInt32 numDefined = numItems; + SZ_READ_BYTE(allAreDefined); + if (!allAreDefined) + { + size_t numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + numDefined = CountDefinedBits(sd->Data, numItems); + SKIP_DATA(sd, numBytes); + } + if (numDefined > (sd->Size >> 2)) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, (size_t)numDefined * 4); + return SZ_OK; +} + +static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAllocPtr alloc) +{ + RINOK(SzReadNumber32(sd, &p->NumPackStreams)); + + RINOK(WaitId(sd, k7zIdSize)); + MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc); + { + UInt64 sum = 0; + UInt32 i; + UInt32 numPackStreams = p->NumPackStreams; + for (i = 0; i < numPackStreams; i++) + { + UInt64 packSize; + p->PackPositions[i] = sum; + RINOK(ReadNumber(sd, &packSize)); + sum += packSize; + if (sum < packSize) + return SZ_ERROR_ARCHIVE; + } + p->PackPositions[i] = sum; + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + /* CRC of packed streams is unused now */ + RINOK(SkipBitUi32s(sd, p->NumPackStreams)); + continue; + } + RINOK(SkipData(sd)); + } +} + +/* +static SRes SzReadSwitch(CSzData *sd) +{ + Byte external; + RINOK(SzReadByte(sd, &external)); + return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; +} +*/ + +#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) +{ + UInt32 numCoders, i; + UInt32 numInStreams = 0; + const Byte *dataStart = sd->Data; + + f->NumCoders = 0; + f->NumBonds = 0; + f->NumPackStreams = 0; + f->UnpackStream = 0; + + RINOK(SzReadNumber32(sd, &numCoders)); + if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numCoders; i++) + { + Byte mainByte; + CSzCoderInfo *coder = f->Coders + i; + unsigned idSize, j; + UInt64 id; + + SZ_READ_BYTE(mainByte); + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + + idSize = (unsigned)(mainByte & 0xF); + if (idSize > sizeof(id)) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd->Size) + return SZ_ERROR_ARCHIVE; + id = 0; + for (j = 0; j < idSize; j++) + { + id = ((id << 8) | *sd->Data); + sd->Data++; + sd->Size--; + } + if (id > (UInt32)0xFFFFFFFF) + return SZ_ERROR_UNSUPPORTED; + coder->MethodID = (UInt32)id; + + coder->NumStreams = 1; + coder->PropsOffset = 0; + coder->PropsSize = 0; + + if ((mainByte & 0x10) != 0) + { + UInt32 numStreams; + + RINOK(SzReadNumber32(sd, &numStreams)); + if (numStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + coder->NumStreams = (Byte)numStreams; + + RINOK(SzReadNumber32(sd, &numStreams)); + if (numStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coder->NumStreams; + + if (numInStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize = 0; + RINOK(SzReadNumber32(sd, &propsSize)); + if (propsSize > sd->Size) + return SZ_ERROR_ARCHIVE; + if (propsSize >= 0x80) + return SZ_ERROR_UNSUPPORTED; + coder->PropsOffset = sd->Data - dataStart; + coder->PropsSize = (Byte)propsSize; + sd->Data += (size_t)propsSize; + sd->Size -= (size_t)propsSize; + } + } + + /* + if (numInStreams == 1 && numCoders == 1) + { + f->NumPackStreams = 1; + f->PackStreams[0] = 0; + } + else + */ + { + Byte streamUsed[k_NumCodersStreams_in_Folder_MAX]; + UInt32 numBonds, numPackStreams; + + numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumBonds = numBonds; + + numPackStreams = numInStreams - numBonds; + if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumPackStreams = numPackStreams; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + + if (numBonds != 0) + { + Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX]; + + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + CSzBond *bp = f->Bonds + i; + + RINOK(SzReadNumber32(sd, &bp->InIndex)); + if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) + return SZ_ERROR_ARCHIVE; + streamUsed[bp->InIndex] = True; + + RINOK(SzReadNumber32(sd, &bp->OutIndex)); + if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) + return SZ_ERROR_ARCHIVE; + coderUsed[bp->OutIndex] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + f->UnpackStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + if (numPackStreams == 1) + { + for (i = 0; i < numInStreams; i++) + if (!streamUsed[i]) + break; + if (i == numInStreams) + return SZ_ERROR_ARCHIVE; + f->PackStreams[0] = i; + } + else + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + f->PackStreams[i] = index; + } + } + + f->NumCoders = numCoders; + + return SZ_OK; +} + + +static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) +{ + CSzData sd; + sd = *sd2; + for (; num != 0; num--) + { + Byte firstByte, mask; + unsigned i; + SZ_READ_BYTE_2(firstByte); + if ((firstByte & 0x80) == 0) + continue; + if ((firstByte & 0x40) == 0) + { + if (sd.Size == 0) + return SZ_ERROR_ARCHIVE; + sd.Size--; + sd.Data++; + continue; + } + mask = 0x20; + for (i = 2; i < 8 && (firstByte & mask) != 0; i++) + mask >>= 1; + if (i > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, i); + } + *sd2 = sd; + return SZ_OK; +} + + +#define k_Scan_NumCoders_MAX 64 +#define k_Scan_NumCodersStreams_in_Folder_MAX 64 + + +static SRes ReadUnpackInfo(CSzAr *p, + CSzData *sd2, + UInt32 numFoldersMax, + const CBuf *tempBufs, UInt32 numTempBufs, + ISzAllocPtr alloc) +{ + CSzData sd; + + UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex; + const Byte *startBufPtr; + Byte external; + + RINOK(WaitId(sd2, k7zIdFolder)); + + RINOK(SzReadNumber32(sd2, &numFolders)); + if (numFolders > numFoldersMax) + return SZ_ERROR_UNSUPPORTED; + p->NumFolders = numFolders; + + SZ_READ_BYTE_SD(sd2, external); + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)); + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc); + MY_ALLOC_ZE(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc); + + startBufPtr = sd.Data; + + packStreamIndex = 0; + numCodersOutStreams = 0; + + for (fo = 0; fo < numFolders; fo++) + { + UInt32 numCoders, ci, numInStreams = 0; + + p->FoCodersOffsets[fo] = sd.Data - startBufPtr; + + RINOK(SzReadNumber32(&sd, &numCoders)); + if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (ci = 0; ci < numCoders; ci++) + { + Byte mainByte; + unsigned idSize; + UInt32 coderInStreams; + + SZ_READ_BYTE_2(mainByte); + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + idSize = (mainByte & 0xF); + if (idSize > 8) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, idSize); + + coderInStreams = 1; + + if ((mainByte & 0x10) != 0) + { + UInt32 coderOutStreams; + RINOK(SzReadNumber32(&sd, &coderInStreams)); + RINOK(SzReadNumber32(&sd, &coderOutStreams)); + if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coderInStreams; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize; + RINOK(SzReadNumber32(&sd, &propsSize)); + if (propsSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, propsSize); + } + } + + { + UInt32 indexOfMainStream = 0; + UInt32 numPackStreams = 1; + + if (numCoders != 1 || numInStreams != 1) + { + Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX]; + Byte coderUsed[k_Scan_NumCoders_MAX]; + + UInt32 i; + UInt32 numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + + if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + UInt32 index; + + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numCoders || coderUsed[index]) + return SZ_ERROR_ARCHIVE; + coderUsed[index] = True; + } + + numPackStreams = numInStreams - numBonds; + + if (numPackStreams != 1) + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + indexOfMainStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; + numCodersOutStreams += numCoders; + if (numCodersOutStreams < numCoders) + return SZ_ERROR_UNSUPPORTED; + if (numPackStreams > p->NumPackStreams - packStreamIndex) + return SZ_ERROR_ARCHIVE; + packStreamIndex += numPackStreams; + } + } + + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + + { + size_t dataSize = sd.Data - startBufPtr; + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoCodersOffsets[fo] = dataSize; + MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc); + } + + if (external != 0) + { + if (sd.Size != 0) + return SZ_ERROR_ARCHIVE; + sd = *sd2; + } + + RINOK(WaitId(&sd, k7zIdCodersUnpackSize)); + + MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc); + { + UInt32 i; + for (i = 0; i < numCodersOutStreams; i++) + { + RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)); + } + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(&sd, &type)); + if (type == k7zIdEnd) + { + *sd2 = sd; + return SZ_OK; + } + if (type == k7zIdCRC) + { + RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)); + continue; + } + RINOK(SkipData(&sd)); + } +} + + +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex) +{ + return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]]; +} + + +typedef struct +{ + UInt32 NumTotalSubStreams; + UInt32 NumSubDigests; + CSzData sdNumSubStreams; + CSzData sdSizes; + CSzData sdCRCs; +} CSubStreamInfo; + + +static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) +{ + UInt64 type = 0; + UInt32 numSubDigests = 0; + UInt32 numFolders = p->NumFolders; + UInt32 numUnpackStreams = numFolders; + UInt32 numUnpackSizesInData = 0; + + for (;;) + { + RINOK(ReadID(sd, &type)); + if (type == k7zIdNumUnpackStream) + { + UInt32 i; + ssi->sdNumSubStreams.Data = sd->Data; + numUnpackStreams = 0; + numSubDigests = 0; + for (i = 0; i < numFolders; i++) + { + UInt32 numStreams; + RINOK(SzReadNumber32(sd, &numStreams)); + if (numUnpackStreams > numUnpackStreams + numStreams) + return SZ_ERROR_UNSUPPORTED; + numUnpackStreams += numStreams; + if (numStreams != 0) + numUnpackSizesInData += (numStreams - 1); + if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i)) + numSubDigests += numStreams; + } + ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data; + continue; + } + if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + + if (!ssi->sdNumSubStreams.Data) + { + numSubDigests = numFolders; + if (p->FolderCRCs.Defs) + numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders); + } + + ssi->NumTotalSubStreams = numUnpackStreams; + ssi->NumSubDigests = numSubDigests; + + if (type == k7zIdSize) + { + ssi->sdSizes.Data = sd->Data; + RINOK(SkipNumbers(sd, numUnpackSizesInData)); + ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data; + RINOK(ReadID(sd, &type)); + } + + for (;;) + { + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + ssi->sdCRCs.Data = sd->Data; + RINOK(SkipBitUi32s(sd, numSubDigests)); + ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data; + } + else + { + RINOK(SkipData(sd)); + } + RINOK(ReadID(sd, &type)); + } +} + +static SRes SzReadStreamsInfo(CSzAr *p, + CSzData *sd, + UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs, + UInt64 *dataOffset, + CSubStreamInfo *ssi, + ISzAllocPtr alloc) +{ + UInt64 type; + + SzData_Clear(&ssi->sdSizes); + SzData_Clear(&ssi->sdCRCs); + SzData_Clear(&ssi->sdNumSubStreams); + + *dataOffset = 0; + RINOK(ReadID(sd, &type)); + if (type == k7zIdPackInfo) + { + RINOK(ReadNumber(sd, dataOffset)); + RINOK(ReadPackInfo(p, sd, alloc)); + RINOK(ReadID(sd, &type)); + } + if (type == k7zIdUnpackInfo) + { + RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)); + RINOK(ReadID(sd, &type)); + } + if (type == k7zIdSubStreamsInfo) + { + RINOK(ReadSubStreamsInfo(p, sd, ssi)); + RINOK(ReadID(sd, &type)); + } + else + { + ssi->NumTotalSubStreams = p->NumFolders; + // ssi->NumSubDigests = 0; + } + + return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED); +} + +static SRes SzReadAndDecodePackedStreams( + ILookInStream *inStream, + CSzData *sd, + CBuf *tempBufs, + UInt32 numFoldersMax, + UInt64 baseOffset, + CSzAr *p, + ISzAllocPtr allocTemp) +{ + UInt64 dataStartPos; + UInt32 fo; + CSubStreamInfo ssi; + + RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)); + + dataStartPos += baseOffset; + if (p->NumFolders == 0) + return SZ_ERROR_ARCHIVE; + + for (fo = 0; fo < p->NumFolders; fo++) + Buf_Init(tempBufs + fo); + + for (fo = 0; fo < p->NumFolders; fo++) + { + CBuf *tempBuf = tempBufs + fo; + UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); + if ((size_t)unpackSize != unpackSize) + return SZ_ERROR_MEM; + if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) + return SZ_ERROR_MEM; + } + + for (fo = 0; fo < p->NumFolders; fo++) + { + const CBuf *tempBuf = tempBufs + fo; + RINOK(LookInStream_SeekTo(inStream, dataStartPos)); + RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)); + } + + return SZ_OK; +} + +static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets) +{ + size_t pos = 0; + *offsets++ = 0; + if (numFiles == 0) + return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE; + if (size < 2) + return SZ_ERROR_ARCHIVE; + if (data[size - 2] != 0 || data[size - 1] != 0) + return SZ_ERROR_ARCHIVE; + do + { + const Byte *p; + if (pos == size) + return SZ_ERROR_ARCHIVE; + for (p = data + pos; + #ifdef _WIN32 + *(const UInt16 *)p != 0 + #else + p[0] != 0 || p[1] != 0 + #endif + ; p += 2); + pos = p - data + 2; + *offsets++ = (pos >> 1); + } + while (--numFiles); + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, + CSzData *sd2, + const CBuf *tempBufs, UInt32 numTempBufs, + ISzAllocPtr alloc) +{ + CSzData sd; + UInt32 i; + CNtfsFileTime *vals; + Byte *defs; + Byte external; + + RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)); + + SZ_READ_BYTE_SD(sd2, external); + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)); + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc); + vals = p->Vals; + defs = p->Defs; + for (i = 0; i < num; i++) + if (SzBitArray_Check(defs, i)) + { + if (sd.Size < 8) + return SZ_ERROR_ARCHIVE; + vals[i].Low = GetUi32(sd.Data); + vals[i].High = GetUi32(sd.Data + 4); + SKIP_DATA2(sd, 8); + } + else + vals[i].High = vals[i].Low = 0; + + if (external == 0) + *sd2 = sd; + + return SZ_OK; +} + + +#define NUM_ADDITIONAL_STREAMS_MAX 8 + + +static SRes SzReadHeader2( + CSzArEx *p, /* allocMain */ + CSzData *sd, + ILookInStream *inStream, + CBuf *tempBufs, UInt32 *numTempBufs, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp + ) +{ + CSubStreamInfo ssi; + +{ + UInt64 type; + + SzData_Clear(&ssi.sdSizes); + SzData_Clear(&ssi.sdCRCs); + SzData_Clear(&ssi.sdNumSubStreams); + + ssi.NumSubDigests = 0; + ssi.NumTotalSubStreams = 0; + + RINOK(ReadID(sd, &type)); + + if (type == k7zIdArchiveProperties) + { + for (;;) + { + UInt64 type2; + RINOK(ReadID(sd, &type2)); + if (type2 == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdAdditionalStreamsInfo) + { + CSzAr tempAr; + SRes res; + + SzAr_Init(&tempAr); + res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, + p->startPosAfterHeader, &tempAr, allocTemp); + *numTempBufs = tempAr.NumFolders; + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + return res; + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdMainStreamsInfo) + { + RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs, + &p->dataPos, &ssi, allocMain)); + p->dataPos += p->startPosAfterHeader; + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdEnd) + { + return SZ_OK; + } + + if (type != k7zIdFilesInfo) + return SZ_ERROR_ARCHIVE; +} + +{ + UInt32 numFiles = 0; + UInt32 numEmptyStreams = 0; + const Byte *emptyStreams = NULL; + const Byte *emptyFiles = NULL; + + RINOK(SzReadNumber32(sd, &numFiles)); + p->NumFiles = numFiles; + + for (;;) + { + UInt64 type; + UInt64 size; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(ReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + + if (type >= ((UInt32)1 << 8)) + { + SKIP_DATA(sd, size); + } + else switch ((unsigned)type) + { + case k7zIdName: + { + size_t namesSize; + const Byte *namesData; + Byte external; + + SZ_READ_BYTE(external); + if (external == 0) + { + namesSize = (size_t)size - 1; + namesData = sd->Data; + } + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + namesData = (tempBufs)[index].data; + namesSize = (tempBufs)[index].size; + } + + if ((namesSize & 1) != 0) + return SZ_ERROR_ARCHIVE; + MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); + MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain); + RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) + if (external == 0) + { + SKIP_DATA(sd, namesSize); + } + break; + } + case k7zIdEmptyStream: + { + RINOK(RememberBitVector(sd, numFiles, &emptyStreams)); + numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); + emptyFiles = NULL; + break; + } + case k7zIdEmptyFile: + { + RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)); + break; + } + case k7zIdWinAttrib: + { + Byte external; + CSzData sdSwitch; + CSzData *sdPtr; + SzBitUi32s_Free(&p->Attribs, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)); + + SZ_READ_BYTE(external); + if (external == 0) + sdPtr = sd; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + sdSwitch.Data = (tempBufs)[index].data; + sdSwitch.Size = (tempBufs)[index].size; + sdPtr = &sdSwitch; + } + RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)); + break; + } + /* + case k7zParent: + { + SzBitUi32s_Free(&p->Parents, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain)); + RINOK(SzReadSwitch(sd)); + RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain)); + break; + } + */ + case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; + case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; + default: + { + SKIP_DATA(sd, size); + } + } + } + + if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + + { + UInt32 i; + UInt32 emptyFileIndex = 0; + UInt32 folderIndex = 0; + UInt32 remSubStreams = 0; + UInt32 numSubStreams = 0; + UInt64 unpackPos = 0; + const Byte *digestsDefs = NULL; + const Byte *digestsVals = NULL; + UInt32 digestsValsIndex = 0; + UInt32 digestIndex; + Byte allDigestsDefined = 0; + Byte isDirMask = 0; + Byte crcMask = 0; + Byte mask = 0x80; + + MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain); + MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain); + MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain); + MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain); + + RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)); + + if (ssi.sdCRCs.Size != 0) + { + SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined); + if (allDigestsDefined) + digestsVals = ssi.sdCRCs.Data; + else + { + size_t numBytes = (ssi.NumSubDigests + 7) >> 3; + digestsDefs = ssi.sdCRCs.Data; + digestsVals = digestsDefs + numBytes; + } + } + + digestIndex = 0; + + for (i = 0; i < numFiles; i++, mask >>= 1) + { + if (mask == 0) + { + UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + isDirMask = 0; + crcMask = 0; + mask = 0x80; + } + + p->UnpackPositions[i] = unpackPos; + p->CRCs.Vals[i] = 0; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + { + if (emptyFiles) + { + if (!SzBitArray_Check(emptyFiles, emptyFileIndex)) + isDirMask |= mask; + emptyFileIndex++; + } + else + isDirMask |= mask; + if (remSubStreams == 0) + { + p->FileToFolder[i] = (UInt32)-1; + continue; + } + } + + if (remSubStreams == 0) + { + for (;;) + { + if (folderIndex >= p->db.NumFolders) + return SZ_ERROR_ARCHIVE; + p->FolderToFile[folderIndex] = i; + numSubStreams = 1; + if (ssi.sdNumSubStreams.Data) + { + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + } + remSubStreams = numSubStreams; + if (numSubStreams != 0) + break; + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + + folderIndex++; + } + } + + p->FileToFolder[i] = folderIndex; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + continue; + + if (--remSubStreams == 0) + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; + if (folderUnpackSize < unpackPos - startFolderUnpackPos) + return SZ_ERROR_ARCHIVE; + unpackPos = startFolderUnpackPos + folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + + if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i)) + { + p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; + crcMask |= mask; + } + else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + { + p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); + digestsValsIndex++; + crcMask |= mask; + } + + folderIndex++; + } + else + { + UInt64 v; + RINOK(ReadNumber(&ssi.sdSizes, &v)); + unpackPos += v; + if (unpackPos < v) + return SZ_ERROR_ARCHIVE; + if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + { + p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); + digestsValsIndex++; + crcMask |= mask; + } + } + } + + if (mask != 0x80) + { + UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + } + + p->UnpackPositions[i] = unpackPos; + + if (remSubStreams != 0) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + p->FolderToFile[folderIndex] = i; + if (folderIndex >= p->db.NumFolders) + break; + if (!ssi.sdNumSubStreams.Data) + return SZ_ERROR_ARCHIVE; + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + if (numSubStreams != 0) + return SZ_ERROR_ARCHIVE; + /* + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + */ + folderIndex++; + } + + if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0) + return SZ_ERROR_ARCHIVE; + } +} + return SZ_OK; +} + + +static SRes SzReadHeader( + CSzArEx *p, + CSzData *sd, + ILookInStream *inStream, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp) +{ + UInt32 i; + UInt32 numTempBufs = 0; + SRes res; + CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX]; + + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Init(tempBufs + i); + + res = SzReadHeader2(p, sd, inStream, + tempBufs, &numTempBufs, + allocMain, allocTemp); + + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Free(tempBufs + i, allocTemp); + + RINOK(res); + + if (sd->Size != 0) + return SZ_ERROR_FAIL; + + return res; +} + +static SRes SzArEx_Open2( + CSzArEx *p, + ILookInStream *inStream, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp) +{ + Byte header[k7zStartHeaderSize]; + Int64 startArcPos; + UInt64 nextHeaderOffset, nextHeaderSize; + size_t nextHeaderSizeT; + UInt32 nextHeaderCRC; + CBuf buf; + SRes res; + + startArcPos = 0; + RINOK(ILookInStream_Seek(inStream, &startArcPos, SZ_SEEK_CUR)); + + RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); + + if (!TestSignatureCandidate(header)) + return SZ_ERROR_NO_ARCHIVE; + if (header[6] != k7zMajorVersion) + return SZ_ERROR_UNSUPPORTED; + + nextHeaderOffset = GetUi64(header + 12); + nextHeaderSize = GetUi64(header + 20); + nextHeaderCRC = GetUi32(header + 28); + + p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; + + if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) + return SZ_ERROR_CRC; + + nextHeaderSizeT = (size_t)nextHeaderSize; + if (nextHeaderSizeT != nextHeaderSize) + return SZ_ERROR_MEM; + if (nextHeaderSizeT == 0) + return SZ_OK; + if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || + nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) + return SZ_ERROR_NO_ARCHIVE; + + { + Int64 pos = 0; + RINOK(ILookInStream_Seek(inStream, &pos, SZ_SEEK_END)); + if ((UInt64)pos < startArcPos + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) + return SZ_ERROR_INPUT_EOF; + } + + RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); + + if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp)) + return SZ_ERROR_MEM; + + res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT); + + if (res == SZ_OK) + { + res = SZ_ERROR_ARCHIVE; + if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC) + { + CSzData sd; + UInt64 type; + sd.Data = buf.data; + sd.Size = buf.size; + + res = ReadID(&sd, &type); + + if (res == SZ_OK && type == k7zIdEncodedHeader) + { + CSzAr tempAr; + CBuf tempBuf; + Buf_Init(&tempBuf); + + SzAr_Init(&tempAr); + res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp); + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + { + Buf_Free(&tempBuf, allocTemp); + } + else + { + Buf_Free(&buf, allocTemp); + buf.data = tempBuf.data; + buf.size = tempBuf.size; + sd.Data = buf.data; + sd.Size = buf.size; + res = ReadID(&sd, &type); + } + } + + if (res == SZ_OK) + { + if (type == k7zIdHeader) + { + /* + CSzData sd2; + unsigned ttt; + for (ttt = 0; ttt < 40000; ttt++) + { + SzArEx_Free(p, allocMain); + sd2 = sd; + res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp); + if (res != SZ_OK) + break; + } + */ + res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp); + } + else + res = SZ_ERROR_UNSUPPORTED; + } + } + } + + Buf_Free(&buf, allocTemp); + return res; +} + + +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, + ISzAllocPtr allocMain, ISzAllocPtr allocTemp) +{ + SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); + if (res != SZ_OK) + SzArEx_Free(p, allocMain); + return res; +} + + +SRes SzArEx_Extract( + const CSzArEx *p, + ILookInStream *inStream, + UInt32 fileIndex, + UInt32 *blockIndex, + Byte **tempBuf, + size_t *outBufferSize, + size_t *offset, + size_t *outSizeProcessed, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp) +{ + UInt32 folderIndex = p->FileToFolder[fileIndex]; + SRes res = SZ_OK; + + *offset = 0; + *outSizeProcessed = 0; + + if (folderIndex == (UInt32)-1) + { + ISzAlloc_Free(allocMain, *tempBuf); + *blockIndex = folderIndex; + *tempBuf = NULL; + *outBufferSize = 0; + return SZ_OK; + } + + if (*tempBuf == NULL || *blockIndex != folderIndex) + { + UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + /* + UInt64 unpackSizeSpec = + p->UnpackPositions[p->FolderToFile[(size_t)folderIndex + 1]] - + p->UnpackPositions[p->FolderToFile[folderIndex]]; + */ + size_t unpackSize = (size_t)unpackSizeSpec; + + if (unpackSize != unpackSizeSpec) + return SZ_ERROR_MEM; + *blockIndex = folderIndex; + ISzAlloc_Free(allocMain, *tempBuf); + *tempBuf = NULL; + + if (res == SZ_OK) + { + *outBufferSize = unpackSize; + if (unpackSize != 0) + { + *tempBuf = (Byte *)ISzAlloc_Alloc(allocMain, unpackSize); + if (*tempBuf == NULL) + res = SZ_ERROR_MEM; + } + + if (res == SZ_OK) + { + res = SzAr_DecodeFolder(&p->db, folderIndex, + inStream, p->dataPos, *tempBuf, unpackSize, allocTemp); + } + } + } + + if (res == SZ_OK) + { + UInt64 unpackPos = p->UnpackPositions[fileIndex]; + *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); + *outSizeProcessed = (size_t)(p->UnpackPositions[(size_t)fileIndex + 1] - unpackPos); + if (*offset + *outSizeProcessed > *outBufferSize) + return SZ_ERROR_FAIL; + if (SzBitWithVals_Check(&p->CRCs, fileIndex)) + if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) + res = SZ_ERROR_CRC; + } + + return res; +} + + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + size_t offs = p->FileNameOffsets[fileIndex]; + size_t len = p->FileNameOffsets[fileIndex + 1] - offs; + if (dest != 0) + { + size_t i; + const Byte *src = p->FileNames + offs * 2; + for (i = 0; i < len; i++) + dest[i] = GetUi16(src + i * 2); + } + return len; +} + +/* +size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex) +{ + size_t len; + if (!p->FileNameOffsets) + return 1; + len = 0; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + if SzBitWithVals_Check(&p->Parents, fileIndex) + parent = p->Parents.Vals[fileIndex]; + if (parent == (UInt32)(Int32)-1) + return len; + fileIndex = parent; + } +} + +UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + BoolInt needSlash; + if (!p->FileNameOffsets) + { + *(--dest) = 0; + return dest; + } + needSlash = False; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen); + if (needSlash) + *(dest - 1) = '/'; + needSlash = True; + dest -= curLen; + + if SzBitWithVals_Check(&p->Parents, fileIndex) + parent = p->Parents.Vals[fileIndex]; + if (parent == (UInt32)(Int32)-1) + return dest; + fileIndex = parent; + } +} +*/ diff --git a/lzma/7zBuf.c b/lzma/7zBuf.c new file mode 100644 index 0000000..438bba6 --- /dev/null +++ b/lzma/7zBuf.c @@ -0,0 +1,36 @@ +/* 7zBuf.c -- Byte Buffer +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zBuf.h" + +void Buf_Init(CBuf *p) +{ + p->data = 0; + p->size = 0; +} + +int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc) +{ + p->size = 0; + if (size == 0) + { + p->data = 0; + return 1; + } + p->data = (Byte *)ISzAlloc_Alloc(alloc, size); + if (p->data) + { + p->size = size; + return 1; + } + return 0; +} + +void Buf_Free(CBuf *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->data); + p->data = 0; + p->size = 0; +} diff --git a/lzma/7zBuf.h b/lzma/7zBuf.h new file mode 100644 index 0000000..5942d6e --- /dev/null +++ b/lzma/7zBuf.h @@ -0,0 +1,35 @@ +/* 7zBuf.h -- Byte Buffer +2017-04-03 : Igor Pavlov : Public domain */ + +#ifndef __7Z_BUF_H +#define __7Z_BUF_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +typedef struct +{ + Byte *data; + size_t size; +} CBuf; + +void Buf_Init(CBuf *p); +int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc); +void Buf_Free(CBuf *p, ISzAllocPtr alloc); + +typedef struct +{ + Byte *data; + size_t size; + size_t pos; +} CDynBuf; + +void DynBuf_Construct(CDynBuf *p); +void DynBuf_SeekToBeg(CDynBuf *p); +int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc); +void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc); + +EXTERN_C_END + +#endif diff --git a/lzma/7zBuf2.c b/lzma/7zBuf2.c new file mode 100644 index 0000000..49b4343 --- /dev/null +++ b/lzma/7zBuf2.c @@ -0,0 +1,52 @@ +/* 7zBuf2.c -- Byte Buffer +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zBuf.h" + +void DynBuf_Construct(CDynBuf *p) +{ + p->data = 0; + p->size = 0; + p->pos = 0; +} + +void DynBuf_SeekToBeg(CDynBuf *p) +{ + p->pos = 0; +} + +int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc) +{ + if (size > p->size - p->pos) + { + size_t newSize = p->pos + size; + Byte *data; + newSize += newSize / 4; + data = (Byte *)ISzAlloc_Alloc(alloc, newSize); + if (!data) + return 0; + p->size = newSize; + if (p->pos != 0) + memcpy(data, p->data, p->pos); + ISzAlloc_Free(alloc, p->data); + p->data = data; + } + if (size != 0) + { + memcpy(p->data + p->pos, buf, size); + p->pos += size; + } + return 1; +} + +void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->data); + p->data = 0; + p->size = 0; + p->pos = 0; +} diff --git a/lzma/7zCrc.c b/lzma/7zCrc.c new file mode 100644 index 0000000..40ab759 --- /dev/null +++ b/lzma/7zCrc.c @@ -0,0 +1,128 @@ +/* 7zCrc.c -- CRC32 init +2017-06-06 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zCrc.h" +#include "CpuArch.h" + +#define kCrcPoly 0xEDB88320 + +#ifdef MY_CPU_LE + #define CRC_NUM_TABLES 8 +#else + #define CRC_NUM_TABLES 9 + + #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) + + UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table); +#endif + +#ifndef MY_CPU_BE + UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); +#endif + +typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); + +CRC_FUNC g_CrcUpdateT4; +CRC_FUNC g_CrcUpdateT8; +CRC_FUNC g_CrcUpdate; + +UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; + +UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) +{ + return g_CrcUpdate(v, data, size, g_CrcTable); +} + +UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) +{ + return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; +} + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + const Byte *pEnd = p + size; + for (; p != pEnd; p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +void MY_FAST_CALL CrcGenerateTable() +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt32 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); + g_CrcTable[i] = r; + } + for (i = 256; i < 256 * CRC_NUM_TABLES; i++) + { + UInt32 r = g_CrcTable[(size_t)i - 256]; + g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); + } + + #if CRC_NUM_TABLES < 4 + + g_CrcUpdate = CrcUpdateT1; + + #else + + #ifdef MY_CPU_LE + + g_CrcUpdateT4 = CrcUpdateT4; + g_CrcUpdate = CrcUpdateT4; + + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; + + #ifdef MY_CPU_X86_OR_AMD64 + if (!CPU_Is_InOrder()) + #endif + g_CrcUpdate = CrcUpdateT8; + #endif + + #else + { + #ifndef MY_CPU_BE + UInt32 k = 0x01020304; + const Byte *p = (const Byte *)&k; + if (p[0] == 4 && p[1] == 3) + { + g_CrcUpdateT4 = CrcUpdateT4; + g_CrcUpdate = CrcUpdateT4; + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; + g_CrcUpdate = CrcUpdateT8; + #endif + } + else if (p[0] != 1 || p[1] != 2) + g_CrcUpdate = CrcUpdateT1; + else + #endif + { + for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) + { + UInt32 x = g_CrcTable[(size_t)i - 256]; + g_CrcTable[i] = CRC_UINT32_SWAP(x); + } + g_CrcUpdateT4 = CrcUpdateT1_BeT4; + g_CrcUpdate = CrcUpdateT1_BeT4; + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT1_BeT8; + g_CrcUpdate = CrcUpdateT1_BeT8; + #endif + } + } + #endif + + #endif +} diff --git a/lzma/7zCrc.h b/lzma/7zCrc.h new file mode 100644 index 0000000..3b04594 --- /dev/null +++ b/lzma/7zCrc.h @@ -0,0 +1,25 @@ +/* 7zCrc.h -- CRC32 calculation +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __7Z_CRC_H +#define __7Z_CRC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +extern UInt32 g_CrcTable[]; + +/* Call CrcGenerateTable one time before other CRC functions */ +void MY_FAST_CALL CrcGenerateTable(void); + +#define CRC_INIT_VAL 0xFFFFFFFF +#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) +#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); +UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); + +EXTERN_C_END + +#endif diff --git a/lzma/7zCrcOpt.c b/lzma/7zCrcOpt.c new file mode 100644 index 0000000..2ee0de8 --- /dev/null +++ b/lzma/7zCrcOpt.c @@ -0,0 +1,115 @@ +/* 7zCrcOpt.c -- CRC32 calculation +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#ifndef MY_CPU_BE + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + v ^= *(const UInt32 *)p; + v = + (table + 0x300)[((v ) & 0xFF)] + ^ (table + 0x200)[((v >> 8) & 0xFF)] + ^ (table + 0x100)[((v >> 16) & 0xFF)] + ^ (table + 0x000)[((v >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32 *)p; + v = + (table + 0x700)[((v ) & 0xFF)] + ^ (table + 0x600)[((v >> 8) & 0xFF)] + ^ (table + 0x500)[((v >> 16) & 0xFF)] + ^ (table + 0x400)[((v >> 24))]; + d = *((const UInt32 *)p + 1); + v ^= + (table + 0x300)[((d ) & 0xFF)] + ^ (table + 0x200)[((d >> 8) & 0xFF)] + ^ (table + 0x100)[((d >> 16) & 0xFF)] + ^ (table + 0x000)[((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +#endif + + +#ifndef MY_CPU_LE + +#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) + +#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8)) + +UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + table += 0x100; + v = CRC_UINT32_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + v ^= *(const UInt32 *)p; + v = + (table + 0x000)[((v ) & 0xFF)] + ^ (table + 0x100)[((v >> 8) & 0xFF)] + ^ (table + 0x200)[((v >> 16) & 0xFF)] + ^ (table + 0x300)[((v >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT32_SWAP(v); +} + +UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + table += 0x100; + v = CRC_UINT32_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32 *)p; + v = + (table + 0x400)[((v ) & 0xFF)] + ^ (table + 0x500)[((v >> 8) & 0xFF)] + ^ (table + 0x600)[((v >> 16) & 0xFF)] + ^ (table + 0x700)[((v >> 24))]; + d = *((const UInt32 *)p + 1); + v ^= + (table + 0x000)[((d ) & 0xFF)] + ^ (table + 0x100)[((d >> 8) & 0xFF)] + ^ (table + 0x200)[((d >> 16) & 0xFF)] + ^ (table + 0x300)[((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT32_SWAP(v); +} + +#endif diff --git a/lzma/7zDec.c b/lzma/7zDec.c new file mode 100644 index 0000000..2a7b090 --- /dev/null +++ b/lzma/7zDec.c @@ -0,0 +1,591 @@ +/* 7zDec.c -- Decoding from 7z folder +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define _7ZIP_PPMD_SUPPPORT */ + +#include "7z.h" +#include "7zCrc.h" + +#include "Bcj2.h" +#include "Bra.h" +#include "CpuArch.h" +#include "Delta.h" +#include "LzmaDec.h" +#include "Lzma2Dec.h" +#ifdef _7ZIP_PPMD_SUPPPORT +#include "Ppmd7.h" +#endif + +#define k_Copy 0 +#define k_Delta 3 +#define k_LZMA2 0x21 +#define k_LZMA 0x30101 +#define k_BCJ 0x3030103 +#define k_BCJ2 0x303011B +#define k_PPC 0x3030205 +#define k_IA64 0x3030401 +#define k_ARM 0x3030501 +#define k_ARMT 0x3030701 +#define k_SPARC 0x3030805 + + +#ifdef _7ZIP_PPMD_SUPPPORT + +#define k_PPMD 0x30401 + +typedef struct +{ + IByteIn vt; + const Byte *cur; + const Byte *end; + const Byte *begin; + UInt64 processed; + BoolInt extra; + SRes res; + const ILookInStream *inStream; +} CByteInToLook; + +static Byte ReadByte(const IByteIn *pp) +{ + CByteInToLook *p = CONTAINER_FROM_VTBL(pp, CByteInToLook, vt); + if (p->cur != p->end) + return *p->cur++; + if (p->res == SZ_OK) + { + size_t size = p->cur - p->begin; + p->processed += size; + p->res = ILookInStream_Skip(p->inStream, size); + size = (1 << 25); + p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size); + p->cur = p->begin; + p->end = p->begin + size; + if (size != 0) + return *p->cur++;; + } + p->extra = True; + return 0; +} + +static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, const ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) +{ + CPpmd7 ppmd; + CByteInToLook s; + SRes res = SZ_OK; + + s.vt.Read = ReadByte; + s.inStream = inStream; + s.begin = s.end = s.cur = NULL; + s.extra = False; + s.res = SZ_OK; + s.processed = 0; + + if (propsSize != 5) + return SZ_ERROR_UNSUPPORTED; + + { + unsigned order = props[0]; + UInt32 memSize = GetUi32(props + 1); + if (order < PPMD7_MIN_ORDER || + order > PPMD7_MAX_ORDER || + memSize < PPMD7_MIN_MEM_SIZE || + memSize > PPMD7_MAX_MEM_SIZE) + return SZ_ERROR_UNSUPPORTED; + Ppmd7_Construct(&ppmd); + if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) + return SZ_ERROR_MEM; + Ppmd7_Init(&ppmd, order); + } + { + CPpmd7z_RangeDec rc; + Ppmd7z_RangeDec_CreateVTable(&rc); + rc.Stream = &s.vt; + if (!Ppmd7z_RangeDec_Init(&rc)) + res = SZ_ERROR_DATA; + else if (s.extra) + res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); + else + { + SizeT i; + for (i = 0; i < outSize; i++) + { + int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.vt); + if (s.extra || sym < 0) + break; + outBuffer[i] = (Byte)sym; + } + if (i != outSize) + res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); + else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc)) + res = SZ_ERROR_DATA; + } + } + Ppmd7_Free(&ppmd, allocMain); + return res; +} + +#endif + + +static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) +{ + CLzmaDec state; + SRes res = SZ_OK; + + LzmaDec_Construct(&state); + RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)); + state.dic = outBuffer; + state.dicBufSize = outSize; + LzmaDec_Init(&state); + + for (;;) + { + const void *inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = ILookInStream_Look(inStream, &inBuf, &lookahead); + if (res != SZ_OK) + break; + + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; + ELzmaStatus status; + res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (outSize != state.dicPos || inSize != 0) + res = SZ_ERROR_DATA; + break; + } + + if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + break; + + if (inProcessed == 0 && dicPos == state.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + + res = ILookInStream_Skip(inStream, inProcessed); + if (res != SZ_OK) + break; + } + } + + LzmaDec_FreeProbs(&state, allocMain); + return res; +} + + +#ifndef _7Z_NO_METHOD_LZMA2 + +static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) +{ + CLzma2Dec state; + SRes res = SZ_OK; + + Lzma2Dec_Construct(&state); + if (propsSize != 1) + return SZ_ERROR_DATA; + RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)); + state.decoder.dic = outBuffer; + state.decoder.dicBufSize = outSize; + Lzma2Dec_Init(&state); + + for (;;) + { + const void *inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = ILookInStream_Look(inStream, &inBuf, &lookahead); + if (res != SZ_OK) + break; + + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; + ELzmaStatus status; + res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (outSize != state.decoder.dicPos || inSize != 0) + res = SZ_ERROR_DATA; + break; + } + + if (inProcessed == 0 && dicPos == state.decoder.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + + res = ILookInStream_Skip(inStream, inProcessed); + if (res != SZ_OK) + break; + } + } + + Lzma2Dec_FreeProbs(&state, allocMain); + return res; +} + +#endif + + +static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) +{ + while (inSize > 0) + { + const void *inBuf; + size_t curSize = (1 << 18); + if (curSize > inSize) + curSize = (size_t)inSize; + RINOK(ILookInStream_Look(inStream, &inBuf, &curSize)); + if (curSize == 0) + return SZ_ERROR_INPUT_EOF; + memcpy(outBuffer, inBuf, curSize); + outBuffer += curSize; + inSize -= curSize; + RINOK(ILookInStream_Skip(inStream, curSize)); + } + return SZ_OK; +} + +static BoolInt IS_MAIN_METHOD(UInt32 m) +{ + switch (m) + { + case k_Copy: + case k_LZMA: + #ifndef _7Z_NO_METHOD_LZMA2 + case k_LZMA2: + #endif + #ifdef _7ZIP_PPMD_SUPPPORT + case k_PPMD: + #endif + return True; + } + return False; +} + +static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c) +{ + return + c->NumStreams == 1 + /* && c->MethodID <= (UInt32)0xFFFFFFFF */ + && IS_MAIN_METHOD((UInt32)c->MethodID); +} + +#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4) + +static SRes CheckSupportedFolder(const CSzFolder *f) +{ + if (f->NumCoders < 1 || f->NumCoders > 4) + return SZ_ERROR_UNSUPPORTED; + if (!IS_SUPPORTED_CODER(&f->Coders[0])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumCoders == 1) + { + if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + + + #ifndef _7Z_NO_METHODS_FILTERS + + if (f->NumCoders == 2) + { + const CSzCoderInfo *c = &f->Coders[1]; + if ( + /* c->MethodID > (UInt32)0xFFFFFFFF || */ + c->NumStreams != 1 + || f->NumPackStreams != 1 + || f->PackStreams[0] != 0 + || f->NumBonds != 1 + || f->Bonds[0].InIndex != 1 + || f->Bonds[0].OutIndex != 0) + return SZ_ERROR_UNSUPPORTED; + switch ((UInt32)c->MethodID) + { + case k_Delta: + case k_BCJ: + case k_PPC: + case k_IA64: + case k_SPARC: + case k_ARM: + case k_ARMT: + break; + default: + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; + } + + #endif + + + if (f->NumCoders == 4) + { + if (!IS_SUPPORTED_CODER(&f->Coders[1]) + || !IS_SUPPORTED_CODER(&f->Coders[2]) + || !IS_BCJ2(&f->Coders[3])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumPackStreams != 4 + || f->PackStreams[0] != 2 + || f->PackStreams[1] != 6 + || f->PackStreams[2] != 1 + || f->PackStreams[3] != 0 + || f->NumBonds != 3 + || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0 + || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1 + || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + + return SZ_ERROR_UNSUPPORTED; +} + +#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; + +static SRes SzFolder_Decode2(const CSzFolder *folder, + const Byte *propsData, + const UInt64 *unpackSizes, + const UInt64 *packPositions, + ILookInStream *inStream, UInt64 startPos, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain, + Byte *tempBuf[]) +{ + UInt32 ci; + SizeT tempSizes[3] = { 0, 0, 0}; + SizeT tempSize3 = 0; + Byte *tempBuf3 = 0; + + RINOK(CheckSupportedFolder(folder)); + + for (ci = 0; ci < folder->NumCoders; ci++) + { + const CSzCoderInfo *coder = &folder->Coders[ci]; + + if (IS_MAIN_METHOD((UInt32)coder->MethodID)) + { + UInt32 si = 0; + UInt64 offset; + UInt64 inSize; + Byte *outBufCur = outBuffer; + SizeT outSizeCur = outSize; + if (folder->NumCoders == 4) + { + UInt32 indices[] = { 3, 2, 0 }; + UInt64 unpackSize = unpackSizes[ci]; + si = indices[ci]; + if (ci < 2) + { + Byte *temp; + outSizeCur = (SizeT)unpackSize; + if (outSizeCur != unpackSize) + return SZ_ERROR_MEM; + temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur); + if (!temp && outSizeCur != 0) + return SZ_ERROR_MEM; + outBufCur = tempBuf[1 - ci] = temp; + tempSizes[1 - ci] = outSizeCur; + } + else if (ci == 2) + { + if (unpackSize > outSize) /* check it */ + return SZ_ERROR_PARAM; + tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); + tempSize3 = outSizeCur = (SizeT)unpackSize; + } + else + return SZ_ERROR_UNSUPPORTED; + } + offset = packPositions[si]; + inSize = packPositions[(size_t)si + 1] - offset; + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + + if (coder->MethodID == k_Copy) + { + if (inSize != outSizeCur) /* check it */ + return SZ_ERROR_DATA; + RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); + } + else if (coder->MethodID == k_LZMA) + { + RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); + } + #ifndef _7Z_NO_METHOD_LZMA2 + else if (coder->MethodID == k_LZMA2) + { + RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); + } + #endif + #ifdef _7ZIP_PPMD_SUPPPORT + else if (coder->MethodID == k_PPMD) + { + RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); + } + #endif + else + return SZ_ERROR_UNSUPPORTED; + } + else if (coder->MethodID == k_BCJ2) + { + UInt64 offset = packPositions[1]; + UInt64 s3Size = packPositions[2] - offset; + + if (ci != 3) + return SZ_ERROR_UNSUPPORTED; + + tempSizes[2] = (SizeT)s3Size; + if (tempSizes[2] != s3Size) + return SZ_ERROR_MEM; + tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]); + if (!tempBuf[2] && tempSizes[2] != 0) + return SZ_ERROR_MEM; + + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])); + + if ((tempSizes[0] & 3) != 0 || + (tempSizes[1] & 3) != 0 || + tempSize3 + tempSizes[0] + tempSizes[1] != outSize) + return SZ_ERROR_DATA; + + { + CBcj2Dec p; + + p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3; + p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0]; + p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1]; + p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2]; + + p.dest = outBuffer; + p.destLim = outBuffer + outSize; + + Bcj2Dec_Init(&p); + RINOK(Bcj2Dec_Decode(&p)); + + { + unsigned i; + for (i = 0; i < 4; i++) + if (p.bufs[i] != p.lims[i]) + return SZ_ERROR_DATA; + + if (!Bcj2Dec_IsFinished(&p)) + return SZ_ERROR_DATA; + + if (p.dest != p.destLim + || p.state != BCJ2_STREAM_MAIN) + return SZ_ERROR_DATA; + } + } + } + #ifndef _7Z_NO_METHODS_FILTERS + else if (ci == 1) + { + if (coder->MethodID == k_Delta) + { + if (coder->PropsSize != 1) + return SZ_ERROR_UNSUPPORTED; + { + Byte state[DELTA_STATE_SIZE]; + Delta_Init(state); + Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); + } + } + else + { + if (coder->PropsSize != 0) + return SZ_ERROR_UNSUPPORTED; + switch (coder->MethodID) + { + case k_BCJ: + { + UInt32 state; + x86_Convert_Init(state); + x86_Convert(outBuffer, outSize, 0, &state, 0); + break; + } + CASE_BRA_CONV(PPC) + CASE_BRA_CONV(IA64) + CASE_BRA_CONV(SPARC) + CASE_BRA_CONV(ARM) + CASE_BRA_CONV(ARMT) + default: + return SZ_ERROR_UNSUPPORTED; + } + } + } + #endif + else + return SZ_ERROR_UNSUPPORTED; + } + + return SZ_OK; +} + + +SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, + ILookInStream *inStream, UInt64 startPos, + Byte *outBuffer, size_t outSize, + ISzAllocPtr allocMain) +{ + SRes res; + CSzFolder folder; + CSzData sd; + + const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex]; + sd.Data = data; + sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex]; + + res = SzGetNextFolderItem(&folder, &sd); + + if (res != SZ_OK) + return res; + + if (sd.Size != 0 + || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex] + || outSize != SzAr_GetFolderUnpackSize(p, folderIndex)) + return SZ_ERROR_FAIL; + { + unsigned i; + Byte *tempBuf[3] = { 0, 0, 0}; + + res = SzFolder_Decode2(&folder, data, + &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]], + p->PackPositions + p->FoStartPackStreamIndex[folderIndex], + inStream, startPos, + outBuffer, (SizeT)outSize, allocMain, tempBuf); + + for (i = 0; i < 3; i++) + ISzAlloc_Free(allocMain, tempBuf[i]); + + if (res == SZ_OK) + if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex)) + if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex]) + res = SZ_ERROR_CRC; + + return res; + } +} diff --git a/lzma/7zFile.c b/lzma/7zFile.c new file mode 100644 index 0000000..e486901 --- /dev/null +++ b/lzma/7zFile.c @@ -0,0 +1,286 @@ +/* 7zFile.c -- File IO +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zFile.h" + +#ifndef USE_WINDOWS_FILE + +#ifndef UNDER_CE +#include +#endif + +#else + +/* + ReadFile and WriteFile functions in Windows have BUG: + If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) + from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES + (Insufficient system resources exist to complete the requested service). + Probably in some version of Windows there are problems with other sizes: + for 32 MB (maybe also for 16 MB). + And message can be "Network connection was lost" +*/ + +#define kChunkSizeMax (1 << 22) + +#endif + +void File_Construct(CSzFile *p) +{ + #ifdef USE_WINDOWS_FILE + p->handle = INVALID_HANDLE_VALUE; + #else + p->file = NULL; + #endif +} + +#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) +static WRes File_Open(CSzFile *p, const char *name, int writeMode) +{ + #ifdef USE_WINDOWS_FILE + p->handle = CreateFileA(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); + #else + p->file = fopen(name, writeMode ? "wb+" : "rb"); + return (p->file != 0) ? 0 : + #ifdef UNDER_CE + 2; /* ENOENT */ + #else + errno; + #endif + #endif +} + +WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } +WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); } +#endif + +#ifdef USE_WINDOWS_FILE +static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) +{ + p->handle = CreateFileW(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); +} +WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } +WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } +#endif + +WRes File_Close(CSzFile *p) +{ + #ifdef USE_WINDOWS_FILE + if (p->handle != INVALID_HANDLE_VALUE) + { + if (!CloseHandle(p->handle)) + return GetLastError(); + p->handle = INVALID_HANDLE_VALUE; + } + #else + if (p->file != NULL) + { + int res = fclose(p->file); + if (res != 0) + return res; + p->file = NULL; + } + #endif + return 0; +} + +WRes File_Read(CSzFile *p, void *data, size_t *size) +{ + size_t originalSize = *size; + if (originalSize == 0) + return 0; + + #ifdef USE_WINDOWS_FILE + + *size = 0; + do + { + DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); + data = (void *)((Byte *)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + if (processed == 0) + break; + } + while (originalSize > 0); + return 0; + + #else + + *size = fread(data, 1, originalSize, p->file); + if (*size == originalSize) + return 0; + return ferror(p->file); + + #endif +} + +WRes File_Write(CSzFile *p, const void *data, size_t *size) +{ + size_t originalSize = *size; + if (originalSize == 0) + return 0; + + #ifdef USE_WINDOWS_FILE + + *size = 0; + do + { + DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); + data = (void *)((Byte *)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + if (processed == 0) + break; + } + while (originalSize > 0); + return 0; + + #else + + *size = fwrite(data, 1, originalSize, p->file); + if (*size == originalSize) + return 0; + return ferror(p->file); + + #endif +} + +WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) +{ + #ifdef USE_WINDOWS_FILE + + LARGE_INTEGER value; + DWORD moveMethod; + value.LowPart = (DWORD)*pos; + value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ + switch (origin) + { + case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; + case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; + case SZ_SEEK_END: moveMethod = FILE_END; break; + default: return ERROR_INVALID_PARAMETER; + } + value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); + if (value.LowPart == 0xFFFFFFFF) + { + WRes res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *pos = ((Int64)value.HighPart << 32) | value.LowPart; + return 0; + + #else + + int moveMethod; + int res; + switch (origin) + { + case SZ_SEEK_SET: moveMethod = SEEK_SET; break; + case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; + case SZ_SEEK_END: moveMethod = SEEK_END; break; + default: return 1; + } + res = fseek(p->file, (long)*pos, moveMethod); + *pos = ftell(p->file); + return res; + + #endif +} + +WRes File_GetLength(CSzFile *p, UInt64 *length) +{ + #ifdef USE_WINDOWS_FILE + + DWORD sizeHigh; + DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); + if (sizeLow == 0xFFFFFFFF) + { + DWORD res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *length = (((UInt64)sizeHigh) << 32) + sizeLow; + return 0; + + #else + + long pos = ftell(p->file); + int res = fseek(p->file, 0, SEEK_END); + *length = ftell(p->file); + fseek(p->file, pos, SEEK_SET); + return res; + + #endif +} + + +/* ---------- FileSeqInStream ---------- */ + +static SRes FileSeqInStream_Read(const ISeqInStream *pp, void *buf, size_t *size) +{ + CFileSeqInStream *p = CONTAINER_FROM_VTBL(pp, CFileSeqInStream, vt); + return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; +} + +void FileSeqInStream_CreateVTable(CFileSeqInStream *p) +{ + p->vt.Read = FileSeqInStream_Read; +} + + +/* ---------- FileInStream ---------- */ + +static SRes FileInStream_Read(const ISeekInStream *pp, void *buf, size_t *size) +{ + CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); + return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; +} + +static SRes FileInStream_Seek(const ISeekInStream *pp, Int64 *pos, ESzSeek origin) +{ + CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); + return File_Seek(&p->file, pos, origin); +} + +void FileInStream_CreateVTable(CFileInStream *p) +{ + p->vt.Read = FileInStream_Read; + p->vt.Seek = FileInStream_Seek; +} + + +/* ---------- FileOutStream ---------- */ + +static size_t FileOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) +{ + CFileOutStream *p = CONTAINER_FROM_VTBL(pp, CFileOutStream, vt); + File_Write(&p->file, data, &size); + return size; +} + +void FileOutStream_CreateVTable(CFileOutStream *p) +{ + p->vt.Write = FileOutStream_Write; +} diff --git a/lzma/7zFile.h b/lzma/7zFile.h new file mode 100644 index 0000000..7e263be --- /dev/null +++ b/lzma/7zFile.h @@ -0,0 +1,83 @@ +/* 7zFile.h -- File IO +2017-04-03 : Igor Pavlov : Public domain */ + +#ifndef __7Z_FILE_H +#define __7Z_FILE_H + +#ifdef _WIN32 +#define USE_WINDOWS_FILE +#endif + +#ifdef USE_WINDOWS_FILE +#include +#else +#include +#endif + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* ---------- File ---------- */ + +typedef struct +{ + #ifdef USE_WINDOWS_FILE + HANDLE handle; + #else + FILE *file; + #endif +} CSzFile; + +void File_Construct(CSzFile *p); +#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) +WRes InFile_Open(CSzFile *p, const char *name); +WRes OutFile_Open(CSzFile *p, const char *name); +#endif +#ifdef USE_WINDOWS_FILE +WRes InFile_OpenW(CSzFile *p, const WCHAR *name); +WRes OutFile_OpenW(CSzFile *p, const WCHAR *name); +#endif +WRes File_Close(CSzFile *p); + +/* reads max(*size, remain file's size) bytes */ +WRes File_Read(CSzFile *p, void *data, size_t *size); + +/* writes *size bytes */ +WRes File_Write(CSzFile *p, const void *data, size_t *size); + +WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); +WRes File_GetLength(CSzFile *p, UInt64 *length); + + +/* ---------- FileInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + CSzFile file; +} CFileSeqInStream; + +void FileSeqInStream_CreateVTable(CFileSeqInStream *p); + + +typedef struct +{ + ISeekInStream vt; + CSzFile file; +} CFileInStream; + +void FileInStream_CreateVTable(CFileInStream *p); + + +typedef struct +{ + ISeqOutStream vt; + CSzFile file; +} CFileOutStream; + +void FileOutStream_CreateVTable(CFileOutStream *p); + +EXTERN_C_END + +#endif diff --git a/lzma/7zStream.c b/lzma/7zStream.c new file mode 100644 index 0000000..579741f --- /dev/null +++ b/lzma/7zStream.c @@ -0,0 +1,176 @@ +/* 7zStream.c -- 7z Stream functions +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zTypes.h" + +SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType) +{ + while (size != 0) + { + size_t processed = size; + RINOK(ISeqInStream_Read(stream, buf, &processed)); + if (processed == 0) + return errorType; + buf = (void *)((Byte *)buf + processed); + size -= processed; + } + return SZ_OK; +} + +SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size) +{ + return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); +} + +SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf) +{ + size_t processed = 1; + RINOK(ISeqInStream_Read(stream, buf, &processed)); + return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; +} + + + +SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset) +{ + Int64 t = offset; + return ILookInStream_Seek(stream, &t, SZ_SEEK_SET); +} + +SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size) +{ + const void *lookBuf; + if (*size == 0) + return SZ_OK; + RINOK(ILookInStream_Look(stream, &lookBuf, size)); + memcpy(buf, lookBuf, *size); + return ILookInStream_Skip(stream, *size); +} + +SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType) +{ + while (size != 0) + { + size_t processed = size; + RINOK(ILookInStream_Read(stream, buf, &processed)); + if (processed == 0) + return errorType; + buf = (void *)((Byte *)buf + processed); + size -= processed; + } + return SZ_OK; +} + +SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size) +{ + return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); +} + + + +#define GET_LookToRead2 CLookToRead2 *p = CONTAINER_FROM_VTBL(pp, CLookToRead2, vt); + +static SRes LookToRead2_Look_Lookahead(const ILookInStream *pp, const void **buf, size_t *size) +{ + SRes res = SZ_OK; + GET_LookToRead2 + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size != 0) + { + p->pos = 0; + p->size = 0; + size2 = p->bufSize; + res = ISeekInStream_Read(p->realStream, p->buf, &size2); + p->size = size2; + } + if (*size > size2) + *size = size2; + *buf = p->buf + p->pos; + return res; +} + +static SRes LookToRead2_Look_Exact(const ILookInStream *pp, const void **buf, size_t *size) +{ + SRes res = SZ_OK; + GET_LookToRead2 + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size != 0) + { + p->pos = 0; + p->size = 0; + if (*size > p->bufSize) + *size = p->bufSize; + res = ISeekInStream_Read(p->realStream, p->buf, size); + size2 = p->size = *size; + } + if (*size > size2) + *size = size2; + *buf = p->buf + p->pos; + return res; +} + +static SRes LookToRead2_Skip(const ILookInStream *pp, size_t offset) +{ + GET_LookToRead2 + p->pos += offset; + return SZ_OK; +} + +static SRes LookToRead2_Read(const ILookInStream *pp, void *buf, size_t *size) +{ + GET_LookToRead2 + size_t rem = p->size - p->pos; + if (rem == 0) + return ISeekInStream_Read(p->realStream, buf, size); + if (rem > *size) + rem = *size; + memcpy(buf, p->buf + p->pos, rem); + p->pos += rem; + *size = rem; + return SZ_OK; +} + +static SRes LookToRead2_Seek(const ILookInStream *pp, Int64 *pos, ESzSeek origin) +{ + GET_LookToRead2 + p->pos = p->size = 0; + return ISeekInStream_Seek(p->realStream, pos, origin); +} + +void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead) +{ + p->vt.Look = lookahead ? + LookToRead2_Look_Lookahead : + LookToRead2_Look_Exact; + p->vt.Skip = LookToRead2_Skip; + p->vt.Read = LookToRead2_Read; + p->vt.Seek = LookToRead2_Seek; +} + + + +static SRes SecToLook_Read(const ISeqInStream *pp, void *buf, size_t *size) +{ + CSecToLook *p = CONTAINER_FROM_VTBL(pp, CSecToLook, vt); + return LookInStream_LookRead(p->realStream, buf, size); +} + +void SecToLook_CreateVTable(CSecToLook *p) +{ + p->vt.Read = SecToLook_Read; +} + +static SRes SecToRead_Read(const ISeqInStream *pp, void *buf, size_t *size) +{ + CSecToRead *p = CONTAINER_FROM_VTBL(pp, CSecToRead, vt); + return ILookInStream_Read(p->realStream, buf, size); +} + +void SecToRead_CreateVTable(CSecToRead *p) +{ + p->vt.Read = SecToRead_Read; +} diff --git a/lzma/7zTypes.h b/lzma/7zTypes.h new file mode 100644 index 0000000..593f5aa --- /dev/null +++ b/lzma/7zTypes.h @@ -0,0 +1,375 @@ +/* 7zTypes.h -- Basic types +2018-08-04 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#ifdef _WIN32 +/* #include */ +#endif + +#include + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + + +#ifdef _WIN32 + +/* typedef DWORD WRes; */ +typedef unsigned WRes; +#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x) + +#else + +typedef int WRes; +#define MY__FACILITY_WIN32 7 +#define MY__FACILITY__WRes MY__FACILITY_WIN32 +#define MY_SRes_HRESULT_FROM_WRes(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (MY__FACILITY__WRes << 16) | 0x80000000))) + +#endif + + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#define UINT64_CONST(n) n +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#define UINT64_CONST(n) n ## ULL +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int BoolInt; +/* typedef BoolInt Bool; */ +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define MY_STD_CALL __stdcall +#else +#define MY_STD_CALL +#endif + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_FORCE_INLINE __forceinline + +#define MY_CDECL __cdecl +#define MY_FAST_CALL __fastcall + +#else + +#define MY_NO_INLINE +#define MY_FORCE_INLINE +#define MY_CDECL +#define MY_FAST_CALL + +/* inline keyword : for C++ / C99 */ + +/* GCC, clang: */ +/* +#if defined (__GNUC__) && (__GNUC__ >= 4) +#define MY_FORCE_INLINE __attribute__((always_inline)) +#define MY_NO_INLINE __attribute__((noinline)) +#endif +*/ + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct IByteIn IByteIn; +struct IByteIn +{ + Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */ +}; +#define IByteIn_Read(p) (p)->Read(p) + + +typedef struct IByteOut IByteOut; +struct IByteOut +{ + void (*Write)(const IByteOut *p, Byte b); +}; +#define IByteOut_Write(p, b) (p)->Write(p, b) + + +typedef struct ISeqInStream ISeqInStream; +struct ISeqInStream +{ + SRes (*Read)(const ISeqInStream *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +}; +#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size) + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf); + + +typedef struct ISeqOutStream ISeqOutStream; +struct ISeqOutStream +{ + size_t (*Write)(const ISeqOutStream *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +}; +#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size) + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + + +typedef struct ISeekInStream ISeekInStream; +struct ISeekInStream +{ + SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(const ISeekInStream *p, Int64 *pos, ESzSeek origin); +}; +#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size) +#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) + + +typedef struct ILookInStream ILookInStream; +struct ILookInStream +{ + SRes (*Look)(const ILookInStream *p, const void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(const ILookInStream *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(const ILookInStream *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(const ILookInStream *p, Int64 *pos, ESzSeek origin); +}; + +#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size) +#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset) +#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size) +#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) + + +SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size); + + + +typedef struct +{ + ILookInStream vt; + const ISeekInStream *realStream; + + size_t pos; + size_t size; /* it's data size */ + + /* the following variables must be set outside */ + Byte *buf; + size_t bufSize; +} CLookToRead2; + +void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead); + +#define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; } + + +typedef struct +{ + ISeqInStream vt; + const ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + + + +typedef struct +{ + ISeqInStream vt; + const ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + + +typedef struct ICompressProgress ICompressProgress; + +struct ICompressProgress +{ + SRes (*Progress)(const ICompressProgress *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +}; +#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize) + + + +typedef struct ISzAlloc ISzAlloc; +typedef const ISzAlloc * ISzAllocPtr; + +struct ISzAlloc +{ + void *(*Alloc)(ISzAllocPtr p, size_t size); + void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */ +}; + +#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size) +#define ISzAlloc_Free(p, a) (p)->Free(p, a) + +/* deprecated */ +#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size) +#define IAlloc_Free(p, a) ISzAlloc_Free(p, a) + + + + + +#ifndef MY_offsetof + #ifdef offsetof + #define MY_offsetof(type, m) offsetof(type, m) + /* + #define MY_offsetof(type, m) FIELD_OFFSET(type, m) + */ + #else + #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m)) + #endif +#endif + + + +#ifndef MY_container_of + +/* +#define MY_container_of(ptr, type, m) container_of(ptr, type, m) +#define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m) +#define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m))) +#define MY_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m)))) +*/ + +/* + GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly" + GCC 3.4.4 : classes with constructor + GCC 4.8.1 : classes with non-public variable members" +*/ + +#define MY_container_of(ptr, type, m) ((type *)((char *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m))) + + +#endif + +#define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(ptr)) + +/* +#define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) +*/ +#define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m) + +#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) +/* +#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m) +*/ + + + +#ifdef _WIN32 + +#define CHAR_PATH_SEPARATOR '\\' +#define WCHAR_PATH_SEPARATOR L'\\' +#define STRING_PATH_SEPARATOR "\\" +#define WSTRING_PATH_SEPARATOR L"\\" + +#else + +#define CHAR_PATH_SEPARATOR '/' +#define WCHAR_PATH_SEPARATOR L'/' +#define STRING_PATH_SEPARATOR "/" +#define WSTRING_PATH_SEPARATOR L"/" + +#endif + +EXTERN_C_END + +#endif diff --git a/lzma/7zVersion.h b/lzma/7zVersion.h new file mode 100644 index 0000000..0074c64 --- /dev/null +++ b/lzma/7zVersion.h @@ -0,0 +1,27 @@ +#define MY_VER_MAJOR 19 +#define MY_VER_MINOR 00 +#define MY_VER_BUILD 0 +#define MY_VERSION_NUMBERS "19.00" +#define MY_VERSION MY_VERSION_NUMBERS + +#ifdef MY_CPU_NAME + #define MY_VERSION_CPU MY_VERSION " (" MY_CPU_NAME ")" +#else + #define MY_VERSION_CPU MY_VERSION +#endif + +#define MY_DATE "2019-02-21" +#undef MY_COPYRIGHT +#undef MY_VERSION_COPYRIGHT_DATE +#define MY_AUTHOR_NAME "Igor Pavlov" +#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2018 Igor Pavlov" + +#ifdef USE_COPYRIGHT_CR + #define MY_COPYRIGHT MY_COPYRIGHT_CR +#else + #define MY_COPYRIGHT MY_COPYRIGHT_PD +#endif + +#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE +#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE diff --git a/lzma/7zVersion.rc b/lzma/7zVersion.rc new file mode 100644 index 0000000..6ed26de --- /dev/null +++ b/lzma/7zVersion.rc @@ -0,0 +1,55 @@ +#define MY_VS_FFI_FILEFLAGSMASK 0x0000003FL +#define MY_VOS_NT_WINDOWS32 0x00040004L +#define MY_VOS_CE_WINDOWS32 0x00050004L + +#define MY_VFT_APP 0x00000001L +#define MY_VFT_DLL 0x00000002L + +// #include + +#ifndef MY_VERSION +#include "7zVersion.h" +#endif + +#define MY_VER MY_VER_MAJOR,MY_VER_MINOR,MY_VER_BUILD,0 + +#ifdef DEBUG +#define DBG_FL VS_FF_DEBUG +#else +#define DBG_FL 0 +#endif + +#define MY_VERSION_INFO(fileType, descr, intName, origName) \ +LANGUAGE 9, 1 \ +1 VERSIONINFO \ + FILEVERSION MY_VER \ + PRODUCTVERSION MY_VER \ + FILEFLAGSMASK MY_VS_FFI_FILEFLAGSMASK \ + FILEFLAGS DBG_FL \ + FILEOS MY_VOS_NT_WINDOWS32 \ + FILETYPE fileType \ + FILESUBTYPE 0x0L \ +BEGIN \ + BLOCK "StringFileInfo" \ + BEGIN \ + BLOCK "040904b0" \ + BEGIN \ + VALUE "CompanyName", "Igor Pavlov" \ + VALUE "FileDescription", descr \ + VALUE "FileVersion", MY_VERSION \ + VALUE "InternalName", intName \ + VALUE "LegalCopyright", MY_COPYRIGHT \ + VALUE "OriginalFilename", origName \ + VALUE "ProductName", "7-Zip" \ + VALUE "ProductVersion", MY_VERSION \ + END \ + END \ + BLOCK "VarFileInfo" \ + BEGIN \ + VALUE "Translation", 0x409, 1200 \ + END \ +END + +#define MY_VERSION_INFO_APP(descr, intName) MY_VERSION_INFO(MY_VFT_APP, descr, intName, intName ".exe") + +#define MY_VERSION_INFO_DLL(descr, intName) MY_VERSION_INFO(MY_VFT_DLL, descr, intName, intName ".dll") diff --git a/lzma/Aes.c b/lzma/Aes.c new file mode 100644 index 0000000..8f7d50e --- /dev/null +++ b/lzma/Aes.c @@ -0,0 +1,306 @@ +/* Aes.c -- AES encryption / decryption +2017-01-24 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Aes.h" +#include "CpuArch.h" + +static UInt32 T[256 * 4]; +static const Byte Sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; + +void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks); + +void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks); + +AES_CODE_FUNC g_AesCbc_Encode; +AES_CODE_FUNC g_AesCbc_Decode; +AES_CODE_FUNC g_AesCtr_Code; + +static UInt32 D[256 * 4]; +static Byte InvS[256]; + +static const Byte Rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +#define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF) + +#define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24)) + +#define gb0(x) ( (x) & 0xFF) +#define gb1(x) (((x) >> ( 8)) & 0xFF) +#define gb2(x) (((x) >> (16)) & 0xFF) +#define gb3(x) (((x) >> (24))) + +#define gb(n, x) gb ## n(x) + +#define TT(x) (T + (x << 8)) +#define DD(x) (D + (x << 8)) + + +void AesGenTables(void) +{ + unsigned i; + for (i = 0; i < 256; i++) + InvS[Sbox[i]] = (Byte)i; + + for (i = 0; i < 256; i++) + { + { + UInt32 a1 = Sbox[i]; + UInt32 a2 = xtime(a1); + UInt32 a3 = a2 ^ a1; + TT(0)[i] = Ui32(a2, a1, a1, a3); + TT(1)[i] = Ui32(a3, a2, a1, a1); + TT(2)[i] = Ui32(a1, a3, a2, a1); + TT(3)[i] = Ui32(a1, a1, a3, a2); + } + { + UInt32 a1 = InvS[i]; + UInt32 a2 = xtime(a1); + UInt32 a4 = xtime(a2); + UInt32 a8 = xtime(a4); + UInt32 a9 = a8 ^ a1; + UInt32 aB = a8 ^ a2 ^ a1; + UInt32 aD = a8 ^ a4 ^ a1; + UInt32 aE = a8 ^ a4 ^ a2; + DD(0)[i] = Ui32(aE, a9, aD, aB); + DD(1)[i] = Ui32(aB, aE, a9, aD); + DD(2)[i] = Ui32(aD, aB, aE, a9); + DD(3)[i] = Ui32(a9, aD, aB, aE); + } + } + + g_AesCbc_Encode = AesCbc_Encode; + g_AesCbc_Decode = AesCbc_Decode; + g_AesCtr_Code = AesCtr_Code; + + #ifdef MY_CPU_X86_OR_AMD64 + if (CPU_Is_Aes_Supported()) + { + g_AesCbc_Encode = AesCbc_Encode_Intel; + g_AesCbc_Decode = AesCbc_Decode_Intel; + g_AesCtr_Code = AesCtr_Code_Intel; + } + #endif +} + + +#define HT(i, x, s) TT(x)[gb(x, s[(i + x) & 3])] + +#define HT4(m, i, s, p) m[i] = \ + HT(i, 0, s) ^ \ + HT(i, 1, s) ^ \ + HT(i, 2, s) ^ \ + HT(i, 3, s) ^ w[p + i] + +#define HT16(m, s, p) \ + HT4(m, 0, s, p); \ + HT4(m, 1, s, p); \ + HT4(m, 2, s, p); \ + HT4(m, 3, s, p); \ + +#define FT(i, x) Sbox[gb(x, m[(i + x) & 3])] +#define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i]; + + +#define HD(i, x, s) DD(x)[gb(x, s[(i - x) & 3])] + +#define HD4(m, i, s, p) m[i] = \ + HD(i, 0, s) ^ \ + HD(i, 1, s) ^ \ + HD(i, 2, s) ^ \ + HD(i, 3, s) ^ w[p + i]; + +#define HD16(m, s, p) \ + HD4(m, 0, s, p); \ + HD4(m, 1, s, p); \ + HD4(m, 2, s, p); \ + HD4(m, 3, s, p); \ + +#define FD(i, x) InvS[gb(x, m[(i - x) & 3])] +#define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i]; + +void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize) +{ + unsigned i, wSize; + wSize = keySize + 28; + keySize /= 4; + w[0] = ((UInt32)keySize / 2) + 3; + w += 4; + + for (i = 0; i < keySize; i++, key += 4) + w[i] = GetUi32(key); + + for (; i < wSize; i++) + { + UInt32 t = w[(size_t)i - 1]; + unsigned rem = i % keySize; + if (rem == 0) + t = Ui32(Sbox[gb1(t)] ^ Rcon[i / keySize], Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]); + else if (keySize > 6 && rem == 4) + t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]); + w[i] = w[i - keySize] ^ t; + } +} + +void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *w, const Byte *key, unsigned keySize) +{ + unsigned i, num; + Aes_SetKey_Enc(w, key, keySize); + num = keySize + 20; + w += 8; + for (i = 0; i < num; i++) + { + UInt32 r = w[i]; + w[i] = + DD(0)[Sbox[gb0(r)]] ^ + DD(1)[Sbox[gb1(r)]] ^ + DD(2)[Sbox[gb2(r)]] ^ + DD(3)[Sbox[gb3(r)]]; + } +} + +/* Aes_Encode and Aes_Decode functions work with little-endian words. + src and dest are pointers to 4 UInt32 words. + src and dest can point to same block */ + +static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src) +{ + UInt32 s[4]; + UInt32 m[4]; + UInt32 numRounds2 = w[0]; + w += 4; + s[0] = src[0] ^ w[0]; + s[1] = src[1] ^ w[1]; + s[2] = src[2] ^ w[2]; + s[3] = src[3] ^ w[3]; + w += 4; + for (;;) + { + HT16(m, s, 0); + if (--numRounds2 == 0) + break; + HT16(s, m, 4); + w += 8; + } + w += 4; + FT4(0); FT4(1); FT4(2); FT4(3); +} + +static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src) +{ + UInt32 s[4]; + UInt32 m[4]; + UInt32 numRounds2 = w[0]; + w += 4 + numRounds2 * 8; + s[0] = src[0] ^ w[0]; + s[1] = src[1] ^ w[1]; + s[2] = src[2] ^ w[2]; + s[3] = src[3] ^ w[3]; + for (;;) + { + w -= 8; + HD16(m, s, 4); + if (--numRounds2 == 0) + break; + HD16(s, m, 0); + } + FD4(0); FD4(1); FD4(2); FD4(3); +} + +void AesCbc_Init(UInt32 *p, const Byte *iv) +{ + unsigned i; + for (i = 0; i < 4; i++) + p[i] = GetUi32(iv + i * 4); +} + +void MY_FAST_CALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks) +{ + for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE) + { + p[0] ^= GetUi32(data); + p[1] ^= GetUi32(data + 4); + p[2] ^= GetUi32(data + 8); + p[3] ^= GetUi32(data + 12); + + Aes_Encode(p + 4, p, p); + + SetUi32(data, p[0]); + SetUi32(data + 4, p[1]); + SetUi32(data + 8, p[2]); + SetUi32(data + 12, p[3]); + } +} + +void MY_FAST_CALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks) +{ + UInt32 in[4], out[4]; + for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE) + { + in[0] = GetUi32(data); + in[1] = GetUi32(data + 4); + in[2] = GetUi32(data + 8); + in[3] = GetUi32(data + 12); + + Aes_Decode(p + 4, out, in); + + SetUi32(data, p[0] ^ out[0]); + SetUi32(data + 4, p[1] ^ out[1]); + SetUi32(data + 8, p[2] ^ out[2]); + SetUi32(data + 12, p[3] ^ out[3]); + + p[0] = in[0]; + p[1] = in[1]; + p[2] = in[2]; + p[3] = in[3]; + } +} + +void MY_FAST_CALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks) +{ + for (; numBlocks != 0; numBlocks--) + { + UInt32 temp[4]; + unsigned i; + + if (++p[0] == 0) + p[1]++; + + Aes_Encode(p + 4, temp, p); + + for (i = 0; i < 4; i++, data += 4) + { + UInt32 t = temp[i]; + + #ifdef MY_CPU_LE_UNALIGN + *((UInt32 *)data) ^= t; + #else + data[0] ^= (t & 0xFF); + data[1] ^= ((t >> 8) & 0xFF); + data[2] ^= ((t >> 16) & 0xFF); + data[3] ^= ((t >> 24)); + #endif + } + } +} diff --git a/lzma/Aes.h b/lzma/Aes.h new file mode 100644 index 0000000..381e979 --- /dev/null +++ b/lzma/Aes.h @@ -0,0 +1,38 @@ +/* Aes.h -- AES encryption / decryption +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __AES_H +#define __AES_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define AES_BLOCK_SIZE 16 + +/* Call AesGenTables one time before other AES functions */ +void AesGenTables(void); + +/* UInt32 pointers must be 16-byte aligned */ + +/* 16-byte (4 * 32-bit words) blocks: 1 (IV) + 1 (keyMode) + 15 (AES-256 roundKeys) */ +#define AES_NUM_IVMRK_WORDS ((1 + 1 + 15) * 4) + +/* aes - 16-byte aligned pointer to keyMode+roundKeys sequence */ +/* keySize = 16 or 24 or 32 (bytes) */ +typedef void (MY_FAST_CALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize); +void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize); +void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *aes, const Byte *key, unsigned keySize); + +/* ivAes - 16-byte aligned pointer to iv+keyMode+roundKeys sequence: UInt32[AES_NUM_IVMRK_WORDS] */ +void AesCbc_Init(UInt32 *ivAes, const Byte *iv); /* iv size is AES_BLOCK_SIZE */ +/* data - 16-byte aligned pointer to data */ +/* numBlocks - the number of 16-byte blocks in data array */ +typedef void (MY_FAST_CALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks); +extern AES_CODE_FUNC g_AesCbc_Encode; +extern AES_CODE_FUNC g_AesCbc_Decode; +extern AES_CODE_FUNC g_AesCtr_Code; + +EXTERN_C_END + +#endif diff --git a/lzma/AesOpt.c b/lzma/AesOpt.c new file mode 100644 index 0000000..0e7f49a --- /dev/null +++ b/lzma/AesOpt.c @@ -0,0 +1,184 @@ +/* AesOpt.c -- Intel's AES +2017-06-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 +#if (_MSC_VER > 1500) || (_MSC_FULL_VER >= 150030729) +#define USE_INTEL_AES +#endif +#endif + +#ifdef USE_INTEL_AES + +#include + +void MY_FAST_CALL AesCbc_Encode_Intel(__m128i *p, __m128i *data, size_t numBlocks) +{ + __m128i m = *p; + for (; numBlocks != 0; numBlocks--, data++) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; + const __m128i *w = p + 3; + m = _mm_xor_si128(m, *data); + m = _mm_xor_si128(m, p[2]); + do + { + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenc_si128(m, w[1]); + w += 2; + } + while (--numRounds2 != 0); + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenclast_si128(m, w[1]); + *data = m; + } + *p = m; +} + +#define NUM_WAYS 3 + +#define AES_OP_W(op, n) { \ + const __m128i t = w[n]; \ + m0 = op(m0, t); \ + m1 = op(m1, t); \ + m2 = op(m2, t); \ + } + +#define AES_DEC(n) AES_OP_W(_mm_aesdec_si128, n) +#define AES_DEC_LAST(n) AES_OP_W(_mm_aesdeclast_si128, n) +#define AES_ENC(n) AES_OP_W(_mm_aesenc_si128, n) +#define AES_ENC_LAST(n) AES_OP_W(_mm_aesenclast_si128, n) + +void MY_FAST_CALL AesCbc_Decode_Intel(__m128i *p, __m128i *data, size_t numBlocks) +{ + __m128i iv = *p; + for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1); + const __m128i *w = p + numRounds2 * 2; + __m128i m0, m1, m2; + { + const __m128i t = w[2]; + m0 = _mm_xor_si128(t, data[0]); + m1 = _mm_xor_si128(t, data[1]); + m2 = _mm_xor_si128(t, data[2]); + } + numRounds2--; + do + { + AES_DEC(1) + AES_DEC(0) + w -= 2; + } + while (--numRounds2 != 0); + AES_DEC(1) + AES_DEC_LAST(0) + + { + __m128i t; + t = _mm_xor_si128(m0, iv); iv = data[0]; data[0] = t; + t = _mm_xor_si128(m1, iv); iv = data[1]; data[1] = t; + t = _mm_xor_si128(m2, iv); iv = data[2]; data[2] = t; + } + } + for (; numBlocks != 0; numBlocks--, data++) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1); + const __m128i *w = p + numRounds2 * 2; + __m128i m = _mm_xor_si128(w[2], *data); + numRounds2--; + do + { + m = _mm_aesdec_si128(m, w[1]); + m = _mm_aesdec_si128(m, w[0]); + w -= 2; + } + while (--numRounds2 != 0); + m = _mm_aesdec_si128(m, w[1]); + m = _mm_aesdeclast_si128(m, w[0]); + + m = _mm_xor_si128(m, iv); + iv = *data; + *data = m; + } + *p = iv; +} + +void MY_FAST_CALL AesCtr_Code_Intel(__m128i *p, __m128i *data, size_t numBlocks) +{ + __m128i ctr = *p; + __m128i one; + one.m128i_u64[0] = 1; + one.m128i_u64[1] = 0; + for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; + const __m128i *w = p; + __m128i m0, m1, m2; + { + const __m128i t = w[2]; + ctr = _mm_add_epi64(ctr, one); m0 = _mm_xor_si128(ctr, t); + ctr = _mm_add_epi64(ctr, one); m1 = _mm_xor_si128(ctr, t); + ctr = _mm_add_epi64(ctr, one); m2 = _mm_xor_si128(ctr, t); + } + w += 3; + do + { + AES_ENC(0) + AES_ENC(1) + w += 2; + } + while (--numRounds2 != 0); + AES_ENC(0) + AES_ENC_LAST(1) + data[0] = _mm_xor_si128(data[0], m0); + data[1] = _mm_xor_si128(data[1], m1); + data[2] = _mm_xor_si128(data[2], m2); + } + for (; numBlocks != 0; numBlocks--, data++) + { + UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; + const __m128i *w = p; + __m128i m; + ctr = _mm_add_epi64(ctr, one); + m = _mm_xor_si128(ctr, p[2]); + w += 3; + do + { + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenc_si128(m, w[1]); + w += 2; + } + while (--numRounds2 != 0); + m = _mm_aesenc_si128(m, w[0]); + m = _mm_aesenclast_si128(m, w[1]); + *data = _mm_xor_si128(*data, m); + } + *p = ctr; +} + +#else + +void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks); +void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks); + +void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *p, Byte *data, size_t numBlocks) +{ + AesCbc_Encode(p, data, numBlocks); +} + +void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *p, Byte *data, size_t numBlocks) +{ + AesCbc_Decode(p, data, numBlocks); +} + +void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *p, Byte *data, size_t numBlocks) +{ + AesCtr_Code(p, data, numBlocks); +} + +#endif diff --git a/lzma/Alloc.c b/lzma/Alloc.c new file mode 100644 index 0000000..30b499e --- /dev/null +++ b/lzma/Alloc.c @@ -0,0 +1,455 @@ +/* Alloc.c -- Memory allocation functions +2018-04-27 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#ifdef _WIN32 +#include +#endif +#include + +#include "Alloc.h" + +/* #define _SZ_ALLOC_DEBUG */ + +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ +#ifdef _SZ_ALLOC_DEBUG + +#include +int g_allocCount = 0; +int g_allocCountMid = 0; +int g_allocCountBig = 0; + + +#define CONVERT_INT_TO_STR(charType, tempSize) \ + unsigned char temp[tempSize]; unsigned i = 0; \ + while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \ + *s++ = (charType)('0' + (unsigned)val); \ + while (i != 0) { i--; *s++ = temp[i]; } \ + *s = 0; + +static void ConvertUInt64ToString(UInt64 val, char *s) +{ + CONVERT_INT_TO_STR(char, 24); +} + +#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) + +static void ConvertUInt64ToHex(UInt64 val, char *s) +{ + UInt64 v = val; + unsigned i; + for (i = 1;; i++) + { + v >>= 4; + if (v == 0) + break; + } + s[i] = 0; + do + { + unsigned t = (unsigned)(val & 0xF); + val >>= 4; + s[--i] = GET_HEX_CHAR(t); + } + while (i); +} + +#define DEBUG_OUT_STREAM stderr + +static void Print(const char *s) +{ + fputs(s, DEBUG_OUT_STREAM); +} + +static void PrintAligned(const char *s, size_t align) +{ + size_t len = strlen(s); + for(;;) + { + fputc(' ', DEBUG_OUT_STREAM); + if (len >= align) + break; + ++len; + } + Print(s); +} + +static void PrintLn() +{ + Print("\n"); +} + +static void PrintHex(UInt64 v, size_t align) +{ + char s[32]; + ConvertUInt64ToHex(v, s); + PrintAligned(s, align); +} + +static void PrintDec(UInt64 v, size_t align) +{ + char s[32]; + ConvertUInt64ToString(v, s); + PrintAligned(s, align); +} + +static void PrintAddr(void *p) +{ + PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12); +} + + +#define PRINT_ALLOC(name, cnt, size, ptr) \ + Print(name " "); \ + PrintDec(cnt++, 10); \ + PrintHex(size, 10); \ + PrintAddr(ptr); \ + PrintLn(); + +#define PRINT_FREE(name, cnt, ptr) if (ptr) { \ + Print(name " "); \ + PrintDec(--cnt, 10); \ + PrintAddr(ptr); \ + PrintLn(); } + +#else + +#define PRINT_ALLOC(name, cnt, size, ptr) +#define PRINT_FREE(name, cnt, ptr) +#define Print(s) +#define PrintLn() +#define PrintHex(v, align) +#define PrintDec(v, align) +#define PrintAddr(p) + +#endif + + + +void *MyAlloc(size_t size) +{ + if (size == 0) + return NULL; + #ifdef _SZ_ALLOC_DEBUG + { + void *p = malloc(size); + PRINT_ALLOC("Alloc ", g_allocCount, size, p); + return p; + } + #else + return malloc(size); + #endif +} + +void MyFree(void *address) +{ + PRINT_FREE("Free ", g_allocCount, address); + + free(address); +} + +#ifdef _WIN32 + +void *MidAlloc(size_t size) +{ + if (size == 0) + return NULL; + + PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, NULL); + + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); +} + +void MidFree(void *address) +{ + PRINT_FREE("Free-Mid", g_allocCountMid, address); + + if (!address) + return; + VirtualFree(address, 0, MEM_RELEASE); +} + +#ifndef MEM_LARGE_PAGES +#undef _7ZIP_LARGE_PAGES +#endif + +#ifdef _7ZIP_LARGE_PAGES +SIZE_T g_LargePageSize = 0; +typedef SIZE_T (WINAPI *GetLargePageMinimumP)(); +#endif + +void SetLargePageSize() +{ + #ifdef _7ZIP_LARGE_PAGES + SIZE_T size; + GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP) + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum"); + if (!largePageMinimum) + return; + size = largePageMinimum(); + if (size == 0 || (size & (size - 1)) != 0) + return; + g_LargePageSize = size; + #endif +} + + +void *BigAlloc(size_t size) +{ + if (size == 0) + return NULL; + + PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL); + + #ifdef _7ZIP_LARGE_PAGES + { + SIZE_T ps = g_LargePageSize; + if (ps != 0 && ps <= (1 << 30) && size > (ps / 2)) + { + size_t size2; + ps--; + size2 = (size + ps) & ~ps; + if (size2 >= size) + { + void *res = VirtualAlloc(NULL, size2, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); + if (res) + return res; + } + } + } + #endif + + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); +} + +void BigFree(void *address) +{ + PRINT_FREE("Free-Big", g_allocCountBig, address); + + if (!address) + return; + VirtualFree(address, 0, MEM_RELEASE); +} + +#endif + + +static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); } +static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MyFree(address); } +const ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MidAlloc(size); } +static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MidFree(address); } +const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree }; + +static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); } +static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); BigFree(address); } +const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; + + +/* + uintptr_t : C99 (optional) + : unsupported in VS6 +*/ + +#ifdef _WIN32 + typedef UINT_PTR UIntPtr; +#else + /* + typedef uintptr_t UIntPtr; + */ + typedef ptrdiff_t UIntPtr; +#endif + + +#define ADJUST_ALLOC_SIZE 0 +/* +#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1) +*/ +/* + Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if + MyAlloc() can return address that is NOT multiple of sizeof(void *). +*/ + + +/* +#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1)))) +*/ +#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1)))) + +#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align) + + +#if (_POSIX_C_SOURCE >= 200112L) && !defined(_WIN32) + #define USE_posix_memalign +#endif + +/* + This posix_memalign() is for test purposes only. + We also need special Free() function instead of free(), + if this posix_memalign() is used. +*/ + +/* +static int posix_memalign(void **ptr, size_t align, size_t size) +{ + size_t newSize = size + align; + void *p; + void *pAligned; + *ptr = NULL; + if (newSize < size) + return 12; // ENOMEM + p = MyAlloc(newSize); + if (!p) + return 12; // ENOMEM + pAligned = MY_ALIGN_PTR_UP_PLUS(p, align); + ((void **)pAligned)[-1] = p; + *ptr = pAligned; + return 0; +} +*/ + +/* + ALLOC_ALIGN_SIZE >= sizeof(void *) + ALLOC_ALIGN_SIZE >= cache_line_size +*/ + +#define ALLOC_ALIGN_SIZE ((size_t)1 << 7) + +static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size) +{ + #ifndef USE_posix_memalign + + void *p; + void *pAligned; + size_t newSize; + UNUSED_VAR(pp); + + /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned + block to prevent cache line sharing with another allocated blocks */ + + newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE; + if (newSize < size) + return NULL; + + p = MyAlloc(newSize); + + if (!p) + return NULL; + pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE); + + Print(" size="); PrintHex(size, 8); + Print(" a_size="); PrintHex(newSize, 8); + Print(" ptr="); PrintAddr(p); + Print(" a_ptr="); PrintAddr(pAligned); + PrintLn(); + + ((void **)pAligned)[-1] = p; + + return pAligned; + + #else + + void *p; + UNUSED_VAR(pp); + if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size)) + return NULL; + + Print(" posix_memalign="); PrintAddr(p); + PrintLn(); + + return p; + + #endif +} + + +static void SzAlignedFree(ISzAllocPtr pp, void *address) +{ + UNUSED_VAR(pp); + #ifndef USE_posix_memalign + if (address) + MyFree(((void **)address)[-1]); + #else + free(address); + #endif +} + + +const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree }; + + + +#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *)) + +/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */ +#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1] +/* +#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1] +*/ + +static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size) +{ + CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt); + void *adr; + void *pAligned; + size_t newSize; + size_t extra; + size_t alignSize = (size_t)1 << p->numAlignBits; + + if (alignSize < sizeof(void *)) + alignSize = sizeof(void *); + + if (p->offset >= alignSize) + return NULL; + + /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned + block to prevent cache line sharing with another allocated blocks */ + extra = p->offset & (sizeof(void *) - 1); + newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE; + if (newSize < size) + return NULL; + + adr = ISzAlloc_Alloc(p->baseAlloc, newSize); + + if (!adr) + return NULL; + + pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr + + alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset; + + PrintLn(); + Print("- Aligned: "); + Print(" size="); PrintHex(size, 8); + Print(" a_size="); PrintHex(newSize, 8); + Print(" ptr="); PrintAddr(adr); + Print(" a_ptr="); PrintAddr(pAligned); + PrintLn(); + + REAL_BLOCK_PTR_VAR(pAligned) = adr; + + return pAligned; +} + + +static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address) +{ + if (address) + { + CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt); + PrintLn(); + Print("- Aligned Free: "); + PrintLn(); + ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address)); + } +} + + +void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p) +{ + p->vt.Alloc = AlignOffsetAlloc_Alloc; + p->vt.Free = AlignOffsetAlloc_Free; +} diff --git a/lzma/Alloc.h b/lzma/Alloc.h new file mode 100644 index 0000000..3d796e5 --- /dev/null +++ b/lzma/Alloc.h @@ -0,0 +1,51 @@ +/* Alloc.h -- Memory allocation functions +2018-02-19 : Igor Pavlov : Public domain */ + +#ifndef __COMMON_ALLOC_H +#define __COMMON_ALLOC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void *MyAlloc(size_t size); +void MyFree(void *address); + +#ifdef _WIN32 + +void SetLargePageSize(); + +void *MidAlloc(size_t size); +void MidFree(void *address); +void *BigAlloc(size_t size); +void BigFree(void *address); + +#else + +#define MidAlloc(size) MyAlloc(size) +#define MidFree(address) MyFree(address) +#define BigAlloc(size) MyAlloc(size) +#define BigFree(address) MyFree(address) + +#endif + +extern const ISzAlloc g_Alloc; +extern const ISzAlloc g_BigAlloc; +extern const ISzAlloc g_MidAlloc; +extern const ISzAlloc g_AlignedAlloc; + + +typedef struct +{ + ISzAlloc vt; + ISzAllocPtr baseAlloc; + unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */ + size_t offset; /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */ +} CAlignOffsetAlloc; + +void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p); + + +EXTERN_C_END + +#endif diff --git a/lzma/Bcj2.c b/lzma/Bcj2.c new file mode 100644 index 0000000..da93985 --- /dev/null +++ b/lzma/Bcj2.c @@ -0,0 +1,257 @@ +/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code) +2018-04-28 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Bcj2.h" +#include "CpuArch.h" + +#define CProb UInt16 + +#define kTopValue ((UInt32)1 << 24) +#define kNumModelBits 11 +#define kBitModelTotal (1 << kNumModelBits) +#define kNumMoveBits 5 + +#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound) +#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); + +void Bcj2Dec_Init(CBcj2Dec *p) +{ + unsigned i; + + p->state = BCJ2_DEC_STATE_OK; + p->ip = 0; + p->temp[3] = 0; + p->range = 0; + p->code = 0; + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} + +SRes Bcj2Dec_Decode(CBcj2Dec *p) +{ + if (p->range <= 5) + { + p->state = BCJ2_DEC_STATE_OK; + for (; p->range != 5; p->range++) + { + if (p->range == 1 && p->code != 0) + return SZ_ERROR_DATA; + + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } + + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + if (p->code == 0xFFFFFFFF) + return SZ_ERROR_DATA; + + p->range = 0xFFFFFFFF; + } + else if (p->state >= BCJ2_DEC_STATE_ORIG_0) + { + while (p->state <= BCJ2_DEC_STATE_ORIG_3) + { + Byte *dest = p->dest; + if (dest == p->destLim) + return SZ_OK; + *dest = p->temp[(size_t)p->state - BCJ2_DEC_STATE_ORIG_0]; + p->state++; + p->dest = dest + 1; + } + } + + /* + if (BCJ2_IS_32BIT_STREAM(p->state)) + { + const Byte *cur = p->bufs[p->state]; + if (cur == p->lims[p->state]) + return SZ_OK; + p->bufs[p->state] = cur + 4; + + { + UInt32 val; + Byte *dest; + SizeT rem; + + p->ip += 4; + val = GetBe32(cur) - p->ip; + dest = p->dest; + rem = p->destLim - dest; + if (rem < 4) + { + SizeT i; + SetUi32(p->temp, val); + for (i = 0; i < rem; i++) + dest[i] = p->temp[i]; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; + return SZ_OK; + } + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; + p->state = BCJ2_DEC_STATE_OK; + } + } + */ + + for (;;) + { + if (BCJ2_IS_32BIT_STREAM(p->state)) + p->state = BCJ2_DEC_STATE_OK; + else + { + if (p->range < kTopValue) + { + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + { + const Byte *src = p->bufs[BCJ2_STREAM_MAIN]; + const Byte *srcLim; + Byte *dest; + SizeT num = p->lims[BCJ2_STREAM_MAIN] - src; + + if (num == 0) + { + p->state = BCJ2_STREAM_MAIN; + return SZ_OK; + } + + dest = p->dest; + if (num > (SizeT)(p->destLim - dest)) + { + num = p->destLim - dest; + if (num == 0) + { + p->state = BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + } + + srcLim = src + num; + + if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80) + *dest = src[0]; + else for (;;) + { + Byte b = *src; + *dest = b; + if (b != 0x0F) + { + if ((b & 0xFE) == 0xE8) + break; + dest++; + if (++src != srcLim) + continue; + break; + } + dest++; + if (++src == srcLim) + break; + if ((*src & 0xF0) != 0x80) + continue; + *dest = *src; + break; + } + + num = src - p->bufs[BCJ2_STREAM_MAIN]; + + if (src == srcLim) + { + p->temp[3] = src[-1]; + p->bufs[BCJ2_STREAM_MAIN] = src; + p->ip += (UInt32)num; + p->dest += num; + p->state = + p->bufs[BCJ2_STREAM_MAIN] == + p->lims[BCJ2_STREAM_MAIN] ? + (unsigned)BCJ2_STREAM_MAIN : + (unsigned)BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + + { + UInt32 bound, ttt; + CProb *prob; + Byte b = src[0]; + Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]); + + p->temp[3] = b; + p->bufs[BCJ2_STREAM_MAIN] = src + 1; + num++; + p->ip += (UInt32)num; + p->dest += num; + + prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0)); + + _IF_BIT_0 + { + _UPDATE_0 + continue; + } + _UPDATE_1 + + } + } + } + + { + UInt32 val; + unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + const Byte *cur = p->bufs[cj]; + Byte *dest; + SizeT rem; + + if (cur == p->lims[cj]) + { + p->state = cj; + break; + } + + val = GetBe32(cur); + p->bufs[cj] = cur + 4; + + p->ip += 4; + val -= p->ip; + dest = p->dest; + rem = p->destLim - dest; + + if (rem < 4) + { + p->temp[0] = (Byte)val; if (rem > 0) dest[0] = (Byte)val; val >>= 8; + p->temp[1] = (Byte)val; if (rem > 1) dest[1] = (Byte)val; val >>= 8; + p->temp[2] = (Byte)val; if (rem > 2) dest[2] = (Byte)val; val >>= 8; + p->temp[3] = (Byte)val; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; + break; + } + + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; + } + } + + if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC]) + { + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + return SZ_OK; +} diff --git a/lzma/Bcj2.h b/lzma/Bcj2.h new file mode 100644 index 0000000..68893d2 --- /dev/null +++ b/lzma/Bcj2.h @@ -0,0 +1,146 @@ +/* Bcj2.h -- BCJ2 Converter for x86 code +2014-11-10 : Igor Pavlov : Public domain */ + +#ifndef __BCJ2_H +#define __BCJ2_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define BCJ2_NUM_STREAMS 4 + +enum +{ + BCJ2_STREAM_MAIN, + BCJ2_STREAM_CALL, + BCJ2_STREAM_JUMP, + BCJ2_STREAM_RC +}; + +enum +{ + BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS, + BCJ2_DEC_STATE_ORIG_1, + BCJ2_DEC_STATE_ORIG_2, + BCJ2_DEC_STATE_ORIG_3, + + BCJ2_DEC_STATE_ORIG, + BCJ2_DEC_STATE_OK +}; + +enum +{ + BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, + BCJ2_ENC_STATE_OK +}; + + +#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) + +/* +CBcj2Dec / CBcj2Enc +bufs sizes: + BUF_SIZE(n) = lims[n] - bufs[n] +bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4: + (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0 + (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0 +*/ + +/* +CBcj2Dec: +dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions: + bufs[BCJ2_STREAM_MAIN] >= dest && + bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv + + BUF_SIZE(BCJ2_STREAM_CALL) + + BUF_SIZE(BCJ2_STREAM_JUMP) + tempReserv = 0 : for first call of Bcj2Dec_Decode + tempReserv = 4 : for any other calls of Bcj2Dec_Decode + overlap with offset = 1 is not allowed +*/ + +typedef struct +{ + const Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + Byte *dest; + const Byte *destLim; + + unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ + + UInt32 ip; + Byte temp[4]; + UInt32 range; + UInt32 code; + UInt16 probs[2 + 256]; +} CBcj2Dec; + +void Bcj2Dec_Init(CBcj2Dec *p); + +/* Returns: SZ_OK or SZ_ERROR_DATA */ +SRes Bcj2Dec_Decode(CBcj2Dec *p); + +#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0) + + + +typedef enum +{ + BCJ2_ENC_FINISH_MODE_CONTINUE, + BCJ2_ENC_FINISH_MODE_END_BLOCK, + BCJ2_ENC_FINISH_MODE_END_STREAM +} EBcj2Enc_FinishMode; + +typedef struct +{ + Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + const Byte *src; + const Byte *srcLim; + + unsigned state; + EBcj2Enc_FinishMode finishMode; + + Byte prevByte; + + Byte cache; + UInt32 range; + UInt64 low; + UInt64 cacheSize; + + UInt32 ip; + + /* 32-bit ralative offset in JUMP/CALL commands is + - (mod 4 GB) in 32-bit mode + - signed Int32 in 64-bit mode + We use (mod 4 GB) check for fileSize. + Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */ + UInt32 fileIp; + UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */ + UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */ + + UInt32 tempTarget; + unsigned tempPos; + Byte temp[4 * 2]; + + unsigned flushPos; + + UInt16 probs[2 + 256]; +} CBcj2Enc; + +void Bcj2Enc_Init(CBcj2Enc *p); +void Bcj2Enc_Encode(CBcj2Enc *p); + +#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos) +#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5) + + +#define BCJ2_RELAT_LIMIT_NUM_BITS 26 +#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS) + +/* limit for CBcj2Enc::fileSize variable */ +#define BCJ2_FileSize_MAX ((UInt32)1 << 31) + +EXTERN_C_END + +#endif diff --git a/lzma/Bcj2Enc.c b/lzma/Bcj2Enc.c new file mode 100644 index 0000000..7a02ecd --- /dev/null +++ b/lzma/Bcj2Enc.c @@ -0,0 +1,311 @@ +/* Bcj2Enc.c -- BCJ2 Encoder (Converter for x86 code) +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +/* #define SHOW_STAT */ + +#ifdef SHOW_STAT +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include + +#include "Bcj2.h" +#include "CpuArch.h" + +#define CProb UInt16 + +#define kTopValue ((UInt32)1 << 24) +#define kNumModelBits 11 +#define kBitModelTotal (1 << kNumModelBits) +#define kNumMoveBits 5 + +void Bcj2Enc_Init(CBcj2Enc *p) +{ + unsigned i; + + p->state = BCJ2_ENC_STATE_OK; + p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + + p->prevByte = 0; + + p->cache = 0; + p->range = 0xFFFFFFFF; + p->low = 0; + p->cacheSize = 1; + + p->ip = 0; + + p->fileIp = 0; + p->fileSize = 0; + p->relatLimit = BCJ2_RELAT_LIMIT; + + p->tempPos = 0; + + p->flushPos = 0; + + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} + +static BoolInt MY_FAST_CALL RangeEnc_ShiftLow(CBcj2Enc *p) +{ + if ((UInt32)p->low < (UInt32)0xFF000000 || (UInt32)(p->low >> 32) != 0) + { + Byte *buf = p->bufs[BCJ2_STREAM_RC]; + do + { + if (buf == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + p->bufs[BCJ2_STREAM_RC] = buf; + return True; + } + *buf++ = (Byte)(p->cache + (Byte)(p->low >> 32)); + p->cache = 0xFF; + } + while (--p->cacheSize); + p->bufs[BCJ2_STREAM_RC] = buf; + p->cache = (Byte)((UInt32)p->low >> 24); + } + p->cacheSize++; + p->low = (UInt32)p->low << 8; + return False; +} + +static void Bcj2Enc_Encode_2(CBcj2Enc *p) +{ + if (BCJ2_IS_32BIT_STREAM(p->state)) + { + Byte *cur = p->bufs[p->state]; + if (cur == p->lims[p->state]) + return; + SetBe32(cur, p->tempTarget); + p->bufs[p->state] = cur + 4; + } + + p->state = BCJ2_ENC_STATE_ORIG; + + for (;;) + { + if (p->range < kTopValue) + { + if (RangeEnc_ShiftLow(p)) + return; + p->range <<= 8; + } + + { + { + const Byte *src = p->src; + const Byte *srcLim; + Byte *dest; + SizeT num = p->srcLim - src; + + if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE) + { + if (num <= 4) + return; + num -= 4; + } + else if (num == 0) + break; + + dest = p->bufs[BCJ2_STREAM_MAIN]; + if (num > (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest)) + { + num = p->lims[BCJ2_STREAM_MAIN] - dest; + if (num == 0) + { + p->state = BCJ2_STREAM_MAIN; + return; + } + } + + srcLim = src + num; + + if (p->prevByte == 0x0F && (src[0] & 0xF0) == 0x80) + *dest = src[0]; + else for (;;) + { + Byte b = *src; + *dest = b; + if (b != 0x0F) + { + if ((b & 0xFE) == 0xE8) + break; + dest++; + if (++src != srcLim) + continue; + break; + } + dest++; + if (++src == srcLim) + break; + if ((*src & 0xF0) != 0x80) + continue; + *dest = *src; + break; + } + + num = src - p->src; + + if (src == srcLim) + { + p->prevByte = src[-1]; + p->bufs[BCJ2_STREAM_MAIN] = dest; + p->src = src; + p->ip += (UInt32)num; + continue; + } + + { + Byte context = (Byte)(num == 0 ? p->prevByte : src[-1]); + BoolInt needConvert; + + p->bufs[BCJ2_STREAM_MAIN] = dest + 1; + p->ip += (UInt32)num + 1; + src++; + + needConvert = False; + + if ((SizeT)(p->srcLim - src) >= 4) + { + UInt32 relatVal = GetUi32(src); + if ((p->fileSize == 0 || (UInt32)(p->ip + 4 + relatVal - p->fileIp) < p->fileSize) + && ((relatVal + p->relatLimit) >> 1) < p->relatLimit) + needConvert = True; + } + + { + UInt32 bound; + unsigned ttt; + Byte b = src[-1]; + CProb *prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)context : (b == 0xE9 ? 1 : 0)); + + ttt = *prob; + bound = (p->range >> kNumModelBits) * ttt; + + if (!needConvert) + { + p->range = bound; + *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); + p->src = src; + p->prevByte = b; + continue; + } + + p->low += bound; + p->range -= bound; + *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); + + { + UInt32 relatVal = GetUi32(src); + UInt32 absVal; + p->ip += 4; + absVal = p->ip + relatVal; + p->prevByte = src[3]; + src += 4; + p->src = src; + { + unsigned cj = (b == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + Byte *cur = p->bufs[cj]; + if (cur == p->lims[cj]) + { + p->state = cj; + p->tempTarget = absVal; + return; + } + SetBe32(cur, absVal); + p->bufs[cj] = cur + 4; + } + } + } + } + } + } + } + + if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM) + return; + + for (; p->flushPos < 5; p->flushPos++) + if (RangeEnc_ShiftLow(p)) + return; + p->state = BCJ2_ENC_STATE_OK; +} + + +void Bcj2Enc_Encode(CBcj2Enc *p) +{ + PRF(printf("\n")); + PRF(printf("---- ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); + + if (p->tempPos != 0) + { + unsigned extra = 0; + + for (;;) + { + const Byte *src = p->src; + const Byte *srcLim = p->srcLim; + EBcj2Enc_FinishMode finishMode = p->finishMode; + + p->src = p->temp; + p->srcLim = p->temp + p->tempPos; + if (src != srcLim) + p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + + PRF(printf(" ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); + + Bcj2Enc_Encode_2(p); + + { + unsigned num = (unsigned)(p->src - p->temp); + unsigned tempPos = p->tempPos - num; + unsigned i; + p->tempPos = tempPos; + for (i = 0; i < tempPos; i++) + p->temp[i] = p->temp[(size_t)i + num]; + + p->src = src; + p->srcLim = srcLim; + p->finishMode = finishMode; + + if (p->state != BCJ2_ENC_STATE_ORIG || src == srcLim) + return; + + if (extra >= tempPos) + { + p->src = src - tempPos; + p->tempPos = 0; + break; + } + + p->temp[tempPos] = src[0]; + p->tempPos = tempPos + 1; + p->src = src + 1; + extra++; + } + } + } + + PRF(printf("++++ ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); + + Bcj2Enc_Encode_2(p); + + if (p->state == BCJ2_ENC_STATE_ORIG) + { + const Byte *src = p->src; + unsigned rem = (unsigned)(p->srcLim - src); + unsigned i; + for (i = 0; i < rem; i++) + p->temp[i] = src[i]; + p->tempPos = rem; + p->src = src + rem; + } +} diff --git a/lzma/Bra.c b/lzma/Bra.c new file mode 100644 index 0000000..cbdcb29 --- /dev/null +++ b/lzma/Bra.c @@ -0,0 +1,230 @@ +/* Bra.c -- Converters for RISC code +2017-04-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" +#include "Bra.h" + +SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + Byte *p; + const Byte *lim; + size &= ~(size_t)3; + ip += 4; + p = data; + lim = data + size; + + if (encoding) + + for (;;) + { + for (;;) + { + if (p >= lim) + return p - data; + p += 4; + if (p[-1] == 0xEB) + break; + } + { + UInt32 v = GetUi32(p - 4); + v <<= 2; + v += ip + (UInt32)(p - data); + v >>= 2; + v &= 0x00FFFFFF; + v |= 0xEB000000; + SetUi32(p - 4, v); + } + } + + for (;;) + { + for (;;) + { + if (p >= lim) + return p - data; + p += 4; + if (p[-1] == 0xEB) + break; + } + { + UInt32 v = GetUi32(p - 4); + v <<= 2; + v -= ip + (UInt32)(p - data); + v >>= 2; + v &= 0x00FFFFFF; + v |= 0xEB000000; + SetUi32(p - 4, v); + } + } +} + + +SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + Byte *p; + const Byte *lim; + size &= ~(size_t)1; + p = data; + lim = data + size - 4; + + if (encoding) + + for (;;) + { + UInt32 b1; + for (;;) + { + UInt32 b3; + if (p > lim) + return p - data; + b1 = p[1]; + b3 = p[3]; + p += 2; + b1 ^= 8; + if ((b3 & b1) >= 0xF8) + break; + } + { + UInt32 v = + ((UInt32)b1 << 19) + + (((UInt32)p[1] & 0x7) << 8) + + (((UInt32)p[-2] << 11)) + + (p[0]); + + p += 2; + { + UInt32 cur = (ip + (UInt32)(p - data)) >> 1; + v += cur; + } + + p[-4] = (Byte)(v >> 11); + p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7)); + p[-2] = (Byte)v; + p[-1] = (Byte)(0xF8 | (v >> 8)); + } + } + + for (;;) + { + UInt32 b1; + for (;;) + { + UInt32 b3; + if (p > lim) + return p - data; + b1 = p[1]; + b3 = p[3]; + p += 2; + b1 ^= 8; + if ((b3 & b1) >= 0xF8) + break; + } + { + UInt32 v = + ((UInt32)b1 << 19) + + (((UInt32)p[1] & 0x7) << 8) + + (((UInt32)p[-2] << 11)) + + (p[0]); + + p += 2; + { + UInt32 cur = (ip + (UInt32)(p - data)) >> 1; + v -= cur; + } + + /* + SetUi16(p - 4, (UInt16)(((v >> 11) & 0x7FF) | 0xF000)); + SetUi16(p - 2, (UInt16)(v | 0xF800)); + */ + + p[-4] = (Byte)(v >> 11); + p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7)); + p[-2] = (Byte)v; + p[-1] = (Byte)(0xF8 | (v >> 8)); + } + } +} + + +SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + Byte *p; + const Byte *lim; + size &= ~(size_t)3; + ip -= 4; + p = data; + lim = data + size; + + for (;;) + { + for (;;) + { + if (p >= lim) + return p - data; + p += 4; + /* if ((v & 0xFC000003) == 0x48000001) */ + if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1) + break; + } + { + UInt32 v = GetBe32(p - 4); + if (encoding) + v += ip + (UInt32)(p - data); + else + v -= ip + (UInt32)(p - data); + v &= 0x03FFFFFF; + v |= 0x48000000; + SetBe32(p - 4, v); + } + } +} + + +SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + Byte *p; + const Byte *lim; + size &= ~(size_t)3; + ip -= 4; + p = data; + lim = data + size; + + for (;;) + { + for (;;) + { + if (p >= lim) + return p - data; + /* + v = GetBe32(p); + p += 4; + m = v + ((UInt32)5 << 29); + m ^= (UInt32)7 << 29; + m += (UInt32)1 << 22; + if ((m & ((UInt32)0x1FF << 23)) == 0) + break; + */ + p += 4; + if ((p[-4] == 0x40 && (p[-3] & 0xC0) == 0) || + (p[-4] == 0x7F && (p[-3] >= 0xC0))) + break; + } + { + UInt32 v = GetBe32(p - 4); + v <<= 2; + if (encoding) + v += ip + (UInt32)(p - data); + else + v -= ip + (UInt32)(p - data); + + v &= 0x01FFFFFF; + v -= (UInt32)1 << 24; + v ^= 0xFF000000; + v >>= 2; + v |= 0x40000000; + SetBe32(p - 4, v); + } + } +} diff --git a/lzma/Bra.h b/lzma/Bra.h new file mode 100644 index 0000000..aba8dce --- /dev/null +++ b/lzma/Bra.h @@ -0,0 +1,64 @@ +/* Bra.h -- Branch converters for executables +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __BRA_H +#define __BRA_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* +These functions convert relative addresses to absolute addresses +in CALL instructions to increase the compression ratio. + + In: + data - data buffer + size - size of data + ip - current virtual Instruction Pinter (IP) value + state - state variable for x86 converter + encoding - 0 (for decoding), 1 (for encoding) + + Out: + state - state variable for x86 converter + + Returns: + The number of processed bytes. If you call these functions with multiple calls, + you must start next call with first byte after block of processed bytes. + + Type Endian Alignment LookAhead + + x86 little 1 4 + ARMT little 2 2 + ARM little 4 0 + PPC big 4 0 + SPARC big 4 0 + IA64 little 16 0 + + size must be >= Alignment + LookAhead, if it's not last block. + If (size < Alignment + LookAhead), converter returns 0. + + Example: + + UInt32 ip = 0; + for () + { + ; size must be >= Alignment + LookAhead, if it's not last block + SizeT processed = Convert(data, size, ip, 1); + data += processed; + size -= processed; + ip += processed; + } +*/ + +#define x86_Convert_Init(state) { state = 0; } +SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); +SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); + +EXTERN_C_END + +#endif diff --git a/lzma/Bra86.c b/lzma/Bra86.c new file mode 100644 index 0000000..a6463c6 --- /dev/null +++ b/lzma/Bra86.c @@ -0,0 +1,82 @@ +/* Bra86.c -- Converter for x86 code (BCJ) +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Bra.h" + +#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0) + +SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) +{ + SizeT pos = 0; + UInt32 mask = *state & 7; + if (size < 5) + return 0; + size -= 4; + ip += 5; + + for (;;) + { + Byte *p = data + pos; + const Byte *limit = data + size; + for (; p < limit; p++) + if ((*p & 0xFE) == 0xE8) + break; + + { + SizeT d = (SizeT)(p - data - pos); + pos = (SizeT)(p - data); + if (p >= limit) + { + *state = (d > 2 ? 0 : mask >> (unsigned)d); + return pos; + } + if (d > 2) + mask = 0; + else + { + mask >>= (unsigned)d; + if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(size_t)(mask >> 1) + 1]))) + { + mask = (mask >> 1) | 4; + pos++; + continue; + } + } + } + + if (Test86MSByte(p[4])) + { + UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); + UInt32 cur = ip + (UInt32)pos; + pos += 5; + if (encoding) + v += cur; + else + v -= cur; + if (mask != 0) + { + unsigned sh = (mask & 6) << 2; + if (Test86MSByte((Byte)(v >> sh))) + { + v ^= (((UInt32)0x100 << sh) - 1); + if (encoding) + v += cur; + else + v -= cur; + } + mask = 0; + } + p[1] = (Byte)v; + p[2] = (Byte)(v >> 8); + p[3] = (Byte)(v >> 16); + p[4] = (Byte)(0 - ((v >> 24) & 1)); + } + else + { + mask = (mask >> 1) | 4; + pos++; + } + } +} diff --git a/lzma/BraIA64.c b/lzma/BraIA64.c new file mode 100644 index 0000000..2656907 --- /dev/null +++ b/lzma/BraIA64.c @@ -0,0 +1,53 @@ +/* BraIA64.c -- Converter for IA-64 code +2017-01-26 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" +#include "Bra.h" + +SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 16) + return 0; + size -= 16; + i = 0; + do + { + unsigned m = ((UInt32)0x334B0000 >> (data[i] & 0x1E)) & 3; + if (m) + { + m++; + do + { + Byte *p = data + (i + (size_t)m * 5 - 8); + if (((p[3] >> m) & 15) == 5 + && (((p[-1] | ((UInt32)p[0] << 8)) >> m) & 0x70) == 0) + { + unsigned raw = GetUi32(p); + unsigned v = raw >> m; + v = (v & 0xFFFFF) | ((v & (1 << 23)) >> 3); + + v <<= 4; + if (encoding) + v += ip + (UInt32)i; + else + v -= ip + (UInt32)i; + v >>= 4; + + v &= 0x1FFFFF; + v += 0x700000; + v &= 0x8FFFFF; + raw &= ~((UInt32)0x8FFFFF << m); + raw |= (v << m); + SetUi32(p, raw); + } + } + while (++m <= 4); + } + i += 16; + } + while (i <= size); + return i; +} diff --git a/lzma/Compiler.h b/lzma/Compiler.h new file mode 100644 index 0000000..c788648 --- /dev/null +++ b/lzma/Compiler.h @@ -0,0 +1,33 @@ +/* Compiler.h +2017-04-03 : Igor Pavlov : Public domain */ + +#ifndef __7Z_COMPILER_H +#define __7Z_COMPILER_H + +#ifdef _MSC_VER + + #ifdef UNDER_CE + #define RPC_NO_WINDOWS_H + /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ + #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union + #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int + #endif + + #if _MSC_VER >= 1300 + #pragma warning(disable : 4996) // This function or variable may be unsafe + #else + #pragma warning(disable : 4511) // copy constructor could not be generated + #pragma warning(disable : 4512) // assignment operator could not be generated + #pragma warning(disable : 4514) // unreferenced inline function has been removed + #pragma warning(disable : 4702) // unreachable code + #pragma warning(disable : 4710) // not inlined + #pragma warning(disable : 4714) // function marked as __forceinline not inlined + #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information + #endif + +#endif + +#define UNUSED_VAR(x) (void)x; +/* #define UNUSED_VAR(x) x=x; */ + +#endif diff --git a/lzma/CpuArch.c b/lzma/CpuArch.c new file mode 100644 index 0000000..ff1890e --- /dev/null +++ b/lzma/CpuArch.c @@ -0,0 +1,218 @@ +/* CpuArch.c -- CPU specific code +2018-02-18: Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 + +#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) +#define USE_ASM +#endif + +#if !defined(USE_ASM) && _MSC_VER >= 1500 +#include +#endif + +#if defined(USE_ASM) && !defined(MY_CPU_AMD64) +static UInt32 CheckFlag(UInt32 flag) +{ + #ifdef _MSC_VER + __asm pushfd; + __asm pop EAX; + __asm mov EDX, EAX; + __asm xor EAX, flag; + __asm push EAX; + __asm popfd; + __asm pushfd; + __asm pop EAX; + __asm xor EAX, EDX; + __asm push EDX; + __asm popfd; + __asm and flag, EAX; + #else + __asm__ __volatile__ ( + "pushf\n\t" + "pop %%EAX\n\t" + "movl %%EAX,%%EDX\n\t" + "xorl %0,%%EAX\n\t" + "push %%EAX\n\t" + "popf\n\t" + "pushf\n\t" + "pop %%EAX\n\t" + "xorl %%EDX,%%EAX\n\t" + "push %%EDX\n\t" + "popf\n\t" + "andl %%EAX, %0\n\t": + "=c" (flag) : "c" (flag) : + "%eax", "%edx"); + #endif + return flag; +} +#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; +#else +#define CHECK_CPUID_IS_SUPPORTED +#endif + +void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) +{ + #ifdef USE_ASM + + #ifdef _MSC_VER + + UInt32 a2, b2, c2, d2; + __asm xor EBX, EBX; + __asm xor ECX, ECX; + __asm xor EDX, EDX; + __asm mov EAX, function; + __asm cpuid; + __asm mov a2, EAX; + __asm mov b2, EBX; + __asm mov c2, ECX; + __asm mov d2, EDX; + + *a = a2; + *b = b2; + *c = c2; + *d = d2; + + #else + + __asm__ __volatile__ ( + #if defined(MY_CPU_AMD64) && defined(__PIC__) + "mov %%rbx, %%rdi;" + "cpuid;" + "xchg %%rbx, %%rdi;" + : "=a" (*a) , + "=D" (*b) , + #elif defined(MY_CPU_X86) && defined(__PIC__) + "mov %%ebx, %%edi;" + "cpuid;" + "xchgl %%ebx, %%edi;" + : "=a" (*a) , + "=D" (*b) , + #else + "cpuid" + : "=a" (*a) , + "=b" (*b) , + #endif + "=c" (*c) , + "=d" (*d) + : "0" (function)) ; + + #endif + + #else + + int CPUInfo[4]; + __cpuid(CPUInfo, function); + *a = CPUInfo[0]; + *b = CPUInfo[1]; + *c = CPUInfo[2]; + *d = CPUInfo[3]; + + #endif +} + +BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p) +{ + CHECK_CPUID_IS_SUPPORTED + MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); + MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); + return True; +} + +static const UInt32 kVendors[][3] = +{ + { 0x756E6547, 0x49656E69, 0x6C65746E}, + { 0x68747541, 0x69746E65, 0x444D4163}, + { 0x746E6543, 0x48727561, 0x736C7561} +}; + +int x86cpuid_GetFirm(const Cx86cpuid *p) +{ + unsigned i; + for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) + { + const UInt32 *v = kVendors[i]; + if (v[0] == p->vendor[0] && + v[1] == p->vendor[1] && + v[2] == p->vendor[2]) + return (int)i; + } + return -1; +} + +BoolInt CPU_Is_InOrder() +{ + Cx86cpuid p; + int firm; + UInt32 family, model; + if (!x86cpuid_CheckAndRead(&p)) + return True; + + family = x86cpuid_GetFamily(p.ver); + model = x86cpuid_GetModel(p.ver); + + firm = x86cpuid_GetFirm(&p); + + switch (firm) + { + case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( + /* In-Order Atom CPU */ + model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ + || model == 0x26 /* 45 nm, Z6xx */ + || model == 0x27 /* 32 nm, Z2460 */ + || model == 0x35 /* 32 nm, Z2760 */ + || model == 0x36 /* 32 nm, N2xxx, D2xxx */ + ))); + case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); + case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); + } + return True; +} + +#if !defined(MY_CPU_AMD64) && defined(_WIN32) +#include +static BoolInt CPU_Sys_Is_SSE_Supported() +{ + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (!GetVersionEx(&vi)) + return False; + return (vi.dwMajorVersion >= 5); +} +#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; +#else +#define CHECK_SYS_SSE_SUPPORT +#endif + +BoolInt CPU_Is_Aes_Supported() +{ + Cx86cpuid p; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_CheckAndRead(&p)) + return False; + return (p.c >> 25) & 1; +} + +BoolInt CPU_IsSupported_PageGB() +{ + Cx86cpuid cpuid; + if (!x86cpuid_CheckAndRead(&cpuid)) + return False; + { + UInt32 d[4] = { 0 }; + MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]); + if (d[0] < 0x80000001) + return False; + } + { + UInt32 d[4] = { 0 }; + MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]); + return (d[3] >> 26) & 1; + } +} + +#endif diff --git a/lzma/CpuArch.h b/lzma/CpuArch.h new file mode 100644 index 0000000..5f74c1c --- /dev/null +++ b/lzma/CpuArch.h @@ -0,0 +1,336 @@ +/* CpuArch.h -- CPU specific code +2018-02-18 : Igor Pavlov : Public domain */ + +#ifndef __CPU_ARCH_H +#define __CPU_ARCH_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* +MY_CPU_LE means that CPU is LITTLE ENDIAN. +MY_CPU_BE means that CPU is BIG ENDIAN. +If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform. + +MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. +*/ + +#if defined(_M_X64) \ + || defined(_M_AMD64) \ + || defined(__x86_64__) \ + || defined(__AMD64__) \ + || defined(__amd64__) + #define MY_CPU_AMD64 + #ifdef __ILP32__ + #define MY_CPU_NAME "x32" + #else + #define MY_CPU_NAME "x64" + #endif + #define MY_CPU_64BIT +#endif + + +#if defined(_M_IX86) \ + || defined(__i386__) + #define MY_CPU_X86 + #define MY_CPU_NAME "x86" + #define MY_CPU_32BIT +#endif + + +#if defined(_M_ARM64) \ + || defined(__AARCH64EL__) \ + || defined(__AARCH64EB__) \ + || defined(__aarch64__) + #define MY_CPU_ARM64 + #define MY_CPU_NAME "arm64" + #define MY_CPU_64BIT +#endif + + +#if defined(_M_ARM) \ + || defined(_M_ARM_NT) \ + || defined(_M_ARMT) \ + || defined(__arm__) \ + || defined(__thumb__) \ + || defined(__ARMEL__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEL__) \ + || defined(__THUMBEB__) + #define MY_CPU_ARM + #define MY_CPU_NAME "arm" + #define MY_CPU_32BIT +#endif + + +#if defined(_M_IA64) \ + || defined(__ia64__) + #define MY_CPU_IA64 + #define MY_CPU_NAME "ia64" + #define MY_CPU_64BIT +#endif + + +#if defined(__mips64) \ + || defined(__mips64__) \ + || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3)) + #define MY_CPU_NAME "mips64" + #define MY_CPU_64BIT +#elif defined(__mips__) + #define MY_CPU_NAME "mips" + /* #define MY_CPU_32BIT */ +#endif + + +#if defined(__ppc64__) \ + || defined(__powerpc64__) + #ifdef __ILP32__ + #define MY_CPU_NAME "ppc64-32" + #else + #define MY_CPU_NAME "ppc64" + #endif + #define MY_CPU_64BIT +#elif defined(__ppc__) \ + || defined(__powerpc__) + #define MY_CPU_NAME "ppc" + #define MY_CPU_32BIT +#endif + + +#if defined(__sparc64__) + #define MY_CPU_NAME "sparc64" + #define MY_CPU_64BIT +#elif defined(__sparc__) + #define MY_CPU_NAME "sparc" + /* #define MY_CPU_32BIT */ +#endif + + +#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) +#define MY_CPU_X86_OR_AMD64 +#endif + + +#ifdef _WIN32 + + #ifdef MY_CPU_ARM + #define MY_CPU_ARM_LE + #endif + + #ifdef MY_CPU_ARM64 + #define MY_CPU_ARM64_LE + #endif + + #ifdef _M_IA64 + #define MY_CPU_IA64_LE + #endif + +#endif + + +#if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM_LE) \ + || defined(MY_CPU_ARM64_LE) \ + || defined(MY_CPU_IA64_LE) \ + || defined(__LITTLE_ENDIAN__) \ + || defined(__ARMEL__) \ + || defined(__THUMBEL__) \ + || defined(__AARCH64EL__) \ + || defined(__MIPSEL__) \ + || defined(__MIPSEL) \ + || defined(_MIPSEL) \ + || defined(__BFIN__) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + #define MY_CPU_LE +#endif + +#if defined(__BIG_ENDIAN__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEB__) \ + || defined(__AARCH64EB__) \ + || defined(__MIPSEB__) \ + || defined(__MIPSEB) \ + || defined(_MIPSEB) \ + || defined(__m68k__) \ + || defined(__s390__) \ + || defined(__s390x__) \ + || defined(__zarch__) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + #define MY_CPU_BE +#endif + + +#if defined(MY_CPU_LE) && defined(MY_CPU_BE) + #error Stop_Compiling_Bad_Endian +#endif + + +#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT) + #error Stop_Compiling_Bad_32_64_BIT +#endif + + +#ifndef MY_CPU_NAME + #ifdef MY_CPU_LE + #define MY_CPU_NAME "LE" + #elif defined(MY_CPU_BE) + #define MY_CPU_NAME "BE" + #else + /* + #define MY_CPU_NAME "" + */ + #endif +#endif + + + + + +#ifdef MY_CPU_LE + #if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM64) \ + || defined(__ARM_FEATURE_UNALIGNED) + #define MY_CPU_LE_UNALIGN + #endif +#endif + + +#ifdef MY_CPU_LE_UNALIGN + +#define GetUi16(p) (*(const UInt16 *)(const void *)(p)) +#define GetUi32(p) (*(const UInt32 *)(const void *)(p)) +#define GetUi64(p) (*(const UInt64 *)(const void *)(p)) + +#define SetUi16(p, v) { *(UInt16 *)(p) = (v); } +#define SetUi32(p, v) { *(UInt32 *)(p) = (v); } +#define SetUi64(p, v) { *(UInt64 *)(p) = (v); } + +#else + +#define GetUi16(p) ( (UInt16) ( \ + ((const Byte *)(p))[0] | \ + ((UInt16)((const Byte *)(p))[1] << 8) )) + +#define GetUi32(p) ( \ + ((const Byte *)(p))[0] | \ + ((UInt32)((const Byte *)(p))[1] << 8) | \ + ((UInt32)((const Byte *)(p))[2] << 16) | \ + ((UInt32)((const Byte *)(p))[3] << 24)) + +#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) + +#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); } + +#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); \ + _ppp_[2] = (Byte)(_vvv_ >> 16); \ + _ppp_[3] = (Byte)(_vvv_ >> 24); } + +#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \ + SetUi32(_ppp2_ , (UInt32)_vvv2_); \ + SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); } + +#endif + +#ifdef __has_builtin + #define MY__has_builtin(x) __has_builtin(x) +#else + #define MY__has_builtin(x) 0 +#endif + +#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300) + +/* Note: we use bswap instruction, that is unsupported in 386 cpu */ + +#include + +#pragma intrinsic(_byteswap_ushort) +#pragma intrinsic(_byteswap_ulong) +#pragma intrinsic(_byteswap_uint64) + +/* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */ +#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) +#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) + +#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v) + +#elif defined(MY_CPU_LE_UNALIGN) && ( \ + (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \ + || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) ) + +/* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const Byte *)(p)) */ +#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p)) +#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p)) + +#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v) + +#else + +#define GetBe32(p) ( \ + ((UInt32)((const Byte *)(p))[0] << 24) | \ + ((UInt32)((const Byte *)(p))[1] << 16) | \ + ((UInt32)((const Byte *)(p))[2] << 8) | \ + ((const Byte *)(p))[3] ) + +#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) + +#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)(_vvv_ >> 24); \ + _ppp_[1] = (Byte)(_vvv_ >> 16); \ + _ppp_[2] = (Byte)(_vvv_ >> 8); \ + _ppp_[3] = (Byte)_vvv_; } + +#endif + + +#ifndef GetBe16 + +#define GetBe16(p) ( (UInt16) ( \ + ((UInt16)((const Byte *)(p))[0] << 8) | \ + ((const Byte *)(p))[1] )) + +#endif + + + +#ifdef MY_CPU_X86_OR_AMD64 + +typedef struct +{ + UInt32 maxFunc; + UInt32 vendor[3]; + UInt32 ver; + UInt32 b; + UInt32 c; + UInt32 d; +} Cx86cpuid; + +enum +{ + CPU_FIRM_INTEL, + CPU_FIRM_AMD, + CPU_FIRM_VIA +}; + +void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d); + +BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p); +int x86cpuid_GetFirm(const Cx86cpuid *p); + +#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF)) +#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF)) +#define x86cpuid_GetStepping(ver) (ver & 0xF) + +BoolInt CPU_Is_InOrder(); +BoolInt CPU_Is_Aes_Supported(); +BoolInt CPU_IsSupported_PageGB(); + +#endif + +EXTERN_C_END + +#endif diff --git a/lzma/Delta.c b/lzma/Delta.c new file mode 100644 index 0000000..6cbbe46 --- /dev/null +++ b/lzma/Delta.c @@ -0,0 +1,64 @@ +/* Delta.c -- Delta converter +2009-05-26 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Delta.h" + +void Delta_Init(Byte *state) +{ + unsigned i; + for (i = 0; i < DELTA_STATE_SIZE; i++) + state[i] = 0; +} + +static void MyMemCpy(Byte *dest, const Byte *src, unsigned size) +{ + unsigned i; + for (i = 0; i < size; i++) + dest[i] = src[i]; +} + +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + Byte b = data[i]; + data[i] = (Byte)(b - buf[j]); + buf[j] = b; + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); +} + +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + buf[j] = data[i] = (Byte)(buf[j] + data[i]); + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); +} diff --git a/lzma/Delta.h b/lzma/Delta.h new file mode 100644 index 0000000..e59d5a2 --- /dev/null +++ b/lzma/Delta.h @@ -0,0 +1,19 @@ +/* Delta.h -- Delta converter +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __DELTA_H +#define __DELTA_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define DELTA_STATE_SIZE 256 + +void Delta_Init(Byte *state); +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); + +EXTERN_C_END + +#endif diff --git a/lzma/DllSecur.c b/lzma/DllSecur.c new file mode 100644 index 0000000..19a22a9 --- /dev/null +++ b/lzma/DllSecur.c @@ -0,0 +1,108 @@ +/* DllSecur.c -- DLL loading security +2018-02-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifdef _WIN32 + +#include + +#include "DllSecur.h" + +#ifndef UNDER_CE + +typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags); + +#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400 +#define MY_LOAD_LIBRARY_SEARCH_SYSTEM32 0x800 + +static const char * const g_Dlls = + #ifndef _CONSOLE + "UXTHEME\0" + #endif + "USERENV\0" + "SETUPAPI\0" + "APPHELP\0" + "PROPSYS\0" + "DWMAPI\0" + "CRYPTBASE\0" + "OLEACC\0" + "CLBCATQ\0" + "VERSION\0" + ; + +#endif + +void My_SetDefaultDllDirectories() +{ + #ifndef UNDER_CE + + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + GetVersionEx(&vi); + if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0) + { + Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories) + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories"); + if (setDllDirs) + if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) + return; + } + + #endif +} + + +void LoadSecurityDlls() +{ + #ifndef UNDER_CE + + wchar_t buf[MAX_PATH + 100]; + + { + // at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ??? + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0) + { + Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories) + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories"); + if (setDllDirs) + if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) + return; + } + } + + { + unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2); + if (len == 0 || len > MAX_PATH) + return; + } + { + const char *dll; + unsigned pos = (unsigned)lstrlenW(buf); + + if (buf[pos - 1] != '\\') + buf[pos++] = '\\'; + + for (dll = g_Dlls; dll[0] != 0;) + { + unsigned k = 0; + for (;;) + { + char c = *dll++; + buf[pos + k] = (Byte)c; + k++; + if (c == 0) + break; + } + + lstrcatW(buf, L".dll"); + LoadLibraryExW(buf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + } + } + + #endif +} + +#endif diff --git a/lzma/DllSecur.h b/lzma/DllSecur.h new file mode 100644 index 0000000..4c11356 --- /dev/null +++ b/lzma/DllSecur.h @@ -0,0 +1,20 @@ +/* DllSecur.h -- DLL loading for security +2018-02-19 : Igor Pavlov : Public domain */ + +#ifndef __DLL_SECUR_H +#define __DLL_SECUR_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#ifdef _WIN32 + +void My_SetDefaultDllDirectories(); +void LoadSecurityDlls(); + +#endif + +EXTERN_C_END + +#endif diff --git a/lzma/LzFind.c b/lzma/LzFind.c new file mode 100644 index 0000000..4eefc17 --- /dev/null +++ b/lzma/LzFind.c @@ -0,0 +1,1127 @@ +/* LzFind.c -- Match finder for LZ algorithms +2018-07-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "LzFind.h" +#include "LzHash.h" + +#define kEmptyHashValue 0 +#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) +#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ +#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1)) +#define kMaxHistorySize ((UInt32)7 << 29) + +#define kStartMaxLen 3 + +static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc) +{ + if (!p->directInput) + { + ISzAlloc_Free(alloc, p->bufferBase); + p->bufferBase = NULL; + } +} + +/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ + +static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAllocPtr alloc) +{ + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; + if (p->directInput) + { + p->blockSize = blockSize; + return 1; + } + if (!p->bufferBase || p->blockSize != blockSize) + { + LzInWindow_Free(p, alloc); + p->blockSize = blockSize; + p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, (size_t)blockSize); + } + return (p->bufferBase != NULL); +} + +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } + +UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) +{ + p->posLimit -= subValue; + p->pos -= subValue; + p->streamPos -= subValue; +} + +static void MatchFinder_ReadBlock(CMatchFinder *p) +{ + if (p->streamEndWasReached || p->result != SZ_OK) + return; + + /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */ + + if (p->directInput) + { + UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos); + if (curSize > p->directInputRem) + curSize = (UInt32)p->directInputRem; + p->directInputRem -= curSize; + p->streamPos += curSize; + if (p->directInputRem == 0) + p->streamEndWasReached = 1; + return; + } + + for (;;) + { + Byte *dest = p->buffer + (p->streamPos - p->pos); + size_t size = (p->bufferBase + p->blockSize - dest); + if (size == 0) + return; + + p->result = ISeqInStream_Read(p->stream, dest, &size); + if (p->result != SZ_OK) + return; + if (size == 0) + { + p->streamEndWasReached = 1; + return; + } + p->streamPos += (UInt32)size; + if (p->streamPos - p->pos > p->keepSizeAfter) + return; + } +} + +void MatchFinder_MoveBlock(CMatchFinder *p) +{ + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, + (size_t)(p->streamPos - p->pos) + p->keepSizeBefore); + p->buffer = p->bufferBase + p->keepSizeBefore; +} + +int MatchFinder_NeedMove(CMatchFinder *p) +{ + if (p->directInput) + return 0; + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); +} + +void MatchFinder_ReadIfRequired(CMatchFinder *p) +{ + if (p->streamEndWasReached) + return; + if (p->keepSizeAfter >= p->streamPos - p->pos) + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) +{ + if (MatchFinder_NeedMove(p)) + MatchFinder_MoveBlock(p); + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_SetDefaultSettings(CMatchFinder *p) +{ + p->cutValue = 32; + p->btMode = 1; + p->numHashBytes = 4; + p->bigHash = 0; +} + +#define kCrcPoly 0xEDB88320 + +void MatchFinder_Construct(CMatchFinder *p) +{ + unsigned i; + p->bufferBase = NULL; + p->directInput = 0; + p->hash = NULL; + p->expectedDataSize = (UInt64)(Int64)-1; + MatchFinder_SetDefaultSettings(p); + + for (i = 0; i < 256; i++) + { + UInt32 r = (UInt32)i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); + p->crc[i] = r; + } +} + +static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->hash); + p->hash = NULL; +} + +void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc) +{ + MatchFinder_FreeThisClassMemory(p, alloc); + LzInWindow_Free(p, alloc); +} + +static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc) +{ + size_t sizeInBytes = (size_t)num * sizeof(CLzRef); + if (sizeInBytes / sizeof(CLzRef) != num) + return NULL; + return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes); +} + +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAllocPtr alloc) +{ + UInt32 sizeReserv; + + if (historySize > kMaxHistorySize) + { + MatchFinder_Free(p, alloc); + return 0; + } + + sizeReserv = historySize >> 1; + if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3; + else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2; + + sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); + + p->keepSizeBefore = historySize + keepAddBufferBefore + 1; + p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; + + /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ + + if (LzInWindow_Create(p, sizeReserv, alloc)) + { + UInt32 newCyclicBufferSize = historySize + 1; + UInt32 hs; + p->matchMaxLen = matchMaxLen; + { + p->fixedHashSize = 0; + if (p->numHashBytes == 2) + hs = (1 << 16) - 1; + else + { + hs = historySize; + if (hs > p->expectedDataSize) + hs = (UInt32)p->expectedDataSize; + if (hs != 0) + hs--; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; /* don't change it! It's required for Deflate */ + if (hs > (1 << 24)) + { + if (p->numHashBytes == 3) + hs = (1 << 24) - 1; + else + hs >>= 1; + /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ + } + } + p->hashMask = hs; + hs++; + if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; + if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; + if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; + hs += p->fixedHashSize; + } + + { + size_t newSize; + size_t numSons; + p->historySize = historySize; + p->hashSizeSum = hs; + p->cyclicBufferSize = newCyclicBufferSize; + + numSons = newCyclicBufferSize; + if (p->btMode) + numSons <<= 1; + newSize = hs + numSons; + + if (p->hash && p->numRefs == newSize) + return 1; + + MatchFinder_FreeThisClassMemory(p, alloc); + p->numRefs = newSize; + p->hash = AllocRefs(newSize, alloc); + + if (p->hash) + { + p->son = p->hash + p->hashSizeSum; + return 1; + } + } + } + + MatchFinder_Free(p, alloc); + return 0; +} + +static void MatchFinder_SetLimits(CMatchFinder *p) +{ + UInt32 limit = kMaxValForNormalize - p->pos; + UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; + + if (limit2 < limit) + limit = limit2; + limit2 = p->streamPos - p->pos; + + if (limit2 <= p->keepSizeAfter) + { + if (limit2 > 0) + limit2 = 1; + } + else + limit2 -= p->keepSizeAfter; + + if (limit2 < limit) + limit = limit2; + + { + UInt32 lenLimit = p->streamPos - p->pos; + if (lenLimit > p->matchMaxLen) + lenLimit = p->matchMaxLen; + p->lenLimit = lenLimit; + } + p->posLimit = p->pos + limit; +} + + +void MatchFinder_Init_LowHash(CMatchFinder *p) +{ + size_t i; + CLzRef *items = p->hash; + size_t numItems = p->fixedHashSize; + for (i = 0; i < numItems; i++) + items[i] = kEmptyHashValue; +} + + +void MatchFinder_Init_HighHash(CMatchFinder *p) +{ + size_t i; + CLzRef *items = p->hash + p->fixedHashSize; + size_t numItems = (size_t)p->hashMask + 1; + for (i = 0; i < numItems; i++) + items[i] = kEmptyHashValue; +} + + +void MatchFinder_Init_3(CMatchFinder *p, int readData) +{ + p->cyclicBufferPos = 0; + p->buffer = p->bufferBase; + p->pos = + p->streamPos = p->cyclicBufferSize; + p->result = SZ_OK; + p->streamEndWasReached = 0; + + if (readData) + MatchFinder_ReadBlock(p); + + MatchFinder_SetLimits(p); +} + + +void MatchFinder_Init(CMatchFinder *p) +{ + MatchFinder_Init_HighHash(p); + MatchFinder_Init_LowHash(p); + MatchFinder_Init_3(p, True); +} + + +static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) +{ + return (p->pos - p->historySize - 1) & kNormalizeMask; +} + +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) +{ + size_t i; + for (i = 0; i < numItems; i++) + { + UInt32 value = items[i]; + if (value <= subValue) + value = kEmptyHashValue; + else + value -= subValue; + items[i] = value; + } +} + +static void MatchFinder_Normalize(CMatchFinder *p) +{ + UInt32 subValue = MatchFinder_GetSubValue(p); + MatchFinder_Normalize3(subValue, p->hash, p->numRefs); + MatchFinder_ReduceOffsets(p, subValue); +} + + +MY_NO_INLINE +static void MatchFinder_CheckLimits(CMatchFinder *p) +{ + if (p->pos == kMaxValForNormalize) + MatchFinder_Normalize(p); + if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) + MatchFinder_CheckAndMoveAndRead(p); + if (p->cyclicBufferPos == p->cyclicBufferSize) + p->cyclicBufferPos = 0; + MatchFinder_SetLimits(p); +} + + +/* + (lenLimit > maxLen) +*/ +MY_FORCE_INLINE +static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, unsigned maxLen) +{ + /* + son[_cyclicBufferPos] = curMatch; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + return distances; + { + const Byte *pb = cur - delta; + curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; + if (pb[maxLen] == cur[maxLen] && *pb == *cur) + { + UInt32 len = 0; + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + maxLen = len; + *distances++ = len; + *distances++ = delta - 1; + if (len == lenLimit) + return distances; + } + } + } + } + */ + + const Byte *lim = cur + lenLimit; + son[_cyclicBufferPos] = curMatch; + do + { + UInt32 delta = pos - curMatch; + if (delta >= _cyclicBufferSize) + break; + { + ptrdiff_t diff; + curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; + diff = (ptrdiff_t)0 - delta; + if (cur[maxLen] == cur[maxLen + diff]) + { + const Byte *c = cur; + while (*c == c[diff]) + { + if (++c == lim) + { + distances[0] = (UInt32)(lim - cur); + distances[1] = delta - 1; + return distances + 2; + } + } + { + unsigned len = (unsigned)(c - cur); + if (maxLen < len) + { + maxLen = len; + distances[0] = (UInt32)len; + distances[1] = delta - 1; + distances += 2; + } + } + } + } + } + while (--cutValue); + + return distances; +} + + +MY_FORCE_INLINE +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + unsigned len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return distances; + } + { + CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + unsigned len = (len0 < len1 ? len0 : len1); + UInt32 pair0 = pair[0]; + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + maxLen = (UInt32)len; + *distances++ = (UInt32)len; + *distances++ = delta - 1; + if (len == lenLimit) + { + *ptr1 = pair0; + *ptr0 = pair[1]; + return distances; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) +{ + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + unsigned len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return; + } + { + CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + unsigned len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + { + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +#define MOVE_POS \ + ++p->cyclicBufferPos; \ + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + +#define MOVE_POS_RET MOVE_POS return (UInt32)offset; + +static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + +#define GET_MATCHES_HEADER2(minLen, ret_op) \ + unsigned lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \ + lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ + cur = p->buffer; + +#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) +#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) + +#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue + +#define GET_MATCHES_FOOTER(offset, maxLen) \ + offset = (unsigned)(GetMatchesSpec1((UInt32)lenLimit, curMatch, MF_PARAMS(p), \ + distances + offset, (UInt32)maxLen) - distances); MOVE_POS_RET; + +#define SKIP_FOOTER \ + SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; + +#define UPDATE_maxLen { \ + ptrdiff_t diff = (ptrdiff_t)0 - d2; \ + const Byte *c = cur + maxLen; \ + const Byte *lim = cur + lenLimit; \ + for (; c != lim; c++) if (*(c + diff) != *c) break; \ + maxLen = (unsigned)(c - cur); } + +static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + unsigned offset; + GET_MATCHES_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 1) +} + +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + unsigned offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 2) +} + +static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, d2, pos; + unsigned maxLen, offset; + UInt32 *hash; + GET_MATCHES_HEADER(3) + + HASH3_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[h2]; + + curMatch = (hash + kFix3HashSize)[hv]; + + hash[h2] = pos; + (hash + kFix3HashSize)[hv] = pos; + + maxLen = 2; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + UPDATE_maxLen + distances[0] = (UInt32)maxLen; + distances[1] = d2 - 1; + offset = 2; + if (maxLen == lenLimit) + { + SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + + GET_MATCHES_FOOTER(offset, maxLen) +} + +static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, d2, d3, pos; + unsigned maxLen, offset; + UInt32 *hash; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + + curMatch = (hash + kFix4HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + (hash + kFix4HashSize)[hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + maxLen = 2; + distances[0] = 2; + distances[1] = d2 - 1; + offset = 2; + } + + if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + maxLen = 3; + distances[(size_t)offset + 1] = d3 - 1; + offset += 2; + d2 = d3; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[(size_t)offset - 2] = (UInt32)maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + + if (maxLen < 3) + maxLen = 3; + + GET_MATCHES_FOOTER(offset, maxLen) +} + +/* +static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos; + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + d4 = pos - (hash + kFix4HashSize)[h4]; + + curMatch = (hash + kFix5HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + (hash + kFix4HashSize)[h4] = pos; + (hash + kFix5HashSize)[hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = d2 - 1; + offset = 2; + if (*(cur - d2 + 2) == cur[2]) + distances[0] = maxLen = 3; + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[2] = maxLen = 3; + distances[3] = d3 - 1; + offset = 4; + d2 = d3; + } + } + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[0] = maxLen = 3; + distances[1] = d3 - 1; + offset = 2; + d2 = d3; + } + + if (d2 != d4 && d4 < p->cyclicBufferSize + && *(cur - d4) == *cur + && *(cur - d4 + 3) == *(cur + 3)) + { + maxLen = 4; + distances[(size_t)offset + 1] = d4 - 1; + offset += 2; + d2 = d4; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[(size_t)offset - 2] = maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + + if (maxLen < 4) + maxLen = 4; + + GET_MATCHES_FOOTER(offset, maxLen) +} +*/ + +static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, d2, d3, pos; + unsigned maxLen, offset; + UInt32 *hash; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + curMatch = (hash + kFix4HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + (hash + kFix4HashSize)[hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + maxLen = 2; + distances[0] = 2; + distances[1] = d2 - 1; + offset = 2; + } + + if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + maxLen = 3; + distances[(size_t)offset + 1] = d3 - 1; + offset += 2; + d2 = d3; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[(size_t)offset - 2] = (UInt32)maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + + if (maxLen < 3) + maxLen = 3; + + offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} + +/* +static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + d4 = pos - (hash + kFix4HashSize)[h4]; + + curMatch = (hash + kFix5HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + (hash + kFix4HashSize)[h4] = pos; + (hash + kFix5HashSize)[hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = d2 - 1; + offset = 2; + if (*(cur - d2 + 2) == cur[2]) + distances[0] = maxLen = 3; + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[2] = maxLen = 3; + distances[3] = d3 - 1; + offset = 4; + d2 = d3; + } + } + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[0] = maxLen = 3; + distances[1] = d3 - 1; + offset = 2; + d2 = d3; + } + + if (d2 != d4 && d4 < p->cyclicBufferSize + && *(cur - d4) == *cur + && *(cur - d4 + 3) == *(cur + 3)) + { + maxLen = 4; + distances[(size_t)offset + 1] = d4 - 1; + offset += 2; + d2 = d4; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[(size_t)offset - 2] = maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + + if (maxLen < 4) + maxLen = 4; + + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} +*/ + +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + unsigned offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances, 2) - (distances)); + MOVE_POS_RET +} + +static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2; + UInt32 *hash; + SKIP_HEADER(3) + HASH3_CALC; + hash = p->hash; + curMatch = (hash + kFix3HashSize)[hv]; + hash[h2] = + (hash + kFix3HashSize)[hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3; + UInt32 *hash; + SKIP_HEADER(4) + HASH4_CALC; + hash = p->hash; + curMatch = (hash + kFix4HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + (hash + kFix4HashSize)[hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +/* +static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3, h4; + UInt32 *hash; + SKIP_HEADER(5) + HASH5_CALC; + hash = p->hash; + curMatch = (hash + kFix5HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + (hash + kFix4HashSize)[h4] = + (hash + kFix5HashSize)[hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} +*/ + +static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3; + UInt32 *hash; + SKIP_HEADER(4) + HASH4_CALC; + hash = p->hash; + curMatch = (hash + kFix4HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + (hash + kFix4HashSize)[hv] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +/* +static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3, h4; + UInt32 *hash; + SKIP_HEADER(5) + HASH5_CALC; + hash = p->hash; + curMatch = hash + kFix5HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + (hash + kFix4HashSize)[h4] = + (hash + kFix5HashSize)[hv] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} +*/ + +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; + if (!p->btMode) + { + /* if (p->numHashBytes <= 4) */ + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + } + /* + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip; + } + */ + } + else if (p->numHashBytes == 2) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; + } + else if (p->numHashBytes == 3) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; + } + else /* if (p->numHashBytes == 4) */ + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; + } + /* + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip; + } + */ +} diff --git a/lzma/LzFind.h b/lzma/LzFind.h new file mode 100644 index 0000000..c77adde --- /dev/null +++ b/lzma/LzFind.h @@ -0,0 +1,121 @@ +/* LzFind.h -- Match finder for LZ algorithms +2017-06-10 : Igor Pavlov : Public domain */ + +#ifndef __LZ_FIND_H +#define __LZ_FIND_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +typedef UInt32 CLzRef; + +typedef struct _CMatchFinder +{ + Byte *buffer; + UInt32 pos; + UInt32 posLimit; + UInt32 streamPos; + UInt32 lenLimit; + + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + + Byte streamEndWasReached; + Byte btMode; + Byte bigHash; + Byte directInput; + + UInt32 matchMaxLen; + CLzRef *hash; + CLzRef *son; + UInt32 hashMask; + UInt32 cutValue; + + Byte *bufferBase; + ISeqInStream *stream; + + UInt32 blockSize; + UInt32 keepSizeBefore; + UInt32 keepSizeAfter; + + UInt32 numHashBytes; + size_t directInputRem; + UInt32 historySize; + UInt32 fixedHashSize; + UInt32 hashSizeSum; + SRes result; + UInt32 crc[256]; + size_t numRefs; + + UInt64 expectedDataSize; +} CMatchFinder; + +#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) + +#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + +#define Inline_MatchFinder_IsFinishedOK(p) \ + ((p)->streamEndWasReached \ + && (p)->streamPos == (p)->pos \ + && (!(p)->directInput || (p)->directInputRem == 0)) + +int MatchFinder_NeedMove(CMatchFinder *p); +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +void MatchFinder_MoveBlock(CMatchFinder *p); +void MatchFinder_ReadIfRequired(CMatchFinder *p); + +void MatchFinder_Construct(CMatchFinder *p); + +/* Conditions: + historySize <= 3 GB + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB +*/ +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAllocPtr alloc); +void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc); +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems); +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *distances, UInt32 maxLen); + +/* +Conditions: + Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. + Mf_GetPointerToCurrentPos_Func's result must be used only before any other function +*/ + +typedef void (*Mf_Init_Func)(void *object); +typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); +typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); +typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); +typedef void (*Mf_Skip_Func)(void *object, UInt32); + +typedef struct _IMatchFinder +{ + Mf_Init_Func Init; + Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; + Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; + Mf_GetMatches_Func GetMatches; + Mf_Skip_Func Skip; +} IMatchFinder; + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + +void MatchFinder_Init_LowHash(CMatchFinder *p); +void MatchFinder_Init_HighHash(CMatchFinder *p); +void MatchFinder_Init_3(CMatchFinder *p, int readData); +void MatchFinder_Init(CMatchFinder *p); + +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); + +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); + +EXTERN_C_END + +#endif diff --git a/lzma/LzFindMt.c b/lzma/LzFindMt.c new file mode 100644 index 0000000..df32146 --- /dev/null +++ b/lzma/LzFindMt.c @@ -0,0 +1,853 @@ +/* LzFindMt.c -- multithreaded Match finder for LZ algorithms +2018-12-29 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "LzHash.h" + +#include "LzFindMt.h" + +static void MtSync_Construct(CMtSync *p) +{ + p->wasCreated = False; + p->csWasInitialized = False; + p->csWasEntered = False; + Thread_Construct(&p->thread); + Event_Construct(&p->canStart); + Event_Construct(&p->wasStarted); + Event_Construct(&p->wasStopped); + Semaphore_Construct(&p->freeSemaphore); + Semaphore_Construct(&p->filledSemaphore); +} + +static void MtSync_GetNextBlock(CMtSync *p) +{ + if (p->needStart) + { + p->numProcessedBlocks = 1; + p->needStart = False; + p->stopWriting = False; + p->exit = False; + Event_Reset(&p->wasStarted); + Event_Reset(&p->wasStopped); + + Event_Set(&p->canStart); + Event_Wait(&p->wasStarted); + + // if (mt) MatchFinder_Init_LowHash(mt->MatchFinder); + } + else + { + CriticalSection_Leave(&p->cs); + p->csWasEntered = False; + p->numProcessedBlocks++; + Semaphore_Release1(&p->freeSemaphore); + } + Semaphore_Wait(&p->filledSemaphore); + CriticalSection_Enter(&p->cs); + p->csWasEntered = True; +} + +/* MtSync_StopWriting must be called if Writing was started */ + +static void MtSync_StopWriting(CMtSync *p) +{ + UInt32 myNumBlocks = p->numProcessedBlocks; + if (!Thread_WasCreated(&p->thread) || p->needStart) + return; + p->stopWriting = True; + if (p->csWasEntered) + { + CriticalSection_Leave(&p->cs); + p->csWasEntered = False; + } + Semaphore_Release1(&p->freeSemaphore); + + Event_Wait(&p->wasStopped); + + while (myNumBlocks++ != p->numProcessedBlocks) + { + Semaphore_Wait(&p->filledSemaphore); + Semaphore_Release1(&p->freeSemaphore); + } + p->needStart = True; +} + +static void MtSync_Destruct(CMtSync *p) +{ + if (Thread_WasCreated(&p->thread)) + { + MtSync_StopWriting(p); + p->exit = True; + if (p->needStart) + Event_Set(&p->canStart); + Thread_Wait(&p->thread); + Thread_Close(&p->thread); + } + if (p->csWasInitialized) + { + CriticalSection_Delete(&p->cs); + p->csWasInitialized = False; + } + + Event_Close(&p->canStart); + Event_Close(&p->wasStarted); + Event_Close(&p->wasStopped); + Semaphore_Close(&p->freeSemaphore); + Semaphore_Close(&p->filledSemaphore); + + p->wasCreated = False; +} + +#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } + +static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) +{ + if (p->wasCreated) + return SZ_OK; + + RINOK_THREAD(CriticalSection_Init(&p->cs)); + p->csWasInitialized = True; + + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)); + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted)); + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)); + + RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks)); + RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks)); + + p->needStart = True; + + RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj)); + p->wasCreated = True; + return SZ_OK; +} + +static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) +{ + SRes res = MtSync_Create2(p, startAddress, obj, numBlocks); + if (res != SZ_OK) + MtSync_Destruct(p); + return res; +} + +void MtSync_Init(CMtSync *p) { p->needStart = True; } + +#define kMtMaxValForNormalize 0xFFFFFFFF + +#define DEF_GetHeads2(name, v, action) \ + static void GetHeads ## name(const Byte *p, UInt32 pos, \ + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ + { action; for (; numHeads != 0; numHeads--) { \ + const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } + +#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) + +DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) +DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask) +DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask) +DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask) +/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */ + +static void HashThreadFunc(CMatchFinderMt *mt) +{ + CMtSync *p = &mt->hashSync; + for (;;) + { + UInt32 numProcessedBlocks = 0; + Event_Wait(&p->canStart); + Event_Set(&p->wasStarted); + + MatchFinder_Init_HighHash(mt->MatchFinder); + + for (;;) + { + if (p->exit) + return; + if (p->stopWriting) + { + p->numProcessedBlocks = numProcessedBlocks; + Event_Set(&p->wasStopped); + break; + } + + { + CMatchFinder *mf = mt->MatchFinder; + if (MatchFinder_NeedMove(mf)) + { + CriticalSection_Enter(&mt->btSync.cs); + CriticalSection_Enter(&mt->hashSync.cs); + { + const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf); + ptrdiff_t offset; + MatchFinder_MoveBlock(mf); + offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf); + mt->pointerToCurPos -= offset; + mt->buffer -= offset; + } + CriticalSection_Leave(&mt->btSync.cs); + CriticalSection_Leave(&mt->hashSync.cs); + continue; + } + + Semaphore_Wait(&p->freeSemaphore); + + MatchFinder_ReadIfRequired(mf); + if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize)) + { + UInt32 subValue = (mf->pos - mf->historySize - 1); + MatchFinder_ReduceOffsets(mf, subValue); + MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1); + } + { + UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize; + UInt32 num = mf->streamPos - mf->pos; + heads[0] = 2; + heads[1] = num; + if (num >= mf->numHashBytes) + { + num = num - mf->numHashBytes + 1; + if (num > kMtHashBlockSize - 2) + num = kMtHashBlockSize - 2; + mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); + heads[0] = 2 + num; + } + mf->pos += num; + mf->buffer += num; + } + } + + Semaphore_Release1(&p->filledSemaphore); + } + } +} + +static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) +{ + MtSync_GetNextBlock(&p->hashSync); + p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize; + p->hashBufPosLimit += p->hashBuf[p->hashBufPos++]; + p->hashNumAvail = p->hashBuf[p->hashBufPos++]; +} + +#define kEmptyHashValue 0 + +#define MFMT_GM_INLINE + +#ifdef MFMT_GM_INLINE + +/* + we use size_t for _cyclicBufferPos instead of UInt32 + to eliminate "movsx" BUG in old MSVC x64 compiler. +*/ + +MY_NO_INLINE +static UInt32 *GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *distances, UInt32 _maxLen, const UInt32 *hash, const UInt32 *limit, UInt32 size, UInt32 *posRes) +{ + do + { + UInt32 *_distances = ++distances; + UInt32 delta = *hash++; + + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + unsigned len0 = 0, len1 = 0; + UInt32 cutValue = _cutValue; + unsigned maxLen = (unsigned)_maxLen; + + /* + if (size > 1) + { + UInt32 delta = *hash; + if (delta < _cyclicBufferSize) + { + UInt32 cyc1 = _cyclicBufferPos + 1; + CLzRef *pair = son + ((size_t)(cyc1 - delta + ((delta > cyc1) ? _cyclicBufferSize : 0)) << 1); + Byte b = *(cur + 1 - delta); + _distances[0] = pair[0]; + _distances[1] = b; + } + } + */ + if (cutValue == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + } + else + for(;;) + { + { + CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((_cyclicBufferPos < delta) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + unsigned len = (len0 < len1 ? len0 : len1); + UInt32 pair0 = *pair; + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + maxLen = len; + *distances++ = (UInt32)len; + *distances++ = delta - 1; + if (len == lenLimit) + { + UInt32 pair1 = pair[1]; + *ptr1 = pair0; + *ptr0 = pair1; + break; + } + } + } + { + UInt32 curMatch = pos - delta; + // delta = pos - *pair; + // delta = pos - pair[((UInt32)pb[len] - (UInt32)cur[len]) >> 31]; + if (pb[len] < cur[len]) + { + delta = pos - pair[1]; + *ptr1 = curMatch; + ptr1 = pair + 1; + len1 = len; + } + else + { + delta = pos - *pair; + *ptr0 = curMatch; + ptr0 = pair; + len0 = len; + } + } + } + if (--cutValue == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + break; + } + } + pos++; + _cyclicBufferPos++; + cur++; + { + UInt32 num = (UInt32)(distances - _distances); + _distances[-1] = num; + } + } + while (distances < limit && --size != 0); + *posRes = pos; + return distances; +} + +#endif + + + +static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + UInt32 numProcessed = 0; + UInt32 curPos = 2; + UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); // * 2 + + distances[1] = p->hashNumAvail; + + while (curPos < limit) + { + if (p->hashBufPos == p->hashBufPosLimit) + { + MatchFinderMt_GetNextBlock_Hash(p); + distances[1] = numProcessed + p->hashNumAvail; + if (p->hashNumAvail >= p->numHashBytes) + continue; + distances[0] = curPos + p->hashNumAvail; + distances += curPos; + for (; p->hashNumAvail != 0; p->hashNumAvail--) + *distances++ = 0; + return; + } + { + UInt32 size = p->hashBufPosLimit - p->hashBufPos; + UInt32 lenLimit = p->matchMaxLen; + UInt32 pos = p->pos; + UInt32 cyclicBufferPos = p->cyclicBufferPos; + if (lenLimit >= p->hashNumAvail) + lenLimit = p->hashNumAvail; + { + UInt32 size2 = p->hashNumAvail - lenLimit + 1; + if (size2 < size) + size = size2; + size2 = p->cyclicBufferSize - cyclicBufferPos; + if (size2 < size) + size = size2; + } + + #ifndef MFMT_GM_INLINE + while (curPos < limit && size-- != 0) + { + UInt32 *startDistances = distances + curPos; + UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], + pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + startDistances + 1, p->numHashBytes - 1) - startDistances); + *startDistances = num - 1; + curPos += num; + cyclicBufferPos++; + pos++; + p->buffer++; + } + #else + { + UInt32 posRes; + curPos = (UInt32)(GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, + distances + limit, + size, &posRes) - distances); + p->hashBufPos += posRes - pos; + cyclicBufferPos += posRes - pos; + p->buffer += posRes - pos; + pos = posRes; + } + #endif + + numProcessed += pos - p->pos; + p->hashNumAvail -= pos - p->pos; + p->pos = pos; + if (cyclicBufferPos == p->cyclicBufferSize) + cyclicBufferPos = 0; + p->cyclicBufferPos = cyclicBufferPos; + } + } + + distances[0] = curPos; +} + +static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) +{ + CMtSync *sync = &p->hashSync; + if (!sync->needStart) + { + CriticalSection_Enter(&sync->cs); + sync->csWasEntered = True; + } + + BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize); + + if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize) + { + UInt32 subValue = p->pos - p->cyclicBufferSize; + MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2); + p->pos -= subValue; + } + + if (!sync->needStart) + { + CriticalSection_Leave(&sync->cs); + sync->csWasEntered = False; + } +} + +void BtThreadFunc(CMatchFinderMt *mt) +{ + CMtSync *p = &mt->btSync; + for (;;) + { + UInt32 blockIndex = 0; + Event_Wait(&p->canStart); + Event_Set(&p->wasStarted); + for (;;) + { + if (p->exit) + return; + if (p->stopWriting) + { + p->numProcessedBlocks = blockIndex; + MtSync_StopWriting(&mt->hashSync); + Event_Set(&p->wasStopped); + break; + } + Semaphore_Wait(&p->freeSemaphore); + BtFillBlock(mt, blockIndex++); + Semaphore_Release1(&p->filledSemaphore); + } + } +} + +void MatchFinderMt_Construct(CMatchFinderMt *p) +{ + p->hashBuf = NULL; + MtSync_Construct(&p->hashSync); + MtSync_Construct(&p->btSync); +} + +static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->hashBuf); + p->hashBuf = NULL; +} + +void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc) +{ + MtSync_Destruct(&p->hashSync); + MtSync_Destruct(&p->btSync); + MatchFinderMt_FreeMem(p, alloc); +} + +#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) +#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p) +{ + Byte allocaDummy[0x180]; + unsigned i = 0; + for (i = 0; i < 16; i++) + allocaDummy[i] = (Byte)0; + if (allocaDummy[0] == 0) + BtThreadFunc((CMatchFinderMt *)p); + return 0; +} + +SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc) +{ + CMatchFinder *mf = p->MatchFinder; + p->historySize = historySize; + if (kMtBtBlockSize <= matchMaxLen * 4) + return SZ_ERROR_PARAM; + if (!p->hashBuf) + { + p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32)); + if (!p->hashBuf) + return SZ_ERROR_MEM; + p->btBuf = p->hashBuf + kHashBufferSize; + } + keepAddBufferBefore += (kHashBufferSize + kBtBufferSize); + keepAddBufferAfter += kMtHashBlockSize; + if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc)) + return SZ_ERROR_MEM; + + RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks)); + RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks)); + return SZ_OK; +} + +/* Call it after ReleaseStream / SetStream */ +static void MatchFinderMt_Init(CMatchFinderMt *p) +{ + CMatchFinder *mf = p->MatchFinder; + + p->btBufPos = + p->btBufPosLimit = 0; + p->hashBufPos = + p->hashBufPosLimit = 0; + + /* Init without data reading. We don't want to read data in this thread */ + MatchFinder_Init_3(mf, False); + MatchFinder_Init_LowHash(mf); + + p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf); + p->btNumAvailBytes = 0; + p->lzPos = p->historySize + 1; + + p->hash = mf->hash; + p->fixedHashSize = mf->fixedHashSize; + p->crc = mf->crc; + + p->son = mf->son; + p->matchMaxLen = mf->matchMaxLen; + p->numHashBytes = mf->numHashBytes; + p->pos = mf->pos; + p->buffer = mf->buffer; + p->cyclicBufferPos = mf->cyclicBufferPos; + p->cyclicBufferSize = mf->cyclicBufferSize; + p->cutValue = mf->cutValue; +} + +/* ReleaseStream is required to finish multithreading */ +void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) +{ + MtSync_StopWriting(&p->btSync); + /* p->MatchFinder->ReleaseStream(); */ +} + +static void MatchFinderMt_Normalize(CMatchFinderMt *p) +{ + MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize); + p->lzPos = p->historySize + 1; +} + +static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) +{ + UInt32 blockIndex; + MtSync_GetNextBlock(&p->btSync); + blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask); + p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize; + p->btBufPosLimit += p->btBuf[p->btBufPos++]; + p->btNumAvailBytes = p->btBuf[p->btBufPos++]; + if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize) + MatchFinderMt_Normalize(p); +} + +static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) +{ + return p->pointerToCurPos; +} + +#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); + +static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) +{ + GET_NEXT_BLOCK_IF_REQUIRED; + return p->btNumAvailBytes; +} + +static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 h2, curMatch2; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH2_CALC + + curMatch2 = hash[h2]; + hash[h2] = lzPos; + + if (curMatch2 >= matchMinPos) + if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + *distances++ = 2; + *distances++ = lzPos - curMatch2 - 1; + } + + return distances; +} + +static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 h2, h3, curMatch2, curMatch3; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH3_CALC + + curMatch2 = hash[ h2]; + curMatch3 = (hash + kFix3HashSize)[h3]; + + hash[ h2] = lzPos; + (hash + kFix3HashSize)[h3] = lzPos; + + if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch2 - 1; + if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) + { + distances[0] = 3; + return distances + 2; + } + distances[0] = 2; + distances += 2; + } + + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) + { + *distances++ = 3; + *distances++ = lzPos - curMatch3 - 1; + } + + return distances; +} + +/* +static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH4_CALC + + curMatch2 = hash[ h2]; + curMatch3 = (hash + kFix3HashSize)[h3]; + curMatch4 = (hash + kFix4HashSize)[h4]; + + hash[ h2] = lzPos; + (hash + kFix3HashSize)[h3] = lzPos; + (hash + kFix4HashSize)[h4] = lzPos; + + if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch2 - 1; + if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) + { + distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; + return distances + 2; + } + distances[0] = 2; + distances += 2; + } + + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch3 - 1; + if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3]) + { + distances[0] = 4; + return distances + 2; + } + distances[0] = 3; + distances += 2; + } + + if (curMatch4 >= matchMinPos) + if ( + cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] && + cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3] + ) + { + *distances++ = 4; + *distances++ = lzPos - curMatch4 - 1; + } + + return distances; +} +*/ + +#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; + +static UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + const UInt32 *btBuf = p->btBuf + p->btBufPos; + UInt32 len = *btBuf++; + p->btBufPos += 1 + len; + p->btNumAvailBytes--; + { + UInt32 i; + for (i = 0; i < len; i += 2) + { + UInt32 v0 = btBuf[0]; + UInt32 v1 = btBuf[1]; + btBuf += 2; + distances[0] = v0; + distances[1] = v1; + distances += 2; + } + } + INCREASE_LZ_POS + return len; +} + +static UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + const UInt32 *btBuf = p->btBuf + p->btBufPos; + UInt32 len = *btBuf++; + p->btBufPos += 1 + len; + + if (len == 0) + { + /* change for bt5 ! */ + if (p->btNumAvailBytes-- >= 4) + len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances)); + } + else + { + /* Condition: there are matches in btBuf with length < p->numHashBytes */ + UInt32 *distances2; + p->btNumAvailBytes--; + distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances); + do + { + UInt32 v0 = btBuf[0]; + UInt32 v1 = btBuf[1]; + btBuf += 2; + distances2[0] = v0; + distances2[1] = v1; + distances2 += 2; + } + while ((len -= 2) != 0); + len = (UInt32)(distances2 - (distances)); + } + INCREASE_LZ_POS + return len; +} + +#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED +#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; +#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0); + +static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER2_MT { p->btNumAvailBytes--; + SKIP_FOOTER_MT +} + +static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(2) + UInt32 h2; + MT_HASH2_CALC + hash[h2] = p->lzPos; + SKIP_FOOTER_MT +} + +static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(3) + UInt32 h2, h3; + MT_HASH3_CALC + (hash + kFix3HashSize)[h3] = + hash[ h2] = + p->lzPos; + SKIP_FOOTER_MT +} + +/* +static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(4) + UInt32 h2, h3, h4; + MT_HASH4_CALC + (hash + kFix4HashSize)[h4] = + (hash + kFix3HashSize)[h3] = + hash[ h2] = + p->lzPos; + SKIP_FOOTER_MT +} +*/ + +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; + vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; + + switch (p->MatchFinder->numHashBytes) + { + case 2: + p->GetHeadsFunc = GetHeads2; + p->MixMatchesFunc = (Mf_Mix_Matches)NULL; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip; + vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches; + break; + case 3: + p->GetHeadsFunc = GetHeads3; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip; + break; + default: + /* case 4: */ + p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; + break; + /* + default: + p->GetHeadsFunc = GetHeads5; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip; + break; + */ + } +} diff --git a/lzma/LzFindMt.h b/lzma/LzFindMt.h new file mode 100644 index 0000000..fdd1700 --- /dev/null +++ b/lzma/LzFindMt.h @@ -0,0 +1,101 @@ +/* LzFindMt.h -- multithreaded Match finder for LZ algorithms +2018-07-04 : Igor Pavlov : Public domain */ + +#ifndef __LZ_FIND_MT_H +#define __LZ_FIND_MT_H + +#include "LzFind.h" +#include "Threads.h" + +EXTERN_C_BEGIN + +#define kMtHashBlockSize (1 << 13) +#define kMtHashNumBlocks (1 << 3) +#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1) + +#define kMtBtBlockSize (1 << 14) +#define kMtBtNumBlocks (1 << 6) +#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1) + +typedef struct _CMtSync +{ + BoolInt wasCreated; + BoolInt needStart; + BoolInt exit; + BoolInt stopWriting; + + CThread thread; + CAutoResetEvent canStart; + CAutoResetEvent wasStarted; + CAutoResetEvent wasStopped; + CSemaphore freeSemaphore; + CSemaphore filledSemaphore; + BoolInt csWasInitialized; + BoolInt csWasEntered; + CCriticalSection cs; + UInt32 numProcessedBlocks; +} CMtSync; + +typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances); + +/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */ +#define kMtCacheLineDummy 128 + +typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos, + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc); + +typedef struct _CMatchFinderMt +{ + /* LZ */ + const Byte *pointerToCurPos; + UInt32 *btBuf; + UInt32 btBufPos; + UInt32 btBufPosLimit; + UInt32 lzPos; + UInt32 btNumAvailBytes; + + UInt32 *hash; + UInt32 fixedHashSize; + UInt32 historySize; + const UInt32 *crc; + + Mf_Mix_Matches MixMatchesFunc; + + /* LZ + BT */ + CMtSync btSync; + Byte btDummy[kMtCacheLineDummy]; + + /* BT */ + UInt32 *hashBuf; + UInt32 hashBufPos; + UInt32 hashBufPosLimit; + UInt32 hashNumAvail; + + CLzRef *son; + UInt32 matchMaxLen; + UInt32 numHashBytes; + UInt32 pos; + const Byte *buffer; + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be historySize + 1 */ + UInt32 cutValue; + + /* BT + Hash */ + CMtSync hashSync; + /* Byte hashDummy[kMtCacheLineDummy]; */ + + /* Hash */ + Mf_GetHeads GetHeadsFunc; + CMatchFinder *MatchFinder; +} CMatchFinderMt; + +void MatchFinderMt_Construct(CMatchFinderMt *p); +void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc); +SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc); +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable); +void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); + +EXTERN_C_END + +#endif diff --git a/lzma/LzHash.h b/lzma/LzHash.h new file mode 100644 index 0000000..2191444 --- /dev/null +++ b/lzma/LzHash.h @@ -0,0 +1,57 @@ +/* LzHash.h -- HASH functions for LZ algorithms +2015-04-12 : Igor Pavlov : Public domain */ + +#ifndef __LZ_HASH_H +#define __LZ_HASH_H + +#define kHash2Size (1 << 10) +#define kHash3Size (1 << 16) +#define kHash4Size (1 << 20) + +#define kFix3HashSize (kHash2Size) +#define kFix4HashSize (kHash2Size + kHash3Size) +#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) + +#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8); + +#define HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + +#define HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; } + +#define HASH5_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + temp ^= (p->crc[cur[3]] << 5); \ + h4 = temp & (kHash4Size - 1); \ + hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; } + +/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ +#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; + + +#define MT_HASH2_CALC \ + h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); + +#define MT_HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + +#define MT_HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } + +#endif diff --git a/lzma/Lzma2Dec.c b/lzma/Lzma2Dec.c new file mode 100644 index 0000000..2e63105 --- /dev/null +++ b/lzma/Lzma2Dec.c @@ -0,0 +1,488 @@ +/* Lzma2Dec.c -- LZMA2 Decoder +2019-02-02 : Igor Pavlov : Public domain */ + +/* #define SHOW_DEBUG_INFO */ + +#include "Precomp.h" + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include + +#include "Lzma2Dec.h" + +/* +00000000 - End of data +00000001 U U - Uncompressed, reset dic, need reset state and set new prop +00000010 U U - Uncompressed, no reset +100uuuuu U U P P - LZMA, no reset +101uuuuu U U P P - LZMA, reset state +110uuuuu U U P P S - LZMA, reset state + set new prop +111uuuuu U U P P S - LZMA, reset state + set new prop, reset dic + + u, U - Unpack Size + P - Pack Size + S - Props +*/ + +#define LZMA2_CONTROL_COPY_RESET_DIC 1 + +#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & (1 << 7)) == 0) + +#define LZMA2_LCLP_MAX 4 +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +typedef enum +{ + LZMA2_STATE_CONTROL, + LZMA2_STATE_UNPACK0, + LZMA2_STATE_UNPACK1, + LZMA2_STATE_PACK0, + LZMA2_STATE_PACK1, + LZMA2_STATE_PROP, + LZMA2_STATE_DATA, + LZMA2_STATE_DATA_CONT, + LZMA2_STATE_FINISHED, + LZMA2_STATE_ERROR +} ELzma2State; + +static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) +{ + UInt32 dicSize; + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); + props[0] = (Byte)LZMA2_LCLP_MAX; + props[1] = (Byte)(dicSize); + props[2] = (Byte)(dicSize >> 8); + props[3] = (Byte)(dicSize >> 16); + props[4] = (Byte)(dicSize >> 24); + return SZ_OK; +} + +SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) +{ + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)); + return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); +} + +SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) +{ + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)); + return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); +} + +void Lzma2Dec_Init(CLzma2Dec *p) +{ + p->state = LZMA2_STATE_CONTROL; + p->needInitLevel = 0xE0; + p->isExtraMode = False; + p->unpackSize = 0; + + // p->decoder.dicPos = 0; // we can use it instead of full init + LzmaDec_Init(&p->decoder); +} + +static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) +{ + switch (p->state) + { + case LZMA2_STATE_CONTROL: + p->isExtraMode = False; + p->control = b; + PRF(printf("\n %8X", (unsigned)p->decoder.dicPos)); + PRF(printf(" %02X", (unsigned)b)); + if (b == 0) + return LZMA2_STATE_FINISHED; + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (b == LZMA2_CONTROL_COPY_RESET_DIC) + p->needInitLevel = 0xC0; + else if (b > 2 || p->needInitLevel == 0xE0) + return LZMA2_STATE_ERROR; + } + else + { + if (b < p->needInitLevel) + return LZMA2_STATE_ERROR; + p->needInitLevel = 0; + p->unpackSize = (UInt32)(b & 0x1F) << 16; + } + return LZMA2_STATE_UNPACK0; + + case LZMA2_STATE_UNPACK0: + p->unpackSize |= (UInt32)b << 8; + return LZMA2_STATE_UNPACK1; + + case LZMA2_STATE_UNPACK1: + p->unpackSize |= (UInt32)b; + p->unpackSize++; + PRF(printf(" %7u", (unsigned)p->unpackSize)); + return LZMA2_IS_UNCOMPRESSED_STATE(p) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; + + case LZMA2_STATE_PACK0: + p->packSize = (UInt32)b << 8; + return LZMA2_STATE_PACK1; + + case LZMA2_STATE_PACK1: + p->packSize |= (UInt32)b; + p->packSize++; + // if (p->packSize < 5) return LZMA2_STATE_ERROR; + PRF(printf(" %5u", (unsigned)p->packSize)); + return (p->control & 0x40) ? LZMA2_STATE_PROP : LZMA2_STATE_DATA; + + case LZMA2_STATE_PROP: + { + unsigned lc, lp; + if (b >= (9 * 5 * 5)) + return LZMA2_STATE_ERROR; + lc = b % 9; + b /= 9; + p->decoder.prop.pb = (Byte)(b / 5); + lp = b % 5; + if (lc + lp > LZMA2_LCLP_MAX) + return LZMA2_STATE_ERROR; + p->decoder.prop.lc = (Byte)lc; + p->decoder.prop.lp = (Byte)lp; + return LZMA2_STATE_DATA; + } + } + return LZMA2_STATE_ERROR; +} + +static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) +{ + memcpy(p->dic + p->dicPos, src, size); + p->dicPos += size; + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) + p->checkDicSize = p->prop.dicSize; + p->processedPos += (UInt32)size; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState); + + +SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->state != LZMA2_STATE_ERROR) + { + SizeT dicPos; + + if (p->state == LZMA2_STATE_FINISHED) + { + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + } + + dicPos = p->decoder.dicPos; + + if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) + { + if (*srcLen == inSize) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + (*srcLen)++; + p->state = Lzma2Dec_UpdateState(p, *src++); + if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) + break; + continue; + } + + { + SizeT inCur = inSize - *srcLen; + SizeT outCur = dicLimit - dicPos; + ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; + + if (outCur >= p->unpackSize) + { + outCur = (SizeT)p->unpackSize; + curFinishMode = LZMA_FINISH_END; + } + + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (inCur == 0) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + if (p->state == LZMA2_STATE_DATA) + { + BoolInt initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); + LzmaDec_InitDicAndState(&p->decoder, initDic, False); + } + + if (inCur > outCur) + inCur = outCur; + if (inCur == 0) + break; + + LzmaDec_UpdateWithUncompressed(&p->decoder, src, inCur); + + src += inCur; + *srcLen += inCur; + p->unpackSize -= (UInt32)inCur; + p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; + } + else + { + SRes res; + + if (p->state == LZMA2_STATE_DATA) + { + BoolInt initDic = (p->control >= 0xE0); + BoolInt initState = (p->control >= 0xA0); + LzmaDec_InitDicAndState(&p->decoder, initDic, initState); + p->state = LZMA2_STATE_DATA_CONT; + } + + if (inCur > p->packSize) + inCur = (SizeT)p->packSize; + + res = LzmaDec_DecodeToDic(&p->decoder, dicPos + outCur, src, &inCur, curFinishMode, status); + + src += inCur; + *srcLen += inCur; + p->packSize -= (UInt32)inCur; + outCur = p->decoder.dicPos - dicPos; + p->unpackSize -= (UInt32)outCur; + + if (res != 0) + break; + + if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (p->packSize == 0) + break; + return SZ_OK; + } + + if (inCur == 0 && outCur == 0) + { + if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + || p->unpackSize != 0 + || p->packSize != 0) + break; + p->state = LZMA2_STATE_CONTROL; + } + + *status = LZMA_STATUS_NOT_SPECIFIED; + } + } + } + + *status = LZMA_STATUS_NOT_SPECIFIED; + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; +} + + + + +ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, + SizeT outSize, + const Byte *src, SizeT *srcLen, + int checkFinishBlock) +{ + SizeT inSize = *srcLen; + *srcLen = 0; + + while (p->state != LZMA2_STATE_ERROR) + { + if (p->state == LZMA2_STATE_FINISHED) + return (ELzma2ParseStatus)LZMA_STATUS_FINISHED_WITH_MARK; + + if (outSize == 0 && !checkFinishBlock) + return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; + + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) + { + if (*srcLen == inSize) + return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; + (*srcLen)++; + + p->state = Lzma2Dec_UpdateState(p, *src++); + + if (p->state == LZMA2_STATE_UNPACK0) + { + // if (p->decoder.dicPos != 0) + if (p->control == LZMA2_CONTROL_COPY_RESET_DIC || p->control >= 0xE0) + return LZMA2_PARSE_STATUS_NEW_BLOCK; + // if (outSize == 0) return LZMA_STATUS_NOT_FINISHED; + } + + // The following code can be commented. + // It's not big problem, if we read additional input bytes. + // It will be stopped later in LZMA2_STATE_DATA / LZMA2_STATE_DATA_CONT state. + + if (outSize == 0 && p->state != LZMA2_STATE_FINISHED) + { + // checkFinishBlock is true. So we expect that block must be finished, + // We can return LZMA_STATUS_NOT_SPECIFIED or LZMA_STATUS_NOT_FINISHED here + // break; + return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; + } + + if (p->state == LZMA2_STATE_DATA) + return LZMA2_PARSE_STATUS_NEW_CHUNK; + + continue; + } + + if (outSize == 0) + return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; + + { + SizeT inCur = inSize - *srcLen; + + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (inCur == 0) + return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; + if (inCur > p->unpackSize) + inCur = p->unpackSize; + if (inCur > outSize) + inCur = outSize; + p->decoder.dicPos += inCur; + src += inCur; + *srcLen += inCur; + outSize -= inCur; + p->unpackSize -= (UInt32)inCur; + p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; + } + else + { + p->isExtraMode = True; + + if (inCur == 0) + { + if (p->packSize != 0) + return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; + } + else if (p->state == LZMA2_STATE_DATA) + { + p->state = LZMA2_STATE_DATA_CONT; + if (*src != 0) + { + // first byte of lzma chunk must be Zero + *srcLen += 1; + p->packSize--; + break; + } + } + + if (inCur > p->packSize) + inCur = (SizeT)p->packSize; + + src += inCur; + *srcLen += inCur; + p->packSize -= (UInt32)inCur; + + if (p->packSize == 0) + { + SizeT rem = outSize; + if (rem > p->unpackSize) + rem = p->unpackSize; + p->decoder.dicPos += rem; + p->unpackSize -= (UInt32)rem; + outSize -= rem; + if (p->unpackSize == 0) + p->state = LZMA2_STATE_CONTROL; + } + } + } + } + + p->state = LZMA2_STATE_ERROR; + return (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; +} + + + + +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen, inSize = *srcLen; + *srcLen = *destLen = 0; + + for (;;) + { + SizeT inCur = inSize, outCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + + if (p->decoder.dicPos == p->decoder.dicBufSize) + p->decoder.dicPos = 0; + dicPos = p->decoder.dicPos; + curFinishMode = LZMA_FINISH_ANY; + outCur = p->decoder.dicBufSize - dicPos; + + if (outCur >= outSize) + { + outCur = outSize; + curFinishMode = finishMode; + } + + res = Lzma2Dec_DecodeToDic(p, dicPos + outCur, src, &inCur, curFinishMode, status); + + src += inCur; + inSize -= inCur; + *srcLen += inCur; + outCur = p->decoder.dicPos - dicPos; + memcpy(dest, p->decoder.dic + dicPos, outCur); + dest += outCur; + outSize -= outCur; + *destLen += outCur; + if (res != 0) + return res; + if (outCur == 0 || outSize == 0) + return SZ_OK; + } +} + + +SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc) +{ + CLzma2Dec p; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + Lzma2Dec_Construct(&p); + RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)); + p.decoder.dic = dest; + p.decoder.dicBufSize = outSize; + Lzma2Dec_Init(&p); + *srcLen = inSize; + res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + *destLen = p.decoder.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + Lzma2Dec_FreeProbs(&p, alloc); + return res; +} diff --git a/lzma/Lzma2Dec.h b/lzma/Lzma2Dec.h new file mode 100644 index 0000000..da50387 --- /dev/null +++ b/lzma/Lzma2Dec.h @@ -0,0 +1,120 @@ +/* Lzma2Dec.h -- LZMA2 Decoder +2018-02-19 : Igor Pavlov : Public domain */ + +#ifndef __LZMA2_DEC_H +#define __LZMA2_DEC_H + +#include "LzmaDec.h" + +EXTERN_C_BEGIN + +/* ---------- State Interface ---------- */ + +typedef struct +{ + unsigned state; + Byte control; + Byte needInitLevel; + Byte isExtraMode; + Byte _pad_; + UInt32 packSize; + UInt32 unpackSize; + CLzmaDec decoder; +} CLzma2Dec; + +#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder) +#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc) +#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc) + +SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); +SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); +void Lzma2Dec_Init(CLzma2Dec *p); + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen or dicLimit). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + SZ_ERROR_DATA - Data error +*/ + +SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- LZMA2 block and chunk parsing ---------- */ + +/* +Lzma2Dec_Parse() parses compressed data stream up to next independent block or next chunk data. +It can return LZMA_STATUS_* code or LZMA2_PARSE_STATUS_* code: + - LZMA2_PARSE_STATUS_NEW_BLOCK - there is new block, and 1 additional byte (control byte of next block header) was read from input. + - LZMA2_PARSE_STATUS_NEW_CHUNK - there is new chunk, and only lzma2 header of new chunk was read. + CLzma2Dec::unpackSize contains unpack size of that chunk +*/ + +typedef enum +{ +/* + LZMA_STATUS_NOT_SPECIFIED // data error + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED // + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK // unused +*/ + LZMA2_PARSE_STATUS_NEW_BLOCK = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + 1, + LZMA2_PARSE_STATUS_NEW_CHUNK +} ELzma2ParseStatus; + +ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, + SizeT outSize, // output size + const Byte *src, SizeT *srcLen, + int checkFinishBlock // set (checkFinishBlock = 1), if it must read full input data, if decoder.dicPos reaches blockMax position. + ); + +/* +LZMA2 parser doesn't decode LZMA chunks, so we must read + full input LZMA chunk to decode some part of LZMA chunk. + +Lzma2Dec_GetUnpackExtra() returns the value that shows + max possible number of output bytes that can be output by decoder + at current input positon. +*/ + +#define Lzma2Dec_GetUnpackExtra(p) ((p)->isExtraMode ? (p)->unpackSize : 0); + + +/* ---------- One Call Interface ---------- */ + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc); + +EXTERN_C_END + +#endif diff --git a/lzma/Lzma2DecMt.c b/lzma/Lzma2DecMt.c new file mode 100644 index 0000000..87d5567 --- /dev/null +++ b/lzma/Lzma2DecMt.c @@ -0,0 +1,1082 @@ +/* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define PRF_STR(s) PRF(printf("\n" s "\n")) +#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) +#define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2)) + +// #define _7ZIP_ST + +#include "Alloc.h" + +#include "Lzma2Dec.h" +#include "Lzma2DecMt.h" + +#ifndef _7ZIP_ST +#include "MtDec.h" +#endif + + +#define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28) + +void Lzma2DecMtProps_Init(CLzma2DecMtProps *p) +{ + p->inBufSize_ST = 1 << 20; + p->outStep_ST = 1 << 20; + + #ifndef _7ZIP_ST + p->numThreads = 1; + p->inBufSize_MT = 1 << 18; + p->outBlockMax = LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT; + p->inBlockMax = p->outBlockMax + p->outBlockMax / 16; + #endif +} + + + +#ifndef _7ZIP_ST + +/* ---------- CLzma2DecMtThread ---------- */ + +typedef struct +{ + CLzma2Dec dec; + Byte dec_created; + Byte needInit; + + Byte *outBuf; + size_t outBufSize; + + EMtDecParseState state; + ELzma2ParseStatus parseStatus; + + size_t inPreSize; + size_t outPreSize; + + size_t inCodeSize; + size_t outCodeSize; + SRes codeRes; + + CAlignOffsetAlloc alloc; + + Byte mtPad[1 << 7]; +} CLzma2DecMtThread; + +#endif + + +/* ---------- CLzma2DecMt ---------- */ + +typedef struct +{ + // ISzAllocPtr alloc; + ISzAllocPtr allocMid; + + CAlignOffsetAlloc alignOffsetAlloc; + CLzma2DecMtProps props; + Byte prop; + + ISeqInStream *inStream; + ISeqOutStream *outStream; + ICompressProgress *progress; + + BoolInt finishMode; + BoolInt outSize_Defined; + UInt64 outSize; + + UInt64 outProcessed; + UInt64 inProcessed; + BoolInt readWasFinished; + SRes readRes; + + Byte *inBuf; + size_t inBufSize; + Byte dec_created; + CLzma2Dec dec; + + size_t inPos; + size_t inLim; + + #ifndef _7ZIP_ST + UInt64 outProcessed_Parse; + BoolInt mtc_WasConstructed; + CMtDec mtc; + CLzma2DecMtThread coders[MTDEC__THREADS_MAX]; + #endif + +} CLzma2DecMt; + + + +CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) +{ + CLzma2DecMt *p = (CLzma2DecMt *)ISzAlloc_Alloc(alloc, sizeof(CLzma2DecMt)); + if (!p) + return NULL; + + // p->alloc = alloc; + p->allocMid = allocMid; + + AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); + p->alignOffsetAlloc.numAlignBits = 7; + p->alignOffsetAlloc.offset = 0; + p->alignOffsetAlloc.baseAlloc = alloc; + + p->inBuf = NULL; + p->inBufSize = 0; + p->dec_created = False; + + // Lzma2DecMtProps_Init(&p->props); + + #ifndef _7ZIP_ST + p->mtc_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + t->dec_created = False; + t->outBuf = NULL; + t->outBufSize = 0; + } + } + #endif + + return p; +} + + +#ifndef _7ZIP_ST + +static void Lzma2DecMt_FreeOutBufs(CLzma2DecMt *p) +{ + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + if (t->outBuf) + { + ISzAlloc_Free(p->allocMid, t->outBuf); + t->outBuf = NULL; + t->outBufSize = 0; + } + } +} + +#endif + + +static void Lzma2DecMt_FreeSt(CLzma2DecMt *p) +{ + if (p->dec_created) + { + Lzma2Dec_Free(&p->dec, &p->alignOffsetAlloc.vt); + p->dec_created = False; + } + if (p->inBuf) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBuf = NULL; + } + p->inBufSize = 0; +} + + +void Lzma2DecMt_Destroy(CLzma2DecMtHandle pp) +{ + CLzma2DecMt *p = (CLzma2DecMt *)pp; + + Lzma2DecMt_FreeSt(p); + + #ifndef _7ZIP_ST + + if (p->mtc_WasConstructed) + { + MtDec_Destruct(&p->mtc); + p->mtc_WasConstructed = False; + } + { + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + if (t->dec_created) + { + // we don't need to free dict here + Lzma2Dec_FreeProbs(&t->dec, &t->alloc.vt); // p->alloc !!! + t->dec_created = False; + } + } + } + Lzma2DecMt_FreeOutBufs(p); + + #endif + + ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp); +} + + + +#ifndef _7ZIP_ST + +static void Lzma2DecMt_MtCallback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) +{ + CLzma2DecMt *me = (CLzma2DecMt *)obj; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + + PRF_STR_INT_2("Parse", coderIndex, cc->srcSize); + + cc->state = MTDEC_PARSE_CONTINUE; + + if (cc->startCall) + { + if (!t->dec_created) + { + Lzma2Dec_Construct(&t->dec); + t->dec_created = True; + AlignOffsetAlloc_CreateVTable(&t->alloc); + { + /* (1 << 12) is expected size of one way in data cache. + We optimize alignment for cache line size of 128 bytes and smaller */ + const unsigned kNumAlignBits = 12; + const unsigned kNumCacheLineBits = 7; /* <= kNumAlignBits */ + t->alloc.numAlignBits = kNumAlignBits; + t->alloc.offset = ((UInt32)coderIndex * ((1 << 11) + (1 << 8) + (1 << 6))) & ((1 << kNumAlignBits) - (1 << kNumCacheLineBits)); + t->alloc.baseAlloc = me->alignOffsetAlloc.baseAlloc; + } + } + Lzma2Dec_Init(&t->dec); + + t->inPreSize = 0; + t->outPreSize = 0; + // t->blockWasFinished = False; + // t->finishedWithMark = False; + t->parseStatus = (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; + t->state = MTDEC_PARSE_CONTINUE; + + t->inCodeSize = 0; + t->outCodeSize = 0; + t->codeRes = SZ_OK; + + // (cc->srcSize == 0) is allowed + } + + { + ELzma2ParseStatus status; + BoolInt overflow; + UInt32 unpackRem = 0; + + int checkFinishBlock = True; + size_t limit = me->props.outBlockMax; + if (me->outSize_Defined) + { + UInt64 rem = me->outSize - me->outProcessed_Parse; + if (limit >= rem) + { + limit = (size_t)rem; + if (!me->finishMode) + checkFinishBlock = False; + } + } + + // checkFinishBlock = False, if we want to decode partial data + // that must be finished at position <= outBlockMax. + + { + const SizeT srcOrig = cc->srcSize; + SizeT srcSize_Point = 0; + SizeT dicPos_Point = 0; + + cc->srcSize = 0; + overflow = False; + + for (;;) + { + SizeT srcCur = srcOrig - cc->srcSize; + + status = Lzma2Dec_Parse(&t->dec, + limit - t->dec.decoder.dicPos, + cc->src + cc->srcSize, &srcCur, + checkFinishBlock); + + cc->srcSize += srcCur; + + if (status == LZMA2_PARSE_STATUS_NEW_CHUNK) + { + if (t->dec.unpackSize > me->props.outBlockMax - t->dec.decoder.dicPos) + { + overflow = True; + break; + } + continue; + } + + if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) + { + if (t->dec.decoder.dicPos == 0) + continue; + // we decode small blocks in one thread + if (t->dec.decoder.dicPos >= (1 << 14)) + break; + dicPos_Point = t->dec.decoder.dicPos; + srcSize_Point = cc->srcSize; + continue; + } + + if ((int)status == LZMA_STATUS_NOT_FINISHED && checkFinishBlock + // && limit == t->dec.decoder.dicPos + // && limit == me->props.outBlockMax + ) + { + overflow = True; + break; + } + + unpackRem = Lzma2Dec_GetUnpackExtra(&t->dec); + break; + } + + if (dicPos_Point != 0 + && (int)status != LZMA2_PARSE_STATUS_NEW_BLOCK + && (int)status != LZMA_STATUS_FINISHED_WITH_MARK + && (int)status != LZMA_STATUS_NOT_SPECIFIED) + { + // we revert to latest newBlock state + status = LZMA2_PARSE_STATUS_NEW_BLOCK; + unpackRem = 0; + t->dec.decoder.dicPos = dicPos_Point; + cc->srcSize = srcSize_Point; + overflow = False; + } + } + + t->inPreSize += cc->srcSize; + t->parseStatus = status; + + if (overflow) + cc->state = MTDEC_PARSE_OVERFLOW; + else + { + size_t dicPos = t->dec.decoder.dicPos; + + if ((int)status != LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) + { + cc->state = MTDEC_PARSE_NEW; + cc->srcSize--; // we don't need control byte of next block + t->inPreSize--; + } + else + { + cc->state = MTDEC_PARSE_END; + if ((int)status != LZMA_STATUS_FINISHED_WITH_MARK) + { + // (status == LZMA_STATUS_NOT_SPECIFIED) + // (status == LZMA_STATUS_NOT_FINISHED) + if (unpackRem != 0) + { + /* we also reserve space for max possible number of output bytes of current LZMA chunk */ + SizeT rem = limit - dicPos; + if (rem > unpackRem) + rem = unpackRem; + dicPos += rem; + } + } + } + + me->outProcessed_Parse += dicPos; + } + + cc->outPos = dicPos; + t->outPreSize = (size_t)dicPos; + } + + t->state = cc->state; + return; + } +} + + +static SRes Lzma2DecMt_MtCallback_PreCode(void *pp, unsigned coderIndex) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + Byte *dest = t->outBuf; + + if (t->inPreSize == 0) + { + t->codeRes = SZ_ERROR_DATA; + return t->codeRes; + } + + if (!dest || t->outBufSize < t->outPreSize) + { + if (dest) + { + ISzAlloc_Free(me->allocMid, dest); + t->outBuf = NULL; + t->outBufSize = 0; + } + + dest = (Byte *)ISzAlloc_Alloc(me->allocMid, t->outPreSize + // + (1 << 28) + ); + // Sleep(200); + if (!dest) + return SZ_ERROR_MEM; + t->outBuf = dest; + t->outBufSize = t->outPreSize; + } + + t->dec.decoder.dic = dest; + t->dec.decoder.dicBufSize = t->outPreSize; + + t->needInit = True; + + return Lzma2Dec_AllocateProbs(&t->dec, me->prop, &t->alloc.vt); // alloc.vt +} + + +static SRes Lzma2DecMt_MtCallback_Code(void *pp, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + // int finished, int blockFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + + UNUSED_VAR(srcFinished) + + PRF_STR_INT_2("Code", coderIndex, srcSize); + + *inCodePos = t->inCodeSize; + *outCodePos = 0; + *stop = True; + + if (t->needInit) + { + Lzma2Dec_Init(&t->dec); + t->needInit = False; + } + + { + ELzmaStatus status; + size_t srcProcessed = srcSize; + BoolInt blockWasFinished = + ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK); + + SRes res = Lzma2Dec_DecodeToDic(&t->dec, + t->outPreSize, + src, &srcProcessed, + blockWasFinished ? LZMA_FINISH_END : LZMA_FINISH_ANY, + &status); + + t->codeRes = res; + + t->inCodeSize += srcProcessed; + *inCodePos = t->inCodeSize; + t->outCodeSize = t->dec.decoder.dicPos; + *outCodePos = t->dec.decoder.dicPos; + + if (res != SZ_OK) + return res; + + if (srcProcessed == srcSize) + *stop = False; + + if (blockWasFinished) + { + if (srcSize != srcProcessed) + return SZ_ERROR_FAIL; + + if (t->inPreSize == t->inCodeSize) + { + if (t->outPreSize != t->outCodeSize) + return SZ_ERROR_FAIL; + *stop = True; + } + } + else + { + if (t->outPreSize == t->outCodeSize) + *stop = True; + } + + return SZ_OK; + } +} + + +#define LZMA2DECMT_STREAM_WRITE_STEP (1 << 24) + +static SRes Lzma2DecMt_MtCallback_Write(void *pp, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, + BoolInt *needContinue, BoolInt *canRecode) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + const CLzma2DecMtThread *t = &me->coders[coderIndex]; + size_t size = t->outCodeSize; + const Byte *data = t->outBuf; + BoolInt needContinue2 = True; + + PRF_STR_INT_2("Write", coderIndex, srcSize); + + *needContinue = False; + *canRecode = True; + UNUSED_VAR(src) + UNUSED_VAR(srcSize) + + if ( + // t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + t->state == MTDEC_PARSE_OVERFLOW + || t->state == MTDEC_PARSE_END) + needContinue2 = False; + + + if (!needWriteToStream) + return SZ_OK; + + me->mtc.inProcessed += t->inCodeSize; + + if (t->codeRes == SZ_OK) + if ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK) + if (t->outPreSize != t->outCodeSize + || t->inPreSize != t->inCodeSize) + return SZ_ERROR_FAIL; + + *canRecode = False; + + if (me->outStream) + { + for (;;) + { + size_t cur = size; + size_t written; + if (cur > LZMA2DECMT_STREAM_WRITE_STEP) + cur = LZMA2DECMT_STREAM_WRITE_STEP; + + written = ISeqOutStream_Write(me->outStream, data, cur); + + me->outProcessed += written; + // me->mtc.writtenTotal += written; + if (written != cur) + return SZ_ERROR_WRITE; + data += cur; + size -= cur; + if (size == 0) + { + *needContinue = needContinue2; + return SZ_OK; + } + RINOK(MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0)); + } + } + + return SZ_ERROR_FAIL; + /* + if (size > me->outBufSize) + return SZ_ERROR_OUTPUT_EOF; + memcpy(me->outBuf, data, size); + me->outBufSize -= size; + me->outBuf += size; + *needContinue = needContinue2; + return SZ_OK; + */ +} + +#endif + + +static SRes Lzma2Dec_Prepare_ST(CLzma2DecMt *p) +{ + if (!p->dec_created) + { + Lzma2Dec_Construct(&p->dec); + p->dec_created = True; + } + + RINOK(Lzma2Dec_Allocate(&p->dec, p->prop, &p->alignOffsetAlloc.vt)); + + if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBufSize = 0; + p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); + if (!p->inBuf) + return SZ_ERROR_MEM; + p->inBufSize = p->props.inBufSize_ST; + } + + Lzma2Dec_Init(&p->dec); + + return SZ_OK; +} + + +static SRes Lzma2Dec_Decode_ST(CLzma2DecMt *p + #ifndef _7ZIP_ST + , BoolInt tMode + #endif + ) +{ + SizeT wrPos; + size_t inPos, inLim; + const Byte *inData; + UInt64 inPrev, outPrev; + + CLzma2Dec *dec; + + #ifndef _7ZIP_ST + if (tMode) + { + Lzma2DecMt_FreeOutBufs(p); + tMode = MtDec_PrepareRead(&p->mtc); + } + #endif + + RINOK(Lzma2Dec_Prepare_ST(p)); + + dec = &p->dec; + + inPrev = p->inProcessed; + outPrev = p->outProcessed; + + inPos = 0; + inLim = 0; + inData = NULL; + wrPos = dec->decoder.dicPos; + + for (;;) + { + SizeT dicPos; + SizeT size; + ELzmaFinishMode finishMode; + SizeT inProcessed; + ELzmaStatus status; + SRes res; + + SizeT outProcessed; + BoolInt outFinished; + BoolInt needStop; + + if (inPos == inLim) + { + #ifndef _7ZIP_ST + if (tMode) + { + inData = MtDec_Read(&p->mtc, &inLim); + inPos = 0; + if (inData) + continue; + tMode = False; + inLim = 0; + } + #endif + + if (!p->readWasFinished) + { + inPos = 0; + inLim = p->inBufSize; + inData = p->inBuf; + p->readRes = ISeqInStream_Read(p->inStream, (void *)inData, &inLim); + // p->readProcessed += inLim; + // inLim -= 5; p->readWasFinished = True; // for test + if (inLim == 0 || p->readRes != SZ_OK) + p->readWasFinished = True; + } + } + + dicPos = dec->decoder.dicPos; + { + SizeT next = dec->decoder.dicBufSize; + if (next - wrPos > p->props.outStep_ST) + next = wrPos + p->props.outStep_ST; + size = next - dicPos; + } + + finishMode = LZMA_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (size >= rem) + { + size = (SizeT)rem; + if (p->finishMode) + finishMode = LZMA_FINISH_END; + } + } + + inProcessed = inLim - inPos; + + res = Lzma2Dec_DecodeToDic(dec, dicPos + size, inData + inPos, &inProcessed, finishMode, &status); + + inPos += inProcessed; + p->inProcessed += inProcessed; + outProcessed = dec->decoder.dicPos - dicPos; + p->outProcessed += outProcessed; + + outFinished = (p->outSize_Defined && p->outSize <= p->outProcessed); + + needStop = (res != SZ_OK + || (inProcessed == 0 && outProcessed == 0) + || status == LZMA_STATUS_FINISHED_WITH_MARK + || (!p->finishMode && outFinished)); + + if (needStop || outProcessed >= size) + { + SRes res2; + { + size_t writeSize = dec->decoder.dicPos - wrPos; + size_t written = ISeqOutStream_Write(p->outStream, dec->decoder.dic + wrPos, writeSize); + res2 = (written == writeSize) ? SZ_OK : SZ_ERROR_WRITE; + } + + if (dec->decoder.dicPos == dec->decoder.dicBufSize) + dec->decoder.dicPos = 0; + wrPos = dec->decoder.dicPos; + + RINOK(res2); + + if (needStop) + { + if (res != SZ_OK) + return res; + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (p->finishMode) + { + if (p->outSize_Defined && p->outSize != p->outProcessed) + return SZ_ERROR_DATA; + } + return SZ_OK; + } + + if (!p->finishMode && outFinished) + return SZ_OK; + + if (status == LZMA_STATUS_NEEDS_MORE_INPUT) + return SZ_ERROR_INPUT_EOF; + + return SZ_ERROR_DATA; + } + } + + if (p->progress) + { + UInt64 inDelta = p->inProcessed - inPrev; + UInt64 outDelta = p->outProcessed - outPrev; + if (inDelta >= (1 << 22) || outDelta >= (1 << 22)) + { + RINOK(ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed)); + inPrev = p->inProcessed; + outPrev = p->outProcessed; + } + } + } +} + + + +SRes Lzma2DecMt_Decode(CLzma2DecMtHandle pp, + Byte prop, + const CLzma2DecMtProps *props, + ISeqOutStream *outStream, const UInt64 *outDataSize, int finishMode, + // Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + // const Byte *inData, size_t inDataSize, + UInt64 *inProcessed, + // UInt64 *outProcessed, + int *isMT, + ICompressProgress *progress) +{ + CLzma2DecMt *p = (CLzma2DecMt *)pp; + #ifndef _7ZIP_ST + BoolInt tMode; + #endif + + *inProcessed = 0; + + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + + p->prop = prop; + p->props = *props; + + p->inStream = inStream; + p->outStream = outStream; + p->progress = progress; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + p->finishMode = finishMode; + + p->outProcessed = 0; + p->inProcessed = 0; + + p->readWasFinished = False; + + *isMT = False; + + + #ifndef _7ZIP_ST + + tMode = False; + + // p->mtc.parseRes = SZ_OK; + + // p->mtc.numFilledThreads = 0; + // p->mtc.crossStart = 0; + // p->mtc.crossEnd = 0; + // p->mtc.allocError_for_Read_BlockIndex = 0; + // p->mtc.isAllocError = False; + + if (p->props.numThreads > 1) + { + IMtDecCallback vt; + + Lzma2DecMt_FreeSt(p); + + p->outProcessed_Parse = 0; + + if (!p->mtc_WasConstructed) + { + p->mtc_WasConstructed = True; + MtDec_Construct(&p->mtc); + } + + p->mtc.progress = progress; + p->mtc.inStream = inStream; + + // p->outBuf = NULL; + // p->outBufSize = 0; + /* + if (!outStream) + { + // p->outBuf = outBuf; + // p->outBufSize = *outBufSize; + // *outBufSize = 0; + return SZ_ERROR_PARAM; + } + */ + + // p->mtc.inBlockMax = p->props.inBlockMax; + p->mtc.alloc = &p->alignOffsetAlloc.vt; + // p->alignOffsetAlloc.baseAlloc; + // p->mtc.inData = inData; + // p->mtc.inDataSize = inDataSize; + p->mtc.mtCallback = &vt; + p->mtc.mtCallbackObject = p; + + p->mtc.inBufSize = p->props.inBufSize_MT; + + p->mtc.numThreadsMax = p->props.numThreads; + + *isMT = True; + + vt.Parse = Lzma2DecMt_MtCallback_Parse; + vt.PreCode = Lzma2DecMt_MtCallback_PreCode; + vt.Code = Lzma2DecMt_MtCallback_Code; + vt.Write = Lzma2DecMt_MtCallback_Write; + + { + BoolInt needContinue = False; + + SRes res = MtDec_Code(&p->mtc); + + /* + if (!outStream) + *outBufSize = p->outBuf - outBuf; + */ + + *inProcessed = p->mtc.inProcessed; + + needContinue = False; + + if (res == SZ_OK) + { + if (p->mtc.mtProgress.res != SZ_OK) + res = p->mtc.mtProgress.res; + else + needContinue = p->mtc.needContinue; + } + + if (!needContinue) + { + if (res == SZ_OK) + return p->mtc.readRes; + return res; + } + + tMode = True; + p->readRes = p->mtc.readRes; + p->readWasFinished = p->mtc.readWasFinished; + p->inProcessed = p->mtc.inProcessed; + + PRF_STR("----- decoding ST -----"); + } + } + + #endif + + + *isMT = False; + + { + SRes res = Lzma2Dec_Decode_ST(p + #ifndef _7ZIP_ST + , tMode + #endif + ); + + *inProcessed = p->inProcessed; + + // res = SZ_OK; // for test + if (res == SZ_OK && p->readRes != SZ_OK) + res = p->readRes; + + /* + #ifndef _7ZIP_ST + if (res == SZ_OK && tMode && p->mtc.parseRes != SZ_OK) + res = p->mtc.parseRes; + #endif + */ + + return res; + } +} + + +/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ + +SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp, + Byte prop, + const CLzma2DecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqInStream *inStream) +{ + CLzma2DecMt *p = (CLzma2DecMt *)pp; + + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + + p->prop = prop; + p->props = *props; + + p->inStream = inStream; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + p->finishMode = finishMode; + + p->outProcessed = 0; + p->inProcessed = 0; + + p->inPos = 0; + p->inLim = 0; + + return Lzma2Dec_Prepare_ST(p); +} + + +SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp, + Byte *data, size_t *outSize, + UInt64 *inStreamProcessed) +{ + CLzma2DecMt *p = (CLzma2DecMt *)pp; + ELzmaFinishMode finishMode; + SRes readRes; + size_t size = *outSize; + + *outSize = 0; + *inStreamProcessed = 0; + + finishMode = LZMA_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (size >= rem) + { + size = (size_t)rem; + if (p->finishMode) + finishMode = LZMA_FINISH_END; + } + } + + readRes = SZ_OK; + + for (;;) + { + SizeT inCur; + SizeT outCur; + ELzmaStatus status; + SRes res; + + if (p->inPos == p->inLim && readRes == SZ_OK) + { + p->inPos = 0; + p->inLim = p->props.inBufSize_ST; + readRes = ISeqInStream_Read(p->inStream, p->inBuf, &p->inLim); + } + + inCur = p->inLim - p->inPos; + outCur = size; + + res = Lzma2Dec_DecodeToBuf(&p->dec, data, &outCur, + p->inBuf + p->inPos, &inCur, finishMode, &status); + + p->inPos += inCur; + p->inProcessed += inCur; + *inStreamProcessed += inCur; + p->outProcessed += outCur; + *outSize += outCur; + size -= outCur; + data += outCur; + + if (res != 0) + return res; + + /* + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + return readRes; + + if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (p->finishMode && p->outSize_Defined && p->outProcessed >= p->outSize) + return SZ_ERROR_DATA; + return readRes; + } + */ + + if (inCur == 0 && outCur == 0) + return readRes; + } +} diff --git a/lzma/Lzma2DecMt.h b/lzma/Lzma2DecMt.h new file mode 100644 index 0000000..96f89a3 --- /dev/null +++ b/lzma/Lzma2DecMt.h @@ -0,0 +1,79 @@ +/* Lzma2DecMt.h -- LZMA2 Decoder Multi-thread +2018-02-17 : Igor Pavlov : Public domain */ + +#ifndef __LZMA2_DEC_MT_H +#define __LZMA2_DEC_MT_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +typedef struct +{ + size_t inBufSize_ST; + size_t outStep_ST; + + #ifndef _7ZIP_ST + unsigned numThreads; + size_t inBufSize_MT; + size_t outBlockMax; + size_t inBlockMax; + #endif +} CLzma2DecMtProps; + +/* init to single-thread mode */ +void Lzma2DecMtProps_Init(CLzma2DecMtProps *p); + + +/* ---------- CLzma2DecMtHandle Interface ---------- */ + +/* Lzma2DecMt_ * functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + // SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef void * CLzma2DecMtHandle; + +CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); +void Lzma2DecMt_Destroy(CLzma2DecMtHandle p); + +SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p, + Byte prop, + const CLzma2DecMtProps *props, + ISeqOutStream *outStream, + const UInt64 *outDataSize, // NULL means undefined + int finishMode, // 0 - partial unpacking is allowed, 1 - if lzma2 stream must be finished + // Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + // const Byte *inData, size_t inDataSize, + + // out variables: + UInt64 *inProcessed, + int *isMT, /* out: (*isMT == 0), if single thread decoding was used */ + + // UInt64 *outProcessed, + ICompressProgress *progress); + + +/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ + +SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp, + Byte prop, + const CLzma2DecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqInStream *inStream); + +SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp, + Byte *data, size_t *outSize, + UInt64 *inStreamProcessed); + + +EXTERN_C_END + +#endif diff --git a/lzma/Lzma2Enc.c b/lzma/Lzma2Enc.c new file mode 100644 index 0000000..d541477 --- /dev/null +++ b/lzma/Lzma2Enc.c @@ -0,0 +1,803 @@ +/* Lzma2Enc.c -- LZMA2 Encoder +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define _7ZIP_ST */ + +#include "Lzma2Enc.h" + +#ifndef _7ZIP_ST +#include "MtCoder.h" +#else +#define MTCODER__THREADS_MAX 1 +#endif + +#define LZMA2_CONTROL_LZMA (1 << 7) +#define LZMA2_CONTROL_COPY_NO_RESET 2 +#define LZMA2_CONTROL_COPY_RESET_DIC 1 +#define LZMA2_CONTROL_EOF 0 + +#define LZMA2_LCLP_MAX 4 + +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +#define LZMA2_PACK_SIZE_MAX (1 << 16) +#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX +#define LZMA2_UNPACK_SIZE_MAX (1 << 21) +#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX + +#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) + + +#define PRF(x) /* x */ + + +/* ---------- CLimitedSeqInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + ISeqInStream *realStream; + UInt64 limit; + UInt64 processed; + int finished; +} CLimitedSeqInStream; + +static void LimitedSeqInStream_Init(CLimitedSeqInStream *p) +{ + p->limit = (UInt64)(Int64)-1; + p->processed = 0; + p->finished = 0; +} + +static SRes LimitedSeqInStream_Read(const ISeqInStream *pp, void *data, size_t *size) +{ + CLimitedSeqInStream *p = CONTAINER_FROM_VTBL(pp, CLimitedSeqInStream, vt); + size_t size2 = *size; + SRes res = SZ_OK; + + if (p->limit != (UInt64)(Int64)-1) + { + UInt64 rem = p->limit - p->processed; + if (size2 > rem) + size2 = (size_t)rem; + } + if (size2 != 0) + { + res = ISeqInStream_Read(p->realStream, data, &size2); + p->finished = (size2 == 0 ? 1 : 0); + p->processed += size2; + } + *size = size2; + return res; +} + + +/* ---------- CLzma2EncInt ---------- */ + +typedef struct +{ + CLzmaEncHandle enc; + Byte propsAreSet; + Byte propsByte; + Byte needInitState; + Byte needInitProp; + UInt64 srcPos; +} CLzma2EncInt; + + +static SRes Lzma2EncInt_InitStream(CLzma2EncInt *p, const CLzma2EncProps *props) +{ + if (!p->propsAreSet) + { + SizeT propsSize = LZMA_PROPS_SIZE; + Byte propsEncoded[LZMA_PROPS_SIZE]; + RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)); + RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)); + p->propsByte = propsEncoded[0]; + p->propsAreSet = True; + } + return SZ_OK; +} + +static void Lzma2EncInt_InitBlock(CLzma2EncInt *p) +{ + p->srcPos = 0; + p->needInitState = True; + p->needInitProp = True; +} + + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp); +void LzmaEnc_Finish(CLzmaEncHandle pp); +void LzmaEnc_SaveState(CLzmaEncHandle pp); +void LzmaEnc_RestoreState(CLzmaEncHandle pp); + +/* +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp); +*/ + +static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, + size_t *packSizeRes, ISeqOutStream *outStream) +{ + size_t packSizeLimit = *packSizeRes; + size_t packSize = packSizeLimit; + UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; + unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); + BoolInt useCopyBlock; + SRes res; + + *packSizeRes = 0; + if (packSize < lzHeaderSize) + return SZ_ERROR_OUTPUT_EOF; + packSize -= lzHeaderSize; + + LzmaEnc_SaveState(p->enc); + res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, + outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); + + PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); + + if (unpackSize == 0) + return res; + + if (res == SZ_OK) + useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); + else + { + if (res != SZ_ERROR_OUTPUT_EOF) + return res; + res = SZ_OK; + useCopyBlock = True; + } + + if (useCopyBlock) + { + size_t destPos = 0; + PRF(printf("################# COPY ")); + + while (unpackSize > 0) + { + UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; + if (packSizeLimit - destPos < u + 3) + return SZ_ERROR_OUTPUT_EOF; + outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); + outBuf[destPos++] = (Byte)((u - 1) >> 8); + outBuf[destPos++] = (Byte)(u - 1); + memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); + unpackSize -= u; + destPos += u; + p->srcPos += u; + + if (outStream) + { + *packSizeRes += destPos; + if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) + return SZ_ERROR_WRITE; + destPos = 0; + } + else + *packSizeRes = destPos; + /* needInitState = True; */ + } + + LzmaEnc_RestoreState(p->enc); + return SZ_OK; + } + + { + size_t destPos = 0; + UInt32 u = unpackSize - 1; + UInt32 pm = (UInt32)(packSize - 1); + unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); + + PRF(printf(" ")); + + outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); + outBuf[destPos++] = (Byte)(u >> 8); + outBuf[destPos++] = (Byte)u; + outBuf[destPos++] = (Byte)(pm >> 8); + outBuf[destPos++] = (Byte)pm; + + if (p->needInitProp) + outBuf[destPos++] = p->propsByte; + + p->needInitProp = False; + p->needInitState = False; + destPos += packSize; + p->srcPos += unpackSize; + + if (outStream) + if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) + return SZ_ERROR_WRITE; + + *packSizeRes = destPos; + return SZ_OK; + } +} + + +/* ---------- Lzma2 Props ---------- */ + +void Lzma2EncProps_Init(CLzma2EncProps *p) +{ + LzmaEncProps_Init(&p->lzmaProps); + p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO; + p->numBlockThreads_Reduced = -1; + p->numBlockThreads_Max = -1; + p->numTotalThreads = -1; +} + +void Lzma2EncProps_Normalize(CLzma2EncProps *p) +{ + UInt64 fileSize; + int t1, t1n, t2, t2r, t3; + { + CLzmaEncProps lzmaProps = p->lzmaProps; + LzmaEncProps_Normalize(&lzmaProps); + t1n = lzmaProps.numThreads; + } + + t1 = p->lzmaProps.numThreads; + t2 = p->numBlockThreads_Max; + t3 = p->numTotalThreads; + + if (t2 > MTCODER__THREADS_MAX) + t2 = MTCODER__THREADS_MAX; + + if (t3 <= 0) + { + if (t2 <= 0) + t2 = 1; + t3 = t1n * t2; + } + else if (t2 <= 0) + { + t2 = t3 / t1n; + if (t2 == 0) + { + t1 = 1; + t2 = t3; + } + if (t2 > MTCODER__THREADS_MAX) + t2 = MTCODER__THREADS_MAX; + } + else if (t1 <= 0) + { + t1 = t3 / t2; + if (t1 == 0) + t1 = 1; + } + else + t3 = t1n * t2; + + p->lzmaProps.numThreads = t1; + + t2r = t2; + + fileSize = p->lzmaProps.reduceSize; + + if ( p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID + && p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO + && (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) + p->lzmaProps.reduceSize = p->blockSize; + + LzmaEncProps_Normalize(&p->lzmaProps); + + p->lzmaProps.reduceSize = fileSize; + + t1 = p->lzmaProps.numThreads; + + if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) + { + t2r = t2 = 1; + t3 = t1; + } + else if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO && t2 <= 1) + { + /* if there is no block multi-threading, we use SOLID block */ + p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; + } + else + { + if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) + { + const UInt32 kMinSize = (UInt32)1 << 20; + const UInt32 kMaxSize = (UInt32)1 << 28; + const UInt32 dictSize = p->lzmaProps.dictSize; + UInt64 blockSize = (UInt64)dictSize << 2; + if (blockSize < kMinSize) blockSize = kMinSize; + if (blockSize > kMaxSize) blockSize = kMaxSize; + if (blockSize < dictSize) blockSize = dictSize; + blockSize += (kMinSize - 1); + blockSize &= ~(UInt64)(kMinSize - 1); + p->blockSize = blockSize; + } + + if (t2 > 1 && fileSize != (UInt64)(Int64)-1) + { + UInt64 numBlocks = fileSize / p->blockSize; + if (numBlocks * p->blockSize != fileSize) + numBlocks++; + if (numBlocks < (unsigned)t2) + { + t2r = (unsigned)numBlocks; + if (t2r == 0) + t2r = 1; + t3 = t1 * t2r; + } + } + } + + p->numBlockThreads_Max = t2; + p->numBlockThreads_Reduced = t2r; + p->numTotalThreads = t3; +} + + +static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) +{ + return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; +} + + +/* ---------- Lzma2 ---------- */ + +typedef struct +{ + Byte propEncoded; + CLzma2EncProps props; + UInt64 expectedDataSize; + + Byte *tempBufLzma; + + ISzAllocPtr alloc; + ISzAllocPtr allocBig; + + CLzma2EncInt coders[MTCODER__THREADS_MAX]; + + #ifndef _7ZIP_ST + + ISeqOutStream *outStream; + Byte *outBuf; + size_t outBuf_Rem; /* remainder in outBuf */ + + size_t outBufSize; /* size of allocated outBufs[i] */ + size_t outBufsDataSizes[MTCODER__BLOCKS_MAX]; + BoolInt mtCoder_WasConstructed; + CMtCoder mtCoder; + Byte *outBufs[MTCODER__BLOCKS_MAX]; + + #endif + +} CLzma2Enc; + + + +CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc)); + if (!p) + return NULL; + Lzma2EncProps_Init(&p->props); + Lzma2EncProps_Normalize(&p->props); + p->expectedDataSize = (UInt64)(Int64)-1; + p->tempBufLzma = NULL; + p->alloc = alloc; + p->allocBig = allocBig; + { + unsigned i; + for (i = 0; i < MTCODER__THREADS_MAX; i++) + p->coders[i].enc = NULL; + } + + #ifndef _7ZIP_ST + p->mtCoder_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + p->outBufs[i] = NULL; + p->outBufSize = 0; + } + #endif + + return p; +} + + +#ifndef _7ZIP_ST + +static void Lzma2Enc_FreeOutBufs(CLzma2Enc *p) +{ + unsigned i; + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + if (p->outBufs[i]) + { + ISzAlloc_Free(p->alloc, p->outBufs[i]); + p->outBufs[i] = NULL; + } + p->outBufSize = 0; +} + +#endif + + +void Lzma2Enc_Destroy(CLzma2EncHandle pp) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + unsigned i; + for (i = 0; i < MTCODER__THREADS_MAX; i++) + { + CLzma2EncInt *t = &p->coders[i]; + if (t->enc) + { + LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); + t->enc = NULL; + } + } + + + #ifndef _7ZIP_ST + if (p->mtCoder_WasConstructed) + { + MtCoder_Destruct(&p->mtCoder); + p->mtCoder_WasConstructed = False; + } + Lzma2Enc_FreeOutBufs(p); + #endif + + ISzAlloc_Free(p->alloc, p->tempBufLzma); + p->tempBufLzma = NULL; + + ISzAlloc_Free(p->alloc, pp); +} + + +SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + CLzmaEncProps lzmaProps = props->lzmaProps; + LzmaEncProps_Normalize(&lzmaProps); + if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) + return SZ_ERROR_PARAM; + p->props = *props; + Lzma2EncProps_Normalize(&p->props); + return SZ_OK; +} + + +void Lzma2Enc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + p->expectedDataSize = expectedDataSiize; +} + + +Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + unsigned i; + UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); + for (i = 0; i < 40; i++) + if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) + break; + return (Byte)i; +} + + +static SRes Lzma2Enc_EncodeMt1( + CLzma2Enc *me, + CLzma2EncInt *p, + ISeqOutStream *outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + const Byte *inData, size_t inDataSize, + int finished, + ICompressProgress *progress) +{ + UInt64 unpackTotal = 0; + UInt64 packTotal = 0; + size_t outLim = 0; + CLimitedSeqInStream limitedInStream; + + if (outBuf) + { + outLim = *outBufSize; + *outBufSize = 0; + } + + if (!p->enc) + { + p->propsAreSet = False; + p->enc = LzmaEnc_Create(me->alloc); + if (!p->enc) + return SZ_ERROR_MEM; + } + + limitedInStream.realStream = inStream; + if (inStream) + { + limitedInStream.vt.Read = LimitedSeqInStream_Read; + } + + if (!outBuf) + { + // outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma + if (!me->tempBufLzma) + { + me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); + if (!me->tempBufLzma) + return SZ_ERROR_MEM; + } + } + + RINOK(Lzma2EncInt_InitStream(p, &me->props)); + + for (;;) + { + SRes res = SZ_OK; + size_t inSizeCur = 0; + + Lzma2EncInt_InitBlock(p); + + LimitedSeqInStream_Init(&limitedInStream); + limitedInStream.limit = me->props.blockSize; + + if (inStream) + { + UInt64 expected = (UInt64)(Int64)-1; + // inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize + if (me->expectedDataSize != (UInt64)(Int64)-1 + && me->expectedDataSize >= unpackTotal) + expected = me->expectedDataSize - unpackTotal; + if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID + && expected > me->props.blockSize) + expected = (size_t)me->props.blockSize; + + LzmaEnc_SetDataSize(p->enc, expected); + + RINOK(LzmaEnc_PrepareForLzma2(p->enc, + &limitedInStream.vt, + LZMA2_KEEP_WINDOW_SIZE, + me->alloc, + me->allocBig)); + } + else + { + inSizeCur = inDataSize - (size_t)unpackTotal; + if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID + && inSizeCur > me->props.blockSize) + inSizeCur = (size_t)me->props.blockSize; + + // LzmaEnc_SetDataSize(p->enc, inSizeCur); + + RINOK(LzmaEnc_MemPrepare(p->enc, + inData + (size_t)unpackTotal, inSizeCur, + LZMA2_KEEP_WINDOW_SIZE, + me->alloc, + me->allocBig)); + } + + for (;;) + { + size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; + if (outBuf) + packSize = outLim - (size_t)packTotal; + + res = Lzma2EncInt_EncodeSubblock(p, + outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize, + outBuf ? NULL : outStream); + + if (res != SZ_OK) + break; + + packTotal += packSize; + if (outBuf) + *outBufSize = (size_t)packTotal; + + res = Progress(progress, unpackTotal + p->srcPos, packTotal); + if (res != SZ_OK) + break; + + /* + if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0) + break; + */ + + if (packSize == 0) + break; + } + + LzmaEnc_Finish(p->enc); + + unpackTotal += p->srcPos; + + RINOK(res); + + if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur)) + return SZ_ERROR_FAIL; + + if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize)) + { + if (finished) + { + if (outBuf) + { + size_t destPos = *outBufSize; + if (destPos >= outLim) + return SZ_ERROR_OUTPUT_EOF; + outBuf[destPos] = 0; + *outBufSize = destPos + 1; + } + else + { + Byte b = 0; + if (ISeqOutStream_Write(outStream, &b, 1) != 1) + return SZ_ERROR_WRITE; + } + } + return SZ_OK; + } + } +} + + + +#ifndef _7ZIP_ST + +static SRes Lzma2Enc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished) +{ + CLzma2Enc *me = (CLzma2Enc *)pp; + size_t destSize = me->outBufSize; + SRes res; + CMtProgressThunk progressThunk; + + Byte *dest = me->outBufs[outBufIndex]; + + me->outBufsDataSizes[outBufIndex] = 0; + + if (!dest) + { + dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); + if (!dest) + return SZ_ERROR_MEM; + me->outBufs[outBufIndex] = dest; + } + + MtProgressThunk_CreateVTable(&progressThunk); + progressThunk.mtProgress = &me->mtCoder.mtProgress; + progressThunk.inSize = 0; + progressThunk.outSize = 0; + + res = Lzma2Enc_EncodeMt1(me, + &me->coders[coderIndex], + NULL, dest, &destSize, + NULL, src, srcSize, + finished, + &progressThunk.vt); + + me->outBufsDataSizes[outBufIndex] = destSize; + + return res; +} + + +static SRes Lzma2Enc_MtCallback_Write(void *pp, unsigned outBufIndex) +{ + CLzma2Enc *me = (CLzma2Enc *)pp; + size_t size = me->outBufsDataSizes[outBufIndex]; + const Byte *data = me->outBufs[outBufIndex]; + + if (me->outStream) + return ISeqOutStream_Write(me->outStream, data, size) == size ? SZ_OK : SZ_ERROR_WRITE; + + if (size > me->outBuf_Rem) + return SZ_ERROR_OUTPUT_EOF; + memcpy(me->outBuf, data, size); + me->outBuf_Rem -= size; + me->outBuf += size; + return SZ_OK; +} + +#endif + + + +SRes Lzma2Enc_Encode2(CLzma2EncHandle pp, + ISeqOutStream *outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + const Byte *inData, size_t inDataSize, + ICompressProgress *progress) +{ + CLzma2Enc *p = (CLzma2Enc *)pp; + + if (inStream && inData) + return SZ_ERROR_PARAM; + + if (outStream && outBuf) + return SZ_ERROR_PARAM; + + { + unsigned i; + for (i = 0; i < MTCODER__THREADS_MAX; i++) + p->coders[i].propsAreSet = False; + } + + #ifndef _7ZIP_ST + + if (p->props.numBlockThreads_Reduced > 1) + { + IMtCoderCallback2 vt; + + if (!p->mtCoder_WasConstructed) + { + p->mtCoder_WasConstructed = True; + MtCoder_Construct(&p->mtCoder); + } + + vt.Code = Lzma2Enc_MtCallback_Code; + vt.Write = Lzma2Enc_MtCallback_Write; + + p->outStream = outStream; + p->outBuf = NULL; + p->outBuf_Rem = 0; + if (!outStream) + { + p->outBuf = outBuf; + p->outBuf_Rem = *outBufSize; + *outBufSize = 0; + } + + p->mtCoder.allocBig = p->allocBig; + p->mtCoder.progress = progress; + p->mtCoder.inStream = inStream; + p->mtCoder.inData = inData; + p->mtCoder.inDataSize = inDataSize; + p->mtCoder.mtCallback = &vt; + p->mtCoder.mtCallbackObject = p; + + p->mtCoder.blockSize = (size_t)p->props.blockSize; + if (p->mtCoder.blockSize != p->props.blockSize) + return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ + + { + size_t destBlockSize = p->mtCoder.blockSize + (p->mtCoder.blockSize >> 10) + 16; + if (destBlockSize < p->mtCoder.blockSize) + return SZ_ERROR_PARAM; + if (p->outBufSize != destBlockSize) + Lzma2Enc_FreeOutBufs(p); + p->outBufSize = destBlockSize; + } + + p->mtCoder.numThreadsMax = p->props.numBlockThreads_Max; + p->mtCoder.expectedDataSize = p->expectedDataSize; + + { + SRes res = MtCoder_Code(&p->mtCoder); + if (!outStream) + *outBufSize = p->outBuf - outBuf; + return res; + } + } + + #endif + + + return Lzma2Enc_EncodeMt1(p, + &p->coders[0], + outStream, outBuf, outBufSize, + inStream, inData, inDataSize, + True, /* finished */ + progress); +} diff --git a/lzma/Lzma2Enc.h b/lzma/Lzma2Enc.h new file mode 100644 index 0000000..65f2dd1 --- /dev/null +++ b/lzma/Lzma2Enc.h @@ -0,0 +1,55 @@ +/* Lzma2Enc.h -- LZMA2 Encoder +2017-07-27 : Igor Pavlov : Public domain */ + +#ifndef __LZMA2_ENC_H +#define __LZMA2_ENC_H + +#include "LzmaEnc.h" + +EXTERN_C_BEGIN + +#define LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO 0 +#define LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID ((UInt64)(Int64)-1) + +typedef struct +{ + CLzmaEncProps lzmaProps; + UInt64 blockSize; + int numBlockThreads_Reduced; + int numBlockThreads_Max; + int numTotalThreads; +} CLzma2EncProps; + +void Lzma2EncProps_Init(CLzma2EncProps *p); +void Lzma2EncProps_Normalize(CLzma2EncProps *p); + +/* ---------- CLzmaEnc2Handle Interface ---------- */ + +/* Lzma2Enc_* functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef void * CLzma2EncHandle; + +CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); +void Lzma2Enc_Destroy(CLzma2EncHandle p); +SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props); +void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize); +Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p); +SRes Lzma2Enc_Encode2(CLzma2EncHandle p, + ISeqOutStream *outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + const Byte *inData, size_t inDataSize, + ICompressProgress *progress); + +EXTERN_C_END + +#endif diff --git a/lzma/Lzma86.h b/lzma/Lzma86.h new file mode 100644 index 0000000..83057e5 --- /dev/null +++ b/lzma/Lzma86.h @@ -0,0 +1,111 @@ +/* Lzma86.h -- LZMA + x86 (BCJ) Filter +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __LZMA86_H +#define __LZMA86_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define LZMA86_SIZE_OFFSET (1 + 5) +#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8) + +/* +It's an example for LZMA + x86 Filter use. +You can use .lzma86 extension, if you write that stream to file. +.lzma86 header adds one additional byte to standard .lzma header. +.lzma86 header (14 bytes): + Offset Size Description + 0 1 = 0 - no filter, pure LZMA + = 1 - x86 filter + LZMA + 1 1 lc, lp and pb in encoded form + 2 4 dictSize (little endian) + 6 8 uncompressed size (little endian) + + +Lzma86_Encode +------------- +level - compression level: 0 <= level <= 9, the default value for "level" is 5. + +dictSize - The dictionary size in bytes. The maximum value is + 128 MB = (1 << 27) bytes for 32-bit version + 1 GB = (1 << 30) bytes for 64-bit version + The default value is 16 MB = (1 << 24) bytes, for level = 5. + It's recommended to use the dictionary that is larger than 4 KB and + that can be calculated as (1 << N) or (3 << N) sizes. + For better compression ratio dictSize must be >= inSize. + +filterMode: + SZ_FILTER_NO - no Filter + SZ_FILTER_YES - x86 Filter + SZ_FILTER_AUTO - it tries both alternatives to select best. + Encoder will use 2 or 3 passes: + 2 passes when FILTER_NO provides better compression. + 3 passes when FILTER_YES provides better compression. + +Lzma86Encode allocates Data with MyAlloc functions. +RAM Requirements for compressing: + RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize + filterMode FilterBlockSize + SZ_FILTER_NO 0 + SZ_FILTER_YES inSize + SZ_FILTER_AUTO inSize + + +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +enum ESzFilterMode +{ + SZ_FILTER_NO, + SZ_FILTER_YES, + SZ_FILTER_AUTO +}; + +SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, + int level, UInt32 dictSize, int filterMode); + + +/* +Lzma86_GetUnpackSize: + In: + src - input data + srcLen - input data size + Out: + unpackSize - size of uncompressed stream + Return code: + SZ_OK - OK + SZ_ERROR_INPUT_EOF - Error in headers +*/ + +SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize); + +/* +Lzma86_Decode: + In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size + Out: + destLen - processed output size + srcLen - processed input size + Return code: + SZ_OK - OK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - unsupported file + SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer +*/ + +SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen); + +EXTERN_C_END + +#endif diff --git a/lzma/Lzma86Dec.c b/lzma/Lzma86Dec.c new file mode 100644 index 0000000..20ac5e7 --- /dev/null +++ b/lzma/Lzma86Dec.c @@ -0,0 +1,54 @@ +/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder +2016-05-16 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Lzma86.h" + +#include "Alloc.h" +#include "Bra.h" +#include "LzmaDec.h" + +SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize) +{ + unsigned i; + if (srcLen < LZMA86_HEADER_SIZE) + return SZ_ERROR_INPUT_EOF; + *unpackSize = 0; + for (i = 0; i < sizeof(UInt64); i++) + *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i); + return SZ_OK; +} + +SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) +{ + SRes res; + int useFilter; + SizeT inSizePure; + ELzmaStatus status; + + if (*srcLen < LZMA86_HEADER_SIZE) + return SZ_ERROR_INPUT_EOF; + + useFilter = src[0]; + + if (useFilter > 1) + { + *destLen = 0; + return SZ_ERROR_UNSUPPORTED; + } + + inSizePure = *srcLen - LZMA86_HEADER_SIZE; + res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure, + src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc); + *srcLen = inSizePure + LZMA86_HEADER_SIZE; + if (res != SZ_OK) + return res; + if (useFilter == 1) + { + UInt32 x86State; + x86_Convert_Init(x86State); + x86_Convert(dest, *destLen, 0, &x86State, 0); + } + return SZ_OK; +} diff --git a/lzma/Lzma86Enc.c b/lzma/Lzma86Enc.c new file mode 100644 index 0000000..8d35e6d --- /dev/null +++ b/lzma/Lzma86Enc.c @@ -0,0 +1,106 @@ +/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "Lzma86.h" + +#include "Alloc.h" +#include "Bra.h" +#include "LzmaEnc.h" + +#define SZE_OUT_OVERFLOW SZE_DATA_ERROR + +int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, + int level, UInt32 dictSize, int filterMode) +{ + size_t outSize2 = *destLen; + Byte *filteredStream; + BoolInt useFilter; + int mainResult = SZ_ERROR_OUTPUT_EOF; + CLzmaEncProps props; + LzmaEncProps_Init(&props); + props.level = level; + props.dictSize = dictSize; + + *destLen = 0; + if (outSize2 < LZMA86_HEADER_SIZE) + return SZ_ERROR_OUTPUT_EOF; + + { + int i; + UInt64 t = srcLen; + for (i = 0; i < 8; i++, t >>= 8) + dest[LZMA86_SIZE_OFFSET + i] = (Byte)t; + } + + filteredStream = 0; + useFilter = (filterMode != SZ_FILTER_NO); + if (useFilter) + { + if (srcLen != 0) + { + filteredStream = (Byte *)MyAlloc(srcLen); + if (filteredStream == 0) + return SZ_ERROR_MEM; + memcpy(filteredStream, src, srcLen); + } + { + UInt32 x86State; + x86_Convert_Init(x86State); + x86_Convert(filteredStream, srcLen, 0, &x86State, 1); + } + } + + { + size_t minSize = 0; + BoolInt bestIsFiltered = False; + + /* passes for SZ_FILTER_AUTO: + 0 - BCJ + LZMA + 1 - LZMA + 2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better. + */ + int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1; + + int i; + for (i = 0; i < numPasses; i++) + { + size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE; + size_t outPropsSize = 5; + SRes curRes; + BoolInt curModeIsFiltered = (numPasses > 1 && i == numPasses - 1); + if (curModeIsFiltered && !bestIsFiltered) + break; + if (useFilter && i == 0) + curModeIsFiltered = True; + + curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed, + curModeIsFiltered ? filteredStream : src, srcLen, + &props, dest + 1, &outPropsSize, 0, + NULL, &g_Alloc, &g_Alloc); + + if (curRes != SZ_ERROR_OUTPUT_EOF) + { + if (curRes != SZ_OK) + { + mainResult = curRes; + break; + } + if (outSizeProcessed <= minSize || mainResult != SZ_OK) + { + minSize = outSizeProcessed; + bestIsFiltered = curModeIsFiltered; + mainResult = SZ_OK; + } + } + } + dest[0] = (Byte)(bestIsFiltered ? 1 : 0); + *destLen = LZMA86_HEADER_SIZE + minSize; + } + if (useFilter) + MyFree(filteredStream); + return mainResult; +} diff --git a/lzma/LzmaDec.c b/lzma/LzmaDec.c new file mode 100644 index 0000000..4d15764 --- /dev/null +++ b/lzma/LzmaDec.c @@ -0,0 +1,1185 @@ +/* LzmaDec.c -- LZMA Decoder +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #include "CpuArch.h" */ +#include "LzmaDec.h" + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } + +#define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); } + +#define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \ + { UPDATE_0(p + i); A0; } else \ + { UPDATE_1(p + i); A1; } +#define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; ) +#define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; ) +#define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; ) + +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol) +#define MATCHED_LITER_DEC \ + matchByte += matchByte; \ + bit = offs; \ + offs &= matchByte; \ + probLit = prob + (offs + bit + symbol); \ + GET_BIT2(probLit, symbol, offs ^= bit; , ;) + + + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \ + { UPDATE_0_CHECK; i += m; m += m; } else \ + { UPDATE_1_CHECK; m += m; i += m; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenLow 0 +#define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + +#define LenChoice LenLow +#define LenChoice2 (LenLow + (1 << kLenNumLowBits)) + +#define kNumStates 12 +#define kNumStates2 16 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols) + +/* External ASM code needs same CLzmaProb array layout. So don't change it. */ + +/* (probs_1664) is faster and better for code size at some platforms */ +/* +#ifdef MY_CPU_X86_OR_AMD64 +*/ +#define kStartOffset 1664 +#define GET_PROBS p->probs_1664 +/* +#define GET_PROBS p->probs + kStartOffset +#else +#define kStartOffset 0 +#define GET_PROBS p->probs +#endif +*/ + +#define SpecPos (-kStartOffset) +#define IsRep0Long (SpecPos + kNumFullDistances) +#define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax)) +#define LenCoder (RepLenCoder + kNumLenProbs) +#define IsMatch (LenCoder + kNumLenProbs) +#define Align (IsMatch + (kNumStates2 << kNumPosBitsMax)) +#define IsRep (Align + kAlignTableSize) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define PosSlot (IsRepG2 + kNumStates) +#define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define NUM_BASE_PROBS (Literal + kStartOffset) + +#if Align != 0 && kStartOffset != 0 + #error Stop_Compiling_Bad_LZMA_kAlign +#endif + +#if NUM_BASE_PROBS != 1984 + #error Stop_Compiling_Bad_LZMA_PROBS +#endif + + +#define LZMA_LIT_SIZE 0x300 + +#define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + + +#define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4) +#define COMBINED_PS_STATE (posState + state) +#define GET_LEN_STATE (posState) + +#define LZMA_DIC_MIN (1 << 12) + +/* +p->remainLen : shows status of LZMA decoder: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : need init range coder + = kMatchSpecLenStart + 2 : need init range coder and state +*/ + +/* ---------- LZMA_DECODE_REAL ---------- */ +/* +LzmaDec_DecodeReal_3() can be implemented in external ASM file. +3 - is the code compatibility version of that function for check at link time. +*/ + +#define LZMA_DECODE_REAL LzmaDec_DecodeReal_3 + +/* +LZMA_DECODE_REAL() +In: + RangeCoder is normalized + if (p->dicPos == limit) + { + LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases. + So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol + is not END_OF_PAYALOAD_MARKER, then function returns error code. + } + +Processing: + first LZMA symbol will be decoded in any case + All checks for limits are at the end of main loop, + It will decode new LZMA-symbols while (p->buf < bufLimit && dicPos < limit), + RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked. + +Out: + RangeCoder is normalized + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished +*/ + + +#ifdef _LZMA_DEC_OPT + +int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit); + +#else + +static +int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = GET_PROBS; + unsigned state = (unsigned)p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lc = p->prop.lc; + unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc); + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = CALC_POS_STATE(processedPos, pbMask); + + prob = probs + IsMatch + COMBINED_PS_STATE; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (processedPos != 0 || checkDicSize != 0) + prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc); + processedPos++; + + if (state < kNumLitStates) + { + state -= (state < 4) ? state : 3; + symbol = 1; + #ifdef _LZMA_SIZE_OPT + do { NORMAL_LITER_DEC } while (symbol < 0x100); + #else + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + #endif + } + else + { + unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; + symbol = 1; + #ifdef _LZMA_SIZE_OPT + do + { + unsigned bit; + CLzmaProb *probLit; + MATCHED_LITER_DEC + } + while (symbol < 0x100); + #else + { + unsigned bit; + CLzmaProb *probLit; + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + } + #endif + } + + dic[dicPos++] = (Byte)symbol; + continue; + } + + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + /* + // that case was checked before with kBadRepCode + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + */ + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + COMBINED_PS_STATE; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + + #ifdef _LZMA_SIZE_OPT + { + unsigned lim, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + GET_LEN_STATE; + offset = 0; + lim = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); + offset = kLenNumLowSymbols; + lim = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols * 2; + lim = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, lim, len); + len += offset; + } + #else + { + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + GET_LEN_STATE; + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + len -= 8; + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + TREE_DECODE(probLen, (1 << kLenNumHighBits), len); + len += kLenNumLowSymbols * 2; + } + } + } + #endif + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos; + { + UInt32 m = 1; + distance++; + do + { + REV_BIT_VAR(prob, distance, m); + } + while (--numDirectBits); + distance -= m; + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + REV_BIT_CONST(prob, i, 1); + REV_BIT_CONST(prob, i, 2); + REV_BIT_CONST(prob, i, 4); + REV_BIT_LAST (prob, i, 8); + distance |= i; + } + if (distance == (UInt32)0xFFFFFFFF) + { + len = kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize)) + { + p->dicPos = dicPos; + return SZ_ERROR_DATA; + } + } + + len += kMatchMinLen; + + { + SizeT rem; + unsigned curLen; + SizeT pos; + + if ((rem = limit - dicPos) == 0) + { + p->dicPos = dicPos; + return SZ_ERROR_DATA; + } + + curLen = ((rem < len) ? (unsigned)rem : len); + pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); + + processedPos += (UInt32)curLen; + + len -= curLen; + if (curLen <= dicBufSize - pos) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += (SizeT)curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + + NORMALIZE; + + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = (UInt32)len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = (UInt32)state; + + return SZ_OK; +} +#endif + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = (unsigned)p->remainLen; + SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ + SizeT rem = limit - dicPos; + if (rem < len) + len = (unsigned)(rem); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += (UInt32)len; + p->remainLen -= (UInt32)len; + while (len != 0) + { + len--; + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + + +#define kRange0 0xFFFFFFFF +#define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)) +#define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))) +#if kBadRepCode != (0xC0000000 - 0x400) + #error Stop_Compiling_Bad_LZMA_Check +#endif + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + + if (p->processedPos == 0) + if (p->code >= kBadRepCode) + return SZ_ERROR_DATA; + } + + RINOK(LZMA_DECODE_REAL(p, limit2, bufLimit)); + + if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + const CLzmaProb *probs = GET_PROBS; + unsigned state = (unsigned)p->state; + ELzmaDummy res; + + { + const CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = CALC_POS_STATE(p->processedPos, (1 << p->prop.pb) - 1); + + prob = probs + IsMatch + COMBINED_PS_STATE; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += ((UInt32)LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + const CLzmaProb *probLit; + matchByte += matchByte; + bit = offs; + offs &= matchByte; + probLit = prob + (offs + bit + symbol); + GET_BIT2_CHECK(probLit, symbol, offs ^= bit; , ; ) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + COMBINED_PS_STATE; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + const CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + GET_LEN_STATE; + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols * 2; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + unsigned numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits); + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + unsigned m = 1; + do + { + REV_BIT_CHECK(prob, i, m); + } + while (--numDirectBits); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState) +{ + p->remainLen = kMatchSpecLenStart + 1; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->remainLen = kMatchSpecLenStart + 2; + } + if (initState) + p->remainLen = kMatchSpecLenStart + 2; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + + *status = LZMA_STATUS_NOT_SPECIFIED; + + if (p->remainLen > kMatchSpecLenStart) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize != 0 && p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + p->code = + ((UInt32)p->tempBuf[1] << 24) + | ((UInt32)p->tempBuf[2] << 16) + | ((UInt32)p->tempBuf[3] << 8) + | ((UInt32)p->tempBuf[4]); + p->range = 0xFFFFFFFF; + p->tempBufSize = 0; + + if (p->remainLen > kMatchSpecLenStart + 1) + { + SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); + SizeT i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + } + + p->remainLen = 0; + } + + LzmaDec_WriteRem(p, dicLimit); + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow = 0; + + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, (SizeT)rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += (SizeT)lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + + { + unsigned kkk = (unsigned)(p->buf - p->tempBuf); + if (rem < kkk) + return SZ_ERROR_FAIL; /* some internal error */ + rem -= kkk; + if (lookAhead < rem) + return SZ_ERROR_FAIL; /* some internal error */ + lookAhead -= rem; + } + (*srcLen) += (SizeT)lookAhead; + src += lookAhead; + inSize -= (SizeT)lookAhead; + p->tempBufSize = 0; + } + } + + if (p->code != 0) + return SZ_ERROR_DATA; + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return SZ_OK; +} + + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->probs); + p->probs = NULL; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->dic); + p->dic = NULL; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = (Byte)(d % 9); + d /= 9; + p->pb = (Byte)(d / 5); + p->lp = (Byte)(d % 5); + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (!p->probs || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb)); + if (!p->probs) + return SZ_ERROR_MEM; + p->probs_1664 = p->probs + 1664; + p->numProbs = numProbs; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + + { + UInt32 dictSize = propNew.dicSize; + SizeT mask = ((UInt32)1 << 12) - 1; + if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; + else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;; + dicBufSize = ((SizeT)dictSize + mask) & ~mask; + if (dicBufSize < dictSize) + dicBufSize = dictSize; + } + + if (!p->dic || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)ISzAlloc_Alloc(alloc, dicBufSize); + if (!p->dic) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAllocPtr alloc) +{ + CLzmaDec p; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + LzmaDec_Construct(&p); + RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); + p.dic = dest; + p.dicBufSize = outSize; + LzmaDec_Init(&p); + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + *destLen = p.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/lzma/LzmaDec.h b/lzma/LzmaDec.h new file mode 100644 index 0000000..28ce60c --- /dev/null +++ b/lzma/LzmaDec.h @@ -0,0 +1,234 @@ +/* LzmaDec.h -- LZMA Decoder +2018-04-21 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_DEC_H +#define __LZMA_DEC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* #define _LZMA_PROB32 */ +/* _LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +typedef +#ifdef _LZMA_PROB32 + UInt32 +#else + UInt16 +#endif + CLzmaProb; + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + Byte lc; + Byte lp; + Byte pb; + Byte _pad_; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + /* Don't change this structure. ASM code can use it. */ + CLzmaProps prop; + CLzmaProb *probs; + CLzmaProb *probs_1664; + Byte *dic; + SizeT dicBufSize; + SizeT dicPos; + const Byte *buf; + UInt32 range; + UInt32 code; + UInt32 processedPos; + UInt32 checkDicSize; + UInt32 reps[4]; + UInt32 state; + UInt32 remainLen; + + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_Construct(p) { (p)->dic = NULL; (p)->probs = NULL; } + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + - Stream with end mark. That end mark adds about 6 bytes to compressed size. + - Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc); + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); +void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Construct() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAllocPtr alloc); + +EXTERN_C_END + +#endif diff --git a/lzma/LzmaEnc.c b/lzma/LzmaEnc.c new file mode 100644 index 0000000..14086fc --- /dev/null +++ b/lzma/LzmaEnc.c @@ -0,0 +1,2976 @@ +/* LzmaEnc.c -- LZMA Encoder +2019-01-10: Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define SHOW_STAT */ +/* #define SHOW_STAT2 */ + +#if defined(SHOW_STAT) || defined(SHOW_STAT2) +#include +#endif + +#include "LzmaEnc.h" + +#include "LzFind.h" +#ifndef _7ZIP_ST +#include "LzFindMt.h" +#endif + +#ifdef SHOW_STAT +static unsigned g_STAT_OFFSET = 0; +#endif + +#define kLzmaMaxHistorySize ((UInt32)3 << 29) +/* #define kLzmaMaxHistorySize ((UInt32)7 << 29) */ + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 +#define kProbInitValue (kBitModelTotal >> 1) + +#define kNumMoveReducingBits 4 +#define kNumBitPriceShiftBits 4 +#define kBitPrice (1 << kNumBitPriceShiftBits) + +#define REP_LEN_COUNT 64 + +void LzmaEncProps_Init(CLzmaEncProps *p) +{ + p->level = 5; + p->dictSize = p->mc = 0; + p->reduceSize = (UInt64)(Int64)-1; + p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; + p->writeEndMark = 0; +} + +void LzmaEncProps_Normalize(CLzmaEncProps *p) +{ + int level = p->level; + if (level < 0) level = 5; + p->level = level; + + if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level <= 7 ? (1 << 25) : (1 << 26))); + if (p->dictSize > p->reduceSize) + { + unsigned i; + UInt32 reduceSize = (UInt32)p->reduceSize; + for (i = 11; i <= 30; i++) + { + if (reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; } + if (reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; } + } + } + + if (p->lc < 0) p->lc = 3; + if (p->lp < 0) p->lp = 0; + if (p->pb < 0) p->pb = 2; + + if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); + if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); + if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); + if (p->numHashBytes < 0) p->numHashBytes = 4; + if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + + if (p->numThreads < 0) + p->numThreads = + #ifndef _7ZIP_ST + ((p->btMode && p->algo) ? 2 : 1); + #else + 1; + #endif +} + +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) +{ + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + return props.dictSize; +} + +#if (_MSC_VER >= 1400) +/* BSR code is fast for some new CPUs */ +/* #define LZMA_LOG_BSR */ +#endif + +#ifdef LZMA_LOG_BSR + +#define kDicLogSizeMaxCompress 32 + +#define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); res = (zz + zz) + ((pos >> (zz - 1)) & 1); } + +static unsigned GetPosSlot1(UInt32 pos) +{ + unsigned res; + BSR2_RET(pos, res); + return res; +} +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } + +#else + +#define kNumLogBits (9 + sizeof(size_t) / 2) +/* #define kNumLogBits (11 + sizeof(size_t) / 8 * 3) */ + +#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +static void LzmaEnc_FastPosInit(Byte *g_FastPos) +{ + unsigned slot; + g_FastPos[0] = 0; + g_FastPos[1] = 1; + g_FastPos += 2; + + for (slot = 2; slot < kNumLogBits * 2; slot++) + { + size_t k = ((size_t)1 << ((slot >> 1) - 1)); + size_t j; + for (j = 0; j < k; j++) + g_FastPos[j] = (Byte)slot; + g_FastPos += k; + } +} + +/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */ +/* +#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ + res = p->g_FastPos[pos >> zz] + (zz * 2); } +*/ + +/* +#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \ + res = p->g_FastPos[pos >> zz] + (zz * 2); } +*/ + +#define BSR2_RET(pos, res) { unsigned zz = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \ + res = p->g_FastPos[pos >> zz] + (zz * 2); } + +/* +#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ + p->g_FastPos[pos >> 6] + 12 : \ + p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } +*/ + +#define GetPosSlot1(pos) p->g_FastPos[pos] +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos & (kNumFullDistances - 1)]; else BSR2_RET(pos, res); } + +#endif + + +#define LZMA_NUM_REPS 4 + +typedef UInt16 CState; +typedef UInt16 CExtra; + +typedef struct +{ + UInt32 price; + CState state; + CExtra extra; + // 0 : normal + // 1 : LIT : MATCH + // > 1 : MATCH (extra-1) : LIT : REP0 (len) + UInt32 len; + UInt32 dist; + UInt32 reps[LZMA_NUM_REPS]; +} COptimal; + + +// 18.06 +#define kNumOpts (1 << 11) +#define kPackReserve (kNumOpts * 8) +// #define kNumOpts (1 << 12) +// #define kPackReserve (1 + kNumOpts * 2) + +#define kNumLenToPosStates 4 +#define kNumPosSlotBits 6 +#define kDicLogSizeMin 0 +#define kDicLogSizeMax 32 +#define kDistTableSizeMax (kDicLogSizeMax * 2) + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) +#define kAlignMask (kAlignTableSize - 1) + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +typedef +#ifdef _LZMA_PROB32 + UInt32 +#else + UInt16 +#endif + CLzmaProb; + +#define LZMA_PB_MAX 4 +#define LZMA_LC_MAX 8 +#define LZMA_LP_MAX 4 + +#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) +#define kLenNumSymbolsTotal (kLenNumLowSymbols * 2 + kLenNumHighSymbols) + +#define LZMA_MATCH_LEN_MIN 2 +#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) + +#define kNumStates 12 + + +typedef struct +{ + CLzmaProb low[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)]; + CLzmaProb high[kLenNumHighSymbols]; +} CLenEnc; + + +typedef struct +{ + unsigned tableSize; + UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; + // UInt32 prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2]; + // UInt32 prices2[kLenNumSymbolsTotal]; +} CLenPriceEnc; + +#define GET_PRICE_LEN(p, posState, len) \ + ((p)->prices[posState][(size_t)(len) - LZMA_MATCH_LEN_MIN]) + +/* +#define GET_PRICE_LEN(p, posState, len) \ + ((p)->prices2[(size_t)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9))) +*/ + +typedef struct +{ + UInt32 range; + unsigned cache; + UInt64 low; + UInt64 cacheSize; + Byte *buf; + Byte *bufLim; + Byte *bufBase; + ISeqOutStream *outStream; + UInt64 processed; + SRes res; +} CRangeEnc; + + +typedef struct +{ + CLzmaProb *litProbs; + + unsigned state; + UInt32 reps[LZMA_NUM_REPS]; + + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances]; + + CLenEnc lenProbs; + CLenEnc repLenProbs; + +} CSaveState; + + +typedef UInt32 CProbPrice; + + +typedef struct +{ + void *matchFinderObj; + IMatchFinder matchFinder; + + unsigned optCur; + unsigned optEnd; + + unsigned longestMatchLen; + unsigned numPairs; + UInt32 numAvail; + + unsigned state; + unsigned numFastBytes; + unsigned additionalOffset; + UInt32 reps[LZMA_NUM_REPS]; + unsigned lpMask, pbMask; + CLzmaProb *litProbs; + CRangeEnc rc; + + UInt32 backRes; + + unsigned lc, lp, pb; + unsigned lclp; + + BoolInt fastMode; + BoolInt writeEndMark; + BoolInt finished; + BoolInt multiThread; + BoolInt needInit; + // BoolInt _maxMode; + + UInt64 nowPos64; + + unsigned matchPriceCount; + // unsigned alignPriceCount; + int repLenEncCounter; + + unsigned distTableSize; + + UInt32 dictSize; + SRes result; + + #ifndef _7ZIP_ST + BoolInt mtMode; + // begin of CMatchFinderMt is used in LZ thread + CMatchFinderMt matchFinderMt; + // end of CMatchFinderMt is used in BT and HASH threads + #endif + + CMatchFinder matchFinderBase; + + #ifndef _7ZIP_ST + Byte pad[128]; + #endif + + // LZ thread + CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; + + UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; + + UInt32 alignPrices[kAlignTableSize]; + UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; + UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; + + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances]; + + CLenEnc lenProbs; + CLenEnc repLenProbs; + + #ifndef LZMA_LOG_BSR + Byte g_FastPos[1 << kNumLogBits]; + #endif + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + COptimal opt[kNumOpts]; + + CSaveState saveState; + + #ifndef _7ZIP_ST + Byte pad2[128]; + #endif +} CLzmaEnc; + + + +#define COPY_ARR(dest, src, arr) memcpy(dest->arr, src->arr, sizeof(src->arr)); + +void LzmaEnc_SaveState(CLzmaEncHandle pp) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CSaveState *dest = &p->saveState; + + dest->state = p->state; + + dest->lenProbs = p->lenProbs; + dest->repLenProbs = p->repLenProbs; + + COPY_ARR(dest, p, reps); + + COPY_ARR(dest, p, posAlignEncoder); + COPY_ARR(dest, p, isRep); + COPY_ARR(dest, p, isRepG0); + COPY_ARR(dest, p, isRepG1); + COPY_ARR(dest, p, isRepG2); + COPY_ARR(dest, p, isMatch); + COPY_ARR(dest, p, isRep0Long); + COPY_ARR(dest, p, posSlotEncoder); + COPY_ARR(dest, p, posEncoders); + + memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb)); +} + + +void LzmaEnc_RestoreState(CLzmaEncHandle pp) +{ + CLzmaEnc *dest = (CLzmaEnc *)pp; + const CSaveState *p = &dest->saveState; + + dest->state = p->state; + + dest->lenProbs = p->lenProbs; + dest->repLenProbs = p->repLenProbs; + + COPY_ARR(dest, p, reps); + + COPY_ARR(dest, p, posAlignEncoder); + COPY_ARR(dest, p, isRep); + COPY_ARR(dest, p, isRepG0); + COPY_ARR(dest, p, isRepG1); + COPY_ARR(dest, p, isRepG2); + COPY_ARR(dest, p, isMatch); + COPY_ARR(dest, p, isRep0Long); + COPY_ARR(dest, p, posSlotEncoder); + COPY_ARR(dest, p, posEncoders); + + memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb)); +} + + + +SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + + if (props.lc > LZMA_LC_MAX + || props.lp > LZMA_LP_MAX + || props.pb > LZMA_PB_MAX + || props.dictSize > ((UInt64)1 << kDicLogSizeMaxCompress) + || props.dictSize > kLzmaMaxHistorySize) + return SZ_ERROR_PARAM; + + p->dictSize = props.dictSize; + { + unsigned fb = props.fb; + if (fb < 5) + fb = 5; + if (fb > LZMA_MATCH_LEN_MAX) + fb = LZMA_MATCH_LEN_MAX; + p->numFastBytes = fb; + } + p->lc = props.lc; + p->lp = props.lp; + p->pb = props.pb; + p->fastMode = (props.algo == 0); + // p->_maxMode = True; + p->matchFinderBase.btMode = (Byte)(props.btMode ? 1 : 0); + { + unsigned numHashBytes = 4; + if (props.btMode) + { + if (props.numHashBytes < 2) + numHashBytes = 2; + else if (props.numHashBytes < 4) + numHashBytes = props.numHashBytes; + } + p->matchFinderBase.numHashBytes = numHashBytes; + } + + p->matchFinderBase.cutValue = props.mc; + + p->writeEndMark = props.writeEndMark; + + #ifndef _7ZIP_ST + /* + if (newMultiThread != _multiThread) + { + ReleaseMatchFinder(); + _multiThread = newMultiThread; + } + */ + p->multiThread = (props.numThreads > 1); + #endif + + return SZ_OK; +} + + +void LzmaEnc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.expectedDataSize = expectedDataSiize; +} + + +#define kState_Start 0 +#define kState_LitAfterMatch 4 +#define kState_LitAfterRep 5 +#define kState_MatchAfterLit 7 +#define kState_RepAfterLit 8 + +static const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; +static const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; +static const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; +static const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + +#define IsLitState(s) ((s) < 7) +#define GetLenToPosState2(len) (((len) < kNumLenToPosStates - 1) ? (len) : kNumLenToPosStates - 1) +#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) + +#define kInfinityPrice (1 << 30) + +static void RangeEnc_Construct(CRangeEnc *p) +{ + p->outStream = NULL; + p->bufBase = NULL; +} + +#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) +#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + ((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize) + +#define RC_BUF_SIZE (1 << 16) + +static int RangeEnc_Alloc(CRangeEnc *p, ISzAllocPtr alloc) +{ + if (!p->bufBase) + { + p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE); + if (!p->bufBase) + return 0; + p->bufLim = p->bufBase + RC_BUF_SIZE; + } + return 1; +} + +static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->bufBase); + p->bufBase = 0; +} + +static void RangeEnc_Init(CRangeEnc *p) +{ + /* Stream.Init(); */ + p->range = 0xFFFFFFFF; + p->cache = 0; + p->low = 0; + p->cacheSize = 0; + + p->buf = p->bufBase; + + p->processed = 0; + p->res = SZ_OK; +} + +MY_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p) +{ + size_t num; + if (p->res != SZ_OK) + return; + num = p->buf - p->bufBase; + if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num)) + p->res = SZ_ERROR_WRITE; + p->processed += num; + p->buf = p->bufBase; +} + +MY_NO_INLINE static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) +{ + UInt32 low = (UInt32)p->low; + unsigned high = (unsigned)(p->low >> 32); + p->low = (UInt32)(low << 8); + if (low < (UInt32)0xFF000000 || high != 0) + { + { + Byte *buf = p->buf; + *buf++ = (Byte)(p->cache + high); + p->cache = (unsigned)(low >> 24); + p->buf = buf; + if (buf == p->bufLim) + RangeEnc_FlushStream(p); + if (p->cacheSize == 0) + return; + } + high += 0xFF; + for (;;) + { + Byte *buf = p->buf; + *buf++ = (Byte)(high); + p->buf = buf; + if (buf == p->bufLim) + RangeEnc_FlushStream(p); + if (--p->cacheSize == 0) + return; + } + } + p->cacheSize++; +} + +static void RangeEnc_FlushData(CRangeEnc *p) +{ + int i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + +#define RC_NORM(p) if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(p); } + +#define RC_BIT_PRE(p, prob) \ + ttt = *(prob); \ + newBound = (range >> kNumBitModelTotalBits) * ttt; + +// #define _LZMA_ENC_USE_BRANCH + +#ifdef _LZMA_ENC_USE_BRANCH + +#define RC_BIT(p, prob, bit) { \ + RC_BIT_PRE(p, prob) \ + if (bit == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } \ + else { (p)->low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; } \ + *(prob) = (CLzmaProb)ttt; \ + RC_NORM(p) \ + } + +#else + +#define RC_BIT(p, prob, bit) { \ + UInt32 mask; \ + RC_BIT_PRE(p, prob) \ + mask = 0 - (UInt32)bit; \ + range &= mask; \ + mask &= newBound; \ + range -= mask; \ + (p)->low += mask; \ + mask = (UInt32)bit - 1; \ + range += newBound & mask; \ + mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1)); \ + mask += ((1 << kNumMoveBits) - 1); \ + ttt += (Int32)(mask - ttt) >> kNumMoveBits; \ + *(prob) = (CLzmaProb)ttt; \ + RC_NORM(p) \ + } + +#endif + + + + +#define RC_BIT_0_BASE(p, prob) \ + range = newBound; *(prob) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); + +#define RC_BIT_1_BASE(p, prob) \ + range -= newBound; (p)->low += newBound; *(prob) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); \ + +#define RC_BIT_0(p, prob) \ + RC_BIT_0_BASE(p, prob) \ + RC_NORM(p) + +#define RC_BIT_1(p, prob) \ + RC_BIT_1_BASE(p, prob) \ + RC_NORM(p) + +static void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob) +{ + UInt32 range, ttt, newBound; + range = p->range; + RC_BIT_PRE(p, prob) + RC_BIT_0(p, prob) + p->range = range; +} + +static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 sym) +{ + UInt32 range = p->range; + sym |= 0x100; + do + { + UInt32 ttt, newBound; + // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1); + CLzmaProb *prob = probs + (sym >> 8); + UInt32 bit = (sym >> 7) & 1; + sym <<= 1; + RC_BIT(p, prob, bit); + } + while (sym < 0x10000); + p->range = range; +} + +static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 sym, UInt32 matchByte) +{ + UInt32 range = p->range; + UInt32 offs = 0x100; + sym |= 0x100; + do + { + UInt32 ttt, newBound; + CLzmaProb *prob; + UInt32 bit; + matchByte <<= 1; + // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1); + prob = probs + (offs + (matchByte & offs) + (sym >> 8)); + bit = (sym >> 7) & 1; + sym <<= 1; + offs &= ~(matchByte ^ sym); + RC_BIT(p, prob, bit); + } + while (sym < 0x10000); + p->range = range; +} + + + +static void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices) +{ + UInt32 i; + for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++) + { + const unsigned kCyclesBits = kNumBitPriceShiftBits; + UInt32 w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1)); + unsigned bitCount = 0; + unsigned j; + for (j = 0; j < kCyclesBits; j++) + { + w = w * w; + bitCount <<= 1; + while (w >= ((UInt32)1 << 16)) + { + w >>= 1; + bitCount++; + } + } + ProbPrices[i] = (CProbPrice)((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); + // printf("\n%3d: %5d", i, ProbPrices[i]); + } +} + + +#define GET_PRICE(prob, bit) \ + p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICEa(prob, bit) \ + ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +#define GET_PRICEa_0(prob) ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICEa_1(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + + +static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 sym, const CProbPrice *ProbPrices) +{ + UInt32 price = 0; + sym |= 0x100; + do + { + unsigned bit = sym & 1; + sym >>= 1; + price += GET_PRICEa(probs[sym], bit); + } + while (sym >= 2); + return price; +} + + +static UInt32 LitEnc_Matched_GetPrice(const CLzmaProb *probs, UInt32 sym, UInt32 matchByte, const CProbPrice *ProbPrices) +{ + UInt32 price = 0; + UInt32 offs = 0x100; + sym |= 0x100; + do + { + matchByte <<= 1; + price += GET_PRICEa(probs[offs + (matchByte & offs) + (sym >> 8)], (sym >> 7) & 1); + sym <<= 1; + offs &= ~(matchByte ^ sym); + } + while (sym < 0x10000); + return price; +} + + +static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, unsigned numBits, unsigned sym) +{ + UInt32 range = rc->range; + unsigned m = 1; + do + { + UInt32 ttt, newBound; + unsigned bit = sym & 1; + // RangeEnc_EncodeBit(rc, probs + m, bit); + sym >>= 1; + RC_BIT(rc, probs + m, bit); + m = (m << 1) | bit; + } + while (--numBits); + rc->range = range; +} + + + +static void LenEnc_Init(CLenEnc *p) +{ + unsigned i; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++) + p->low[i] = kProbInitValue; + for (i = 0; i < kLenNumHighSymbols; i++) + p->high[i] = kProbInitValue; +} + +static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posState) +{ + UInt32 range, ttt, newBound; + CLzmaProb *probs = p->low; + range = rc->range; + RC_BIT_PRE(rc, probs); + if (sym >= kLenNumLowSymbols) + { + RC_BIT_1(rc, probs); + probs += kLenNumLowSymbols; + RC_BIT_PRE(rc, probs); + if (sym >= kLenNumLowSymbols * 2) + { + RC_BIT_1(rc, probs); + rc->range = range; + // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2); + LitEnc_Encode(rc, p->high, sym - kLenNumLowSymbols * 2); + return; + } + sym -= kLenNumLowSymbols; + } + + // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym); + { + unsigned m; + unsigned bit; + RC_BIT_0(rc, probs); + probs += (posState << (1 + kLenNumLowBits)); + bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit); m = (1 << 1) + bit; + bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit); m = (m << 1) + bit; + bit = sym & 1; RC_BIT(rc, probs + m, bit); + rc->range = range; + } +} + +static void SetPrices_3(const CLzmaProb *probs, UInt32 startPrice, UInt32 *prices, const CProbPrice *ProbPrices) +{ + unsigned i; + for (i = 0; i < 8; i += 2) + { + UInt32 price = startPrice; + UInt32 prob; + price += GET_PRICEa(probs[1 ], (i >> 2)); + price += GET_PRICEa(probs[2 + (i >> 2)], (i >> 1) & 1); + prob = probs[4 + (i >> 1)]; + prices[i ] = price + GET_PRICEa_0(prob); + prices[i + 1] = price + GET_PRICEa_1(prob); + } +} + + +MY_NO_INLINE static void MY_FAST_CALL LenPriceEnc_UpdateTables( + CLenPriceEnc *p, + unsigned numPosStates, + const CLenEnc *enc, + const CProbPrice *ProbPrices) +{ + UInt32 b; + + { + unsigned prob = enc->low[0]; + UInt32 a, c; + unsigned posState; + b = GET_PRICEa_1(prob); + a = GET_PRICEa_0(prob); + c = b + GET_PRICEa_0(enc->low[kLenNumLowSymbols]); + for (posState = 0; posState < numPosStates; posState++) + { + UInt32 *prices = p->prices[posState]; + const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits)); + SetPrices_3(probs, a, prices, ProbPrices); + SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices); + } + } + + /* + { + unsigned i; + UInt32 b; + a = GET_PRICEa_0(enc->low[0]); + for (i = 0; i < kLenNumLowSymbols; i++) + p->prices2[i] = a; + a = GET_PRICEa_1(enc->low[0]); + b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]); + for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++) + p->prices2[i] = b; + a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]); + } + */ + + // p->counter = numSymbols; + // p->counter = 64; + + { + unsigned i = p->tableSize; + + if (i > kLenNumLowSymbols * 2) + { + const CLzmaProb *probs = enc->high; + UInt32 *prices = p->prices[0] + kLenNumLowSymbols * 2; + i -= kLenNumLowSymbols * 2 - 1; + i >>= 1; + b += GET_PRICEa_1(enc->low[kLenNumLowSymbols]); + do + { + /* + p->prices2[i] = a + + // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices); + LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices); + */ + // UInt32 price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices); + unsigned sym = --i + (1 << (kLenNumHighBits - 1)); + UInt32 price = b; + do + { + unsigned bit = sym & 1; + sym >>= 1; + price += GET_PRICEa(probs[sym], bit); + } + while (sym >= 2); + + { + unsigned prob = probs[(size_t)i + (1 << (kLenNumHighBits - 1))]; + prices[(size_t)i * 2 ] = price + GET_PRICEa_0(prob); + prices[(size_t)i * 2 + 1] = price + GET_PRICEa_1(prob); + } + } + while (i); + + { + unsigned posState; + size_t num = (p->tableSize - kLenNumLowSymbols * 2) * sizeof(p->prices[0][0]); + for (posState = 1; posState < numPosStates; posState++) + memcpy(p->prices[posState] + kLenNumLowSymbols * 2, p->prices[0] + kLenNumLowSymbols * 2, num); + } + } + } +} + +/* + #ifdef SHOW_STAT + g_STAT_OFFSET += num; + printf("\n MovePos %u", num); + #endif +*/ + +#define MOVE_POS(p, num) { \ + p->additionalOffset += (num); \ + p->matchFinder.Skip(p->matchFinderObj, (UInt32)(num)); } + + +static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes) +{ + unsigned numPairs; + + p->additionalOffset++; + p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); + numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + *numPairsRes = numPairs; + + #ifdef SHOW_STAT + printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2); + g_STAT_OFFSET++; + { + unsigned i; + for (i = 0; i < numPairs; i += 2) + printf("%2u %6u | ", p->matches[i], p->matches[i + 1]); + } + #endif + + if (numPairs == 0) + return 0; + { + unsigned len = p->matches[(size_t)numPairs - 2]; + if (len != p->numFastBytes) + return len; + { + UInt32 numAvail = p->numAvail; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + { + const Byte *p1 = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + const Byte *p2 = p1 + len; + ptrdiff_t dif = (ptrdiff_t)-1 - p->matches[(size_t)numPairs - 1]; + const Byte *lim = p1 + numAvail; + for (; p2 != lim && *p2 == p2[dif]; p2++) + {} + return (unsigned)(p2 - p1); + } + } + } +} + +#define MARK_LIT ((UInt32)(Int32)-1) + +#define MakeAs_Lit(p) { (p)->dist = MARK_LIT; (p)->extra = 0; } +#define MakeAs_ShortRep(p) { (p)->dist = 0; (p)->extra = 0; } +#define IsShortRep(p) ((p)->dist == 0) + + +#define GetPrice_ShortRep(p, state, posState) \ + ( GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState])) + +#define GetPrice_Rep_0(p, state, posState) ( \ + GET_PRICE_1(p->isMatch[state][posState]) \ + + GET_PRICE_1(p->isRep0Long[state][posState])) \ + + GET_PRICE_1(p->isRep[state]) \ + + GET_PRICE_0(p->isRepG0[state]) + +MY_FORCE_INLINE +static UInt32 GetPrice_PureRep(const CLzmaEnc *p, unsigned repIndex, size_t state, size_t posState) +{ + UInt32 price; + UInt32 prob = p->isRepG0[state]; + if (repIndex == 0) + { + price = GET_PRICE_0(prob); + price += GET_PRICE_1(p->isRep0Long[state][posState]); + } + else + { + price = GET_PRICE_1(prob); + prob = p->isRepG1[state]; + if (repIndex == 1) + price += GET_PRICE_0(prob); + else + { + price += GET_PRICE_1(prob); + price += GET_PRICE(p->isRepG2[state], repIndex - 2); + } + } + return price; +} + + +static unsigned Backward(CLzmaEnc *p, unsigned cur) +{ + unsigned wr = cur + 1; + p->optEnd = wr; + + for (;;) + { + UInt32 dist = p->opt[cur].dist; + unsigned len = (unsigned)p->opt[cur].len; + unsigned extra = (unsigned)p->opt[cur].extra; + cur -= len; + + if (extra) + { + wr--; + p->opt[wr].len = (UInt32)len; + cur -= extra; + len = extra; + if (extra == 1) + { + p->opt[wr].dist = dist; + dist = MARK_LIT; + } + else + { + p->opt[wr].dist = 0; + len--; + wr--; + p->opt[wr].dist = MARK_LIT; + p->opt[wr].len = 1; + } + } + + if (cur == 0) + { + p->backRes = dist; + p->optCur = wr; + return len; + } + + wr--; + p->opt[wr].dist = dist; + p->opt[wr].len = (UInt32)len; + } +} + + + +#define LIT_PROBS(pos, prevByte) \ + (p->litProbs + (UInt32)3 * (((((pos) << 8) + (prevByte)) & p->lpMask) << p->lc)) + + +static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) +{ + unsigned last, cur; + UInt32 reps[LZMA_NUM_REPS]; + unsigned repLens[LZMA_NUM_REPS]; + UInt32 *matches; + + { + UInt32 numAvail; + unsigned numPairs, mainLen, repMaxIndex, i, posState; + UInt32 matchPrice, repMatchPrice; + const Byte *data; + Byte curByte, matchByte; + + p->optCur = p->optEnd = 0; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLen; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + if (numAvail < 2) + { + p->backRes = MARK_LIT; + return 1; + } + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + repMaxIndex = 0; + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned len; + const Byte *data2; + reps[i] = p->reps[i]; + data2 = data - reps[i]; + if (data[0] != data2[0] || data[1] != data2[1]) + { + repLens[i] = 0; + continue; + } + for (len = 2; len < numAvail && data[len] == data2[len]; len++) + {} + repLens[i] = len; + if (len > repLens[repMaxIndex]) + repMaxIndex = i; + } + + if (repLens[repMaxIndex] >= p->numFastBytes) + { + unsigned len; + p->backRes = (UInt32)repMaxIndex; + len = repLens[repMaxIndex]; + MOVE_POS(p, len - 1) + return len; + } + + matches = p->matches; + + if (mainLen >= p->numFastBytes) + { + p->backRes = matches[(size_t)numPairs - 1] + LZMA_NUM_REPS; + MOVE_POS(p, mainLen - 1) + return mainLen; + } + + curByte = *data; + matchByte = *(data - reps[0]); + + last = repLens[repMaxIndex]; + if (last <= mainLen) + last = mainLen; + + if (last < 2 && curByte != matchByte) + { + p->backRes = MARK_LIT; + return 1; + } + + p->opt[0].state = (CState)p->state; + + posState = (position & p->pbMask); + + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + + (!IsLitState(p->state) ? + LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + MakeAs_Lit(&p->opt[1]); + + matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); + + // 18.06 + if (matchByte == curByte && repLens[0] == 0) + { + UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, p->state, posState); + if (shortRepPrice < p->opt[1].price) + { + p->opt[1].price = shortRepPrice; + MakeAs_ShortRep(&p->opt[1]); + } + if (last < 2) + { + p->backRes = p->opt[1].dist; + return 1; + } + } + + p->opt[1].len = 1; + + p->opt[0].reps[0] = reps[0]; + p->opt[0].reps[1] = reps[1]; + p->opt[0].reps[2] = reps[2]; + p->opt[0].reps[3] = reps[3]; + + // ---------- REP ---------- + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned repLen = repLens[i]; + UInt32 price; + if (repLen < 2) + continue; + price = repMatchPrice + GetPrice_PureRep(p, i, p->state, posState); + do + { + UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, repLen); + COptimal *opt = &p->opt[repLen]; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)repLen; + opt->dist = (UInt32)i; + opt->extra = 0; + } + } + while (--repLen >= 2); + } + + + // ---------- MATCH ---------- + { + unsigned len = repLens[0] + 1; + if (len <= mainLen) + { + unsigned offs = 0; + UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); + + if (len < 2) + len = 2; + else + while (len > matches[offs]) + offs += 2; + + for (; ; len++) + { + COptimal *opt; + UInt32 dist = matches[(size_t)offs + 1]; + UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); + unsigned lenToPosState = GetLenToPosState(len); + + if (dist < kNumFullDistances) + price += p->distancesPrices[lenToPosState][dist & (kNumFullDistances - 1)]; + else + { + unsigned slot; + GetPosSlot2(dist, slot); + price += p->alignPrices[dist & kAlignMask]; + price += p->posSlotPrices[lenToPosState][slot]; + } + + opt = &p->opt[len]; + + if (price < opt->price) + { + opt->price = price; + opt->len = (UInt32)len; + opt->dist = dist + LZMA_NUM_REPS; + opt->extra = 0; + } + + if (len == matches[offs]) + { + offs += 2; + if (offs == numPairs) + break; + } + } + } + } + + + cur = 0; + + #ifdef SHOW_STAT2 + /* if (position >= 0) */ + { + unsigned i; + printf("\n pos = %4X", position); + for (i = cur; i <= last; i++) + printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price); + } + #endif + } + + + + // ---------- Optimal Parsing ---------- + + for (;;) + { + unsigned numAvail; + UInt32 numAvailFull; + unsigned newLen, numPairs, prev, state, posState, startLen; + UInt32 litPrice, matchPrice, repMatchPrice; + BoolInt nextIsLit; + Byte curByte, matchByte; + const Byte *data; + COptimal *curOpt, *nextOpt; + + if (++cur == last) + break; + + // 18.06 + if (cur >= kNumOpts - 64) + { + unsigned j, best; + UInt32 price = p->opt[cur].price; + best = cur; + for (j = cur + 1; j <= last; j++) + { + UInt32 price2 = p->opt[j].price; + if (price >= price2) + { + price = price2; + best = j; + } + } + { + unsigned delta = best - cur; + if (delta != 0) + { + MOVE_POS(p, delta); + } + } + cur = best; + break; + } + + newLen = ReadMatchDistances(p, &numPairs); + + if (newLen >= p->numFastBytes) + { + p->numPairs = numPairs; + p->longestMatchLen = newLen; + break; + } + + curOpt = &p->opt[cur]; + + position++; + + // we need that check here, if skip_items in p->opt are possible + /* + if (curOpt->price >= kInfinityPrice) + continue; + */ + + prev = cur - curOpt->len; + + if (curOpt->len == 1) + { + state = (unsigned)p->opt[prev].state; + if (IsShortRep(curOpt)) + state = kShortRepNextStates[state]; + else + state = kLiteralNextStates[state]; + } + else + { + const COptimal *prevOpt; + UInt32 b0; + UInt32 dist = curOpt->dist; + + if (curOpt->extra) + { + prev -= (unsigned)curOpt->extra; + state = kState_RepAfterLit; + if (curOpt->extra == 1) + state = (dist < LZMA_NUM_REPS ? kState_RepAfterLit : kState_MatchAfterLit); + } + else + { + state = (unsigned)p->opt[prev].state; + if (dist < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + + prevOpt = &p->opt[prev]; + b0 = prevOpt->reps[0]; + + if (dist < LZMA_NUM_REPS) + { + if (dist == 0) + { + reps[0] = b0; + reps[1] = prevOpt->reps[1]; + reps[2] = prevOpt->reps[2]; + reps[3] = prevOpt->reps[3]; + } + else + { + reps[1] = b0; + b0 = prevOpt->reps[1]; + if (dist == 1) + { + reps[0] = b0; + reps[2] = prevOpt->reps[2]; + reps[3] = prevOpt->reps[3]; + } + else + { + reps[2] = b0; + reps[0] = prevOpt->reps[dist]; + reps[3] = prevOpt->reps[dist ^ 1]; + } + } + } + else + { + reps[0] = (dist - LZMA_NUM_REPS + 1); + reps[1] = b0; + reps[2] = prevOpt->reps[1]; + reps[3] = prevOpt->reps[2]; + } + } + + curOpt->state = (CState)state; + curOpt->reps[0] = reps[0]; + curOpt->reps[1] = reps[1]; + curOpt->reps[2] = reps[2]; + curOpt->reps[3] = reps[3]; + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + curByte = *data; + matchByte = *(data - reps[0]); + + posState = (position & p->pbMask); + + /* + The order of Price checks: + < LIT + <= SHORT_REP + < LIT : REP_0 + < REP [ : LIT : REP_0 ] + < MATCH [ : LIT : REP_0 ] + */ + + { + UInt32 curPrice = curOpt->price; + unsigned prob = p->isMatch[state][posState]; + matchPrice = curPrice + GET_PRICE_1(prob); + litPrice = curPrice + GET_PRICE_0(prob); + } + + nextOpt = &p->opt[(size_t)cur + 1]; + nextIsLit = False; + + // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice) + // 18.new.06 + if ((nextOpt->price < kInfinityPrice + // && !IsLitState(state) + && matchByte == curByte) + || litPrice > nextOpt->price + ) + litPrice = 0; + else + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + litPrice += (!IsLitState(state) ? + LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + + if (litPrice < nextOpt->price) + { + nextOpt->price = litPrice; + nextOpt->len = 1; + MakeAs_Lit(nextOpt); + nextIsLit = True; + } + } + + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); + + numAvailFull = p->numAvail; + { + unsigned temp = kNumOpts - 1 - cur; + if (numAvailFull > temp) + numAvailFull = (UInt32)temp; + } + + // 18.06 + // ---------- SHORT_REP ---------- + if (IsLitState(state)) // 18.new + if (matchByte == curByte) + if (repMatchPrice < nextOpt->price) // 18.new + // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1)) + if ( + // nextOpt->price >= kInfinityPrice || + nextOpt->len < 2 // we can check nextOpt->len, if skip items are not allowed in p->opt + || (nextOpt->dist != 0 + // && nextOpt->extra <= 1 // 17.old + ) + ) + { + UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, state, posState); + // if (shortRepPrice <= nextOpt->price) // 17.old + if (shortRepPrice < nextOpt->price) // 18.new + { + nextOpt->price = shortRepPrice; + nextOpt->len = 1; + MakeAs_ShortRep(nextOpt); + nextIsLit = False; + } + } + + if (numAvailFull < 2) + continue; + numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); + + // numAvail <= p->numFastBytes + + // ---------- LIT : REP_0 ---------- + + if (!nextIsLit + && litPrice != 0 // 18.new + && matchByte != curByte + && numAvailFull > 2) + { + const Byte *data2 = data - reps[0]; + if (data[1] == data2[1] && data[2] == data2[2]) + { + unsigned len; + unsigned limit = p->numFastBytes + 1; + if (limit > numAvailFull) + limit = numAvailFull; + for (len = 3; len < limit && data[len] == data2[len]; len++) + {} + + { + unsigned state2 = kLiteralNextStates[state]; + unsigned posState2 = (position + 1) & p->pbMask; + UInt32 price = litPrice + GetPrice_Rep_0(p, state2, posState2); + { + unsigned offset = cur + len; + + if (last < offset) + last = offset; + + // do + { + UInt32 price2; + COptimal *opt; + len--; + // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2); + price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len); + + opt = &p->opt[offset]; + // offset--; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len; + opt->dist = 0; + opt->extra = 1; + } + } + // while (len >= 3); + } + } + } + } + + startLen = 2; /* speed optimization */ + + { + // ---------- REP ---------- + unsigned repIndex = 0; // 17.old + // unsigned repIndex = IsLitState(state) ? 0 : 1; // 18.notused + for (; repIndex < LZMA_NUM_REPS; repIndex++) + { + unsigned len; + UInt32 price; + const Byte *data2 = data - reps[repIndex]; + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + + for (len = 2; len < numAvail && data[len] == data2[len]; len++) + {} + + // if (len < startLen) continue; // 18.new: speed optimization + + { + unsigned offset = cur + len; + if (last < offset) + last = offset; + } + { + unsigned len2 = len; + price = repMatchPrice + GetPrice_PureRep(p, repIndex, state, posState); + do + { + UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, len2); + COptimal *opt = &p->opt[cur + len2]; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len2; + opt->dist = (UInt32)repIndex; + opt->extra = 0; + } + } + while (--len2 >= 2); + } + + if (repIndex == 0) startLen = len + 1; // 17.old + // startLen = len + 1; // 18.new + + /* if (_maxMode) */ + { + // ---------- REP : LIT : REP_0 ---------- + // numFastBytes + 1 + numFastBytes + + unsigned len2 = len + 1; + unsigned limit = len2 + p->numFastBytes; + if (limit > numAvailFull) + limit = numAvailFull; + + len2 += 2; + if (len2 <= limit) + if (data[len2 - 2] == data2[len2 - 2]) + if (data[len2 - 1] == data2[len2 - 1]) + { + unsigned state2 = kRepNextStates[state]; + unsigned posState2 = (position + len) & p->pbMask; + price += GET_PRICE_LEN(&p->repLenEnc, posState, len) + + GET_PRICE_0(p->isMatch[state2][posState2]) + + LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]), + data[len], data2[len], p->ProbPrices); + + // state2 = kLiteralNextStates[state2]; + state2 = kState_LitAfterRep; + posState2 = (posState2 + 1) & p->pbMask; + + + price += GetPrice_Rep_0(p, state2, posState2); + + for (; len2 < limit && data[len2] == data2[len2]; len2++) + {} + + len2 -= len; + // if (len2 >= 3) + { + { + unsigned offset = cur + len + len2; + + if (last < offset) + last = offset; + // do + { + UInt32 price2; + COptimal *opt; + len2--; + // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2); + price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2); + + opt = &p->opt[offset]; + // offset--; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len2; + opt->extra = (CExtra)(len + 1); + opt->dist = (UInt32)repIndex; + } + } + // while (len2 >= 3); + } + } + } + } + } + } + + + // ---------- MATCH ---------- + /* for (unsigned len = 2; len <= newLen; len++) */ + if (newLen > numAvail) + { + newLen = numAvail; + for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); + matches[numPairs] = (UInt32)newLen; + numPairs += 2; + } + + // startLen = 2; /* speed optimization */ + + if (newLen >= startLen) + { + UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); + UInt32 dist; + unsigned offs, posSlot, len; + + { + unsigned offset = cur + newLen; + if (last < offset) + last = offset; + } + + offs = 0; + while (startLen > matches[offs]) + offs += 2; + dist = matches[(size_t)offs + 1]; + + // if (dist >= kNumFullDistances) + GetPosSlot2(dist, posSlot); + + for (len = /*2*/ startLen; ; len++) + { + UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); + { + COptimal *opt; + unsigned lenNorm = len - 2; + lenNorm = GetLenToPosState2(lenNorm); + if (dist < kNumFullDistances) + price += p->distancesPrices[lenNorm][dist & (kNumFullDistances - 1)]; + else + price += p->posSlotPrices[lenNorm][posSlot] + p->alignPrices[dist & kAlignMask]; + + opt = &p->opt[cur + len]; + if (price < opt->price) + { + opt->price = price; + opt->len = (UInt32)len; + opt->dist = dist + LZMA_NUM_REPS; + opt->extra = 0; + } + } + + if (len == matches[offs]) + { + // if (p->_maxMode) { + // MATCH : LIT : REP_0 + + const Byte *data2 = data - dist - 1; + unsigned len2 = len + 1; + unsigned limit = len2 + p->numFastBytes; + if (limit > numAvailFull) + limit = numAvailFull; + + len2 += 2; + if (len2 <= limit) + if (data[len2 - 2] == data2[len2 - 2]) + if (data[len2 - 1] == data2[len2 - 1]) + { + for (; len2 < limit && data[len2] == data2[len2]; len2++) + {} + + len2 -= len; + + // if (len2 >= 3) + { + unsigned state2 = kMatchNextStates[state]; + unsigned posState2 = (position + len) & p->pbMask; + unsigned offset; + price += GET_PRICE_0(p->isMatch[state2][posState2]); + price += LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]), + data[len], data2[len], p->ProbPrices); + + // state2 = kLiteralNextStates[state2]; + state2 = kState_LitAfterMatch; + + posState2 = (posState2 + 1) & p->pbMask; + price += GetPrice_Rep_0(p, state2, posState2); + + offset = cur + len + len2; + + if (last < offset) + last = offset; + // do + { + UInt32 price2; + COptimal *opt; + len2--; + // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2); + price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2); + opt = &p->opt[offset]; + // offset--; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len2; + opt->extra = (CExtra)(len + 1); + opt->dist = dist + LZMA_NUM_REPS; + } + } + // while (len2 >= 3); + } + + } + + offs += 2; + if (offs == numPairs) + break; + dist = matches[(size_t)offs + 1]; + // if (dist >= kNumFullDistances) + GetPosSlot2(dist, posSlot); + } + } + } + } + + do + p->opt[last].price = kInfinityPrice; + while (--last); + + return Backward(p, cur); +} + + + +#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) + + + +static unsigned GetOptimumFast(CLzmaEnc *p) +{ + UInt32 numAvail, mainDist; + unsigned mainLen, numPairs, repIndex, repLen, i; + const Byte *data; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLen; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + p->backRes = MARK_LIT; + if (numAvail < 2) + return 1; + // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + repLen = repIndex = 0; + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned len; + const Byte *data2 = data - p->reps[i]; + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (len = 2; len < numAvail && data[len] == data2[len]; len++) + {} + if (len >= p->numFastBytes) + { + p->backRes = (UInt32)i; + MOVE_POS(p, len - 1) + return len; + } + if (len > repLen) + { + repIndex = i; + repLen = len; + } + } + + if (mainLen >= p->numFastBytes) + { + p->backRes = p->matches[(size_t)numPairs - 1] + LZMA_NUM_REPS; + MOVE_POS(p, mainLen - 1) + return mainLen; + } + + mainDist = 0; /* for GCC */ + + if (mainLen >= 2) + { + mainDist = p->matches[(size_t)numPairs - 1]; + while (numPairs > 2) + { + UInt32 dist2; + if (mainLen != p->matches[(size_t)numPairs - 4] + 1) + break; + dist2 = p->matches[(size_t)numPairs - 3]; + if (!ChangePair(dist2, mainDist)) + break; + numPairs -= 2; + mainLen--; + mainDist = dist2; + } + if (mainLen == 2 && mainDist >= 0x80) + mainLen = 1; + } + + if (repLen >= 2) + if ( repLen + 1 >= mainLen + || (repLen + 2 >= mainLen && mainDist >= (1 << 9)) + || (repLen + 3 >= mainLen && mainDist >= (1 << 15))) + { + p->backRes = (UInt32)repIndex; + MOVE_POS(p, repLen - 1) + return repLen; + } + + if (mainLen < 2 || numAvail <= 2) + return 1; + + { + unsigned len1 = ReadMatchDistances(p, &p->numPairs); + p->longestMatchLen = len1; + + if (len1 >= 2) + { + UInt32 newDist = p->matches[(size_t)p->numPairs - 1]; + if ( (len1 >= mainLen && newDist < mainDist) + || (len1 == mainLen + 1 && !ChangePair(mainDist, newDist)) + || (len1 > mainLen + 1) + || (len1 + 1 >= mainLen && mainLen >= 3 && ChangePair(newDist, mainDist))) + return 1; + } + } + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned len, limit; + const Byte *data2 = data - p->reps[i]; + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + limit = mainLen - 1; + for (len = 2;; len++) + { + if (len >= limit) + return 1; + if (data[len] != data2[len]) + break; + } + } + + p->backRes = mainDist + LZMA_NUM_REPS; + if (mainLen != 2) + { + MOVE_POS(p, mainLen - 2) + } + return mainLen; +} + + + + +static void WriteEndMarker(CLzmaEnc *p, unsigned posState) +{ + UInt32 range; + range = p->rc.range; + { + UInt32 ttt, newBound; + CLzmaProb *prob = &p->isMatch[p->state][posState]; + RC_BIT_PRE(&p->rc, prob) + RC_BIT_1(&p->rc, prob) + prob = &p->isRep[p->state]; + RC_BIT_PRE(&p->rc, prob) + RC_BIT_0(&p->rc, prob) + } + p->state = kMatchNextStates[p->state]; + + p->rc.range = range; + LenEnc_Encode(&p->lenProbs, &p->rc, 0, posState); + range = p->rc.range; + + { + // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1); + CLzmaProb *probs = p->posSlotEncoder[0]; + unsigned m = 1; + do + { + UInt32 ttt, newBound; + RC_BIT_PRE(p, probs + m) + RC_BIT_1(&p->rc, probs + m); + m = (m << 1) + 1; + } + while (m < (1 << kNumPosSlotBits)); + } + { + // RangeEnc_EncodeDirectBits(&p->rc, ((UInt32)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); UInt32 range = p->range; + unsigned numBits = 30 - kNumAlignBits; + do + { + range >>= 1; + p->rc.low += range; + RC_NORM(&p->rc) + } + while (--numBits); + } + + { + // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); + CLzmaProb *probs = p->posAlignEncoder; + unsigned m = 1; + do + { + UInt32 ttt, newBound; + RC_BIT_PRE(p, probs + m) + RC_BIT_1(&p->rc, probs + m); + m = (m << 1) + 1; + } + while (m < kAlignTableSize); + } + p->rc.range = range; +} + + +static SRes CheckErrors(CLzmaEnc *p) +{ + if (p->result != SZ_OK) + return p->result; + if (p->rc.res != SZ_OK) + p->result = SZ_ERROR_WRITE; + if (p->matchFinderBase.result != SZ_OK) + p->result = SZ_ERROR_READ; + if (p->result != SZ_OK) + p->finished = True; + return p->result; +} + + +MY_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos) +{ + /* ReleaseMFStream(); */ + p->finished = True; + if (p->writeEndMark) + WriteEndMarker(p, nowPos & p->pbMask); + RangeEnc_FlushData(&p->rc); + RangeEnc_FlushStream(&p->rc); + return CheckErrors(p); +} + + +MY_NO_INLINE static void FillAlignPrices(CLzmaEnc *p) +{ + unsigned i; + const CProbPrice *ProbPrices = p->ProbPrices; + const CLzmaProb *probs = p->posAlignEncoder; + // p->alignPriceCount = 0; + for (i = 0; i < kAlignTableSize / 2; i++) + { + UInt32 price = 0; + unsigned sym = i; + unsigned m = 1; + unsigned bit; + UInt32 prob; + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; + prob = probs[m]; + p->alignPrices[i ] = price + GET_PRICEa_0(prob); + p->alignPrices[i + 8] = price + GET_PRICEa_1(prob); + // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); + } +} + + +MY_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p) +{ + // int y; for (y = 0; y < 100; y++) { + + UInt32 tempPrices[kNumFullDistances]; + unsigned i, lps; + + const CProbPrice *ProbPrices = p->ProbPrices; + p->matchPriceCount = 0; + + for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++) + { + unsigned posSlot = GetPosSlot1(i); + unsigned footerBits = (posSlot >> 1) - 1; + unsigned base = ((2 | (posSlot & 1)) << footerBits); + const CLzmaProb *probs = p->posEncoders + (size_t)base * 2; + // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices); + UInt32 price = 0; + unsigned m = 1; + unsigned sym = i; + unsigned offset = (unsigned)1 << footerBits; + base += i; + + if (footerBits) + do + { + unsigned bit = sym & 1; + sym >>= 1; + price += GET_PRICEa(probs[m], bit); + m = (m << 1) + bit; + } + while (--footerBits); + + { + unsigned prob = probs[m]; + tempPrices[base ] = price + GET_PRICEa_0(prob); + tempPrices[base + offset] = price + GET_PRICEa_1(prob); + } + } + + for (lps = 0; lps < kNumLenToPosStates; lps++) + { + unsigned slot; + unsigned distTableSize2 = (p->distTableSize + 1) >> 1; + UInt32 *posSlotPrices = p->posSlotPrices[lps]; + const CLzmaProb *probs = p->posSlotEncoder[lps]; + + for (slot = 0; slot < distTableSize2; slot++) + { + // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices); + UInt32 price; + unsigned bit; + unsigned sym = slot + (1 << (kNumPosSlotBits - 1)); + unsigned prob; + bit = sym & 1; sym >>= 1; price = GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + prob = probs[(size_t)slot + (1 << (kNumPosSlotBits - 1))]; + posSlotPrices[(size_t)slot * 2 ] = price + GET_PRICEa_0(prob); + posSlotPrices[(size_t)slot * 2 + 1] = price + GET_PRICEa_1(prob); + } + + { + UInt32 delta = ((UInt32)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits); + for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++) + { + posSlotPrices[(size_t)slot * 2 ] += delta; + posSlotPrices[(size_t)slot * 2 + 1] += delta; + delta += ((UInt32)1 << kNumBitPriceShiftBits); + } + } + + { + UInt32 *dp = p->distancesPrices[lps]; + + dp[0] = posSlotPrices[0]; + dp[1] = posSlotPrices[1]; + dp[2] = posSlotPrices[2]; + dp[3] = posSlotPrices[3]; + + for (i = 4; i < kNumFullDistances; i += 2) + { + UInt32 slotPrice = posSlotPrices[GetPosSlot1(i)]; + dp[i ] = slotPrice + tempPrices[i]; + dp[i + 1] = slotPrice + tempPrices[i + 1]; + } + } + } + // } +} + + + +void LzmaEnc_Construct(CLzmaEnc *p) +{ + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); + + #ifndef _7ZIP_ST + MatchFinderMt_Construct(&p->matchFinderMt); + p->matchFinderMt.MatchFinder = &p->matchFinderBase; + #endif + + { + CLzmaEncProps props; + LzmaEncProps_Init(&props); + LzmaEnc_SetProps(p, &props); + } + + #ifndef LZMA_LOG_BSR + LzmaEnc_FastPosInit(p->g_FastPos); + #endif + + LzmaEnc_InitPriceTables(p->ProbPrices); + p->litProbs = NULL; + p->saveState.litProbs = NULL; + +} + +CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc) +{ + void *p; + p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc)); + if (p) + LzmaEnc_Construct((CLzmaEnc *)p); + return p; +} + +void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->litProbs); + ISzAlloc_Free(alloc, p->saveState.litProbs); + p->litProbs = NULL; + p->saveState.litProbs = NULL; +} + +void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + #ifndef _7ZIP_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); + #endif + + MatchFinder_Free(&p->matchFinderBase, allocBig); + LzmaEnc_FreeLits(p, alloc); + RangeEnc_Free(&p->rc, alloc); +} + +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); + ISzAlloc_Free(alloc, p); +} + + +static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpackSize) +{ + UInt32 nowPos32, startPos32; + if (p->needInit) + { + p->matchFinder.Init(p->matchFinderObj); + p->needInit = 0; + } + + if (p->finished) + return p->result; + RINOK(CheckErrors(p)); + + nowPos32 = (UInt32)p->nowPos64; + startPos32 = nowPos32; + + if (p->nowPos64 == 0) + { + unsigned numPairs; + Byte curByte; + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + return Flush(p, nowPos32); + ReadMatchDistances(p, &numPairs); + RangeEnc_EncodeBit_0(&p->rc, &p->isMatch[kState_Start][0]); + // p->state = kLiteralNextStates[p->state]; + curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset); + LitEnc_Encode(&p->rc, p->litProbs, curByte); + p->additionalOffset--; + nowPos32++; + } + + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) + + for (;;) + { + UInt32 dist; + unsigned len, posState; + UInt32 range, ttt, newBound; + CLzmaProb *probs; + + if (p->fastMode) + len = GetOptimumFast(p); + else + { + unsigned oci = p->optCur; + if (p->optEnd == oci) + len = GetOptimum(p, nowPos32); + else + { + const COptimal *opt = &p->opt[oci]; + len = opt->len; + p->backRes = opt->dist; + p->optCur = oci + 1; + } + } + + posState = (unsigned)nowPos32 & p->pbMask; + range = p->rc.range; + probs = &p->isMatch[p->state][posState]; + + RC_BIT_PRE(&p->rc, probs) + + dist = p->backRes; + + #ifdef SHOW_STAT2 + printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist); + #endif + + if (dist == MARK_LIT) + { + Byte curByte; + const Byte *data; + unsigned state; + + RC_BIT_0(&p->rc, probs); + p->rc.range = range; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; + probs = LIT_PROBS(nowPos32, *(data - 1)); + curByte = *data; + state = p->state; + p->state = kLiteralNextStates[state]; + if (IsLitState(state)) + LitEnc_Encode(&p->rc, probs, curByte); + else + LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0])); + } + else + { + RC_BIT_1(&p->rc, probs); + probs = &p->isRep[p->state]; + RC_BIT_PRE(&p->rc, probs) + + if (dist < LZMA_NUM_REPS) + { + RC_BIT_1(&p->rc, probs); + probs = &p->isRepG0[p->state]; + RC_BIT_PRE(&p->rc, probs) + if (dist == 0) + { + RC_BIT_0(&p->rc, probs); + probs = &p->isRep0Long[p->state][posState]; + RC_BIT_PRE(&p->rc, probs) + if (len != 1) + { + RC_BIT_1_BASE(&p->rc, probs); + } + else + { + RC_BIT_0_BASE(&p->rc, probs); + p->state = kShortRepNextStates[p->state]; + } + } + else + { + RC_BIT_1(&p->rc, probs); + probs = &p->isRepG1[p->state]; + RC_BIT_PRE(&p->rc, probs) + if (dist == 1) + { + RC_BIT_0_BASE(&p->rc, probs); + dist = p->reps[1]; + } + else + { + RC_BIT_1(&p->rc, probs); + probs = &p->isRepG2[p->state]; + RC_BIT_PRE(&p->rc, probs) + if (dist == 2) + { + RC_BIT_0_BASE(&p->rc, probs); + dist = p->reps[2]; + } + else + { + RC_BIT_1_BASE(&p->rc, probs); + dist = p->reps[3]; + p->reps[3] = p->reps[2]; + } + p->reps[2] = p->reps[1]; + } + p->reps[1] = p->reps[0]; + p->reps[0] = dist; + } + + RC_NORM(&p->rc) + + p->rc.range = range; + + if (len != 1) + { + LenEnc_Encode(&p->repLenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState); + --p->repLenEncCounter; + p->state = kRepNextStates[p->state]; + } + } + else + { + unsigned posSlot; + RC_BIT_0(&p->rc, probs); + p->rc.range = range; + p->state = kMatchNextStates[p->state]; + + LenEnc_Encode(&p->lenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState); + // --p->lenEnc.counter; + + dist -= LZMA_NUM_REPS; + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + p->reps[1] = p->reps[0]; + p->reps[0] = dist + 1; + + p->matchPriceCount++; + GetPosSlot(dist, posSlot); + // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], posSlot); + { + UInt32 sym = (UInt32)posSlot + (1 << kNumPosSlotBits); + range = p->rc.range; + probs = p->posSlotEncoder[GetLenToPosState(len)]; + do + { + CLzmaProb *prob = probs + (sym >> kNumPosSlotBits); + UInt32 bit = (sym >> (kNumPosSlotBits - 1)) & 1; + sym <<= 1; + RC_BIT(&p->rc, prob, bit); + } + while (sym < (1 << kNumPosSlotBits * 2)); + p->rc.range = range; + } + + if (dist >= kStartPosModelIndex) + { + unsigned footerBits = ((posSlot >> 1) - 1); + + if (dist < kNumFullDistances) + { + unsigned base = ((2 | (posSlot & 1)) << footerBits); + RcTree_ReverseEncode(&p->rc, p->posEncoders + base, footerBits, (unsigned)(dist /* - base */)); + } + else + { + UInt32 pos2 = (dist | 0xF) << (32 - footerBits); + range = p->rc.range; + // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); + /* + do + { + range >>= 1; + p->rc.low += range & (0 - ((dist >> --footerBits) & 1)); + RC_NORM(&p->rc) + } + while (footerBits > kNumAlignBits); + */ + do + { + range >>= 1; + p->rc.low += range & (0 - (pos2 >> 31)); + pos2 += pos2; + RC_NORM(&p->rc) + } + while (pos2 != 0xF0000000); + + + // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); + + { + unsigned m = 1; + unsigned bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit; + bit = dist & 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); + p->rc.range = range; + // p->alignPriceCount++; + } + } + } + } + } + + nowPos32 += (UInt32)len; + p->additionalOffset -= len; + + if (p->additionalOffset == 0) + { + UInt32 processed; + + if (!p->fastMode) + { + /* + if (p->alignPriceCount >= 16) // kAlignTableSize + FillAlignPrices(p); + if (p->matchPriceCount >= 128) + FillDistancesPrices(p); + if (p->lenEnc.counter <= 0) + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); + */ + if (p->matchPriceCount >= 64) + { + FillAlignPrices(p); + // { int y; for (y = 0; y < 100; y++) { + FillDistancesPrices(p); + // }} + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); + } + if (p->repLenEncCounter <= 0) + { + p->repLenEncCounter = REP_LEN_COUNT; + LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, &p->repLenProbs, p->ProbPrices); + } + } + + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + break; + processed = nowPos32 - startPos32; + + if (maxPackSize) + { + if (processed + kNumOpts + 300 >= maxUnpackSize + || RangeEnc_GetProcessed_sizet(&p->rc) + kPackReserve >= maxPackSize) + break; + } + else if (processed >= (1 << 17)) + { + p->nowPos64 += nowPos32 - startPos32; + return CheckErrors(p); + } + } + } + + p->nowPos64 += nowPos32 - startPos32; + return Flush(p, nowPos32); +} + + + +#define kBigHashDicLimit ((UInt32)1 << 24) + +static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + UInt32 beforeSize = kNumOpts; + if (!RangeEnc_Alloc(&p->rc, alloc)) + return SZ_ERROR_MEM; + + #ifndef _7ZIP_ST + p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0)); + #endif + + { + unsigned lclp = p->lc + p->lp; + if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp) + { + LzmaEnc_FreeLits(p, alloc); + p->litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); + p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); + if (!p->litProbs || !p->saveState.litProbs) + { + LzmaEnc_FreeLits(p, alloc); + return SZ_ERROR_MEM; + } + p->lclp = lclp; + } + } + + p->matchFinderBase.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0); + + if (beforeSize + p->dictSize < keepWindowSize) + beforeSize = keepWindowSize - p->dictSize; + + #ifndef _7ZIP_ST + if (p->mtMode) + { + RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, + LZMA_MATCH_LEN_MAX + + 1 /* 18.04 */ + , allocBig)); + p->matchFinderObj = &p->matchFinderMt; + p->matchFinderBase.bigHash = (Byte)( + (p->dictSize > kBigHashDicLimit && p->matchFinderBase.hashMask >= 0xFFFFFF) ? 1 : 0); + MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); + } + else + #endif + { + if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) + return SZ_ERROR_MEM; + p->matchFinderObj = &p->matchFinderBase; + MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); + } + + return SZ_OK; +} + +void LzmaEnc_Init(CLzmaEnc *p) +{ + unsigned i; + p->state = 0; + p->reps[0] = + p->reps[1] = + p->reps[2] = + p->reps[3] = 1; + + RangeEnc_Init(&p->rc); + + for (i = 0; i < (1 << kNumAlignBits); i++) + p->posAlignEncoder[i] = kProbInitValue; + + for (i = 0; i < kNumStates; i++) + { + unsigned j; + for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) + { + p->isMatch[i][j] = kProbInitValue; + p->isRep0Long[i][j] = kProbInitValue; + } + p->isRep[i] = kProbInitValue; + p->isRepG0[i] = kProbInitValue; + p->isRepG1[i] = kProbInitValue; + p->isRepG2[i] = kProbInitValue; + } + + { + for (i = 0; i < kNumLenToPosStates; i++) + { + CLzmaProb *probs = p->posSlotEncoder[i]; + unsigned j; + for (j = 0; j < (1 << kNumPosSlotBits); j++) + probs[j] = kProbInitValue; + } + } + { + for (i = 0; i < kNumFullDistances; i++) + p->posEncoders[i] = kProbInitValue; + } + + { + UInt32 num = (UInt32)0x300 << (p->lp + p->lc); + UInt32 k; + CLzmaProb *probs = p->litProbs; + for (k = 0; k < num; k++) + probs[k] = kProbInitValue; + } + + + LenEnc_Init(&p->lenProbs); + LenEnc_Init(&p->repLenProbs); + + p->optEnd = 0; + p->optCur = 0; + + { + for (i = 0; i < kNumOpts; i++) + p->opt[i].price = kInfinityPrice; + } + + p->additionalOffset = 0; + + p->pbMask = (1 << p->pb) - 1; + p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc); +} + + +void LzmaEnc_InitPrices(CLzmaEnc *p) +{ + if (!p->fastMode) + { + FillDistancesPrices(p); + FillAlignPrices(p); + } + + p->lenEnc.tableSize = + p->repLenEnc.tableSize = + p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; + + p->repLenEncCounter = REP_LEN_COUNT; + + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, &p->repLenProbs, p->ProbPrices); +} + +static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + unsigned i; + for (i = kEndPosModelIndex / 2; i < kDicLogSizeMax; i++) + if (p->dictSize <= ((UInt32)1 << i)) + break; + p->distTableSize = i * 2; + + p->finished = False; + p->result = SZ_OK; + RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + p->nowPos64 = 0; + return SZ_OK; +} + +static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, + ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.stream = inStream; + p->needInit = 1; + p->rc.outStream = outStream; + return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +} + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, + ISeqInStream *inStream, UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.stream = inStream; + p->needInit = 1; + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) +{ + p->matchFinderBase.directInput = 1; + p->matchFinderBase.bufferBase = (Byte *)src; + p->matchFinderBase.directInputRem = srcLen; +} + +SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + LzmaEnc_SetInputBuf(p, src, srcLen); + p->needInit = 1; + + LzmaEnc_SetDataSize(pp, srcLen); + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +void LzmaEnc_Finish(CLzmaEncHandle pp) +{ + #ifndef _7ZIP_ST + CLzmaEnc *p = (CLzmaEnc *)pp; + if (p->mtMode) + MatchFinderMt_ReleaseStream(&p->matchFinderMt); + #else + UNUSED_VAR(pp); + #endif +} + + +typedef struct +{ + ISeqOutStream vt; + Byte *data; + SizeT rem; + BoolInt overflow; +} CLzmaEnc_SeqOutStreamBuf; + +static size_t SeqOutStreamBuf_Write(const ISeqOutStream *pp, const void *data, size_t size) +{ + CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt); + if (p->rem < size) + { + size = p->rem; + p->overflow = True; + } + memcpy(p->data, data, size); + p->rem -= size; + p->data += size; + return size; +} + + +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +} + + +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +} + + +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + UInt64 nowPos64; + SRes res; + CLzmaEnc_SeqOutStreamBuf outStream; + + outStream.vt.Write = SeqOutStreamBuf_Write; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = False; + p->finished = False; + p->result = SZ_OK; + + if (reInit) + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + + nowPos64 = p->nowPos64; + RangeEnc_Init(&p->rc); + p->rc.outStream = &outStream.vt; + + if (desiredPackSize == 0) + return SZ_ERROR_OUTPUT_EOF; + + res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize); + + *unpackSize = (UInt32)(p->nowPos64 - nowPos64); + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + + return res; +} + + +static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) +{ + SRes res = SZ_OK; + + #ifndef _7ZIP_ST + Byte allocaDummy[0x300]; + allocaDummy[0] = 0; + allocaDummy[1] = allocaDummy[0]; + #endif + + for (;;) + { + res = LzmaEnc_CodeOneBlock(p, 0, 0); + if (res != SZ_OK || p->finished) + break; + if (progress) + { + res = ICompressProgress_Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); + if (res != SZ_OK) + { + res = SZ_ERROR_PROGRESS; + break; + } + } + } + + LzmaEnc_Finish(p); + + /* + if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&p->matchFinderBase)) + res = SZ_ERROR_FAIL; + } + */ + + return res; +} + + +SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, + ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); + return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); +} + + +SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + unsigned i; + UInt32 dictSize = p->dictSize; + if (*size < LZMA_PROPS_SIZE) + return SZ_ERROR_PARAM; + *size = LZMA_PROPS_SIZE; + props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); + + if (dictSize >= ((UInt32)1 << 22)) + { + UInt32 kDictMask = ((UInt32)1 << 20) - 1; + if (dictSize < (UInt32)0xFFFFFFFF - kDictMask) + dictSize = (dictSize + kDictMask) & ~kDictMask; + } + else for (i = 11; i <= 30; i++) + { + if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; } + if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; } + } + + for (i = 0; i < 4; i++) + props[1 + i] = (Byte)(dictSize >> (8 * i)); + return SZ_OK; +} + + +unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle pp) +{ + return ((CLzmaEnc *)pp)->writeEndMark; +} + + +SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + SRes res; + CLzmaEnc *p = (CLzmaEnc *)pp; + + CLzmaEnc_SeqOutStreamBuf outStream; + + outStream.vt.Write = SeqOutStreamBuf_Write; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = writeEndMark; + p->rc.outStream = &outStream.vt; + + res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); + + if (res == SZ_OK) + { + res = LzmaEnc_Encode2(p, progress); + if (res == SZ_OK && p->nowPos64 != srcLen) + res = SZ_ERROR_FAIL; + } + + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + return res; +} + + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); + SRes res; + if (!p) + return SZ_ERROR_MEM; + + res = LzmaEnc_SetProps(p, props); + if (res == SZ_OK) + { + res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); + if (res == SZ_OK) + res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, + writeEndMark, progress, alloc, allocBig); + } + + LzmaEnc_Destroy(p, alloc, allocBig); + return res; +} diff --git a/lzma/LzmaEnc.h b/lzma/LzmaEnc.h new file mode 100644 index 0000000..c9938f0 --- /dev/null +++ b/lzma/LzmaEnc.h @@ -0,0 +1,76 @@ +/* LzmaEnc.h -- LZMA Encoder +2017-07-27 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_ENC_H +#define __LZMA_ENC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaEncProps +{ + int level; /* 0 <= level <= 9 */ + UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version + (1 << 12) <= dictSize <= (3 << 29) for 64-bit version + default = (1 << 24) */ + int lc; /* 0 <= lc <= 8, default = 3 */ + int lp; /* 0 <= lp <= 4, default = 0 */ + int pb; /* 0 <= pb <= 4, default = 2 */ + int algo; /* 0 - fast, 1 - normal, default = 1 */ + int fb; /* 5 <= fb <= 273, default = 32 */ + int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ + int numHashBytes; /* 2, 3 or 4, default = 4 */ + UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ + unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ + int numThreads; /* 1 or 2, default = 2 */ + + UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1. + Encoder uses this value to reduce dictionary size */ +} CLzmaEncProps; + +void LzmaEncProps_Init(CLzmaEncProps *p); +void LzmaEncProps_Normalize(CLzmaEncProps *p); +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); + + +/* ---------- CLzmaEncHandle Interface ---------- */ + +/* LzmaEnc* functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef void * CLzmaEncHandle; + +CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc); +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig); + +SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); +void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize); +SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p); + +SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, + ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); + + +/* ---------- One Call Interface ---------- */ + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); + +EXTERN_C_END + +#endif diff --git a/lzma/LzmaLib.c b/lzma/LzmaLib.c new file mode 100644 index 0000000..c10cf1a --- /dev/null +++ b/lzma/LzmaLib.c @@ -0,0 +1,40 @@ +/* LzmaLib.c -- LZMA library wrapper +2015-06-13 : Igor Pavlov : Public domain */ + +#include "Alloc.h" +#include "LzmaDec.h" +#include "LzmaEnc.h" +#include "LzmaLib.h" + +MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads /* 1 or 2, default = 2 */ +) +{ + CLzmaEncProps props; + LzmaEncProps_Init(&props); + props.level = level; + props.dictSize = dictSize; + props.lc = lc; + props.lp = lp; + props.pb = pb; + props.fb = fb; + props.numThreads = numThreads; + + return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0, + NULL, &g_Alloc, &g_Alloc); +} + + +MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, + const unsigned char *props, size_t propsSize) +{ + ELzmaStatus status; + return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc); +} diff --git a/lzma/LzmaLib.h b/lzma/LzmaLib.h new file mode 100644 index 0000000..5c35e53 --- /dev/null +++ b/lzma/LzmaLib.h @@ -0,0 +1,131 @@ +/* LzmaLib.h -- LZMA library interface +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_LIB_H +#define __LZMA_LIB_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define MY_STDAPI int MY_STD_CALL + +#define LZMA_PROPS_SIZE 5 + +/* +RAM requirements for LZMA: + for compression: (dictSize * 11.5 + 6 MB) + state_size + for decompression: dictSize + state_size + state_size = (4 + (1.5 << (lc + lp))) KB + by default (lc=3, lp=0), state_size = 16 KB. + +LZMA properties (5 bytes) format + Offset Size Description + 0 1 lc, lp and pb in encoded form. + 1 4 dictSize (little endian). +*/ + +/* +LzmaCompress +------------ + +outPropsSize - + In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + + LZMA Encoder will use defult values for any parameter, if it is + -1 for any from: level, loc, lp, pb, fb, numThreads + 0 for dictSize + +level - compression level: 0 <= level <= 9; + + level dictSize algo fb + 0: 16 KB 0 32 + 1: 64 KB 0 32 + 2: 256 KB 0 32 + 3: 1 MB 0 32 + 4: 4 MB 0 32 + 5: 16 MB 1 32 + 6: 32 MB 1 32 + 7+: 64 MB 1 64 + + The default value for "level" is 5. + + algo = 0 means fast method + algo = 1 means normal method + +dictSize - The dictionary size in bytes. The maximum value is + 128 MB = (1 << 27) bytes for 32-bit version + 1 GB = (1 << 30) bytes for 64-bit version + The default value is 16 MB = (1 << 24) bytes. + It's recommended to use the dictionary that is larger than 4 KB and + that can be calculated as (1 << N) or (3 << N) sizes. + +lc - The number of literal context bits (high bits of previous literal). + It can be in the range from 0 to 8. The default value is 3. + Sometimes lc=4 gives the gain for big files. + +lp - The number of literal pos bits (low bits of current position for literals). + It can be in the range from 0 to 4. The default value is 0. + The lp switch is intended for periodical data when the period is equal to 2^lp. + For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's + better to set lc=0, if you change lp switch. + +pb - The number of pos bits (low bits of current position). + It can be in the range from 0 to 4. The default value is 2. + The pb switch is intended for periodical data when the period is equal 2^pb. + +fb - Word size (the number of fast bytes). + It can be in the range from 5 to 273. The default value is 32. + Usually, a big number gives a little bit better compression ratio and + slower compression process. + +numThreads - The number of thereads. 1 or 2. The default value is 2. + Fast mode (algo = 0) can use only 1 thread. + +Out: + destLen - processed output size +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */ + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* default = (1 << 24) */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads /* 1 or 2, default = 2 */ + ); + +/* +LzmaUncompress +-------------- +In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size +Out: + destLen - processed output size + srcLen - processed input size +Returns: + SZ_OK - OK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation arror + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src) +*/ + +MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen, + const unsigned char *props, size_t propsSize); + +EXTERN_C_END + +#endif diff --git a/lzma/MtCoder.c b/lzma/MtCoder.c new file mode 100644 index 0000000..5667f2d --- /dev/null +++ b/lzma/MtCoder.c @@ -0,0 +1,601 @@ +/* MtCoder.c -- Multi-thread Coder +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "MtCoder.h" + +#ifndef _7ZIP_ST + +SRes MtProgressThunk_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize) +{ + CMtProgressThunk *thunk = CONTAINER_FROM_VTBL(pp, CMtProgressThunk, vt); + UInt64 inSize2 = 0; + UInt64 outSize2 = 0; + if (inSize != (UInt64)(Int64)-1) + { + inSize2 = inSize - thunk->inSize; + thunk->inSize = inSize; + } + if (outSize != (UInt64)(Int64)-1) + { + outSize2 = outSize - thunk->outSize; + thunk->outSize = outSize; + } + return MtProgress_ProgressAdd(thunk->mtProgress, inSize2, outSize2); +} + + +void MtProgressThunk_CreateVTable(CMtProgressThunk *p) +{ + p->vt.Progress = MtProgressThunk_Progress; +} + + + +#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } + + +static WRes ArEvent_OptCreate_And_Reset(CEvent *p) +{ + if (Event_IsCreated(p)) + return Event_Reset(p); + return AutoResetEvent_CreateNotSignaled(p); +} + + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp); + + +static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t) +{ + WRes wres = ArEvent_OptCreate_And_Reset(&t->startEvent); + if (wres == 0) + { + t->stop = False; + if (!Thread_WasCreated(&t->thread)) + wres = Thread_Create(&t->thread, ThreadFunc, t); + if (wres == 0) + wres = Event_Set(&t->startEvent); + } + if (wres == 0) + return SZ_OK; + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +static void MtCoderThread_Destruct(CMtCoderThread *t) +{ + if (Thread_WasCreated(&t->thread)) + { + t->stop = 1; + Event_Set(&t->startEvent); + Thread_Wait(&t->thread); + Thread_Close(&t->thread); + } + + Event_Close(&t->startEvent); + + if (t->inBuf) + { + ISzAlloc_Free(t->mtCoder->allocBig, t->inBuf); + t->inBuf = NULL; + } +} + + + +static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize) +{ + size_t size = *processedSize; + *processedSize = 0; + while (size != 0) + { + size_t cur = size; + SRes res = ISeqInStream_Read(stream, data, &cur); + *processedSize += cur; + data += cur; + size -= cur; + RINOK(res); + if (cur == 0) + return SZ_OK; + } + return SZ_OK; +} + + +/* + ThreadFunc2() returns: + SZ_OK - in all normal cases (even for stream error or memory allocation error) + SZ_ERROR_THREAD - in case of failure in system synch function +*/ + +static SRes ThreadFunc2(CMtCoderThread *t) +{ + CMtCoder *mtc = t->mtCoder; + + for (;;) + { + unsigned bi; + SRes res; + SRes res2; + BoolInt finished; + unsigned bufIndex; + size_t size; + const Byte *inData; + UInt64 readProcessed = 0; + + RINOK_THREAD(Event_Wait(&mtc->readEvent)) + + /* after Event_Wait(&mtc->readEvent) we must call Event_Set(&mtc->readEvent) in any case to unlock another threads */ + + if (mtc->stopReading) + { + return Event_Set(&mtc->readEvent) == 0 ? SZ_OK : SZ_ERROR_THREAD; + } + + res = MtProgress_GetError(&mtc->mtProgress); + + size = 0; + inData = NULL; + finished = True; + + if (res == SZ_OK) + { + size = mtc->blockSize; + if (mtc->inStream) + { + if (!t->inBuf) + { + t->inBuf = (Byte *)ISzAlloc_Alloc(mtc->allocBig, mtc->blockSize); + if (!t->inBuf) + res = SZ_ERROR_MEM; + } + if (res == SZ_OK) + { + res = FullRead(mtc->inStream, t->inBuf, &size); + readProcessed = mtc->readProcessed + size; + mtc->readProcessed = readProcessed; + } + if (res != SZ_OK) + { + mtc->readRes = res; + /* after reading error - we can stop encoding of previous blocks */ + MtProgress_SetError(&mtc->mtProgress, res); + } + else + finished = (size != mtc->blockSize); + } + else + { + size_t rem; + readProcessed = mtc->readProcessed; + rem = mtc->inDataSize - (size_t)readProcessed; + if (size > rem) + size = rem; + inData = mtc->inData + (size_t)readProcessed; + readProcessed += size; + mtc->readProcessed = readProcessed; + finished = (mtc->inDataSize == (size_t)readProcessed); + } + } + + /* we must get some block from blocksSemaphore before Event_Set(&mtc->readEvent) */ + + res2 = SZ_OK; + + if (Semaphore_Wait(&mtc->blocksSemaphore) != 0) + { + res2 = SZ_ERROR_THREAD; + if (res == SZ_OK) + { + res = res2; + // MtProgress_SetError(&mtc->mtProgress, res); + } + } + + bi = mtc->blockIndex; + + if (++mtc->blockIndex >= mtc->numBlocksMax) + mtc->blockIndex = 0; + + bufIndex = (unsigned)(int)-1; + + if (res == SZ_OK) + res = MtProgress_GetError(&mtc->mtProgress); + + if (res != SZ_OK) + finished = True; + + if (!finished) + { + if (mtc->numStartedThreads < mtc->numStartedThreadsLimit + && mtc->expectedDataSize != readProcessed) + { + res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]); + if (res == SZ_OK) + mtc->numStartedThreads++; + else + { + MtProgress_SetError(&mtc->mtProgress, res); + finished = True; + } + } + } + + if (finished) + mtc->stopReading = True; + + RINOK_THREAD(Event_Set(&mtc->readEvent)) + + if (res2 != SZ_OK) + return res2; + + if (res == SZ_OK) + { + CriticalSection_Enter(&mtc->cs); + bufIndex = mtc->freeBlockHead; + mtc->freeBlockHead = mtc->freeBlockList[bufIndex]; + CriticalSection_Leave(&mtc->cs); + + res = mtc->mtCallback->Code(mtc->mtCallbackObject, t->index, bufIndex, + mtc->inStream ? t->inBuf : inData, size, finished); + + // MtProgress_Reinit(&mtc->mtProgress, t->index); + + if (res != SZ_OK) + MtProgress_SetError(&mtc->mtProgress, res); + } + + { + CMtCoderBlock *block = &mtc->blocks[bi]; + block->res = res; + block->bufIndex = bufIndex; + block->finished = finished; + } + + #ifdef MTCODER__USE_WRITE_THREAD + RINOK_THREAD(Event_Set(&mtc->writeEvents[bi])) + #else + { + unsigned wi; + { + CriticalSection_Enter(&mtc->cs); + wi = mtc->writeIndex; + if (wi == bi) + mtc->writeIndex = (unsigned)(int)-1; + else + mtc->ReadyBlocks[bi] = True; + CriticalSection_Leave(&mtc->cs); + } + + if (wi != bi) + { + if (res != SZ_OK || finished) + return 0; + continue; + } + + if (mtc->writeRes != SZ_OK) + res = mtc->writeRes; + + for (;;) + { + if (res == SZ_OK && bufIndex != (unsigned)(int)-1) + { + res = mtc->mtCallback->Write(mtc->mtCallbackObject, bufIndex); + if (res != SZ_OK) + { + mtc->writeRes = res; + MtProgress_SetError(&mtc->mtProgress, res); + } + } + + if (++wi >= mtc->numBlocksMax) + wi = 0; + { + BoolInt isReady; + + CriticalSection_Enter(&mtc->cs); + + if (bufIndex != (unsigned)(int)-1) + { + mtc->freeBlockList[bufIndex] = mtc->freeBlockHead; + mtc->freeBlockHead = bufIndex; + } + + isReady = mtc->ReadyBlocks[wi]; + + if (isReady) + mtc->ReadyBlocks[wi] = False; + else + mtc->writeIndex = wi; + + CriticalSection_Leave(&mtc->cs); + + RINOK_THREAD(Semaphore_Release1(&mtc->blocksSemaphore)) + + if (!isReady) + break; + } + + { + CMtCoderBlock *block = &mtc->blocks[wi]; + if (res == SZ_OK && block->res != SZ_OK) + res = block->res; + bufIndex = block->bufIndex; + finished = block->finished; + } + } + } + #endif + + if (finished || res != SZ_OK) + return 0; + } +} + + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp) +{ + CMtCoderThread *t = (CMtCoderThread *)pp; + for (;;) + { + if (Event_Wait(&t->startEvent) != 0) + return SZ_ERROR_THREAD; + if (t->stop) + return 0; + { + SRes res = ThreadFunc2(t); + CMtCoder *mtc = t->mtCoder; + if (res != SZ_OK) + { + MtProgress_SetError(&mtc->mtProgress, res); + } + + #ifndef MTCODER__USE_WRITE_THREAD + { + unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads); + if (numFinished == mtc->numStartedThreads) + if (Event_Set(&mtc->finishedEvent) != 0) + return SZ_ERROR_THREAD; + } + #endif + } + } +} + + + +void MtCoder_Construct(CMtCoder *p) +{ + unsigned i; + + p->blockSize = 0; + p->numThreadsMax = 0; + p->expectedDataSize = (UInt64)(Int64)-1; + + p->inStream = NULL; + p->inData = NULL; + p->inDataSize = 0; + + p->progress = NULL; + p->allocBig = NULL; + + p->mtCallback = NULL; + p->mtCallbackObject = NULL; + + p->allocatedBufsSize = 0; + + Event_Construct(&p->readEvent); + Semaphore_Construct(&p->blocksSemaphore); + + for (i = 0; i < MTCODER__THREADS_MAX; i++) + { + CMtCoderThread *t = &p->threads[i]; + t->mtCoder = p; + t->index = i; + t->inBuf = NULL; + t->stop = False; + Event_Construct(&t->startEvent); + Thread_Construct(&t->thread); + } + + #ifdef MTCODER__USE_WRITE_THREAD + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + Event_Construct(&p->writeEvents[i]); + #else + Event_Construct(&p->finishedEvent); + #endif + + CriticalSection_Init(&p->cs); + CriticalSection_Init(&p->mtProgress.cs); +} + + + + +static void MtCoder_Free(CMtCoder *p) +{ + unsigned i; + + /* + p->stopReading = True; + if (Event_IsCreated(&p->readEvent)) + Event_Set(&p->readEvent); + */ + + for (i = 0; i < MTCODER__THREADS_MAX; i++) + MtCoderThread_Destruct(&p->threads[i]); + + Event_Close(&p->readEvent); + Semaphore_Close(&p->blocksSemaphore); + + #ifdef MTCODER__USE_WRITE_THREAD + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + Event_Close(&p->writeEvents[i]); + #else + Event_Close(&p->finishedEvent); + #endif +} + + +void MtCoder_Destruct(CMtCoder *p) +{ + MtCoder_Free(p); + + CriticalSection_Delete(&p->cs); + CriticalSection_Delete(&p->mtProgress.cs); +} + + +SRes MtCoder_Code(CMtCoder *p) +{ + unsigned numThreads = p->numThreadsMax; + unsigned numBlocksMax; + unsigned i; + SRes res = SZ_OK; + + if (numThreads > MTCODER__THREADS_MAX) + numThreads = MTCODER__THREADS_MAX; + numBlocksMax = MTCODER__GET_NUM_BLOCKS_FROM_THREADS(numThreads); + + if (p->blockSize < ((UInt32)1 << 26)) numBlocksMax++; + if (p->blockSize < ((UInt32)1 << 24)) numBlocksMax++; + if (p->blockSize < ((UInt32)1 << 22)) numBlocksMax++; + + if (numBlocksMax > MTCODER__BLOCKS_MAX) + numBlocksMax = MTCODER__BLOCKS_MAX; + + if (p->blockSize != p->allocatedBufsSize) + { + for (i = 0; i < MTCODER__THREADS_MAX; i++) + { + CMtCoderThread *t = &p->threads[i]; + if (t->inBuf) + { + ISzAlloc_Free(p->allocBig, t->inBuf); + t->inBuf = NULL; + } + } + p->allocatedBufsSize = p->blockSize; + } + + p->readRes = SZ_OK; + + MtProgress_Init(&p->mtProgress, p->progress); + + #ifdef MTCODER__USE_WRITE_THREAD + for (i = 0; i < numBlocksMax; i++) + { + RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->writeEvents[i])); + } + #else + RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->finishedEvent)); + #endif + + { + RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->readEvent)); + + if (Semaphore_IsCreated(&p->blocksSemaphore)) + { + RINOK_THREAD(Semaphore_Close(&p->blocksSemaphore)); + } + RINOK_THREAD(Semaphore_Create(&p->blocksSemaphore, numBlocksMax, numBlocksMax)); + } + + for (i = 0; i < MTCODER__BLOCKS_MAX - 1; i++) + p->freeBlockList[i] = i + 1; + p->freeBlockList[MTCODER__BLOCKS_MAX - 1] = (unsigned)(int)-1; + p->freeBlockHead = 0; + + p->readProcessed = 0; + p->blockIndex = 0; + p->numBlocksMax = numBlocksMax; + p->stopReading = False; + + #ifndef MTCODER__USE_WRITE_THREAD + p->writeIndex = 0; + p->writeRes = SZ_OK; + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + p->ReadyBlocks[i] = False; + p->numFinishedThreads = 0; + #endif + + p->numStartedThreadsLimit = numThreads; + p->numStartedThreads = 0; + + // for (i = 0; i < numThreads; i++) + { + CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++]; + RINOK(MtCoderThread_CreateAndStart(nextThread)); + } + + RINOK_THREAD(Event_Set(&p->readEvent)) + + #ifdef MTCODER__USE_WRITE_THREAD + { + unsigned bi = 0; + + for (;; bi++) + { + if (bi >= numBlocksMax) + bi = 0; + + RINOK_THREAD(Event_Wait(&p->writeEvents[bi])) + + { + const CMtCoderBlock *block = &p->blocks[bi]; + unsigned bufIndex = block->bufIndex; + BoolInt finished = block->finished; + if (res == SZ_OK && block->res != SZ_OK) + res = block->res; + + if (bufIndex != (unsigned)(int)-1) + { + if (res == SZ_OK) + { + res = p->mtCallback->Write(p->mtCallbackObject, bufIndex); + if (res != SZ_OK) + MtProgress_SetError(&p->mtProgress, res); + } + + CriticalSection_Enter(&p->cs); + { + p->freeBlockList[bufIndex] = p->freeBlockHead; + p->freeBlockHead = bufIndex; + } + CriticalSection_Leave(&p->cs); + } + + RINOK_THREAD(Semaphore_Release1(&p->blocksSemaphore)) + + if (finished) + break; + } + } + } + #else + { + WRes wres = Event_Wait(&p->finishedEvent); + res = MY_SRes_HRESULT_FROM_WRes(wres); + } + #endif + + if (res == SZ_OK) + res = p->readRes; + + if (res == SZ_OK) + res = p->mtProgress.res; + + #ifndef MTCODER__USE_WRITE_THREAD + if (res == SZ_OK) + res = p->writeRes; + #endif + + if (res != SZ_OK) + MtCoder_Free(p); + return res; +} + +#endif diff --git a/lzma/MtCoder.h b/lzma/MtCoder.h new file mode 100644 index 0000000..603329d --- /dev/null +++ b/lzma/MtCoder.h @@ -0,0 +1,141 @@ +/* MtCoder.h -- Multi-thread Coder +2018-07-04 : Igor Pavlov : Public domain */ + +#ifndef __MT_CODER_H +#define __MT_CODER_H + +#include "MtDec.h" + +EXTERN_C_BEGIN + +/* + if ( defined MTCODER__USE_WRITE_THREAD) : main thread writes all data blocks to output stream + if (not defined MTCODER__USE_WRITE_THREAD) : any coder thread can write data blocks to output stream +*/ +/* #define MTCODER__USE_WRITE_THREAD */ + +#ifndef _7ZIP_ST + #define MTCODER__GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1) + #define MTCODER__THREADS_MAX 64 + #define MTCODER__BLOCKS_MAX (MTCODER__GET_NUM_BLOCKS_FROM_THREADS(MTCODER__THREADS_MAX) + 3) +#else + #define MTCODER__THREADS_MAX 1 + #define MTCODER__BLOCKS_MAX 1 +#endif + + +#ifndef _7ZIP_ST + + +typedef struct +{ + ICompressProgress vt; + CMtProgress *mtProgress; + UInt64 inSize; + UInt64 outSize; +} CMtProgressThunk; + +void MtProgressThunk_CreateVTable(CMtProgressThunk *p); + +#define MtProgressThunk_Init(p) { (p)->inSize = 0; (p)->outSize = 0; } + + +struct _CMtCoder; + + +typedef struct +{ + struct _CMtCoder *mtCoder; + unsigned index; + int stop; + Byte *inBuf; + + CAutoResetEvent startEvent; + CThread thread; +} CMtCoderThread; + + +typedef struct +{ + SRes (*Code)(void *p, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished); + SRes (*Write)(void *p, unsigned outBufIndex); +} IMtCoderCallback2; + + +typedef struct +{ + SRes res; + unsigned bufIndex; + BoolInt finished; +} CMtCoderBlock; + + +typedef struct _CMtCoder +{ + /* input variables */ + + size_t blockSize; /* size of input block */ + unsigned numThreadsMax; + UInt64 expectedDataSize; + + ISeqInStream *inStream; + const Byte *inData; + size_t inDataSize; + + ICompressProgress *progress; + ISzAllocPtr allocBig; + + IMtCoderCallback2 *mtCallback; + void *mtCallbackObject; + + + /* internal variables */ + + size_t allocatedBufsSize; + + CAutoResetEvent readEvent; + CSemaphore blocksSemaphore; + + BoolInt stopReading; + SRes readRes; + + #ifdef MTCODER__USE_WRITE_THREAD + CAutoResetEvent writeEvents[MTCODER__BLOCKS_MAX]; + #else + CAutoResetEvent finishedEvent; + SRes writeRes; + unsigned writeIndex; + Byte ReadyBlocks[MTCODER__BLOCKS_MAX]; + LONG numFinishedThreads; + #endif + + unsigned numStartedThreadsLimit; + unsigned numStartedThreads; + + unsigned numBlocksMax; + unsigned blockIndex; + UInt64 readProcessed; + + CCriticalSection cs; + + unsigned freeBlockHead; + unsigned freeBlockList[MTCODER__BLOCKS_MAX]; + + CMtProgress mtProgress; + CMtCoderBlock blocks[MTCODER__BLOCKS_MAX]; + CMtCoderThread threads[MTCODER__THREADS_MAX]; +} CMtCoder; + + +void MtCoder_Construct(CMtCoder *p); +void MtCoder_Destruct(CMtCoder *p); +SRes MtCoder_Code(CMtCoder *p); + + +#endif + + +EXTERN_C_END + +#endif diff --git a/lzma/MtDec.c b/lzma/MtDec.c new file mode 100644 index 0000000..25a8b04 --- /dev/null +++ b/lzma/MtDec.c @@ -0,0 +1,1138 @@ +/* MtDec.c -- Multi-thread Decoder +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SHOW_DEBUG_INFO + +// #include + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) + +#include "MtDec.h" + +#ifndef _7ZIP_ST + +void MtProgress_Init(CMtProgress *p, ICompressProgress *progress) +{ + p->progress = progress; + p->res = SZ_OK; + p->totalInSize = 0; + p->totalOutSize = 0; +} + + +SRes MtProgress_Progress_ST(CMtProgress *p) +{ + if (p->res == SZ_OK && p->progress) + if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) + p->res = SZ_ERROR_PROGRESS; + return p->res; +} + + +SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize) +{ + SRes res; + CriticalSection_Enter(&p->cs); + + p->totalInSize += inSize; + p->totalOutSize += outSize; + if (p->res == SZ_OK && p->progress) + if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) + p->res = SZ_ERROR_PROGRESS; + res = p->res; + + CriticalSection_Leave(&p->cs); + return res; +} + + +SRes MtProgress_GetError(CMtProgress *p) +{ + SRes res; + CriticalSection_Enter(&p->cs); + res = p->res; + CriticalSection_Leave(&p->cs); + return res; +} + + +void MtProgress_SetError(CMtProgress *p, SRes res) +{ + CriticalSection_Enter(&p->cs); + if (p->res == SZ_OK) + p->res = res; + CriticalSection_Leave(&p->cs); +} + + +#define RINOK_THREAD(x) RINOK(x) + + +static WRes ArEvent_OptCreate_And_Reset(CEvent *p) +{ + if (Event_IsCreated(p)) + return Event_Reset(p); + return AutoResetEvent_CreateNotSignaled(p); +} + + +struct __CMtDecBufLink +{ + struct __CMtDecBufLink *next; + void *pad[3]; +}; + +typedef struct __CMtDecBufLink CMtDecBufLink; + +#define MTDEC__LINK_DATA_OFFSET sizeof(CMtDecBufLink) +#define MTDEC__DATA_PTR_FROM_LINK(link) ((Byte *)(link) + MTDEC__LINK_DATA_OFFSET) + + + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp); + + +static WRes MtDecThread_CreateEvents(CMtDecThread *t) +{ + WRes wres = ArEvent_OptCreate_And_Reset(&t->canWrite); + if (wres == 0) + { + wres = ArEvent_OptCreate_And_Reset(&t->canRead); + if (wres == 0) + return SZ_OK; + } + return wres; +} + + +static SRes MtDecThread_CreateAndStart(CMtDecThread *t) +{ + WRes wres = MtDecThread_CreateEvents(t); + // wres = 17; // for test + if (wres == 0) + { + if (Thread_WasCreated(&t->thread)) + return SZ_OK; + wres = Thread_Create(&t->thread, ThreadFunc, t); + if (wres == 0) + return SZ_OK; + } + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +void MtDecThread_FreeInBufs(CMtDecThread *t) +{ + if (t->inBuf) + { + void *link = t->inBuf; + t->inBuf = NULL; + do + { + void *next = ((CMtDecBufLink *)link)->next; + ISzAlloc_Free(t->mtDec->alloc, link); + link = next; + } + while (link); + } +} + + +static void MtDecThread_CloseThread(CMtDecThread *t) +{ + if (Thread_WasCreated(&t->thread)) + { + Event_Set(&t->canWrite); /* we can disable it. There are no threads waiting canWrite in normal cases */ + Event_Set(&t->canRead); + Thread_Wait(&t->thread); + Thread_Close(&t->thread); + } + + Event_Close(&t->canRead); + Event_Close(&t->canWrite); +} + +static void MtDec_CloseThreads(CMtDec *p) +{ + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + MtDecThread_CloseThread(&p->threads[i]); +} + +static void MtDecThread_Destruct(CMtDecThread *t) +{ + MtDecThread_CloseThread(t); + MtDecThread_FreeInBufs(t); +} + + + +static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize) +{ + size_t size = *processedSize; + *processedSize = 0; + while (size != 0) + { + size_t cur = size; + SRes res = ISeqInStream_Read(stream, data, &cur); + *processedSize += cur; + data += cur; + size -= cur; + RINOK(res); + if (cur == 0) + return SZ_OK; + } + return SZ_OK; +} + + +static SRes MtDec_GetError_Spec(CMtDec *p, UInt64 interruptIndex, BoolInt *wasInterrupted) +{ + SRes res; + CriticalSection_Enter(&p->mtProgress.cs); + *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); + res = p->mtProgress.res; + CriticalSection_Leave(&p->mtProgress.cs); + return res; +} + +static SRes MtDec_Progress_GetError_Spec(CMtDec *p, UInt64 inSize, UInt64 outSize, UInt64 interruptIndex, BoolInt *wasInterrupted) +{ + SRes res; + CriticalSection_Enter(&p->mtProgress.cs); + + p->mtProgress.totalInSize += inSize; + p->mtProgress.totalOutSize += outSize; + if (p->mtProgress.res == SZ_OK && p->mtProgress.progress) + if (ICompressProgress_Progress(p->mtProgress.progress, p->mtProgress.totalInSize, p->mtProgress.totalOutSize) != SZ_OK) + p->mtProgress.res = SZ_ERROR_PROGRESS; + + *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); + res = p->mtProgress.res; + + CriticalSection_Leave(&p->mtProgress.cs); + + return res; +} + +static void MtDec_Interrupt(CMtDec *p, UInt64 interruptIndex) +{ + CriticalSection_Enter(&p->mtProgress.cs); + if (!p->needInterrupt || interruptIndex < p->interruptIndex) + { + p->interruptIndex = interruptIndex; + p->needInterrupt = True; + } + CriticalSection_Leave(&p->mtProgress.cs); +} + +Byte *MtDec_GetCrossBuff(CMtDec *p) +{ + Byte *cr = p->crossBlock; + if (!cr) + { + cr = (Byte *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); + if (!cr) + return NULL; + p->crossBlock = cr; + } + return MTDEC__DATA_PTR_FROM_LINK(cr); +} + + +/* + ThreadFunc2() returns: + 0 - in all normal cases (even for stream error or memory allocation error) + (!= 0) - WRes error return by system threading function +*/ + +// #define MTDEC_ProgessStep (1 << 22) +#define MTDEC_ProgessStep (1 << 0) + +static WRes ThreadFunc2(CMtDecThread *t) +{ + CMtDec *p = t->mtDec; + + PRF_STR_INT("ThreadFunc2", t->index); + + // SetThreadAffinityMask(GetCurrentThread(), 1 << t->index); + + for (;;) + { + SRes res, codeRes; + BoolInt wasInterrupted, isAllocError, overflow, finish; + SRes threadingErrorSRes; + BoolInt needCode, needWrite, needContinue; + + size_t inDataSize_Start; + UInt64 inDataSize; + // UInt64 inDataSize_Full; + + UInt64 blockIndex; + + UInt64 inPrev = 0; + UInt64 outPrev = 0; + UInt64 inCodePos; + UInt64 outCodePos; + + Byte *afterEndData = NULL; + size_t afterEndData_Size = 0; + + BoolInt canCreateNewThread = False; + // CMtDecCallbackInfo parse; + CMtDecThread *nextThread; + + PRF_STR_INT("Event_Wait(&t->canRead)", t->index); + + RINOK_THREAD(Event_Wait(&t->canRead)); + if (p->exitThread) + return 0; + + PRF_STR_INT("after Event_Wait(&t->canRead)", t->index); + + // if (t->index == 3) return 19; // for test + + blockIndex = p->blockIndex++; + + // PRF(printf("\ncanRead\n")) + + res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); + + finish = p->readWasFinished; + needCode = False; + needWrite = False; + isAllocError = False; + overflow = False; + + inDataSize_Start = 0; + inDataSize = 0; + // inDataSize_Full = 0; + + if (res == SZ_OK && !wasInterrupted) + { + // if (p->inStream) + { + CMtDecBufLink *prev = NULL; + CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; + size_t crossSize = p->crossEnd - p->crossStart; + + PRF(printf("\ncrossSize = %d\n", crossSize)); + + for (;;) + { + if (!link) + { + link = (CMtDecBufLink *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); + if (!link) + { + finish = True; + // p->allocError_for_Read_BlockIndex = blockIndex; + isAllocError = True; + break; + } + link->next = NULL; + if (prev) + { + // static unsigned g_num = 0; + // printf("\n%6d : %x", ++g_num, (unsigned)(size_t)((Byte *)link - (Byte *)prev)); + prev->next = link; + } + else + t->inBuf = (void *)link; + } + + { + Byte *data = MTDEC__DATA_PTR_FROM_LINK(link); + Byte *parseData = data; + size_t size; + + if (crossSize != 0) + { + inDataSize = crossSize; + // inDataSize_Full = inDataSize; + inDataSize_Start = crossSize; + size = crossSize; + parseData = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; + PRF(printf("\ncross : crossStart = %7d crossEnd = %7d finish = %1d", + (int)p->crossStart, (int)p->crossEnd, (int)finish)); + } + else + { + size = p->inBufSize; + + res = FullRead(p->inStream, data, &size); + + // size = 10; // test + + inDataSize += size; + // inDataSize_Full = inDataSize; + if (!prev) + inDataSize_Start = size; + + p->readProcessed += size; + finish = (size != p->inBufSize); + if (finish) + p->readWasFinished = True; + + // res = E_INVALIDARG; // test + + if (res != SZ_OK) + { + // PRF(printf("\nRead error = %d\n", res)) + // we want to decode all data before error + p->readRes = res; + // p->readError_BlockIndex = blockIndex; + p->readWasFinished = True; + finish = True; + res = SZ_OK; + // break; + } + + if (inDataSize - inPrev >= MTDEC_ProgessStep) + { + res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); + if (res != SZ_OK || wasInterrupted) + break; + inPrev = inDataSize; + } + } + + { + CMtDecCallbackInfo parse; + + parse.startCall = (prev == NULL); + parse.src = parseData; + parse.srcSize = size; + parse.srcFinished = finish; + parse.canCreateNewThread = True; + + // PRF(printf("\nParse size = %d\n", (unsigned)size)) + + p->mtCallback->Parse(p->mtCallbackObject, t->index, &parse); + + needWrite = True; + canCreateNewThread = parse.canCreateNewThread; + + // printf("\n\n%12I64u %12I64u", (UInt64)p->mtProgress.totalInSize, (UInt64)p->mtProgress.totalOutSize); + + if ( + // parseRes != SZ_OK || + // inDataSize - (size - parse.srcSize) > p->inBlockMax + // || + parse.state == MTDEC_PARSE_OVERFLOW + // || wasInterrupted + ) + { + // Overflow or Parse error - switch from MT decoding to ST decoding + finish = True; + overflow = True; + + { + PRF(printf("\n Overflow")); + // PRF(printf("\nisBlockFinished = %d", (unsigned)parse.blockWasFinished)); + PRF(printf("\n inDataSize = %d", (unsigned)inDataSize)); + } + + if (crossSize != 0) + memcpy(data, parseData, size); + p->crossStart = 0; + p->crossEnd = 0; + break; + } + + if (crossSize != 0) + { + memcpy(data, parseData, parse.srcSize); + p->crossStart += parse.srcSize; + } + + if (parse.state != MTDEC_PARSE_CONTINUE || finish) + { + // we don't need to parse in current thread anymore + + if (parse.state == MTDEC_PARSE_END) + finish = True; + + needCode = True; + // p->crossFinished = finish; + + if (parse.srcSize == size) + { + // full parsed - no cross transfer + p->crossStart = 0; + p->crossEnd = 0; + break; + } + + if (parse.state == MTDEC_PARSE_END) + { + p->crossStart = 0; + p->crossEnd = 0; + + if (crossSize != 0) + memcpy(data + parse.srcSize, parseData + parse.srcSize, size - parse.srcSize); // we need all data + afterEndData_Size = size - parse.srcSize; + afterEndData = parseData + parse.srcSize; + + // we reduce data size to required bytes (parsed only) + inDataSize -= (size - parse.srcSize); + if (!prev) + inDataSize_Start = parse.srcSize; + break; + } + + { + // partial parsed - need cross transfer + if (crossSize != 0) + inDataSize = parse.srcSize; // it's only parsed now + else + { + // partial parsed - is not in initial cross block - we need to copy new data to cross block + Byte *cr = MtDec_GetCrossBuff(p); + if (!cr) + { + { + PRF(printf("\ncross alloc error error\n")); + // res = SZ_ERROR_MEM; + finish = True; + // p->allocError_for_Read_BlockIndex = blockIndex; + isAllocError = True; + break; + } + } + + { + size_t crSize = size - parse.srcSize; + inDataSize -= crSize; + p->crossEnd = crSize; + p->crossStart = 0; + memcpy(cr, parseData + parse.srcSize, crSize); + } + } + + // inDataSize_Full = inDataSize; + if (!prev) + inDataSize_Start = parse.srcSize; // it's partial size (parsed only) + + finish = False; + break; + } + } + + if (parse.srcSize != size) + { + res = SZ_ERROR_FAIL; + PRF(printf("\nfinished error SZ_ERROR_FAIL = %d\n", res)); + break; + } + } + } + + prev = link; + link = link->next; + + if (crossSize != 0) + { + crossSize = 0; + p->crossStart = 0; + p->crossEnd = 0; + } + } + } + + if (res == SZ_OK) + res = MtDec_GetError_Spec(p, blockIndex, &wasInterrupted); + } + + codeRes = SZ_OK; + + if (res == SZ_OK && needCode && !wasInterrupted) + { + codeRes = p->mtCallback->PreCode(p->mtCallbackObject, t->index); + if (codeRes != SZ_OK) + { + needCode = False; + finish = True; + // SZ_ERROR_MEM is expected error here. + // if (codeRes == SZ_ERROR_MEM) - we will try single-thread decoding later. + // if (codeRes != SZ_ERROR_MEM) - we can stop decoding or try single-thread decoding. + } + } + + if (res != SZ_OK || wasInterrupted) + finish = True; + + nextThread = NULL; + threadingErrorSRes = SZ_OK; + + if (!finish) + { + if (p->numStartedThreads < p->numStartedThreads_Limit && canCreateNewThread) + { + SRes res2 = MtDecThread_CreateAndStart(&p->threads[p->numStartedThreads]); + if (res2 == SZ_OK) + { + // if (p->numStartedThreads % 1000 == 0) PRF(printf("\n numStartedThreads=%d\n", p->numStartedThreads)); + p->numStartedThreads++; + } + else + { + PRF(printf("\nERROR: numStartedThreads=%d\n", p->numStartedThreads)); + if (p->numStartedThreads == 1) + { + // if only one thread is possible, we leave muti-threading code + finish = True; + needCode = False; + threadingErrorSRes = res2; + } + else + p->numStartedThreads_Limit = p->numStartedThreads; + } + } + + if (!finish) + { + unsigned nextIndex = t->index + 1; + nextThread = &p->threads[nextIndex >= p->numStartedThreads ? 0 : nextIndex]; + RINOK_THREAD(Event_Set(&nextThread->canRead)) + // We have started executing for new iteration (with next thread) + // And that next thread now is responsible for possible exit from decoding (threading_code) + } + } + + // each call of Event_Set(&nextThread->canRead) must be followed by call of Event_Set(&nextThread->canWrite) + // if ( !finish ) we must call Event_Set(&nextThread->canWrite) in any case + // if ( finish ) we switch to single-thread mode and there are 2 ways at the end of current iteration (current block): + // - if (needContinue) after Write(&needContinue), we restore decoding with new iteration + // - otherwise we stop decoding and exit from ThreadFunc2() + + // Don't change (finish) variable in the further code + + + // ---------- CODE ---------- + + inPrev = 0; + outPrev = 0; + inCodePos = 0; + outCodePos = 0; + + if (res == SZ_OK && needCode && codeRes == SZ_OK) + { + BoolInt isStartBlock = True; + CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; + + for (;;) + { + size_t inSize; + int stop; + + if (isStartBlock) + inSize = inDataSize_Start; + else + { + UInt64 rem = inDataSize - inCodePos; + inSize = p->inBufSize; + if (inSize > rem) + inSize = (size_t)rem; + } + + inCodePos += inSize; + stop = True; + + codeRes = p->mtCallback->Code(p->mtCallbackObject, t->index, + (const Byte *)MTDEC__DATA_PTR_FROM_LINK(link), inSize, + (inCodePos == inDataSize), // srcFinished + &inCodePos, &outCodePos, &stop); + + if (codeRes != SZ_OK) + { + PRF(printf("\nCode Interrupt error = %x\n", codeRes)); + // we interrupt only later blocks + MtDec_Interrupt(p, blockIndex); + break; + } + + if (stop || inCodePos == inDataSize) + break; + + { + const UInt64 inDelta = inCodePos - inPrev; + const UInt64 outDelta = outCodePos - outPrev; + if (inDelta >= MTDEC_ProgessStep || outDelta >= MTDEC_ProgessStep) + { + // Sleep(1); + res = MtDec_Progress_GetError_Spec(p, inDelta, outDelta, blockIndex, &wasInterrupted); + if (res != SZ_OK || wasInterrupted) + break; + inPrev = inCodePos; + outPrev = outCodePos; + } + } + + link = link->next; + isStartBlock = False; + } + } + + + // ---------- WRITE ---------- + + RINOK_THREAD(Event_Wait(&t->canWrite)); + + { + BoolInt isErrorMode = False; + BoolInt canRecode = True; + BoolInt needWriteToStream = needWrite; + + if (p->exitThread) return 0; // it's never executed in normal cases + + if (p->wasInterrupted) + wasInterrupted = True; + else + { + if (codeRes != SZ_OK) // || !needCode // check it !!! + { + p->wasInterrupted = True; + p->codeRes = codeRes; + if (codeRes == SZ_ERROR_MEM) + isAllocError = True; + } + + if (threadingErrorSRes) + { + p->wasInterrupted = True; + p->threadingErrorSRes = threadingErrorSRes; + needWriteToStream = False; + } + if (isAllocError) + { + p->wasInterrupted = True; + p->isAllocError = True; + needWriteToStream = False; + } + if (overflow) + { + p->wasInterrupted = True; + p->overflow = True; + needWriteToStream = False; + } + } + + if (needCode) + { + if (wasInterrupted) + { + inCodePos = 0; + outCodePos = 0; + } + { + const UInt64 inDelta = inCodePos - inPrev; + const UInt64 outDelta = outCodePos - outPrev; + // if (inDelta != 0 || outDelta != 0) + res = MtProgress_ProgressAdd(&p->mtProgress, inDelta, outDelta); + } + } + + needContinue = (!finish); + + // if (res == SZ_OK && needWrite && !wasInterrupted) + if (needWrite) + { + // p->inProcessed += inCodePos; + + res = p->mtCallback->Write(p->mtCallbackObject, t->index, + res == SZ_OK && needWriteToStream && !wasInterrupted, // needWrite + afterEndData, afterEndData_Size, + &needContinue, + &canRecode); + + // res= E_INVALIDARG; // for test + + PRF(printf("\nAfter Write needContinue = %d\n", (unsigned)needContinue)); + PRF(printf("\nprocessed = %d\n", (unsigned)p->inProcessed)); + + if (res != SZ_OK) + { + PRF(printf("\nWrite error = %d\n", res)); + isErrorMode = True; + p->wasInterrupted = True; + } + if (res != SZ_OK + || (!needContinue && !finish)) + { + PRF(printf("\nWrite Interrupt error = %x\n", res)); + MtDec_Interrupt(p, blockIndex); + } + } + + if (canRecode) + if (!needCode + || res != SZ_OK + || p->wasInterrupted + || codeRes != SZ_OK + || wasInterrupted + || p->numFilledThreads != 0 + || isErrorMode) + { + if (p->numFilledThreads == 0) + p->filledThreadStart = t->index; + if (inDataSize != 0 || !finish) + { + t->inDataSize_Start = inDataSize_Start; + t->inDataSize = inDataSize; + p->numFilledThreads++; + } + PRF(printf("\np->numFilledThreads = %d\n", p->numFilledThreads)); + PRF(printf("p->filledThreadStart = %d\n", p->filledThreadStart)); + } + + if (!finish) + { + RINOK_THREAD(Event_Set(&nextThread->canWrite)); + } + else + { + if (needContinue) + { + // we restore decoding with new iteration + RINOK_THREAD(Event_Set(&p->threads[0].canWrite)); + } + else + { + // we exit from decoding + if (t->index == 0) + return SZ_OK; + p->exitThread = True; + } + RINOK_THREAD(Event_Set(&p->threads[0].canRead)); + } + } + } +} + +#ifdef _WIN32 +#define USE_ALLOCA +#endif + +#ifdef USE_ALLOCA +#ifdef _WIN32 +#include +#else +#include +#endif +#endif + + +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc1(void *pp) +{ + WRes res; + + CMtDecThread *t = (CMtDecThread *)pp; + CMtDec *p; + + // fprintf(stdout, "\n%d = %p\n", t->index, &t); + + res = ThreadFunc2(t); + p = t->mtDec; + if (res == 0) + return p->exitThreadWRes; + { + // it's unexpected situation for some threading function error + if (p->exitThreadWRes == 0) + p->exitThreadWRes = res; + PRF(printf("\nthread exit error = %d\n", res)); + p->exitThread = True; + Event_Set(&p->threads[0].canRead); + Event_Set(&p->threads[0].canWrite); + MtProgress_SetError(&p->mtProgress, MY_SRes_HRESULT_FROM_WRes(res)); + } + return res; +} + +static MY_NO_INLINE THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp) +{ + CMtDecThread *t = (CMtDecThread *)pp; + + // fprintf(stderr, "\n%d = %p - before", t->index, &t); + #ifdef USE_ALLOCA + t->allocaPtr = alloca(t->index * 128); + #endif + return ThreadFunc1(pp); +} + + +int MtDec_PrepareRead(CMtDec *p) +{ + if (p->crossBlock && p->crossStart == p->crossEnd) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + + { + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + if (i > p->numStartedThreads + || p->numFilledThreads <= + (i >= p->filledThreadStart ? + i - p->filledThreadStart : + i + p->numStartedThreads - p->filledThreadStart)) + MtDecThread_FreeInBufs(&p->threads[i]); + } + + return (p->numFilledThreads != 0) || (p->crossStart != p->crossEnd); +} + + +const Byte *MtDec_Read(CMtDec *p, size_t *inLim) +{ + while (p->numFilledThreads != 0) + { + CMtDecThread *t = &p->threads[p->filledThreadStart]; + + if (*inLim != 0) + { + { + void *link = t->inBuf; + void *next = ((CMtDecBufLink *)link)->next; + ISzAlloc_Free(p->alloc, link); + t->inBuf = next; + } + + if (t->inDataSize == 0) + { + MtDecThread_FreeInBufs(t); + if (--p->numFilledThreads == 0) + break; + if (++p->filledThreadStart == p->numStartedThreads) + p->filledThreadStart = 0; + t = &p->threads[p->filledThreadStart]; + } + } + + { + size_t lim = t->inDataSize_Start; + if (lim != 0) + t->inDataSize_Start = 0; + else + { + UInt64 rem = t->inDataSize; + lim = p->inBufSize; + if (lim > rem) + lim = (size_t)rem; + } + t->inDataSize -= lim; + *inLim = lim; + return (const Byte *)MTDEC__DATA_PTR_FROM_LINK(t->inBuf); + } + } + + { + size_t crossSize = p->crossEnd - p->crossStart; + if (crossSize != 0) + { + const Byte *data = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; + *inLim = crossSize; + p->crossStart = 0; + p->crossEnd = 0; + return data; + } + *inLim = 0; + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + return NULL; + } +} + + +void MtDec_Construct(CMtDec *p) +{ + unsigned i; + + p->inBufSize = (size_t)1 << 18; + + p->numThreadsMax = 0; + + p->inStream = NULL; + + // p->inData = NULL; + // p->inDataSize = 0; + + p->crossBlock = NULL; + p->crossStart = 0; + p->crossEnd = 0; + + p->numFilledThreads = 0; + + p->progress = NULL; + p->alloc = NULL; + + p->mtCallback = NULL; + p->mtCallbackObject = NULL; + + p->allocatedBufsSize = 0; + + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CMtDecThread *t = &p->threads[i]; + t->mtDec = p; + t->index = i; + t->inBuf = NULL; + Event_Construct(&t->canRead); + Event_Construct(&t->canWrite); + Thread_Construct(&t->thread); + } + + // Event_Construct(&p->finishedEvent); + + CriticalSection_Init(&p->mtProgress.cs); +} + + +static void MtDec_Free(CMtDec *p) +{ + unsigned i; + + p->exitThread = True; + + for (i = 0; i < MTDEC__THREADS_MAX; i++) + MtDecThread_Destruct(&p->threads[i]); + + // Event_Close(&p->finishedEvent); + + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } +} + + +void MtDec_Destruct(CMtDec *p) +{ + MtDec_Free(p); + + CriticalSection_Delete(&p->mtProgress.cs); +} + + +SRes MtDec_Code(CMtDec *p) +{ + unsigned i; + + p->inProcessed = 0; + + p->blockIndex = 1; // it must be larger than not_defined index (0) + p->isAllocError = False; + p->overflow = False; + p->threadingErrorSRes = SZ_OK; + + p->needContinue = True; + + p->readWasFinished = False; + p->needInterrupt = False; + p->interruptIndex = (UInt64)(Int64)-1; + + p->readProcessed = 0; + p->readRes = SZ_OK; + p->codeRes = SZ_OK; + p->wasInterrupted = False; + + p->crossStart = 0; + p->crossEnd = 0; + + p->filledThreadStart = 0; + p->numFilledThreads = 0; + + { + unsigned numThreads = p->numThreadsMax; + if (numThreads > MTDEC__THREADS_MAX) + numThreads = MTDEC__THREADS_MAX; + p->numStartedThreads_Limit = numThreads; + p->numStartedThreads = 0; + } + + if (p->inBufSize != p->allocatedBufsSize) + { + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CMtDecThread *t = &p->threads[i]; + if (t->inBuf) + MtDecThread_FreeInBufs(t); + } + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + + p->allocatedBufsSize = p->inBufSize; + } + + MtProgress_Init(&p->mtProgress, p->progress); + + // RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->finishedEvent)); + p->exitThread = False; + p->exitThreadWRes = 0; + + { + WRes wres; + WRes sres; + CMtDecThread *nextThread = &p->threads[p->numStartedThreads++]; + // wres = MtDecThread_CreateAndStart(nextThread); + wres = MtDecThread_CreateEvents(nextThread); + if (wres == 0) { wres = Event_Set(&nextThread->canWrite); + if (wres == 0) { wres = Event_Set(&nextThread->canRead); + if (wres == 0) { wres = ThreadFunc(nextThread); + if (wres != 0) + { + p->needContinue = False; + MtDec_CloseThreads(p); + }}}} + + // wres = 17; // for test + // wres = Event_Wait(&p->finishedEvent); + + sres = MY_SRes_HRESULT_FROM_WRes(wres); + + if (sres != 0) + p->threadingErrorSRes = sres; + + if ( + // wres == 0 + // wres != 0 + // || p->mtc.codeRes == SZ_ERROR_MEM + p->isAllocError + || p->threadingErrorSRes != SZ_OK + || p->overflow) + { + // p->needContinue = True; + } + else + p->needContinue = False; + + if (p->needContinue) + return SZ_OK; + + // if (sres != SZ_OK) + return sres; + // return E_FAIL; + } +} + +#endif diff --git a/lzma/MtDec.h b/lzma/MtDec.h new file mode 100644 index 0000000..9864cc8 --- /dev/null +++ b/lzma/MtDec.h @@ -0,0 +1,201 @@ +/* MtDec.h -- Multi-thread Decoder +2018-07-04 : Igor Pavlov : Public domain */ + +#ifndef __MT_DEC_H +#define __MT_DEC_H + +#include "7zTypes.h" + +#ifndef _7ZIP_ST +#include "Threads.h" +#endif + +EXTERN_C_BEGIN + +#ifndef _7ZIP_ST + +#ifndef _7ZIP_ST + #define MTDEC__THREADS_MAX 32 +#else + #define MTDEC__THREADS_MAX 1 +#endif + + +typedef struct +{ + ICompressProgress *progress; + SRes res; + UInt64 totalInSize; + UInt64 totalOutSize; + CCriticalSection cs; +} CMtProgress; + +void MtProgress_Init(CMtProgress *p, ICompressProgress *progress); +SRes MtProgress_Progress_ST(CMtProgress *p); +SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize); +SRes MtProgress_GetError(CMtProgress *p); +void MtProgress_SetError(CMtProgress *p, SRes res); + +struct _CMtDec; + +typedef struct +{ + struct _CMtDec *mtDec; + unsigned index; + void *inBuf; + + size_t inDataSize_Start; // size of input data in start block + UInt64 inDataSize; // total size of input data in all blocks + + CThread thread; + CAutoResetEvent canRead; + CAutoResetEvent canWrite; + void *allocaPtr; +} CMtDecThread; + +void MtDecThread_FreeInBufs(CMtDecThread *t); + + +typedef enum +{ + MTDEC_PARSE_CONTINUE, // continue this block with more input data + MTDEC_PARSE_OVERFLOW, // MT buffers overflow, need switch to single-thread + MTDEC_PARSE_NEW, // new block + MTDEC_PARSE_END // end of block threading. But we still can return to threading after Write(&needContinue) +} EMtDecParseState; + +typedef struct +{ + // in + int startCall; + const Byte *src; + size_t srcSize; + // in : (srcSize == 0) is allowed + // out : it's allowed to return less that actually was used ? + int srcFinished; + + // out + EMtDecParseState state; + BoolInt canCreateNewThread; + UInt64 outPos; // check it (size_t) +} CMtDecCallbackInfo; + + +typedef struct +{ + void (*Parse)(void *p, unsigned coderIndex, CMtDecCallbackInfo *ci); + + // PreCode() and Code(): + // (SRes_return_result != SZ_OK) means stop decoding, no need another blocks + SRes (*PreCode)(void *p, unsigned coderIndex); + SRes (*Code)(void *p, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop); + // stop - means stop another Code calls + + + /* Write() must be called, if Parse() was called + set (needWrite) if + { + && (was not interrupted by progress) + && (was not interrupted in previous block) + } + + out: + if (*needContinue), decoder still need to continue decoding with new iteration, + even after MTDEC_PARSE_END + if (*canRecode), we didn't flush current block data, so we still can decode current block later. + */ + SRes (*Write)(void *p, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, + // int srcFinished, + BoolInt *needContinue, + BoolInt *canRecode); +} IMtDecCallback; + + + +typedef struct _CMtDec +{ + /* input variables */ + + size_t inBufSize; /* size of input block */ + unsigned numThreadsMax; + // size_t inBlockMax; + unsigned numThreadsMax_2; + + ISeqInStream *inStream; + // const Byte *inData; + // size_t inDataSize; + + ICompressProgress *progress; + ISzAllocPtr alloc; + + IMtDecCallback *mtCallback; + void *mtCallbackObject; + + + /* internal variables */ + + size_t allocatedBufsSize; + + BoolInt exitThread; + WRes exitThreadWRes; + + UInt64 blockIndex; + BoolInt isAllocError; + BoolInt overflow; + SRes threadingErrorSRes; + + BoolInt needContinue; + + // CAutoResetEvent finishedEvent; + + SRes readRes; + SRes codeRes; + + BoolInt wasInterrupted; + + unsigned numStartedThreads_Limit; + unsigned numStartedThreads; + + Byte *crossBlock; + size_t crossStart; + size_t crossEnd; + UInt64 readProcessed; + BoolInt readWasFinished; + UInt64 inProcessed; + + unsigned filledThreadStart; + unsigned numFilledThreads; + + #ifndef _7ZIP_ST + BoolInt needInterrupt; + UInt64 interruptIndex; + CMtProgress mtProgress; + CMtDecThread threads[MTDEC__THREADS_MAX]; + #endif +} CMtDec; + + +void MtDec_Construct(CMtDec *p); +void MtDec_Destruct(CMtDec *p); + +/* +MtDec_Code() returns: + SZ_OK - in most cases + MY_SRes_HRESULT_FROM_WRes(WRes_error) - in case of unexpected error in threading function +*/ + +SRes MtDec_Code(CMtDec *p); +Byte *MtDec_GetCrossBuff(CMtDec *p); + +int MtDec_PrepareRead(CMtDec *p); +const Byte *MtDec_Read(CMtDec *p, size_t *inLim); + +#endif + +EXTERN_C_END + +#endif diff --git a/lzma/Ppmd.h b/lzma/Ppmd.h new file mode 100644 index 0000000..4b99415 --- /dev/null +++ b/lzma/Ppmd.h @@ -0,0 +1,85 @@ +/* Ppmd.h -- PPMD codec common code +2017-04-03 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#ifndef __PPMD_H +#define __PPMD_H + +#include "CpuArch.h" + +EXTERN_C_BEGIN + +#ifdef MY_CPU_32BIT + #define PPMD_32BIT +#endif + +#define PPMD_INT_BITS 7 +#define PPMD_PERIOD_BITS 7 +#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) + +#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) +#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) +#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) +#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) + +#define PPMD_N1 4 +#define PPMD_N2 4 +#define PPMD_N3 4 +#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) +#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) + +#pragma pack(push, 1) +/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ + +/* SEE-contexts for PPM-contexts with masked symbols */ +typedef struct +{ + UInt16 Summ; /* Freq */ + Byte Shift; /* Speed of Freq change; low Shift is for fast change */ + Byte Count; /* Count to next change of Shift */ +} CPpmd_See; + +#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ + { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } + +typedef struct +{ + Byte Symbol; + Byte Freq; + UInt16 SuccessorLow; + UInt16 SuccessorHigh; +} CPpmd_State; + +#pragma pack(pop) + +typedef + #ifdef PPMD_32BIT + CPpmd_State * + #else + UInt32 + #endif + CPpmd_State_Ref; + +typedef + #ifdef PPMD_32BIT + void * + #else + UInt32 + #endif + CPpmd_Void_Ref; + +typedef + #ifdef PPMD_32BIT + Byte * + #else + UInt32 + #endif + CPpmd_Byte_Ref; + +#define PPMD_SetAllBitsIn256Bytes(p) \ + { size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \ + p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }} + +EXTERN_C_END + +#endif diff --git a/lzma/Ppmd7.c b/lzma/Ppmd7.c new file mode 100644 index 0000000..80e7de9 --- /dev/null +++ b/lzma/Ppmd7.c @@ -0,0 +1,712 @@ +/* Ppmd7.c -- PPMdH codec +2018-07-04 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include + +#include "Ppmd7.h" + +const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1]) +#define I2U(indx) (p->Indx2Units[indx]) + +#ifdef PPMD_32BIT + #define REF(ptr) (ptr) +#else + #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) +#endif + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +#define STATS(ctx) Ppmd7_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd7_Context * CTX_PTR; + +struct CPpmd7_Node_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Node_ * + #else + UInt32 + #endif + CPpmd7_Node_Ref; + +typedef struct CPpmd7_Node_ +{ + UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ + UInt16 NU; + CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ + CPpmd7_Node_Ref Prev; +} CPpmd7_Node; + +#ifdef PPMD_32BIT + #define NODE(ptr) (ptr) +#else + #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) +#endif + +void Ppmd7_Construct(CPpmd7 *p) +{ + unsigned i, k, m; + + p->Base = 0; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while (--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 3; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 256; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 2; + } + + memset(p->HB2Flag, 0, 0x40); + memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); +} + +void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; +} + +BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc) +{ + if (!p->Base || p->Size != size) + { + size_t size2; + Ppmd7_Free(p, alloc); + size2 = 0 + #ifndef PPMD_32BIT + + UNIT_SIZE + #endif + ; + p->AlignOffset = + #ifdef PPMD_32BIT + (4 - size) & 3; + #else + 4 - (size & 3); + #endif + if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size + size2)) == 0) + return False; + p->Size = size; + } + return True; +} + +static void InsertNode(CPpmd7 *p, void *node, unsigned indx) +{ + *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; + p->FreeList[indx] = REF(node); +} + +static void *RemoveNode(CPpmd7 *p, unsigned indx) +{ + CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); + p->FreeList[indx] = *node; + return node; +} + +static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); +} + +static void GlueFreeBlocks(CPpmd7 *p) +{ + #ifdef PPMD_32BIT + CPpmd7_Node headItem; + CPpmd7_Node_Ref head = &headItem; + #else + CPpmd7_Node_Ref head = p->AlignOffset + p->Size; + #endif + + CPpmd7_Node_Ref n = head; + unsigned i; + + p->GlueCount = 255; + + /* create doubly-linked list of free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + UInt16 nu = I2U(i); + CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd7_Node *node = NODE(next); + node->Next = n; + n = NODE(n)->Prev = next; + next = *(const CPpmd7_Node_Ref *)node; + node->Stamp = 0; + node->NU = (UInt16)nu; + } + } + NODE(head)->Stamp = 1; + NODE(head)->Next = n; + NODE(n)->Prev = head; + if (p->LoUnit != p->HiUnit) + ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; + + /* Glue free blocks */ + while (n != head) + { + CPpmd7_Node *node = NODE(n); + UInt32 nu = (UInt32)node->NU; + for (;;) + { + CPpmd7_Node *node2 = NODE(n) + nu; + nu += node2->NU; + if (node2->Stamp != 0 || nu >= 0x10000) + break; + NODE(node2->Prev)->Next = node2->Next; + NODE(node2->Next)->Prev = node2->Prev; + node->NU = (UInt16)nu; + } + n = node->Next; + } + + /* Fill lists of free blocks */ + for (n = NODE(head)->Next; n != head;) + { + CPpmd7_Node *node = NODE(n); + unsigned nu; + CPpmd7_Node_Ref next = node->Next; + for (nu = node->NU; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + n = next; + } +} + +static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) +{ + unsigned i; + void *retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; +} + +static void *AllocUnits(CPpmd7 *p, unsigned indx) +{ + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void *retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); +} + +#define MyMem12Cpy(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ + do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while (--n); } + +static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + +#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) + +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); +} + +static void RestartModel(CPpmd7 *p) +{ + unsigned i, k, m; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + p->Text = p->Base + p->AlignOffset; + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 256; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State *s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + for (i = 0; i < 128; i++) + for (k = 0; k < 8; k++) + { + UInt16 *dest = p->BinSumm[i] + k; + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); + for (m = 0; m < 64; m += 8) + dest[m] = val; + } + + for (i = 0; i < 25; i++) + for (k = 0; k < 16; k++) + { + CPpmd_See *s = &p->See[i][k]; + s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 4; + } +} + +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) +{ + p->MaxOrder = maxOrder; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ +} + +static CTX_PTR CreateSuccessors(CPpmd7 *p, BoolInt skip) +{ + CPpmd_State upState; + CTX_PTR c = p->MinContext; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + CPpmd_State *ps[PPMD7_MAX_ORDER]; + unsigned numPs = 0; + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + if (c->NumStats != 1) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + } + else + s = ONE_STATE(c); + successor = SUCCESSOR(s); + if (successor != upBranch) + { + c = CTX(successor); + if (numPs == 0) + return c; + break; + } + ps[numPs++] = s; + } + + upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + + if (c->NumStats == 1) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + } + + do + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 1; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + +static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + +static void UpdateModel(CPpmd7 *p) +{ + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns; + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 1) + { + CPpmd_State *s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + CPpmd_State *s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + if (p->OrderFall == 0) + { + p->MinContext = p->MaxContext = CreateSuccessors(p, True); + if (p->MinContext == 0) + { + RestartModel(p); + return; + } + SetSuccessor(p->FoundState, REF(p->MinContext)); + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RestartModel(p); + return; + } + + if (fSuccessor) + { + if (fSuccessor <= successor) + { + CTX_PTR cs = CreateSuccessors(p, False); + if (cs == NULL) + { + RestartModel(p); + return; + } + fSuccessor = REF(cs); + } + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + } + else + { + SetSuccessor(p->FoundState, successor); + fSuccessor = REF(p->MinContext); + } + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); + + for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + /* Expand for one UNIT */ + unsigned oldNU = ns1 >> 1; + unsigned i = U2I(oldNU); + if (i != U2I((size_t)oldNU + 1)) + { + void *ptr = AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RestartModel(p); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); + } + else + { + CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); + if (!s) + { + RestartModel(p); + return; + } + *s = *ONE_STATE(c); + c->Stats = REF(s); + if (s->Freq < MAX_FREQ / 4 - 1) + s->Freq <<= 1; + else + s->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); + } + cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 3; + } + else + { + cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State *s = STATS(c) + ns1; + SetSuccessor(s, successor); + s->Symbol = p->FoundState->Symbol; + s->Freq = (Byte)cf; + c->NumStats = (UInt16)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); +} + +static void Rescale(CPpmd7 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats - 1; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State *s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 1) + { + CPpmd_State tmp = *stats; + do + { + tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); + escFreq >>= 1; + } + while (escFreq > 1); + InsertNode(p, stats, U2I(((numStats + 1) >> 1))); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 1) >> 1; + n1 = (p->MinContext->NumStats + 1) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->FoundState = STATS(p->MinContext); +} + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) +{ + CPpmd_See *see; + unsigned nonMasked = p->MinContext->NumStats - numMasked; + if (p->MinContext->NumStats != 256) + { + see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] + + (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + + 2 * (unsigned)(p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + + 4 * (unsigned)(numMasked > nonMasked) + + p->HiBitsFlag; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + +static void NextContext(CPpmd7 *p) +{ + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte *)c > p->Text) + p->MinContext = p->MaxContext = c; + else + UpdateModel(p); +} + +void Ppmd7_Update1(CPpmd7 *p) +{ + CPpmd_State *s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); +} + +void Ppmd7_Update1_0(CPpmd7 *p) +{ + p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); +} + +void Ppmd7_UpdateBin(CPpmd7 *p) +{ + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +void Ppmd7_Update2(CPpmd7 *p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); +} diff --git a/lzma/Ppmd7.h b/lzma/Ppmd7.h new file mode 100644 index 0000000..cce93f1 --- /dev/null +++ b/lzma/Ppmd7.h @@ -0,0 +1,142 @@ +/* Ppmd7.h -- PPMdH compression codec +2018-07-04 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +/* This code supports virtual RangeDecoder and includes the implementation +of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. +If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ + +#ifndef __PPMD7_H +#define __PPMD7_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD7_MIN_ORDER 2 +#define PPMD7_MAX_ORDER 64 + +#define PPMD7_MIN_MEM_SIZE (1 << 11) +#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) + +struct CPpmd7_Context_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Context_ * + #else + UInt32 + #endif + CPpmd7_Context_Ref; + +typedef struct CPpmd7_Context_ +{ + UInt16 NumStats; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd7_Context_Ref Suffix; +} CPpmd7_Context; + +#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) + +typedef struct +{ + CPpmd7_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; + + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + CPpmd_See DummySee, See[25][16]; + UInt16 BinSumm[128][64]; +} CPpmd7; + +void Ppmd7_Construct(CPpmd7 *p); +BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc); +void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc); +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); +#define Ppmd7_WasAllocated(p) ((p)->Base != NULL) + + +/* ---------- Internal Functions ---------- */ + +extern const Byte PPMD7_kExpEscape[16]; + +#ifdef PPMD_32BIT + #define Ppmd7_GetPtr(p, ptr) (ptr) + #define Ppmd7_GetContext(p, ptr) (ptr) + #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) +#else + #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) + #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) +#endif + +void Ppmd7_Update1(CPpmd7 *p); +void Ppmd7_Update1_0(CPpmd7 *p); +void Ppmd7_Update2(CPpmd7 *p); +void Ppmd7_UpdateBin(CPpmd7 *p); + +#define Ppmd7_GetBinSumm(p) \ + &p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ + p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ + (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ + 2 * p->HB2Flag[(unsigned)Ppmd7Context_OneState(p->MinContext)->Symbol] + \ + ((p->RunLength >> 26) & 0x20)] + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); + + +/* ---------- Decode ---------- */ + +typedef struct IPpmd7_RangeDec IPpmd7_RangeDec; + +struct IPpmd7_RangeDec +{ + UInt32 (*GetThreshold)(const IPpmd7_RangeDec *p, UInt32 total); + void (*Decode)(const IPpmd7_RangeDec *p, UInt32 start, UInt32 size); + UInt32 (*DecodeBit)(const IPpmd7_RangeDec *p, UInt32 size0); +}; + +typedef struct +{ + IPpmd7_RangeDec vt; + UInt32 Range; + UInt32 Code; + IByteIn *Stream; +} CPpmd7z_RangeDec; + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p); +BoolInt Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p); +#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) + +int Ppmd7_DecodeSymbol(CPpmd7 *p, const IPpmd7_RangeDec *rc); + + +/* ---------- Encode ---------- */ + +typedef struct +{ + UInt64 Low; + UInt32 Range; + Byte Cache; + UInt64 CacheSize; + IByteOut *Stream; +} CPpmd7z_RangeEnc; + +void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p); +void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p); + +void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); + +EXTERN_C_END + +#endif diff --git a/lzma/Ppmd7Dec.c b/lzma/Ppmd7Dec.c new file mode 100644 index 0000000..2026407 --- /dev/null +++ b/lzma/Ppmd7Dec.c @@ -0,0 +1,191 @@ +/* Ppmd7Dec.c -- PPMdH Decoder +2018-07-04 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTopValue (1 << 24) + +BoolInt Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) +{ + unsigned i; + p->Code = 0; + p->Range = 0xFFFFFFFF; + if (IByteIn_Read(p->Stream) != 0) + return False; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | IByteIn_Read(p->Stream); + return (p->Code < 0xFFFFFFFF); +} + +#define GET_Ppmd7z_RangeDec CPpmd7z_RangeDec *p = CONTAINER_FROM_VTBL(pp, CPpmd7z_RangeDec, vt); + +static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total) +{ + GET_Ppmd7z_RangeDec + return p->Code / (p->Range /= total); +} + +static void Range_Normalize(CPpmd7z_RangeDec *p) +{ + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | IByteIn_Read(p->Stream); + p->Range <<= 8; + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | IByteIn_Read(p->Stream); + p->Range <<= 8; + } + } +} + +static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size) +{ + GET_Ppmd7z_RangeDec + p->Code -= start * p->Range; + p->Range *= size; + Range_Normalize(p); +} + +static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0) +{ + GET_Ppmd7z_RangeDec + UInt32 newBound = (p->Range >> 14) * size0; + UInt32 symbol; + if (p->Code < newBound) + { + symbol = 0; + p->Range = newBound; + } + else + { + symbol = 1; + p->Code -= newBound; + p->Range -= newBound; + } + Range_Normalize(p); + return symbol; +} + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) +{ + p->vt.GetThreshold = Range_GetThreshold; + p->vt.Decode = Range_Decode; + p->vt.DecodeBit = Range_DecodeBit; +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +int Ppmd7_DecodeSymbol(CPpmd7 *p, const IPpmd7_RangeDec *rc) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + rc->Decode(rc, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats - 1; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + if (rc->DecodeBit(rc, *prob) == 0) + { + Byte symbol; + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + Ppmd7_UpdateBin(p); + return symbol; + } + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See *see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd7_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = rc->GetThreshold(rc, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State **pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + rc->Decode(rc, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + } +} diff --git a/lzma/Ppmd7Enc.c b/lzma/Ppmd7Enc.c new file mode 100644 index 0000000..a74d300 --- /dev/null +++ b/lzma/Ppmd7Enc.c @@ -0,0 +1,187 @@ +/* Ppmd7Enc.c -- PPMdH Encoder +2017-04-03 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTopValue (1 << 24) + +void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p) +{ + p->Low = 0; + p->Range = 0xFFFFFFFF; + p->Cache = 0; + p->CacheSize = 1; +} + +static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p) +{ + if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0) + { + Byte temp = p->Cache; + do + { + IByteOut_Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32))); + temp = 0xFF; + } + while (--p->CacheSize != 0); + p->Cache = (Byte)((UInt32)p->Low >> 24); + } + p->CacheSize++; + p->Low = (UInt32)p->Low << 8; +} + +static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total) +{ + p->Low += start * (p->Range /= total); + p->Range *= size; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0) +{ + p->Range = (p->Range >> 14) * size0; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0) +{ + UInt32 newBound = (p->Range >> 14) * size0; + p->Low += newBound; + p->Range -= newBound; + while (p->Range < kTopValue) + { + p->Range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p) +{ + unsigned i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + UInt32 sum; + unsigned i; + if (s->Symbol == symbol) + { + RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd7_Update1_0(p); + return; + } + p->PrevSuccess = 0; + sum = s->Freq; + i = p->MinContext->NumStats - 1; + do + { + if ((++s)->Symbol == symbol) + { + RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq); + p->FoundState = s; + Ppmd7_Update1(p); + return; + } + sum += s->Freq; + } + while (--i); + + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); + if (s->Symbol == symbol) + { + RangeEnc_EncodeBit_0(rc, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + p->FoundState = s; + Ppmd7_UpdateBin(p); + return; + } + else + { + RangeEnc_EncodeBit_1(rc, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + p->PrevSuccess = 0; + } + } + for (;;) + { + UInt32 escFreq; + CPpmd_See *see; + CPpmd_State *s; + UInt32 sum; + unsigned i, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return; /* EndMarker (symbol = -1) */ + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + + see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq); + s = Ppmd7_GetStats(p, p->MinContext); + sum = 0; + i = p->MinContext->NumStats; + do + { + int cur = s->Symbol; + if (cur == symbol) + { + UInt32 low = sum; + CPpmd_State *s1 = s; + do + { + sum += (s->Freq & (int)(MASK(s->Symbol))); + s++; + } + while (--i); + RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq); + Ppmd_See_Update(see); + p->FoundState = s1; + Ppmd7_Update2(p); + return; + } + sum += (s->Freq & (int)(MASK(cur))); + MASK(cur) = 0; + s++; + } + while (--i); + + RangeEnc_Encode(rc, sum, escFreq, sum + escFreq); + see->Summ = (UInt16)(see->Summ + sum + escFreq); + } +} diff --git a/lzma/Precomp.h b/lzma/Precomp.h new file mode 100644 index 0000000..edb5814 --- /dev/null +++ b/lzma/Precomp.h @@ -0,0 +1,10 @@ +/* Precomp.h -- StdAfx +2013-11-12 : Igor Pavlov : Public domain */ + +#ifndef __7Z_PRECOMP_H +#define __7Z_PRECOMP_H + +#include "Compiler.h" +/* #include "7zTypes.h" */ + +#endif diff --git a/lzma/RotateDefs.h b/lzma/RotateDefs.h new file mode 100644 index 0000000..6c790e7 --- /dev/null +++ b/lzma/RotateDefs.h @@ -0,0 +1,30 @@ +/* RotateDefs.h -- Rotate functions +2015-03-25 : Igor Pavlov : Public domain */ + +#ifndef __ROTATE_DEFS_H +#define __ROTATE_DEFS_H + +#ifdef _MSC_VER + +#include + +/* don't use _rotl with MINGW. It can insert slow call to function. */ + +/* #if (_MSC_VER >= 1200) */ +#pragma intrinsic(_rotl) +#pragma intrinsic(_rotr) +/* #endif */ + +#define rotlFixed(x, n) _rotl((x), (n)) +#define rotrFixed(x, n) _rotr((x), (n)) + +#else + +/* new compilers can translate these macros to fast commands. */ + +#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) + +#endif + +#endif diff --git a/lzma/Sha256.c b/lzma/Sha256.c new file mode 100644 index 0000000..90994e5 --- /dev/null +++ b/lzma/Sha256.c @@ -0,0 +1,248 @@ +/* Crypto/Sha256.c -- SHA-256 Hash +2017-04-03 : Igor Pavlov : Public domain +This code is based on public domain code from Wei Dai's Crypto++ library. */ + +#include "Precomp.h" + +#include + +#include "CpuArch.h" +#include "RotateDefs.h" +#include "Sha256.h" + +/* define it for speed optimization */ +#ifndef _SFX +#define _SHA256_UNROLL +#define _SHA256_UNROLL2 +#endif + +/* #define _SHA256_UNROLL2 */ + +void Sha256_Init(CSha256 *p) +{ + p->state[0] = 0x6a09e667; + p->state[1] = 0xbb67ae85; + p->state[2] = 0x3c6ef372; + p->state[3] = 0xa54ff53a; + p->state[4] = 0x510e527f; + p->state[5] = 0x9b05688c; + p->state[6] = 0x1f83d9ab; + p->state[7] = 0x5be0cd19; + p->count = 0; +} + +#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22)) +#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25)) +#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) +#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10)) + +#define blk0(i) (W[i]) +#define blk2(i) (W[i] += s1(W[((i)-2)&15]) + W[((i)-7)&15] + s0(W[((i)-15)&15])) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) ((x&y)|(z&(x|y))) + +#ifdef _SHA256_UNROLL2 + +#define R(a,b,c,d,e,f,g,h, i) \ + h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + (j ? blk2(i) : blk0(i)); \ + d += h; \ + h += S0(a) + Maj(a, b, c) + +#define RX_8(i) \ + R(a,b,c,d,e,f,g,h, i); \ + R(h,a,b,c,d,e,f,g, i+1); \ + R(g,h,a,b,c,d,e,f, i+2); \ + R(f,g,h,a,b,c,d,e, i+3); \ + R(e,f,g,h,a,b,c,d, i+4); \ + R(d,e,f,g,h,a,b,c, i+5); \ + R(c,d,e,f,g,h,a,b, i+6); \ + R(b,c,d,e,f,g,h,a, i+7) + +#define RX_16 RX_8(0); RX_8(8); + +#else + +#define a(i) T[(0-(i))&7] +#define b(i) T[(1-(i))&7] +#define c(i) T[(2-(i))&7] +#define d(i) T[(3-(i))&7] +#define e(i) T[(4-(i))&7] +#define f(i) T[(5-(i))&7] +#define g(i) T[(6-(i))&7] +#define h(i) T[(7-(i))&7] + +#define R(i) \ + h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[(i)+(size_t)(j)] + (j ? blk2(i) : blk0(i)); \ + d(i) += h(i); \ + h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) \ + +#ifdef _SHA256_UNROLL + +#define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7); +#define RX_16 RX_8(0); RX_8(8); + +#else + +#define RX_16 unsigned i; for (i = 0; i < 16; i++) { R(i); } + +#endif + +#endif + +static const UInt32 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 +}; + +static void Sha256_WriteByteBlock(CSha256 *p) +{ + UInt32 W[16]; + unsigned j; + UInt32 *state; + + #ifdef _SHA256_UNROLL2 + UInt32 a,b,c,d,e,f,g,h; + #else + UInt32 T[8]; + #endif + + for (j = 0; j < 16; j += 4) + { + const Byte *ccc = p->buffer + j * 4; + W[j ] = GetBe32(ccc); + W[j + 1] = GetBe32(ccc + 4); + W[j + 2] = GetBe32(ccc + 8); + W[j + 3] = GetBe32(ccc + 12); + } + + state = p->state; + + #ifdef _SHA256_UNROLL2 + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; + #else + for (j = 0; j < 8; j++) + T[j] = state[j]; + #endif + + for (j = 0; j < 64; j += 16) + { + RX_16 + } + + #ifdef _SHA256_UNROLL2 + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; + #else + for (j = 0; j < 8; j++) + state[j] += T[j]; + #endif + + /* Wipe variables */ + /* memset(W, 0, sizeof(W)); */ + /* memset(T, 0, sizeof(T)); */ +} + +#undef S0 +#undef S1 +#undef s0 +#undef s1 + +void Sha256_Update(CSha256 *p, const Byte *data, size_t size) +{ + if (size == 0) + return; + + { + unsigned pos = (unsigned)p->count & 0x3F; + unsigned num; + + p->count += size; + + num = 64 - pos; + if (num > size) + { + memcpy(p->buffer + pos, data, size); + return; + } + + size -= num; + memcpy(p->buffer + pos, data, num); + data += num; + } + + for (;;) + { + Sha256_WriteByteBlock(p); + if (size < 64) + break; + size -= 64; + memcpy(p->buffer, data, 64); + data += 64; + } + + if (size != 0) + memcpy(p->buffer, data, size); +} + +void Sha256_Final(CSha256 *p, Byte *digest) +{ + unsigned pos = (unsigned)p->count & 0x3F; + unsigned i; + + p->buffer[pos++] = 0x80; + + while (pos != (64 - 8)) + { + pos &= 0x3F; + if (pos == 0) + Sha256_WriteByteBlock(p); + p->buffer[pos++] = 0; + } + + { + UInt64 numBits = (p->count << 3); + SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32)); + SetBe32(p->buffer + 64 - 4, (UInt32)(numBits)); + } + + Sha256_WriteByteBlock(p); + + for (i = 0; i < 8; i += 2) + { + UInt32 v0 = p->state[i]; + UInt32 v1 = p->state[i + 1]; + SetBe32(digest , v0); + SetBe32(digest + 4, v1); + digest += 8; + } + + Sha256_Init(p); +} diff --git a/lzma/Sha256.h b/lzma/Sha256.h new file mode 100644 index 0000000..7f17ccf --- /dev/null +++ b/lzma/Sha256.h @@ -0,0 +1,26 @@ +/* Sha256.h -- SHA-256 Hash +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __CRYPTO_SHA256_H +#define __CRYPTO_SHA256_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define SHA256_DIGEST_SIZE 32 + +typedef struct +{ + UInt32 state[8]; + UInt64 count; + Byte buffer[64]; +} CSha256; + +void Sha256_Init(CSha256 *p); +void Sha256_Update(CSha256 *p, const Byte *data, size_t size); +void Sha256_Final(CSha256 *p, Byte *digest); + +EXTERN_C_END + +#endif diff --git a/lzma/Sort.c b/lzma/Sort.c new file mode 100644 index 0000000..73dcbf0 --- /dev/null +++ b/lzma/Sort.c @@ -0,0 +1,141 @@ +/* Sort.c -- Sort functions +2014-04-05 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Sort.h" + +#define HeapSortDown(p, k, size, temp) \ + { for (;;) { \ + size_t s = (k << 1); \ + if (s > size) break; \ + if (s < size && p[s + 1] > p[s]) s++; \ + if (temp >= p[s]) break; \ + p[k] = p[s]; k = s; \ + } p[k] = temp; } + +void HeapSort(UInt32 *p, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt32 temp = p[i]; + size_t k = i; + HeapSortDown(p, k, size, temp) + } + while (--i != 0); + } + /* + do + { + size_t k = 1; + UInt32 temp = p[size]; + p[size--] = p[1]; + HeapSortDown(p, k, size, temp) + } + while (size > 1); + */ + while (size > 3) + { + UInt32 temp = p[size]; + size_t k = (p[3] > p[2]) ? 3 : 2; + p[size--] = p[1]; + p[1] = p[k]; + HeapSortDown(p, k, size, temp) + } + { + UInt32 temp = p[size]; + p[size] = p[1]; + if (size > 2 && p[2] < temp) + { + p[1] = p[2]; + p[2] = temp; + } + else + p[1] = temp; + } +} + +void HeapSort64(UInt64 *p, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt64 temp = p[i]; + size_t k = i; + HeapSortDown(p, k, size, temp) + } + while (--i != 0); + } + /* + do + { + size_t k = 1; + UInt64 temp = p[size]; + p[size--] = p[1]; + HeapSortDown(p, k, size, temp) + } + while (size > 1); + */ + while (size > 3) + { + UInt64 temp = p[size]; + size_t k = (p[3] > p[2]) ? 3 : 2; + p[size--] = p[1]; + p[1] = p[k]; + HeapSortDown(p, k, size, temp) + } + { + UInt64 temp = p[size]; + p[size] = p[1]; + if (size > 2 && p[2] < temp) + { + p[1] = p[2]; + p[2] = temp; + } + else + p[1] = temp; + } +} + +/* +#define HeapSortRefDown(p, vals, n, size, temp) \ + { size_t k = n; UInt32 val = vals[temp]; for (;;) { \ + size_t s = (k << 1); \ + if (s > size) break; \ + if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \ + if (val >= vals[p[s]]) break; \ + p[k] = p[s]; k = s; \ + } p[k] = temp; } + +void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt32 temp = p[i]; + HeapSortRefDown(p, vals, i, size, temp); + } + while (--i != 0); + } + do + { + UInt32 temp = p[size]; + p[size--] = p[1]; + HeapSortRefDown(p, vals, 1, size, temp); + } + while (size > 1); +} +*/ diff --git a/lzma/Sort.h b/lzma/Sort.h new file mode 100644 index 0000000..7209d78 --- /dev/null +++ b/lzma/Sort.h @@ -0,0 +1,18 @@ +/* Sort.h -- Sort functions +2014-04-05 : Igor Pavlov : Public domain */ + +#ifndef __7Z_SORT_H +#define __7Z_SORT_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void HeapSort(UInt32 *p, size_t size); +void HeapSort64(UInt64 *p, size_t size); + +/* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */ + +EXTERN_C_END + +#endif diff --git a/lzma/Threads.c b/lzma/Threads.c new file mode 100644 index 0000000..8fd86f2 --- /dev/null +++ b/lzma/Threads.c @@ -0,0 +1,95 @@ +/* Threads.c -- multithreading library +2017-06-26 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifndef UNDER_CE +#include +#endif + +#include "Threads.h" + +static WRes GetError() +{ + DWORD res = GetLastError(); + return res ? (WRes)res : 1; +} + +static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); } +static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); } + +WRes HandlePtr_Close(HANDLE *p) +{ + if (*p != NULL) + { + if (!CloseHandle(*p)) + return GetError(); + *p = NULL; + } + return 0; +} + +WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE); } + +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) +{ + /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ + + #ifdef UNDER_CE + + DWORD threadId; + *p = CreateThread(0, 0, func, param, 0, &threadId); + + #else + + unsigned threadId; + *p = (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId); + + #endif + + /* maybe we must use errno here, but probably GetLastError() is also OK. */ + return HandleToWRes(*p); +} + +static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled) +{ + *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL); + return HandleToWRes(*p); +} + +WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); } +WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); } + +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); } +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); } +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } + + +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL); + return HandleToWRes(*p); +} + +static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) + { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); } +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num) + { return Semaphore_Release(p, (LONG)num, NULL); } +WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); } + +WRes CriticalSection_Init(CCriticalSection *p) +{ + /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */ + #ifdef _MSC_VER + __try + #endif + { + InitializeCriticalSection(p); + /* InitializeCriticalSectionAndSpinCount(p, 0); */ + } + #ifdef _MSC_VER + __except (EXCEPTION_EXECUTE_HANDLER) { return 1; } + #endif + return 0; +} diff --git a/lzma/Threads.h b/lzma/Threads.h new file mode 100644 index 0000000..f913241 --- /dev/null +++ b/lzma/Threads.h @@ -0,0 +1,68 @@ +/* Threads.h -- multithreading library +2017-06-18 : Igor Pavlov : Public domain */ + +#ifndef __7Z_THREADS_H +#define __7Z_THREADS_H + +#ifdef _WIN32 +#include +#endif + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +WRes HandlePtr_Close(HANDLE *h); +WRes Handle_WaitObject(HANDLE h); + +typedef HANDLE CThread; +#define Thread_Construct(p) *(p) = NULL +#define Thread_WasCreated(p) (*(p) != NULL) +#define Thread_Close(p) HandlePtr_Close(p) +#define Thread_Wait(p) Handle_WaitObject(*(p)) + +typedef +#ifdef UNDER_CE + DWORD +#else + unsigned +#endif + THREAD_FUNC_RET_TYPE; + +#define THREAD_FUNC_CALL_TYPE MY_STD_CALL +#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE +typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); + +typedef HANDLE CEvent; +typedef CEvent CAutoResetEvent; +typedef CEvent CManualResetEvent; +#define Event_Construct(p) *(p) = NULL +#define Event_IsCreated(p) (*(p) != NULL) +#define Event_Close(p) HandlePtr_Close(p) +#define Event_Wait(p) Handle_WaitObject(*(p)) +WRes Event_Set(CEvent *p); +WRes Event_Reset(CEvent *p); +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); + +typedef HANDLE CSemaphore; +#define Semaphore_Construct(p) *(p) = NULL +#define Semaphore_IsCreated(p) (*(p) != NULL) +#define Semaphore_Close(p) HandlePtr_Close(p) +#define Semaphore_Wait(p) Handle_WaitObject(*(p)) +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); +WRes Semaphore_Release1(CSemaphore *p); + +typedef CRITICAL_SECTION CCriticalSection; +WRes CriticalSection_Init(CCriticalSection *p); +#define CriticalSection_Delete(p) DeleteCriticalSection(p) +#define CriticalSection_Enter(p) EnterCriticalSection(p) +#define CriticalSection_Leave(p) LeaveCriticalSection(p) + +EXTERN_C_END + +#endif diff --git a/lzma/Xz.c b/lzma/Xz.c new file mode 100644 index 0000000..7e061d6 --- /dev/null +++ b/lzma/Xz.c @@ -0,0 +1,90 @@ +/* Xz.c - Xz +2017-05-12 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zCrc.h" +#include "CpuArch.h" +#include "Xz.h" +#include "XzCrc64.h" + +const Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; +/* const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; */ + +unsigned Xz_WriteVarInt(Byte *buf, UInt64 v) +{ + unsigned i = 0; + do + { + buf[i++] = (Byte)((v & 0x7F) | 0x80); + v >>= 7; + } + while (v != 0); + buf[(size_t)i - 1] &= 0x7F; + return i; +} + +void Xz_Construct(CXzStream *p) +{ + p->numBlocks = 0; + p->blocks = NULL; + p->flags = 0; +} + +void Xz_Free(CXzStream *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->blocks); + p->numBlocks = 0; + p->blocks = NULL; +} + +unsigned XzFlags_GetCheckSize(CXzStreamFlags f) +{ + unsigned t = XzFlags_GetCheckType(f); + return (t == 0) ? 0 : (4 << ((t - 1) / 3)); +} + +void XzCheck_Init(CXzCheck *p, unsigned mode) +{ + p->mode = mode; + switch (mode) + { + case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break; + case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break; + case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break; + } +} + +void XzCheck_Update(CXzCheck *p, const void *data, size_t size) +{ + switch (p->mode) + { + case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break; + case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break; + case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break; + } +} + +int XzCheck_Final(CXzCheck *p, Byte *digest) +{ + switch (p->mode) + { + case XZ_CHECK_CRC32: + SetUi32(digest, CRC_GET_DIGEST(p->crc)); + break; + case XZ_CHECK_CRC64: + { + int i; + UInt64 v = CRC64_GET_DIGEST(p->crc64); + for (i = 0; i < 8; i++, v >>= 8) + digest[i] = (Byte)(v & 0xFF); + break; + } + case XZ_CHECK_SHA256: + Sha256_Final(&p->sha, digest); + break; + default: + return 0; + } + return 1; +} diff --git a/lzma/Xz.h b/lzma/Xz.h new file mode 100644 index 0000000..fad56a3 --- /dev/null +++ b/lzma/Xz.h @@ -0,0 +1,460 @@ +/* Xz.h - Xz interface +2018-07-04 : Igor Pavlov : Public domain */ + +#ifndef __XZ_H +#define __XZ_H + +#include "Sha256.h" + +EXTERN_C_BEGIN + +#define XZ_ID_Subblock 1 +#define XZ_ID_Delta 3 +#define XZ_ID_X86 4 +#define XZ_ID_PPC 5 +#define XZ_ID_IA64 6 +#define XZ_ID_ARM 7 +#define XZ_ID_ARMT 8 +#define XZ_ID_SPARC 9 +#define XZ_ID_LZMA2 0x21 + +unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value); +unsigned Xz_WriteVarInt(Byte *buf, UInt64 v); + +/* ---------- xz block ---------- */ + +#define XZ_BLOCK_HEADER_SIZE_MAX 1024 + +#define XZ_NUM_FILTERS_MAX 4 +#define XZ_BF_NUM_FILTERS_MASK 3 +#define XZ_BF_PACK_SIZE (1 << 6) +#define XZ_BF_UNPACK_SIZE (1 << 7) + +#define XZ_FILTER_PROPS_SIZE_MAX 20 + +typedef struct +{ + UInt64 id; + UInt32 propsSize; + Byte props[XZ_FILTER_PROPS_SIZE_MAX]; +} CXzFilter; + +typedef struct +{ + UInt64 packSize; + UInt64 unpackSize; + Byte flags; + CXzFilter filters[XZ_NUM_FILTERS_MAX]; +} CXzBlock; + +#define XzBlock_GetNumFilters(p) (((p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1) +#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0) +#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0) +#define XzBlock_HasUnsupportedFlags(p) (((p)->flags & ~(XZ_BF_NUM_FILTERS_MASK | XZ_BF_PACK_SIZE | XZ_BF_UNPACK_SIZE)) != 0) + +SRes XzBlock_Parse(CXzBlock *p, const Byte *header); +SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, BoolInt *isIndex, UInt32 *headerSizeRes); + +/* ---------- xz stream ---------- */ + +#define XZ_SIG_SIZE 6 +#define XZ_FOOTER_SIG_SIZE 2 + +extern const Byte XZ_SIG[XZ_SIG_SIZE]; + +/* +extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; +*/ + +#define XZ_FOOTER_SIG_0 'Y' +#define XZ_FOOTER_SIG_1 'Z' + +#define XZ_STREAM_FLAGS_SIZE 2 +#define XZ_STREAM_CRC_SIZE 4 + +#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE) +#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4) + +#define XZ_CHECK_MASK 0xF +#define XZ_CHECK_NO 0 +#define XZ_CHECK_CRC32 1 +#define XZ_CHECK_CRC64 4 +#define XZ_CHECK_SHA256 10 + +typedef struct +{ + unsigned mode; + UInt32 crc; + UInt64 crc64; + CSha256 sha; +} CXzCheck; + +void XzCheck_Init(CXzCheck *p, unsigned mode); +void XzCheck_Update(CXzCheck *p, const void *data, size_t size); +int XzCheck_Final(CXzCheck *p, Byte *digest); + +typedef UInt16 CXzStreamFlags; + +#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK) +#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK) +#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32) +unsigned XzFlags_GetCheckSize(CXzStreamFlags f); + +SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf); +SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream); + +typedef struct +{ + UInt64 unpackSize; + UInt64 totalSize; +} CXzBlockSizes; + +typedef struct +{ + CXzStreamFlags flags; + size_t numBlocks; + CXzBlockSizes *blocks; + UInt64 startOffset; +} CXzStream; + +void Xz_Construct(CXzStream *p); +void Xz_Free(CXzStream *p, ISzAllocPtr alloc); + +#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1) + +UInt64 Xz_GetUnpackSize(const CXzStream *p); +UInt64 Xz_GetPackSize(const CXzStream *p); + +typedef struct +{ + size_t num; + size_t numAllocated; + CXzStream *streams; +} CXzs; + +void Xzs_Construct(CXzs *p); +void Xzs_Free(CXzs *p, ISzAllocPtr alloc); +SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAllocPtr alloc); + +UInt64 Xzs_GetNumBlocks(const CXzs *p); +UInt64 Xzs_GetUnpackSize(const CXzs *p); + + +// ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder + +typedef enum +{ + CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ + CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + CODER_STATUS_NOT_FINISHED, /* stream was not finished */ + CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ +} ECoderStatus; + + +// ECoderFinishMode values are identical to ELzmaFinishMode + +typedef enum +{ + CODER_FINISH_ANY, /* finish at any point */ + CODER_FINISH_END /* block must be finished at the end */ +} ECoderFinishMode; + + +typedef struct _IStateCoder +{ + void *p; + void (*Free)(void *p, ISzAllocPtr alloc); + SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAllocPtr alloc); + void (*Init)(void *p); + SRes (*Code2)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished, + ECoderStatus *status); + SizeT (*Filter)(void *p, Byte *data, SizeT size); +} IStateCoder; + + + +#define MIXCODER_NUM_FILTERS_MAX 4 + +typedef struct +{ + ISzAllocPtr alloc; + Byte *buf; + unsigned numCoders; + + Byte *outBuf; + size_t outBufSize; + size_t outWritten; // is equal to lzmaDecoder.dicPos (in outBuf mode) + BoolInt wasFinished; + SRes res; + ECoderStatus status; + // BoolInt SingleBufMode; + + int finished[MIXCODER_NUM_FILTERS_MAX - 1]; + size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; + size_t size[MIXCODER_NUM_FILTERS_MAX - 1]; + UInt64 ids[MIXCODER_NUM_FILTERS_MAX]; + SRes results[MIXCODER_NUM_FILTERS_MAX]; + IStateCoder coders[MIXCODER_NUM_FILTERS_MAX]; +} CMixCoder; + + +typedef enum +{ + XZ_STATE_STREAM_HEADER, + XZ_STATE_STREAM_INDEX, + XZ_STATE_STREAM_INDEX_CRC, + XZ_STATE_STREAM_FOOTER, + XZ_STATE_STREAM_PADDING, + XZ_STATE_BLOCK_HEADER, + XZ_STATE_BLOCK, + XZ_STATE_BLOCK_FOOTER +} EXzState; + + +typedef struct +{ + EXzState state; + UInt32 pos; + unsigned alignPos; + unsigned indexPreSize; + + CXzStreamFlags streamFlags; + + UInt32 blockHeaderSize; + UInt64 packSize; + UInt64 unpackSize; + + UInt64 numBlocks; // number of finished blocks in current stream + UInt64 indexSize; + UInt64 indexPos; + UInt64 padSize; + + UInt64 numStartedStreams; + UInt64 numFinishedStreams; + UInt64 numTotalBlocks; + + UInt32 crc; + CMixCoder decoder; + CXzBlock block; + CXzCheck check; + CSha256 sha; + + BoolInt parseMode; + BoolInt headerParsedOk; + BoolInt decodeToStreamSignature; + unsigned decodeOnlyOneBlock; + + Byte *outBuf; + size_t outBufSize; + size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked + + Byte shaDigest[SHA256_DIGEST_SIZE]; + Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; +} CXzUnpacker; + +/* alloc : aligned for cache line allocation is better */ +void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc); +void XzUnpacker_Init(CXzUnpacker *p); +void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize); +void XzUnpacker_Free(CXzUnpacker *p); + +/* + XzUnpacker + The sequence for decoding functions: + { + XzUnpacker_Construct() + [Decoding_Calls] + XzUnpacker_Free() + } + + [Decoding_Calls] + + There are 3 types of interfaces for [Decoding_Calls] calls: + + Interface-1 : Partial output buffers: + { + XzUnpacker_Init() + for() + XzUnpacker_Code(); + } + + Interface-2 : Direct output buffer: + Use it, if you know exact size of decoded data, and you need + whole xz unpacked data in one output buffer. + xz unpacker doesn't allocate additional buffer for lzma2 dictionary in that mode. + { + XzUnpacker_Init() + XzUnpacker_SetOutBufMode(); // to set output buffer and size + for() + XzUnpacker_Code(); // (dest = NULL) in XzUnpacker_Code() + } + + Interface-3 : Direct output buffer : One call full decoding + It unpacks whole input buffer to output buffer in one call. + It uses Interface-2 internally. + { + XzUnpacker_CodeFull() + } +*/ + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + CODER_FINISH_ANY - use smallest number of input bytes + CODER_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + CODER_STATUS_NOT_FINISHED, + CODER_STATUS_NEEDS_MORE_INPUT - maybe there are more xz streams, + call XzUnpacker_IsStreamWasFinished to check that current stream was finished + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_DATA - Data error + SZ_ERROR_UNSUPPORTED - Unsupported method or method properties + SZ_ERROR_CRC - CRC error + // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). + + SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons: + - xz Stream Signature failure + - CRC32 of xz Stream Header is failed + - The size of Stream padding is not multiple of four bytes. + It's possible to get that error, if xz stream was finished and the stream + contains some another data. In that case you can call XzUnpacker_GetExtraSize() + function to get real size of xz stream. +*/ + + +SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcFinished, + ECoderFinishMode finishMode, ECoderStatus *status); + +SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, + ECoderFinishMode finishMode, ECoderStatus *status); + +BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p); + +/* +XzUnpacker_GetExtraSize() returns then number of uncofirmed bytes, + if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state. +These bytes can be some bytes after xz archive, or +it can be start of new xz stream. + +Call XzUnpacker_GetExtraSize() after XzUnpacker_Code() function to detect real size of +xz stream in two cases, if XzUnpacker_Code() returns: + res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT + res == SZ_ERROR_NO_ARCHIVE +*/ + +UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p); + + +/* + for random block decoding: + XzUnpacker_Init(); + set CXzUnpacker::streamFlags + XzUnpacker_PrepareToRandomBlockDecoding() + loop + { + XzUnpacker_Code() + XzUnpacker_IsBlockFinished() + } +*/ + +void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p); +BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p); + +#define XzUnpacker_GetPackSizeForIndex(p) ((p)->packSize + (p)->blockHeaderSize + XzFlags_GetCheckSize((p)->streamFlags)) + + + +/* ---------- Multi Threading Decoding ---------- */ + + +typedef struct +{ + size_t inBufSize_ST; + size_t outStep_ST; + BoolInt ignoreErrors; + + #ifndef _7ZIP_ST + unsigned numThreads; + size_t inBufSize_MT; + size_t memUseMax; + #endif +} CXzDecMtProps; + +void XzDecMtProps_Init(CXzDecMtProps *p); + + +typedef void * CXzDecMtHandle; + +/* + alloc : XzDecMt uses CAlignOffsetAlloc for addresses allocated by (alloc). + allocMid : for big allocations, aligned allocation is better +*/ + +CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); +void XzDecMt_Destroy(CXzDecMtHandle p); + + +typedef struct +{ + Byte UnpackSize_Defined; + Byte NumStreams_Defined; + Byte NumBlocks_Defined; + + Byte DataAfterEnd; + Byte DecodingTruncated; // Decoding was Truncated, we need only partial output data + + UInt64 InSize; // pack size processed + UInt64 OutSize; + + UInt64 NumStreams; + UInt64 NumBlocks; + + SRes DecodeRes; + SRes ReadRes; + SRes ProgressRes; + SRes CombinedRes; + SRes CombinedRes_Type; + +} CXzStatInfo; + +void XzStatInfo_Clear(CXzStatInfo *p); + +/* +XzDecMt_Decode() +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_NO_ARCHIVE - is not xz archive + SZ_ERROR_ARCHIVE - Headers error + SZ_ERROR_DATA - Data Error + SZ_ERROR_CRC - CRC Error + SZ_ERROR_INPUT_EOF - it needs more input data + SZ_ERROR_WRITE - ISeqOutStream error + (SZ_ERROR_READ) - ISeqInStream errors + (SZ_ERROR_PROGRESS) - ICompressProgress errors + // SZ_ERROR_THREAD - error in multi-threading functions + MY_SRes_HRESULT_FROM_WRes(WRes_error) - error in multi-threading function +*/ + +SRes XzDecMt_Decode(CXzDecMtHandle p, + const CXzDecMtProps *props, + const UInt64 *outDataSize, // NULL means undefined + int finishMode, // 0 - partial unpacking is allowed, 1 - xz stream(s) must be finished + ISeqOutStream *outStream, + // Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + // const Byte *inData, size_t inDataSize, + CXzStatInfo *stat, + int *isMT, // 0 means that ST (Single-Thread) version was used + ICompressProgress *progress); + +EXTERN_C_END + +#endif diff --git a/lzma/XzCrc64.c b/lzma/XzCrc64.c new file mode 100644 index 0000000..e9ca9ec --- /dev/null +++ b/lzma/XzCrc64.c @@ -0,0 +1,86 @@ +/* XzCrc64.c -- CRC64 calculation +2017-05-23 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "XzCrc64.h" +#include "CpuArch.h" + +#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42) + +#ifdef MY_CPU_LE + #define CRC64_NUM_TABLES 4 +#else + #define CRC64_NUM_TABLES 5 + #define CRC_UINT64_SWAP(v) \ + ((v >> 56) \ + | ((v >> 40) & ((UInt64)0xFF << 8)) \ + | ((v >> 24) & ((UInt64)0xFF << 16)) \ + | ((v >> 8) & ((UInt64)0xFF << 24)) \ + | ((v << 8) & ((UInt64)0xFF << 32)) \ + | ((v << 24) & ((UInt64)0xFF << 40)) \ + | ((v << 40) & ((UInt64)0xFF << 48)) \ + | ((v << 56))) + + UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table); +#endif + +#ifndef MY_CPU_BE + UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table); +#endif + +typedef UInt64 (MY_FAST_CALL *CRC64_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table); + +static CRC64_FUNC g_Crc64Update; +UInt64 g_Crc64Table[256 * CRC64_NUM_TABLES]; + +UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size) +{ + return g_Crc64Update(v, data, size, g_Crc64Table); +} + +UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size) +{ + return g_Crc64Update(CRC64_INIT_VAL, data, size, g_Crc64Table) ^ CRC64_INIT_VAL; +} + +void MY_FAST_CALL Crc64GenerateTable() +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt64 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrc64Poly & ((UInt64)0 - (r & 1))); + g_Crc64Table[i] = r; + } + for (i = 256; i < 256 * CRC64_NUM_TABLES; i++) + { + UInt64 r = g_Crc64Table[(size_t)i - 256]; + g_Crc64Table[i] = g_Crc64Table[r & 0xFF] ^ (r >> 8); + } + + #ifdef MY_CPU_LE + + g_Crc64Update = XzCrc64UpdateT4; + + #else + { + #ifndef MY_CPU_BE + UInt32 k = 1; + if (*(const Byte *)&k == 1) + g_Crc64Update = XzCrc64UpdateT4; + else + #endif + { + for (i = 256 * CRC64_NUM_TABLES - 1; i >= 256; i--) + { + UInt64 x = g_Crc64Table[(size_t)i - 256]; + g_Crc64Table[i] = CRC_UINT64_SWAP(x); + } + g_Crc64Update = XzCrc64UpdateT1_BeT4; + } + } + #endif +} diff --git a/lzma/XzCrc64.h b/lzma/XzCrc64.h new file mode 100644 index 0000000..71b10d5 --- /dev/null +++ b/lzma/XzCrc64.h @@ -0,0 +1,26 @@ +/* XzCrc64.h -- CRC64 calculation +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __XZ_CRC64_H +#define __XZ_CRC64_H + +#include + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +extern UInt64 g_Crc64Table[]; + +void MY_FAST_CALL Crc64GenerateTable(void); + +#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF) +#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL) +#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size); +UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size); + +EXTERN_C_END + +#endif diff --git a/lzma/XzCrc64Opt.c b/lzma/XzCrc64Opt.c new file mode 100644 index 0000000..9273465 --- /dev/null +++ b/lzma/XzCrc64Opt.c @@ -0,0 +1,69 @@ +/* XzCrc64Opt.c -- CRC64 calculation +2017-06-30 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#ifndef MY_CPU_BE + +#define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table) +{ + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC64_UPDATE_BYTE_2(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + UInt32 d = (UInt32)v ^ *(const UInt32 *)p; + v = (v >> 32) + ^ (table + 0x300)[((d ) & 0xFF)] + ^ (table + 0x200)[((d >> 8) & 0xFF)] + ^ (table + 0x100)[((d >> 16) & 0xFF)] + ^ (table + 0x000)[((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC64_UPDATE_BYTE_2(v, *p); + return v; +} + +#endif + + +#ifndef MY_CPU_LE + +#define CRC_UINT64_SWAP(v) \ + ((v >> 56) \ + | ((v >> 40) & ((UInt64)0xFF << 8)) \ + | ((v >> 24) & ((UInt64)0xFF << 16)) \ + | ((v >> 8) & ((UInt64)0xFF << 24)) \ + | ((v << 8) & ((UInt64)0xFF << 32)) \ + | ((v << 24) & ((UInt64)0xFF << 40)) \ + | ((v << 40) & ((UInt64)0xFF << 48)) \ + | ((v << 56))) + +#define CRC64_UPDATE_BYTE_2_BE(crc, b) (table[(Byte)((crc) >> 56) ^ (b)] ^ ((crc) << 8)) + +UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table) +{ + const Byte *p = (const Byte *)data; + table += 0x100; + v = CRC_UINT64_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC64_UPDATE_BYTE_2_BE(v, *p); + for (; size >= 4; size -= 4, p += 4) + { + UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)p; + v = (v << 32) + ^ (table + 0x000)[((d ) & 0xFF)] + ^ (table + 0x100)[((d >> 8) & 0xFF)] + ^ (table + 0x200)[((d >> 16) & 0xFF)] + ^ (table + 0x300)[((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC64_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT64_SWAP(v); +} + +#endif diff --git a/lzma/XzDec.c b/lzma/XzDec.c new file mode 100644 index 0000000..4f53272 --- /dev/null +++ b/lzma/XzDec.c @@ -0,0 +1,2766 @@ +/* XzDec.c -- Xz Decode +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #include + +// #define XZ_DUMP + +/* #define XZ_DUMP */ + +#ifdef XZ_DUMP +#include +#endif + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define PRF_STR(s) PRF(printf("\n" s "\n")) +#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) + +#include +#include + +#include "7zCrc.h" +#include "Alloc.h" +#include "Bra.h" +#include "CpuArch.h" +#include "Delta.h" +#include "Lzma2Dec.h" + +// #define USE_SUBBLOCK + +#ifdef USE_SUBBLOCK +#include "Bcj3Dec.c" +#include "SbDec.h" +#endif + +#include "Xz.h" + +#define XZ_CHECK_SIZE_MAX 64 + +#define CODER_BUF_SIZE ((size_t)1 << 17) + +unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) +{ + unsigned i, limit; + *value = 0; + limit = (maxSize > 9) ? 9 : (unsigned)maxSize; + + for (i = 0; i < limit;) + { + Byte b = p[i]; + *value |= (UInt64)(b & 0x7F) << (7 * i++); + if ((b & 0x80) == 0) + return (b == 0 && i != 1) ? 0 : i; + } + return 0; +} + +/* ---------- BraState ---------- */ + +#define BRA_BUF_SIZE (1 << 14) + +typedef struct +{ + size_t bufPos; + size_t bufConv; + size_t bufTotal; + + int encodeMode; + + UInt32 methodId; + UInt32 delta; + UInt32 ip; + UInt32 x86State; + Byte deltaState[DELTA_STATE_SIZE]; + + Byte buf[BRA_BUF_SIZE]; +} CBraState; + +static void BraState_Free(void *pp, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, pp); +} + +static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + CBraState *p = ((CBraState *)pp); + UNUSED_VAR(alloc); + p->ip = 0; + if (p->methodId == XZ_ID_Delta) + { + if (propSize != 1) + return SZ_ERROR_UNSUPPORTED; + p->delta = (unsigned)props[0] + 1; + } + else + { + if (propSize == 4) + { + UInt32 v = GetUi32(props); + switch (p->methodId) + { + case XZ_ID_PPC: + case XZ_ID_ARM: + case XZ_ID_SPARC: + if ((v & 3) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + case XZ_ID_ARMT: + if ((v & 1) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + case XZ_ID_IA64: + if ((v & 0xF) != 0) + return SZ_ERROR_UNSUPPORTED; + break; + } + p->ip = v; + } + else if (propSize != 0) + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; +} + +static void BraState_Init(void *pp) +{ + CBraState *p = ((CBraState *)pp); + p->bufPos = p->bufConv = p->bufTotal = 0; + x86_Convert_Init(p->x86State); + if (p->methodId == XZ_ID_Delta) + Delta_Init(p->deltaState); +} + + +#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: size = isa ## _Convert(data, size, p->ip, p->encodeMode); break; + +static SizeT BraState_Filter(void *pp, Byte *data, SizeT size) +{ + CBraState *p = ((CBraState *)pp); + switch (p->methodId) + { + case XZ_ID_Delta: + if (p->encodeMode) + Delta_Encode(p->deltaState, p->delta, data, size); + else + Delta_Decode(p->deltaState, p->delta, data, size); + break; + case XZ_ID_X86: + size = x86_Convert(data, size, p->ip, &p->x86State, p->encodeMode); + break; + CASE_BRA_CONV(PPC) + CASE_BRA_CONV(IA64) + CASE_BRA_CONV(ARM) + CASE_BRA_CONV(ARMT) + CASE_BRA_CONV(SPARC) + } + p->ip += (UInt32)size; + return size; +} + + +static SRes BraState_Code2(void *pp, + Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcWasFinished, + ECoderFinishMode finishMode, + // int *wasFinished + ECoderStatus *status) +{ + CBraState *p = ((CBraState *)pp); + SizeT destRem = *destLen; + SizeT srcRem = *srcLen; + UNUSED_VAR(finishMode); + + *destLen = 0; + *srcLen = 0; + // *wasFinished = False; + *status = CODER_STATUS_NOT_FINISHED; + + while (destRem > 0) + { + if (p->bufPos != p->bufConv) + { + size_t size = p->bufConv - p->bufPos; + if (size > destRem) + size = destRem; + memcpy(dest, p->buf + p->bufPos, size); + p->bufPos += size; + *destLen += size; + dest += size; + destRem -= size; + continue; + } + + p->bufTotal -= p->bufPos; + memmove(p->buf, p->buf + p->bufPos, p->bufTotal); + p->bufPos = 0; + p->bufConv = 0; + { + size_t size = BRA_BUF_SIZE - p->bufTotal; + if (size > srcRem) + size = srcRem; + memcpy(p->buf + p->bufTotal, src, size); + *srcLen += size; + src += size; + srcRem -= size; + p->bufTotal += size; + } + if (p->bufTotal == 0) + break; + + p->bufConv = BraState_Filter(pp, p->buf, p->bufTotal); + + if (p->bufConv == 0) + { + if (!srcWasFinished) + break; + p->bufConv = p->bufTotal; + } + } + + if (p->bufTotal == p->bufPos && srcRem == 0 && srcWasFinished) + { + *status = CODER_STATUS_FINISHED_WITH_MARK; + // *wasFinished = 1; + } + + return SZ_OK; +} + + +SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc) +{ + CBraState *decoder; + if (id < XZ_ID_Delta || id > XZ_ID_SPARC) + return SZ_ERROR_UNSUPPORTED; + decoder = (CBraState *)p->p; + if (!decoder) + { + decoder = (CBraState *)ISzAlloc_Alloc(alloc, sizeof(CBraState)); + if (!decoder) + return SZ_ERROR_MEM; + p->p = decoder; + p->Free = BraState_Free; + p->SetProps = BraState_SetProps; + p->Init = BraState_Init; + p->Code2 = BraState_Code2; + p->Filter = BraState_Filter; + } + decoder->methodId = (UInt32)id; + decoder->encodeMode = encodeMode; + return SZ_OK; +} + + + +/* ---------- SbState ---------- */ + +#ifdef USE_SUBBLOCK + +static void SbState_Free(void *pp, ISzAllocPtr alloc) +{ + CSbDec *p = (CSbDec *)pp; + SbDec_Free(p); + ISzAlloc_Free(alloc, pp); +} + +static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + UNUSED_VAR(pp); + UNUSED_VAR(props); + UNUSED_VAR(alloc); + return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED; +} + +static void SbState_Init(void *pp) +{ + SbDec_Init((CSbDec *)pp); +} + +static SRes SbState_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished + ECoderStatus *status) +{ + CSbDec *p = (CSbDec *)pp; + SRes res; + UNUSED_VAR(srcWasFinished); + p->dest = dest; + p->destLen = *destLen; + p->src = src; + p->srcLen = *srcLen; + p->finish = finishMode; /* change it */ + res = SbDec_Decode((CSbDec *)pp); + *destLen -= p->destLen; + *srcLen -= p->srcLen; + // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */ + *status = (*destLen == 0 && *srcLen == 0) ? + CODER_STATUS_FINISHED_WITH_MARK : + CODER_STATUS_NOT_FINISHED; + return res; +} + +static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc) +{ + CSbDec *decoder = (CSbDec *)p->p; + if (!decoder) + { + decoder = (CSbDec *)ISzAlloc_Alloc(alloc, sizeof(CSbDec)); + if (!decoder) + return SZ_ERROR_MEM; + p->p = decoder; + p->Free = SbState_Free; + p->SetProps = SbState_SetProps; + p->Init = SbState_Init; + p->Code2 = SbState_Code2; + p->Filter = NULL; + } + SbDec_Construct(decoder); + SbDec_SetAlloc(decoder, alloc); + return SZ_OK; +} + +#endif + + + +/* ---------- Lzma2 ---------- */ + +typedef struct +{ + CLzma2Dec decoder; + BoolInt outBufMode; +} CLzma2Dec_Spec; + + +static void Lzma2State_Free(void *pp, ISzAllocPtr alloc) +{ + CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; + if (p->outBufMode) + Lzma2Dec_FreeProbs(&p->decoder, alloc); + else + Lzma2Dec_Free(&p->decoder, alloc); + ISzAlloc_Free(alloc, pp); +} + +static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + if (propSize != 1) + return SZ_ERROR_UNSUPPORTED; + { + CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; + if (p->outBufMode) + return Lzma2Dec_AllocateProbs(&p->decoder, props[0], alloc); + else + return Lzma2Dec_Allocate(&p->decoder, props[0], alloc); + } +} + +static void Lzma2State_Init(void *pp) +{ + Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder); +} + + +/* + if (outBufMode), then (dest) is not used. Use NULL. + Data is unpacked to (spec->decoder.decoder.dic) output buffer. +*/ + +static SRes Lzma2State_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished, + ECoderStatus *status) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp; + ELzmaStatus status2; + /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */ + SRes res; + UNUSED_VAR(srcWasFinished); + if (spec->outBufMode) + { + SizeT dicPos = spec->decoder.decoder.dicPos; + SizeT dicLimit = dicPos + *destLen; + res = Lzma2Dec_DecodeToDic(&spec->decoder, dicLimit, src, srcLen, (ELzmaFinishMode)finishMode, &status2); + *destLen = spec->decoder.decoder.dicPos - dicPos; + } + else + res = Lzma2Dec_DecodeToBuf(&spec->decoder, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status2); + // *wasFinished = (status2 == LZMA_STATUS_FINISHED_WITH_MARK); + // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder + *status = (ECoderStatus)status2; + return res; +} + + +static SRes Lzma2State_SetFromMethod(IStateCoder *p, Byte *outBuf, size_t outBufSize, ISzAllocPtr alloc) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; + if (!spec) + { + spec = (CLzma2Dec_Spec *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Dec_Spec)); + if (!spec) + return SZ_ERROR_MEM; + p->p = spec; + p->Free = Lzma2State_Free; + p->SetProps = Lzma2State_SetProps; + p->Init = Lzma2State_Init; + p->Code2 = Lzma2State_Code2; + p->Filter = NULL; + Lzma2Dec_Construct(&spec->decoder); + } + spec->outBufMode = False; + if (outBuf) + { + spec->outBufMode = True; + spec->decoder.decoder.dic = outBuf; + spec->decoder.decoder.dicBufSize = outBufSize; + } + return SZ_OK; +} + + +static SRes Lzma2State_ResetOutBuf(IStateCoder *p, Byte *outBuf, size_t outBufSize) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; + if ((spec->outBufMode && !outBuf) || (!spec->outBufMode && outBuf)) + return SZ_ERROR_FAIL; + if (outBuf) + { + spec->decoder.decoder.dic = outBuf; + spec->decoder.decoder.dicBufSize = outBufSize; + } + return SZ_OK; +} + + + +static void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc) +{ + unsigned i; + p->alloc = alloc; + p->buf = NULL; + p->numCoders = 0; + + p->outBufSize = 0; + p->outBuf = NULL; + // p->SingleBufMode = False; + + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) + p->coders[i].p = NULL; +} + + +static void MixCoder_Free(CMixCoder *p) +{ + unsigned i; + p->numCoders = 0; + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) + { + IStateCoder *sc = &p->coders[i]; + if (sc->p) + { + sc->Free(sc->p, p->alloc); + sc->p = NULL; + } + } + if (p->buf) + { + ISzAlloc_Free(p->alloc, p->buf); + p->buf = NULL; /* 9.31: the BUG was fixed */ + } +} + +static void MixCoder_Init(CMixCoder *p) +{ + unsigned i; + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++) + { + p->size[i] = 0; + p->pos[i] = 0; + p->finished[i] = 0; + } + for (i = 0; i < p->numCoders; i++) + { + IStateCoder *coder = &p->coders[i]; + coder->Init(coder->p); + p->results[i] = SZ_OK; + } + p->outWritten = 0; + p->wasFinished = False; + p->res = SZ_OK; + p->status = CODER_STATUS_NOT_SPECIFIED; +} + + +static SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) +{ + IStateCoder *sc = &p->coders[coderIndex]; + p->ids[coderIndex] = methodId; + switch (methodId) + { + case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc); + #ifdef USE_SUBBLOCK + case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc); + #endif + } + if (coderIndex == 0) + return SZ_ERROR_UNSUPPORTED; + return BraState_SetFromMethod(sc, methodId, 0, p->alloc); +} + + +static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) +{ + IStateCoder *sc = &p->coders[coderIndex]; + switch (methodId) + { + case XZ_ID_LZMA2: return Lzma2State_ResetOutBuf(sc, outBuf, outBufSize); + } + return SZ_ERROR_UNSUPPORTED; +} + + + +/* + if (destFinish) - then unpack data block is finished at (*destLen) position, + and we can return data that were not processed by filter + +output (status) can be : + CODER_STATUS_NOT_FINISHED + CODER_STATUS_FINISHED_WITH_MARK + CODER_STATUS_NEEDS_MORE_INPUT - not implemented still +*/ + +static SRes MixCoder_Code(CMixCoder *p, + Byte *dest, SizeT *destLen, int destFinish, + const Byte *src, SizeT *srcLen, int srcWasFinished, + ECoderFinishMode finishMode) +{ + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + + *destLen = 0; + *srcLen = 0; + + if (p->wasFinished) + return p->res; + + p->status = CODER_STATUS_NOT_FINISHED; + + // if (p->SingleBufMode) + if (p->outBuf) + { + SRes res; + SizeT destLen2, srcLen2; + int wasFinished; + + PRF_STR("------- MixCoder Single ----------"); + + srcLen2 = srcLenOrig; + destLen2 = destLenOrig; + + { + IStateCoder *coder = &p->coders[0]; + res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode, + // &wasFinished, + &p->status); + wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK); + } + + p->res = res; + + /* + if (wasFinished) + p->status = CODER_STATUS_FINISHED_WITH_MARK; + else + { + if (res == SZ_OK) + if (destLen2 != destLenOrig) + p->status = CODER_STATUS_NEEDS_MORE_INPUT; + } + */ + + + *srcLen = srcLen2; + src += srcLen2; + p->outWritten += destLen2; + + if (res != SZ_OK || srcWasFinished || wasFinished) + p->wasFinished = True; + + if (p->numCoders == 1) + *destLen = destLen2; + else if (p->wasFinished) + { + unsigned i; + size_t processed = p->outWritten; + + for (i = 1; i < p->numCoders; i++) + { + IStateCoder *coder = &p->coders[i]; + processed = coder->Filter(coder->p, p->outBuf, processed); + if (wasFinished || (destFinish && p->outWritten == destLenOrig)) + processed = p->outWritten; + PRF_STR_INT("filter", i); + } + *destLen = processed; + } + return res; + } + + PRF_STR("standard mix"); + + if (p->numCoders != 1) + { + if (!p->buf) + { + p->buf = (Byte *)ISzAlloc_Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1)); + if (!p->buf) + return SZ_ERROR_MEM; + } + + finishMode = CODER_FINISH_ANY; + } + + for (;;) + { + BoolInt processed = False; + BoolInt allFinished = True; + SRes resMain = SZ_OK; + unsigned i; + + p->status = CODER_STATUS_NOT_FINISHED; + /* + if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY) + break; + */ + + for (i = 0; i < p->numCoders; i++) + { + SRes res; + IStateCoder *coder = &p->coders[i]; + Byte *dest2; + SizeT destLen2, srcLen2; // destLen2_Orig; + const Byte *src2; + int srcFinished2; + int encodingWasFinished; + ECoderStatus status2; + + if (i == 0) + { + src2 = src; + srcLen2 = srcLenOrig - *srcLen; + srcFinished2 = srcWasFinished; + } + else + { + size_t k = i - 1; + src2 = p->buf + (CODER_BUF_SIZE * k) + p->pos[k]; + srcLen2 = p->size[k] - p->pos[k]; + srcFinished2 = p->finished[k]; + } + + if (i == p->numCoders - 1) + { + dest2 = dest; + destLen2 = destLenOrig - *destLen; + } + else + { + if (p->pos[i] != p->size[i]) + continue; + dest2 = p->buf + (CODER_BUF_SIZE * i); + destLen2 = CODER_BUF_SIZE; + } + + // destLen2_Orig = destLen2; + + if (p->results[i] != SZ_OK) + { + if (resMain == SZ_OK) + resMain = p->results[i]; + continue; + } + + res = coder->Code2(coder->p, + dest2, &destLen2, + src2, &srcLen2, srcFinished2, + finishMode, + // &encodingWasFinished, + &status2); + + if (res != SZ_OK) + { + p->results[i] = res; + if (resMain == SZ_OK) + resMain = res; + } + + encodingWasFinished = (status2 == CODER_STATUS_FINISHED_WITH_MARK); + + if (!encodingWasFinished) + { + allFinished = False; + if (p->numCoders == 1 && res == SZ_OK) + p->status = status2; + } + + if (i == 0) + { + *srcLen += srcLen2; + src += srcLen2; + } + else + p->pos[(size_t)i - 1] += srcLen2; + + if (i == p->numCoders - 1) + { + *destLen += destLen2; + dest += destLen2; + } + else + { + p->size[i] = destLen2; + p->pos[i] = 0; + p->finished[i] = encodingWasFinished; + } + + if (destLen2 != 0 || srcLen2 != 0) + processed = True; + } + + if (!processed) + { + if (allFinished) + p->status = CODER_STATUS_FINISHED_WITH_MARK; + return resMain; + } + } +} + + +SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf) +{ + *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE); + if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) != + GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE)) + return SZ_ERROR_NO_ARCHIVE; + return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED; +} + +static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) +{ + return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) + && GetUi32(buf) == CrcCalc(buf + 4, 6) + && flags == GetBe16(buf + 8) + && buf[10] == XZ_FOOTER_SIG_0 + && buf[11] == XZ_FOOTER_SIG_1; +} + +#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ + { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ + if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; } + + +static BoolInt XzBlock_AreSupportedFilters(const CXzBlock *p) +{ + unsigned numFilters = XzBlock_GetNumFilters(p) - 1; + unsigned i; + { + const CXzFilter *f = &p->filters[numFilters]; + if (f->id != XZ_ID_LZMA2 || f->propsSize != 1 || f->props[0] > 40) + return False; + } + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &p->filters[i]; + if (f->id == XZ_ID_Delta) + { + if (f->propsSize != 1) + return False; + } + else if (f->id < XZ_ID_Delta + || f->id > XZ_ID_SPARC + || (f->propsSize != 0 && f->propsSize != 4)) + return False; + } + return True; +} + + +SRes XzBlock_Parse(CXzBlock *p, const Byte *header) +{ + unsigned pos; + unsigned numFilters, i; + unsigned headerSize = (unsigned)header[0] << 2; + + /* (headerSize != 0) : another code checks */ + + if (CrcCalc(header, headerSize) != GetUi32(header + headerSize)) + return SZ_ERROR_ARCHIVE; + + pos = 1; + p->flags = header[pos++]; + + p->packSize = (UInt64)(Int64)-1; + if (XzBlock_HasPackSize(p)) + { + READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize); + if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63) + return SZ_ERROR_ARCHIVE; + } + + p->unpackSize = (UInt64)(Int64)-1; + if (XzBlock_HasUnpackSize(p)) + READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize); + + numFilters = XzBlock_GetNumFilters(p); + for (i = 0; i < numFilters; i++) + { + CXzFilter *filter = p->filters + i; + UInt64 size; + READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id); + READ_VARINT_AND_CHECK(header, pos, headerSize, &size); + if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX) + return SZ_ERROR_ARCHIVE; + filter->propsSize = (UInt32)size; + memcpy(filter->props, header + pos, (size_t)size); + pos += (unsigned)size; + + #ifdef XZ_DUMP + printf("\nf[%u] = %2X: ", i, (unsigned)filter->id); + { + unsigned i; + for (i = 0; i < size; i++) + printf(" %2X", filter->props[i]); + } + #endif + } + + if (XzBlock_HasUnsupportedFlags(p)) + return SZ_ERROR_UNSUPPORTED; + + while (pos < headerSize) + if (header[pos++] != 0) + return SZ_ERROR_ARCHIVE; + return SZ_OK; +} + + + + +static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize) +{ + unsigned i; + BoolInt needReInit = True; + unsigned numFilters = XzBlock_GetNumFilters(block); + + if (numFilters == p->numCoders && ((p->outBuf && outBuf) || (!p->outBuf && !outBuf))) + { + needReInit = False; + for (i = 0; i < numFilters; i++) + if (p->ids[i] != block->filters[numFilters - 1 - i].id) + { + needReInit = True; + break; + } + } + + // p->SingleBufMode = (outBuf != NULL); + p->outBuf = outBuf; + p->outBufSize = outBufSize; + + // p->SingleBufMode = False; + // outBuf = NULL; + + if (needReInit) + { + MixCoder_Free(p); + for (i = 0; i < numFilters; i++) + { + RINOK(MixCoder_SetFromMethod(p, i, block->filters[numFilters - 1 - i].id, outBuf, outBufSize)); + } + p->numCoders = numFilters; + } + else + { + RINOK(MixCoder_ResetFromMethod(p, 0, block->filters[numFilters - 1].id, outBuf, outBufSize)); + } + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &block->filters[numFilters - 1 - i]; + IStateCoder *sc = &p->coders[i]; + RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc)); + } + + MixCoder_Init(p); + return SZ_OK; +} + + + +void XzUnpacker_Init(CXzUnpacker *p) +{ + p->state = XZ_STATE_STREAM_HEADER; + p->pos = 0; + p->numStartedStreams = 0; + p->numFinishedStreams = 0; + p->numTotalBlocks = 0; + p->padSize = 0; + p->decodeOnlyOneBlock = 0; + + p->parseMode = False; + p->decodeToStreamSignature = False; + + // p->outBuf = NULL; + // p->outBufSize = 0; + p->outDataWritten = 0; +} + + +void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize) +{ + p->outBuf = outBuf; + p->outBufSize = outBufSize; +} + + +void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc) +{ + MixCoder_Construct(&p->decoder, alloc); + p->outBuf = NULL; + p->outBufSize = 0; + XzUnpacker_Init(p); +} + + +void XzUnpacker_Free(CXzUnpacker *p) +{ + MixCoder_Free(&p->decoder); +} + + +void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p) +{ + p->indexSize = 0; + p->numBlocks = 0; + Sha256_Init(&p->sha); + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + p->decodeOnlyOneBlock = 1; +} + + +static void XzUnpacker_UpdateIndex(CXzUnpacker *p, UInt64 packSize, UInt64 unpackSize) +{ + Byte temp[32]; + unsigned num = Xz_WriteVarInt(temp, packSize); + num += Xz_WriteVarInt(temp + num, unpackSize); + Sha256_Update(&p->sha, temp, num); + p->indexSize += num; + p->numBlocks++; +} + + + +SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcFinished, + ECoderFinishMode finishMode, ECoderStatus *status) +{ + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + *destLen = 0; + *srcLen = 0; + *status = CODER_STATUS_NOT_SPECIFIED; + + for (;;) + { + SizeT srcRem; + + if (p->state == XZ_STATE_BLOCK) + { + SizeT destLen2 = destLenOrig - *destLen; + SizeT srcLen2 = srcLenOrig - *srcLen; + SRes res; + + ECoderFinishMode finishMode2 = finishMode; + BoolInt srcFinished2 = srcFinished; + BoolInt destFinish = False; + + if (p->block.packSize != (UInt64)(Int64)-1) + { + UInt64 rem = p->block.packSize - p->packSize; + if (srcLen2 >= rem) + { + srcFinished2 = True; + srcLen2 = (SizeT)rem; + } + if (rem == 0 && p->block.unpackSize == p->unpackSize) + return SZ_ERROR_DATA; + } + + if (p->block.unpackSize != (UInt64)(Int64)-1) + { + UInt64 rem = p->block.unpackSize - p->unpackSize; + if (destLen2 >= rem) + { + destFinish = True; + finishMode2 = CODER_FINISH_END; + destLen2 = (SizeT)rem; + } + } + + /* + if (srcLen2 == 0 && destLen2 == 0) + { + *status = CODER_STATUS_NOT_FINISHED; + return SZ_OK; + } + */ + + { + res = MixCoder_Code(&p->decoder, + (p->outBuf ? NULL : dest), &destLen2, destFinish, + src, &srcLen2, srcFinished2, + finishMode2); + + *status = p->decoder.status; + XzCheck_Update(&p->check, (p->outBuf ? p->outBuf + p->outDataWritten : dest), destLen2); + if (!p->outBuf) + dest += destLen2; + p->outDataWritten += destLen2; + } + + (*srcLen) += srcLen2; + src += srcLen2; + p->packSize += srcLen2; + (*destLen) += destLen2; + p->unpackSize += destLen2; + + RINOK(res); + + if (*status != CODER_STATUS_FINISHED_WITH_MARK) + { + if (p->block.packSize == p->packSize + && *status == CODER_STATUS_NEEDS_MORE_INPUT) + { + PRF_STR("CODER_STATUS_NEEDS_MORE_INPUT"); + *status = CODER_STATUS_NOT_SPECIFIED; + return SZ_ERROR_DATA; + } + + return SZ_OK; + } + { + XzUnpacker_UpdateIndex(p, XzUnpacker_GetPackSizeForIndex(p), p->unpackSize); + p->state = XZ_STATE_BLOCK_FOOTER; + p->pos = 0; + p->alignPos = 0; + *status = CODER_STATUS_NOT_SPECIFIED; + + if ((p->block.packSize != (UInt64)(Int64)-1 && p->block.packSize != p->packSize) + || (p->block.unpackSize != (UInt64)(Int64)-1 && p->block.unpackSize != p->unpackSize)) + { + PRF_STR("ERROR: block.size mismatch"); + return SZ_ERROR_DATA; + } + } + // continue; + } + + srcRem = srcLenOrig - *srcLen; + + // XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes + if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + switch (p->state) + { + case XZ_STATE_STREAM_HEADER: + { + if (p->pos < XZ_STREAM_HEADER_SIZE) + { + if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos]) + return SZ_ERROR_NO_ARCHIVE; + if (p->decodeToStreamSignature) + return SZ_OK; + p->buf[p->pos++] = *src++; + (*srcLen)++; + } + else + { + RINOK(Xz_ParseHeader(&p->streamFlags, p->buf)); + p->numStartedStreams++; + p->indexSize = 0; + p->numBlocks = 0; + Sha256_Init(&p->sha); + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + } + break; + } + + case XZ_STATE_BLOCK_HEADER: + { + if (p->pos == 0) + { + p->buf[p->pos++] = *src++; + (*srcLen)++; + if (p->buf[0] == 0) + { + if (p->decodeOnlyOneBlock) + return SZ_ERROR_DATA; + p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); + p->indexPos = p->indexPreSize; + p->indexSize += p->indexPreSize; + Sha256_Final(&p->sha, p->shaDigest); + Sha256_Init(&p->sha); + p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); + p->state = XZ_STATE_STREAM_INDEX; + break; + } + p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4; + break; + } + + if (p->pos != p->blockHeaderSize) + { + UInt32 cur = p->blockHeaderSize - p->pos; + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + } + else + { + RINOK(XzBlock_Parse(&p->block, p->buf)); + if (!XzBlock_AreSupportedFilters(&p->block)) + return SZ_ERROR_UNSUPPORTED; + p->numTotalBlocks++; + p->state = XZ_STATE_BLOCK; + p->packSize = 0; + p->unpackSize = 0; + XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags)); + if (p->parseMode) + { + p->headerParsedOk = True; + return SZ_OK; + } + RINOK(XzDecMix_Init(&p->decoder, &p->block, p->outBuf, p->outBufSize)); + } + break; + } + + case XZ_STATE_BLOCK_FOOTER: + { + if ((((unsigned)p->packSize + p->alignPos) & 3) != 0) + { + if (srcRem == 0) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + (*srcLen)++; + p->alignPos++; + if (*src++ != 0) + return SZ_ERROR_CRC; + } + else + { + UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags); + UInt32 cur = checkSize - p->pos; + if (cur != 0) + { + if (srcRem == 0) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + if (checkSize != p->pos) + break; + } + { + Byte digest[XZ_CHECK_SIZE_MAX]; + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0) + return SZ_ERROR_CRC; + if (p->decodeOnlyOneBlock) + { + *status = CODER_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + } + } + } + break; + } + + case XZ_STATE_STREAM_INDEX: + { + if (p->pos < p->indexPreSize) + { + (*srcLen)++; + if (*src++ != p->buf[p->pos++]) + return SZ_ERROR_CRC; + } + else + { + if (p->indexPos < p->indexSize) + { + UInt64 cur = p->indexSize - p->indexPos; + if (srcRem > cur) + srcRem = (SizeT)cur; + p->crc = CrcUpdate(p->crc, src, srcRem); + Sha256_Update(&p->sha, src, srcRem); + (*srcLen) += srcRem; + src += srcRem; + p->indexPos += srcRem; + } + else if ((p->indexPos & 3) != 0) + { + Byte b = *src++; + p->crc = CRC_UPDATE_BYTE(p->crc, b); + (*srcLen)++; + p->indexPos++; + p->indexSize++; + if (b != 0) + return SZ_ERROR_CRC; + } + else + { + Byte digest[SHA256_DIGEST_SIZE]; + p->state = XZ_STATE_STREAM_INDEX_CRC; + p->indexSize += 4; + p->pos = 0; + Sha256_Final(&p->sha, digest); + if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0) + return SZ_ERROR_CRC; + } + } + break; + } + + case XZ_STATE_STREAM_INDEX_CRC: + { + if (p->pos < 4) + { + (*srcLen)++; + p->buf[p->pos++] = *src++; + } + else + { + p->state = XZ_STATE_STREAM_FOOTER; + p->pos = 0; + if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf)) + return SZ_ERROR_CRC; + } + break; + } + + case XZ_STATE_STREAM_FOOTER: + { + UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos; + if (cur > srcRem) + cur = (UInt32)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + if (p->pos == XZ_STREAM_FOOTER_SIZE) + { + p->state = XZ_STATE_STREAM_PADDING; + p->numFinishedStreams++; + p->padSize = 0; + if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf)) + return SZ_ERROR_CRC; + } + break; + } + + case XZ_STATE_STREAM_PADDING: + { + if (*src != 0) + { + if (((UInt32)p->padSize & 3) != 0) + return SZ_ERROR_NO_ARCHIVE; + p->pos = 0; + p->state = XZ_STATE_STREAM_HEADER; + } + else + { + (*srcLen)++; + src++; + p->padSize++; + } + break; + } + + case XZ_STATE_BLOCK: break; /* to disable GCC warning */ + } + } + /* + if (p->state == XZ_STATE_FINISHED) + *status = CODER_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + */ +} + + +SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, + ECoderFinishMode finishMode, ECoderStatus *status) +{ + XzUnpacker_Init(p); + XzUnpacker_SetOutBuf(p, dest, *destLen); + + return XzUnpacker_Code(p, + NULL, destLen, + src, srcLen, True, + finishMode, status); +} + + +BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p) +{ + return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0); +} + +BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p) +{ + return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0); +} + +UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p) +{ + UInt64 num = 0; + if (p->state == XZ_STATE_STREAM_PADDING) + num = p->padSize; + else if (p->state == XZ_STATE_STREAM_HEADER) + num = p->padSize + p->pos; + return num; +} + + + + + + + + + + + + + + + + + + + + + +#ifndef _7ZIP_ST +#include "MtDec.h" +#endif + + +void XzDecMtProps_Init(CXzDecMtProps *p) +{ + p->inBufSize_ST = 1 << 18; + p->outStep_ST = 1 << 20; + p->ignoreErrors = False; + + #ifndef _7ZIP_ST + p->numThreads = 1; + p->inBufSize_MT = 1 << 18; + p->memUseMax = sizeof(size_t) << 28; + #endif +} + + + +#ifndef _7ZIP_ST + +/* ---------- CXzDecMtThread ---------- */ + +typedef struct +{ + Byte *outBuf; + size_t outBufSize; + size_t outPreSize; + size_t inPreSize; + size_t inPreHeaderSize; + size_t blockPackSize_for_Index; // including block header and checksum. + size_t blockPackTotal; // including stream header, block header and checksum. + size_t inCodeSize; + size_t outCodeSize; + ECoderStatus status; + SRes codeRes; + BoolInt skipMode; + // BoolInt finishedWithMark; + EMtDecParseState parseState; + BoolInt parsing_Truncated; + BoolInt atBlockHeader; + CXzStreamFlags streamFlags; + // UInt64 numFinishedStreams + UInt64 numStreams; + UInt64 numTotalBlocks; + UInt64 numBlocks; + + BoolInt dec_created; + CXzUnpacker dec; + + Byte mtPad[1 << 7]; +} CXzDecMtThread; + +#endif + + +/* ---------- CXzDecMt ---------- */ + +typedef struct +{ + CAlignOffsetAlloc alignOffsetAlloc; + ISzAllocPtr allocMid; + + CXzDecMtProps props; + size_t unpackBlockMaxSize; + + ISeqInStream *inStream; + ISeqOutStream *outStream; + ICompressProgress *progress; + // CXzStatInfo *stat; + + BoolInt finishMode; + BoolInt outSize_Defined; + UInt64 outSize; + + UInt64 outProcessed; + UInt64 inProcessed; + UInt64 readProcessed; + BoolInt readWasFinished; + SRes readRes; + SRes writeRes; + + Byte *outBuf; + size_t outBufSize; + Byte *inBuf; + size_t inBufSize; + + CXzUnpacker dec; + + ECoderStatus status; + SRes codeRes; + + #ifndef _7ZIP_ST + BoolInt mainDecoderWasCalled; + // int statErrorDefined; + int finishedDecoderIndex; + + // global values that are used in Parse stage + CXzStreamFlags streamFlags; + // UInt64 numFinishedStreams + UInt64 numStreams; + UInt64 numTotalBlocks; + UInt64 numBlocks; + + // UInt64 numBadBlocks; + SRes mainErrorCode; + + BoolInt isBlockHeaderState_Parse; + BoolInt isBlockHeaderState_Write; + UInt64 outProcessed_Parse; + BoolInt parsing_Truncated; + + BoolInt mtc_WasConstructed; + CMtDec mtc; + CXzDecMtThread coders[MTDEC__THREADS_MAX]; + #endif + +} CXzDecMt; + + + +CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) +{ + CXzDecMt *p = (CXzDecMt *)ISzAlloc_Alloc(alloc, sizeof(CXzDecMt)); + if (!p) + return NULL; + + AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); + p->alignOffsetAlloc.baseAlloc = alloc; + p->alignOffsetAlloc.numAlignBits = 7; + p->alignOffsetAlloc.offset = 0; + + p->allocMid = allocMid; + + p->outBuf = NULL; + p->outBufSize = 0; + p->inBuf = NULL; + p->inBufSize = 0; + + XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt); + + p->unpackBlockMaxSize = 0; + + XzDecMtProps_Init(&p->props); + + #ifndef _7ZIP_ST + p->mtc_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CXzDecMtThread *coder = &p->coders[i]; + coder->dec_created = False; + coder->outBuf = NULL; + coder->outBufSize = 0; + } + } + #endif + + return p; +} + + +#ifndef _7ZIP_ST + +static void XzDecMt_FreeOutBufs(CXzDecMt *p) +{ + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CXzDecMtThread *coder = &p->coders[i]; + if (coder->outBuf) + { + ISzAlloc_Free(p->allocMid, coder->outBuf); + coder->outBuf = NULL; + coder->outBufSize = 0; + } + } + p->unpackBlockMaxSize = 0; +} + +#endif + + + +static void XzDecMt_FreeSt(CXzDecMt *p) +{ + XzUnpacker_Free(&p->dec); + + if (p->outBuf) + { + ISzAlloc_Free(p->allocMid, p->outBuf); + p->outBuf = NULL; + } + p->outBufSize = 0; + + if (p->inBuf) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBuf = NULL; + } + p->inBufSize = 0; +} + + +void XzDecMt_Destroy(CXzDecMtHandle pp) +{ + CXzDecMt *p = (CXzDecMt *)pp; + + XzDecMt_FreeSt(p); + + #ifndef _7ZIP_ST + + if (p->mtc_WasConstructed) + { + MtDec_Destruct(&p->mtc); + p->mtc_WasConstructed = False; + } + { + unsigned i; + for (i = 0; i < MTDEC__THREADS_MAX; i++) + { + CXzDecMtThread *t = &p->coders[i]; + if (t->dec_created) + { + // we don't need to free dict here + XzUnpacker_Free(&t->dec); + t->dec_created = False; + } + } + } + XzDecMt_FreeOutBufs(p); + + #endif + + ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp); +} + + + +#ifndef _7ZIP_ST + +static void XzDecMt_Callback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) +{ + CXzDecMt *me = (CXzDecMt *)obj; + CXzDecMtThread *coder = &me->coders[coderIndex]; + size_t srcSize = cc->srcSize; + + cc->srcSize = 0; + cc->outPos = 0; + cc->state = MTDEC_PARSE_CONTINUE; + + cc->canCreateNewThread = True; + + if (cc->startCall) + { + coder->outPreSize = 0; + coder->inPreSize = 0; + coder->inPreHeaderSize = 0; + coder->parseState = MTDEC_PARSE_CONTINUE; + coder->parsing_Truncated = False; + coder->skipMode = False; + coder->codeRes = SZ_OK; + coder->status = CODER_STATUS_NOT_SPECIFIED; + coder->inCodeSize = 0; + coder->outCodeSize = 0; + + coder->numStreams = me->numStreams; + coder->numTotalBlocks = me->numTotalBlocks; + coder->numBlocks = me->numBlocks; + + if (!coder->dec_created) + { + XzUnpacker_Construct(&coder->dec, &me->alignOffsetAlloc.vt); + coder->dec_created = True; + } + + XzUnpacker_Init(&coder->dec); + + if (me->isBlockHeaderState_Parse) + { + coder->dec.streamFlags = me->streamFlags; + coder->atBlockHeader = True; + XzUnpacker_PrepareToRandomBlockDecoding(&coder->dec); + } + else + { + coder->atBlockHeader = False; + me->isBlockHeaderState_Parse = True; + } + + coder->dec.numStartedStreams = me->numStreams; + coder->dec.numTotalBlocks = me->numTotalBlocks; + coder->dec.numBlocks = me->numBlocks; + } + + while (!coder->skipMode) + { + ECoderStatus status; + SRes res; + size_t srcSize2 = srcSize; + size_t destSize = (size_t)0 - 1; + + coder->dec.parseMode = True; + coder->dec.headerParsedOk = False; + + PRF_STR_INT("Parse", srcSize2); + + res = XzUnpacker_Code(&coder->dec, + NULL, &destSize, + cc->src, &srcSize2, cc->srcFinished, + CODER_FINISH_END, &status); + + // PRF(printf(" res = %d, srcSize2 = %d", res, (unsigned)srcSize2)); + + coder->codeRes = res; + coder->status = status; + cc->srcSize += srcSize2; + srcSize -= srcSize2; + coder->inPreHeaderSize += srcSize2; + coder->inPreSize = coder->inPreHeaderSize; + + if (res != SZ_OK) + { + cc->state = + coder->parseState = MTDEC_PARSE_END; + /* + if (res == SZ_ERROR_MEM) + return res; + return SZ_OK; + */ + return; // res; + } + + if (coder->dec.headerParsedOk) + { + const CXzBlock *block = &coder->dec.block; + if (XzBlock_HasUnpackSize(block) + // && block->unpackSize <= me->props.outBlockMax + && XzBlock_HasPackSize(block)) + { + { + if (block->unpackSize * 2 * me->mtc.numStartedThreads > me->props.memUseMax) + { + cc->state = MTDEC_PARSE_OVERFLOW; + return; // SZ_OK; + } + } + { + UInt64 packSize = block->packSize; + UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3); + UInt32 checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags); + UInt64 blockPackSum = coder->inPreSize + packSizeAligned + checkSize; + // if (blockPackSum <= me->props.inBlockMax) + // unpackBlockMaxSize + { + coder->blockPackSize_for_Index = (size_t)(coder->dec.blockHeaderSize + packSize + checkSize); + coder->blockPackTotal = (size_t)blockPackSum; + coder->outPreSize = (size_t)block->unpackSize; + coder->streamFlags = coder->dec.streamFlags; + me->streamFlags = coder->dec.streamFlags; + coder->skipMode = True; + break; + } + } + } + } + else + // if (coder->inPreSize <= me->props.inBlockMax) + { + if (!cc->srcFinished) + return; // SZ_OK; + cc->state = + coder->parseState = MTDEC_PARSE_END; + return; // SZ_OK; + } + cc->state = MTDEC_PARSE_OVERFLOW; + return; // SZ_OK; + } + + // ---------- skipMode ---------- + { + UInt64 rem = coder->blockPackTotal - coder->inPreSize; + size_t cur = srcSize; + if (cur > rem) + cur = (size_t)rem; + cc->srcSize += cur; + coder->inPreSize += cur; + srcSize -= cur; + + if (coder->inPreSize == coder->blockPackTotal) + { + if (srcSize == 0) + { + if (!cc->srcFinished) + return; // SZ_OK; + cc->state = MTDEC_PARSE_END; + } + else if ((cc->src)[cc->srcSize] == 0) // we check control byte of next block + cc->state = MTDEC_PARSE_END; + else + { + cc->state = MTDEC_PARSE_NEW; + + { + size_t blockMax = me->unpackBlockMaxSize; + if (blockMax < coder->outPreSize) + blockMax = coder->outPreSize; + { + UInt64 required = (UInt64)blockMax * (me->mtc.numStartedThreads + 1) * 2; + if (me->props.memUseMax < required) + cc->canCreateNewThread = False; + } + } + + if (me->outSize_Defined) + { + // next block can be zero size + const UInt64 rem2 = me->outSize - me->outProcessed_Parse; + if (rem2 < coder->outPreSize) + { + coder->parsing_Truncated = True; + cc->state = MTDEC_PARSE_END; + } + me->outProcessed_Parse += coder->outPreSize; + } + } + } + else if (cc->srcFinished) + cc->state = MTDEC_PARSE_END; + else + return; // SZ_OK; + + coder->parseState = cc->state; + cc->outPos = coder->outPreSize; + + me->numStreams = coder->dec.numStartedStreams; + me->numTotalBlocks = coder->dec.numTotalBlocks; + me->numBlocks = coder->dec.numBlocks + 1; + return; // SZ_OK; + } +} + + +static SRes XzDecMt_Callback_PreCode(void *pp, unsigned coderIndex) +{ + CXzDecMt *me = (CXzDecMt *)pp; + CXzDecMtThread *coder = &me->coders[coderIndex]; + Byte *dest; + + if (!coder->dec.headerParsedOk) + return SZ_OK; + + dest = coder->outBuf; + + if (!dest || coder->outBufSize < coder->outPreSize) + { + if (dest) + { + ISzAlloc_Free(me->allocMid, dest); + coder->outBuf = NULL; + coder->outBufSize = 0; + } + { + size_t outPreSize = coder->outPreSize; + if (outPreSize == 0) + outPreSize = 1; + dest = (Byte *)ISzAlloc_Alloc(me->allocMid, outPreSize); + } + if (!dest) + return SZ_ERROR_MEM; + coder->outBuf = dest; + coder->outBufSize = coder->outPreSize; + + if (coder->outBufSize > me->unpackBlockMaxSize) + me->unpackBlockMaxSize = coder->outBufSize; + } + + // return SZ_ERROR_MEM; + + XzUnpacker_SetOutBuf(&coder->dec, coder->outBuf, coder->outBufSize); + + { + SRes res = XzDecMix_Init(&coder->dec.decoder, &coder->dec.block, coder->outBuf, coder->outBufSize); + // res = SZ_ERROR_UNSUPPORTED; // to test + coder->codeRes = res; + if (res != SZ_OK) + { + // if (res == SZ_ERROR_MEM) return res; + if (me->props.ignoreErrors && res != SZ_ERROR_MEM) + return S_OK; + return res; + } + } + + return SZ_OK; +} + + +static SRes XzDecMt_Callback_Code(void *pp, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + // int finished, int blockFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop) +{ + CXzDecMt *me = (CXzDecMt *)pp; + CXzDecMtThread *coder = &me->coders[coderIndex]; + + *inCodePos = coder->inCodeSize; + *outCodePos = coder->outCodeSize; + *stop = True; + + if (coder->inCodeSize < coder->inPreHeaderSize) + { + UInt64 rem = coder->inPreHeaderSize - coder->inCodeSize; + size_t step = srcSize; + if (step > rem) + step = (size_t)rem; + src += step; + srcSize -= step; + coder->inCodeSize += step; + if (coder->inCodeSize < coder->inPreHeaderSize) + { + *stop = False; + return SZ_OK; + } + } + + if (!coder->dec.headerParsedOk) + return SZ_OK; + if (!coder->outBuf) + return SZ_OK; + + if (coder->codeRes == SZ_OK) + { + ECoderStatus status; + SRes res; + size_t srcProcessed = srcSize; + size_t outSizeCur = coder->outPreSize - coder->dec.outDataWritten; + + // PRF(printf("\nCallback_Code: Code %d %d\n", (unsigned)srcSize, (unsigned)outSizeCur)); + + res = XzUnpacker_Code(&coder->dec, + NULL, &outSizeCur, + src, &srcProcessed, srcFinished, + // coder->finishedWithMark ? CODER_FINISH_END : CODER_FINISH_ANY, + CODER_FINISH_END, + &status); + + // PRF(printf(" res = %d, srcSize2 = %d, outSizeCur = %d", res, (unsigned)srcProcessed, (unsigned)outSizeCur)); + + coder->codeRes = res; + coder->status = status; + coder->inCodeSize += srcProcessed; + coder->outCodeSize = coder->dec.outDataWritten; + *inCodePos = coder->inCodeSize; + *outCodePos = coder->outCodeSize; + + if (res == SZ_OK) + { + if (srcProcessed == srcSize) + *stop = False; + return SZ_OK; + } + } + + if (me->props.ignoreErrors && coder->codeRes != SZ_ERROR_MEM) + { + *inCodePos = coder->inPreSize; + *outCodePos = coder->outPreSize; + return S_OK; + } + return coder->codeRes; +} + + +#define XZDECMT_STREAM_WRITE_STEP (1 << 24) + +static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, + // int srcFinished, + BoolInt *needContinue, + BoolInt *canRecode) +{ + CXzDecMt *me = (CXzDecMt *)pp; + const CXzDecMtThread *coder = &me->coders[coderIndex]; + + // PRF(printf("\nWrite processed = %d srcSize = %d\n", (unsigned)me->mtc.inProcessed, (unsigned)srcSize)); + + *needContinue = False; + *canRecode = True; + + if (!needWriteToStream) + return SZ_OK; + + if (!coder->dec.headerParsedOk || !coder->outBuf) + { + if (me->finishedDecoderIndex < 0) + me->finishedDecoderIndex = coderIndex; + return SZ_OK; + } + + if (me->finishedDecoderIndex >= 0) + return SZ_OK; + + me->mtc.inProcessed += coder->inCodeSize; + + *canRecode = False; + + { + SRes res; + size_t size = coder->outCodeSize; + Byte *data = coder->outBuf; + + // we use in me->dec: sha, numBlocks, indexSize + + if (!me->isBlockHeaderState_Write) + { + XzUnpacker_PrepareToRandomBlockDecoding(&me->dec); + me->dec.decodeOnlyOneBlock = False; + me->dec.numStartedStreams = coder->dec.numStartedStreams; + me->dec.streamFlags = coder->streamFlags; + + me->isBlockHeaderState_Write = True; + } + + me->dec.numTotalBlocks = coder->dec.numTotalBlocks; + XzUnpacker_UpdateIndex(&me->dec, coder->blockPackSize_for_Index, coder->outPreSize); + + if (coder->outPreSize != size) + { + if (me->props.ignoreErrors) + { + memset(data + size, 0, coder->outPreSize - size); + size = coder->outPreSize; + } + // me->numBadBlocks++; + if (me->mainErrorCode == SZ_OK) + { + if ((int)coder->status == LZMA_STATUS_NEEDS_MORE_INPUT) + me->mainErrorCode = SZ_ERROR_INPUT_EOF; + else + me->mainErrorCode = SZ_ERROR_DATA; + } + } + + if (me->writeRes != SZ_OK) + return me->writeRes; + + res = SZ_OK; + { + if (me->outSize_Defined) + { + const UInt64 rem = me->outSize - me->outProcessed; + if (size > rem) + size = (SizeT)rem; + } + + for (;;) + { + size_t cur = size; + size_t written; + if (cur > XZDECMT_STREAM_WRITE_STEP) + cur = XZDECMT_STREAM_WRITE_STEP; + + written = ISeqOutStream_Write(me->outStream, data, cur); + + // PRF(printf("\nWritten ask = %d written = %d\n", (unsigned)cur, (unsigned)written)); + + me->outProcessed += written; + if (written != cur) + { + me->writeRes = SZ_ERROR_WRITE; + res = me->writeRes; + break; + } + data += cur; + size -= cur; + // PRF_STR_INT("Written size =", size); + if (size == 0) + break; + res = MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0); + if (res != SZ_OK) + break; + } + } + + if (coder->codeRes != SZ_OK) + if (!me->props.ignoreErrors) + { + me->finishedDecoderIndex = coderIndex; + return res; + } + + RINOK(res); + + if (coder->inPreSize != coder->inCodeSize + || coder->blockPackTotal != coder->inCodeSize) + { + me->finishedDecoderIndex = coderIndex; + return SZ_OK; + } + + if (coder->parseState != MTDEC_PARSE_END) + { + *needContinue = True; + return SZ_OK; + } + } + + // (coder->state == MTDEC_PARSE_END) means that there are no other working threads + // so we can use mtc variables without lock + + PRF_STR_INT("Write MTDEC_PARSE_END", me->mtc.inProcessed); + + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + { + CXzUnpacker *dec = &me->dec; + + PRF_STR_INT("PostSingle", srcSize); + + { + size_t srcProcessed = srcSize; + ECoderStatus status; + size_t outSizeCur = 0; + SRes res; + + // dec->decodeOnlyOneBlock = False; + dec->decodeToStreamSignature = True; + + me->mainDecoderWasCalled = True; + + if (coder->parsing_Truncated) + { + me->parsing_Truncated = True; + return SZ_OK; + } + + res = XzUnpacker_Code(dec, + NULL, &outSizeCur, + src, &srcProcessed, + me->mtc.readWasFinished, // srcFinished + CODER_FINISH_END, // CODER_FINISH_ANY, + &status); + + me->status = status; + me->codeRes = res; + + me->mtc.inProcessed += srcProcessed; + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + + if (res != SZ_OK) + { + return S_OK; + // return res; + } + + if (dec->state == XZ_STATE_STREAM_HEADER) + { + *needContinue = True; + me->isBlockHeaderState_Parse = False; + me->isBlockHeaderState_Write = False; + { + Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); + if (!crossBuf) + return SZ_ERROR_MEM; + memcpy(crossBuf, src + srcProcessed, srcSize - srcProcessed); + } + me->mtc.crossStart = 0; + me->mtc.crossEnd = srcSize - srcProcessed; + return SZ_OK; + } + + if (status != CODER_STATUS_NEEDS_MORE_INPUT) + { + return E_FAIL; + } + + if (me->mtc.readWasFinished) + { + return SZ_OK; + } + } + + { + size_t inPos; + size_t inLim; + const Byte *inData; + UInt64 inProgressPrev = me->mtc.inProcessed; + + // XzDecMt_Prepare_InBuf_ST(p); + Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); + if (!crossBuf) + return SZ_ERROR_MEM; + + inPos = 0; + inLim = 0; + // outProcessed = 0; + + inData = crossBuf; + + for (;;) + { + SizeT inProcessed; + SizeT outProcessed; + ECoderStatus status; + SRes res; + + if (inPos == inLim) + { + if (!me->mtc.readWasFinished) + { + inPos = 0; + inLim = me->mtc.inBufSize; + me->mtc.readRes = ISeqInStream_Read(me->inStream, (void *)inData, &inLim); + me->mtc.readProcessed += inLim; + if (inLim == 0 || me->mtc.readRes != SZ_OK) + me->mtc.readWasFinished = True; + } + } + + inProcessed = inLim - inPos; + outProcessed = 0; + + res = XzUnpacker_Code(dec, + NULL, &outProcessed, + inData + inPos, &inProcessed, + (inProcessed == 0), // srcFinished + CODER_FINISH_END, &status); + + me->codeRes = res; + me->status = status; + inPos += inProcessed; + me->mtc.inProcessed += inProcessed; + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + + if (res != SZ_OK) + { + return S_OK; + // return res; + } + + if (dec->state == XZ_STATE_STREAM_HEADER) + { + *needContinue = True; + me->mtc.crossStart = inPos; + me->mtc.crossEnd = inLim; + me->isBlockHeaderState_Parse = False; + me->isBlockHeaderState_Write = False; + return SZ_OK; + } + + if (status != CODER_STATUS_NEEDS_MORE_INPUT) + return E_FAIL; + + if (me->mtc.progress) + { + UInt64 inDelta = me->mtc.inProcessed - inProgressPrev; + if (inDelta >= (1 << 22)) + { + RINOK(MtProgress_Progress_ST(&me->mtc.mtProgress)); + inProgressPrev = me->mtc.inProcessed; + } + } + if (me->mtc.readWasFinished) + return SZ_OK; + } + } + } +} + + +#endif + + + +void XzStatInfo_Clear(CXzStatInfo *p) +{ + p->InSize = 0; + p->OutSize = 0; + + p->NumStreams = 0; + p->NumBlocks = 0; + + p->UnpackSize_Defined = False; + + p->NumStreams_Defined = False; + p->NumBlocks_Defined = False; + + // p->IsArc = False; + // p->UnexpectedEnd = False; + // p->Unsupported = False; + // p->HeadersError = False; + // p->DataError = False; + // p->CrcError = False; + + p->DataAfterEnd = False; + p->DecodingTruncated = False; + + p->DecodeRes = SZ_OK; + p->ReadRes = SZ_OK; + p->ProgressRes = SZ_OK; + + p->CombinedRes = SZ_OK; + p->CombinedRes_Type = SZ_OK; +} + + + + +static SRes XzDecMt_Decode_ST(CXzDecMt *p + #ifndef _7ZIP_ST + , BoolInt tMode + #endif + , CXzStatInfo *stat) +{ + size_t outPos; + size_t inPos, inLim; + const Byte *inData; + UInt64 inPrev, outPrev; + + CXzUnpacker *dec; + + #ifndef _7ZIP_ST + if (tMode) + { + XzDecMt_FreeOutBufs(p); + tMode = MtDec_PrepareRead(&p->mtc); + } + #endif + + if (!p->outBuf || p->outBufSize != p->props.outStep_ST) + { + ISzAlloc_Free(p->allocMid, p->outBuf); + p->outBufSize = 0; + p->outBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.outStep_ST); + if (!p->outBuf) + return SZ_ERROR_MEM; + p->outBufSize = p->props.outStep_ST; + } + + if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBufSize = 0; + p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); + if (!p->inBuf) + return SZ_ERROR_MEM; + p->inBufSize = p->props.inBufSize_ST; + } + + dec = &p->dec; + dec->decodeToStreamSignature = False; + // dec->decodeOnlyOneBlock = False; + + XzUnpacker_SetOutBuf(dec, NULL, 0); + + inPrev = p->inProcessed; + outPrev = p->outProcessed; + + inPos = 0; + inLim = 0; + inData = NULL; + outPos = 0; + + for (;;) + { + SizeT outSize; + BoolInt finished; + ECoderFinishMode finishMode; + SizeT inProcessed; + ECoderStatus status; + SRes res; + + SizeT outProcessed; + + + + if (inPos == inLim) + { + #ifndef _7ZIP_ST + if (tMode) + { + inData = MtDec_Read(&p->mtc, &inLim); + inPos = 0; + if (inData) + continue; + tMode = False; + inLim = 0; + } + #endif + + if (!p->readWasFinished) + { + inPos = 0; + inLim = p->inBufSize; + inData = p->inBuf; + p->readRes = ISeqInStream_Read(p->inStream, (void *)inData, &inLim); + p->readProcessed += inLim; + if (inLim == 0 || p->readRes != SZ_OK) + p->readWasFinished = True; + } + } + + outSize = p->props.outStep_ST - outPos; + + finishMode = CODER_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (outSize >= rem) + { + outSize = (SizeT)rem; + if (p->finishMode) + finishMode = CODER_FINISH_END; + } + } + + inProcessed = inLim - inPos; + outProcessed = outSize; + + res = XzUnpacker_Code(dec, p->outBuf + outPos, &outProcessed, + inData + inPos, &inProcessed, + (inPos == inLim), // srcFinished + finishMode, &status); + + p->codeRes = res; + p->status = status; + + inPos += inProcessed; + outPos += outProcessed; + p->inProcessed += inProcessed; + p->outProcessed += outProcessed; + + finished = ((inProcessed == 0 && outProcessed == 0) || res != SZ_OK); + + if (finished || outProcessed >= outSize) + if (outPos != 0) + { + size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos); + p->outProcessed += written; + if (written != outPos) + { + stat->CombinedRes_Type = SZ_ERROR_WRITE; + return SZ_ERROR_WRITE; + } + outPos = 0; + } + + if (p->progress && res == SZ_OK) + { + UInt64 inDelta = p->inProcessed - inPrev; + UInt64 outDelta = p->outProcessed - outPrev; + if (inDelta >= (1 << 22) || outDelta >= (1 << 22)) + { + res = ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed); + if (res != SZ_OK) + { + stat->CombinedRes_Type = SZ_ERROR_PROGRESS; + stat->ProgressRes = res; + return res; + } + inPrev = p->inProcessed; + outPrev = p->outProcessed; + } + } + + if (finished) + return res; + } +} + +static SRes XzStatInfo_SetStat(const CXzUnpacker *dec, + int finishMode, + UInt64 readProcessed, UInt64 inProcessed, + SRes res, ECoderStatus status, + BoolInt decodingTruncated, + CXzStatInfo *stat) +{ + UInt64 extraSize; + + stat->DecodingTruncated = (Byte)(decodingTruncated ? 1 : 0); + stat->InSize = inProcessed; + stat->NumStreams = dec->numStartedStreams; + stat->NumBlocks = dec->numTotalBlocks; + + stat->UnpackSize_Defined = True; + stat->NumStreams_Defined = True; + stat->NumBlocks_Defined = True; + + extraSize = XzUnpacker_GetExtraSize(dec); + + if (res == SZ_OK) + { + if (status == CODER_STATUS_NEEDS_MORE_INPUT) + { + // CODER_STATUS_NEEDS_MORE_INPUT is expected status for correct xz streams + extraSize = 0; + if (!XzUnpacker_IsStreamWasFinished(dec)) + res = SZ_ERROR_INPUT_EOF; + } + else if (!decodingTruncated || finishMode) // (status == CODER_STATUS_NOT_FINISHED) + res = SZ_ERROR_DATA; + } + else if (res == SZ_ERROR_NO_ARCHIVE) + { + /* + SZ_ERROR_NO_ARCHIVE is possible for 2 states: + XZ_STATE_STREAM_HEADER - if bad signature or bad CRC + XZ_STATE_STREAM_PADDING - if non-zero padding data + extraSize / inProcessed don't include "bad" byte + */ + if (inProcessed != extraSize) // if good streams before error + if (extraSize != 0 || readProcessed != inProcessed) + { + stat->DataAfterEnd = True; + // there is some good xz stream before. So we set SZ_OK + res = SZ_OK; + } + } + + stat->DecodeRes = res; + + stat->InSize -= extraSize; + return res; +} + + +SRes XzDecMt_Decode(CXzDecMtHandle pp, + const CXzDecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqOutStream *outStream, + // Byte *outBuf, size_t *outBufSize, + ISeqInStream *inStream, + // const Byte *inData, size_t inDataSize, + CXzStatInfo *stat, + int *isMT, + ICompressProgress *progress) +{ + CXzDecMt *p = (CXzDecMt *)pp; + #ifndef _7ZIP_ST + BoolInt tMode; + #endif + + XzStatInfo_Clear(stat); + + p->props = *props; + + p->inStream = inStream; + p->outStream = outStream; + p->progress = progress; + // p->stat = stat; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + + p->finishMode = finishMode; + + // p->outSize = 457; p->outSize_Defined = True; p->finishMode = False; // for test + + p->writeRes = SZ_OK; + p->outProcessed = 0; + p->inProcessed = 0; + p->readProcessed = 0; + p->readWasFinished = False; + + p->codeRes = 0; + p->status = CODER_STATUS_NOT_SPECIFIED; + + XzUnpacker_Init(&p->dec); + + *isMT = False; + + /* + p->outBuf = NULL; + p->outBufSize = 0; + if (!outStream) + { + p->outBuf = outBuf; + p->outBufSize = *outBufSize; + *outBufSize = 0; + } + */ + + + #ifndef _7ZIP_ST + + p->isBlockHeaderState_Parse = False; + p->isBlockHeaderState_Write = False; + // p->numBadBlocks = 0; + p->mainErrorCode = SZ_OK; + p->mainDecoderWasCalled = False; + + tMode = False; + + if (p->props.numThreads > 1) + { + IMtDecCallback vt; + + // we just free ST buffers here + // but we still keep state variables, that was set in XzUnpacker_Init() + XzDecMt_FreeSt(p); + + p->outProcessed_Parse = 0; + p->parsing_Truncated = False; + + p->numStreams = 0; + p->numTotalBlocks = 0; + p->numBlocks = 0; + p->finishedDecoderIndex = -1; + + if (!p->mtc_WasConstructed) + { + p->mtc_WasConstructed = True; + MtDec_Construct(&p->mtc); + } + + p->mtc.mtCallback = &vt; + p->mtc.mtCallbackObject = p; + + p->mtc.progress = progress; + p->mtc.inStream = inStream; + p->mtc.alloc = &p->alignOffsetAlloc.vt; + // p->mtc.inData = inData; + // p->mtc.inDataSize = inDataSize; + p->mtc.inBufSize = p->props.inBufSize_MT; + // p->mtc.inBlockMax = p->props.inBlockMax; + p->mtc.numThreadsMax = p->props.numThreads; + + *isMT = True; + + vt.Parse = XzDecMt_Callback_Parse; + vt.PreCode = XzDecMt_Callback_PreCode; + vt.Code = XzDecMt_Callback_Code; + vt.Write = XzDecMt_Callback_Write; + + { + BoolInt needContinue; + + SRes res = MtDec_Code(&p->mtc); + + stat->InSize = p->mtc.inProcessed; + + p->inProcessed = p->mtc.inProcessed; + p->readRes = p->mtc.readRes; + p->readWasFinished = p->mtc.readWasFinished; + p->readProcessed = p->mtc.readProcessed; + + tMode = True; + needContinue = False; + + if (res == SZ_OK) + { + if (p->mtc.mtProgress.res != SZ_OK) + { + res = p->mtc.mtProgress.res; + stat->ProgressRes = res; + stat->CombinedRes_Type = SZ_ERROR_PROGRESS; + } + else + needContinue = p->mtc.needContinue; + } + + if (!needContinue) + { + SRes codeRes; + BoolInt truncated = False; + ECoderStatus status; + CXzUnpacker *dec; + + stat->OutSize = p->outProcessed; + + if (p->finishedDecoderIndex >= 0) + { + CXzDecMtThread *coder = &p->coders[(unsigned)p->finishedDecoderIndex]; + codeRes = coder->codeRes; + dec = &coder->dec; + status = coder->status; + } + else if (p->mainDecoderWasCalled) + { + codeRes = p->codeRes; + dec = &p->dec; + status = p->status; + truncated = p->parsing_Truncated; + } + else + return E_FAIL; + + XzStatInfo_SetStat(dec, p->finishMode, + p->mtc.readProcessed, p->mtc.inProcessed, + codeRes, status, + truncated, + stat); + + if (res == SZ_OK) + { + if (p->writeRes != SZ_OK) + { + res = p->writeRes; + stat->CombinedRes_Type = SZ_ERROR_WRITE; + } + else if (p->mtc.readRes != SZ_OK && p->mtc.inProcessed == p->mtc.readProcessed) + { + res = p->mtc.readRes; + stat->ReadRes = res; + stat->CombinedRes_Type = SZ_ERROR_READ; + } + else if (p->mainErrorCode != SZ_OK) + { + res = p->mainErrorCode; + } + } + + stat->CombinedRes = res; + if (stat->CombinedRes_Type == SZ_OK) + stat->CombinedRes_Type = res; + return res; + } + + PRF_STR("----- decoding ST -----"); + } + } + + #endif + + + *isMT = False; + + { + SRes res = XzDecMt_Decode_ST(p + #ifndef _7ZIP_ST + , tMode + #endif + , stat + ); + + XzStatInfo_SetStat(&p->dec, + p->finishMode, + p->readProcessed, p->inProcessed, + p->codeRes, p->status, + False, // truncated + stat); + + if (res == SZ_OK) + { + /* + if (p->writeRes != SZ_OK) + { + res = p->writeRes; + stat->CombinedRes_Type = SZ_ERROR_WRITE; + } + else + */ + if (p->readRes != SZ_OK && p->inProcessed == p->readProcessed) + { + res = p->readRes; + stat->ReadRes = res; + stat->CombinedRes_Type = SZ_ERROR_READ; + } + #ifndef _7ZIP_ST + else if (p->mainErrorCode != SZ_OK) + res = p->mainErrorCode; + #endif + } + + stat->CombinedRes = res; + if (stat->CombinedRes_Type == SZ_OK) + stat->CombinedRes_Type = res; + return res; + } +} diff --git a/lzma/XzEnc.c b/lzma/XzEnc.c new file mode 100644 index 0000000..309eca9 --- /dev/null +++ b/lzma/XzEnc.c @@ -0,0 +1,1329 @@ +/* XzEnc.c -- Xz Encode +2019-02-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include +#include + +#include "7zCrc.h" +#include "Bra.h" +#include "CpuArch.h" + +#ifdef USE_SUBBLOCK +#include "Bcj3Enc.c" +#include "SbFind.c" +#include "SbEnc.c" +#endif + +#include "XzEnc.h" + +// #define _7ZIP_ST + +#ifndef _7ZIP_ST +#include "MtCoder.h" +#else +#define MTCODER__THREADS_MAX 1 +#define MTCODER__BLOCKS_MAX 1 +#endif + +#define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3) + +/* max pack size for LZMA2 block + check-64bytrs: */ +#define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64) + +#define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize)) + + +#define XzBlock_ClearFlags(p) (p)->flags = 0; +#define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1); +#define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE; +#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE; + + +static SRes WriteBytes(ISeqOutStream *s, const void *buf, size_t size) +{ + return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; +} + +static SRes WriteBytesUpdateCrc(ISeqOutStream *s, const void *buf, size_t size, UInt32 *crc) +{ + *crc = CrcUpdate(*crc, buf, size); + return WriteBytes(s, buf, size); +} + + +static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s) +{ + UInt32 crc; + Byte header[XZ_STREAM_HEADER_SIZE]; + memcpy(header, XZ_SIG, XZ_SIG_SIZE); + header[XZ_SIG_SIZE] = (Byte)(f >> 8); + header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); + crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); + SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc); + return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); +} + + +static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s) +{ + Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; + + unsigned pos = 1; + unsigned numFilters, i; + header[pos++] = p->flags; + + if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); + if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); + numFilters = XzBlock_GetNumFilters(p); + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &p->filters[i]; + pos += Xz_WriteVarInt(header + pos, f->id); + pos += Xz_WriteVarInt(header + pos, f->propsSize); + memcpy(header + pos, f->props, f->propsSize); + pos += f->propsSize; + } + + while ((pos & 3) != 0) + header[pos++] = 0; + + header[0] = (Byte)(pos >> 2); + SetUi32(header + pos, CrcCalc(header, pos)); + return WriteBytes(s, header, pos + 4); +} + + + + +typedef struct +{ + size_t numBlocks; + size_t size; + size_t allocated; + Byte *blocks; +} CXzEncIndex; + + +static void XzEncIndex_Construct(CXzEncIndex *p) +{ + p->numBlocks = 0; + p->size = 0; + p->allocated = 0; + p->blocks = NULL; +} + +static void XzEncIndex_Init(CXzEncIndex *p) +{ + p->numBlocks = 0; + p->size = 0; +} + +static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc) +{ + if (p->blocks) + { + ISzAlloc_Free(alloc, p->blocks); + p->blocks = NULL; + } + p->numBlocks = 0; + p->size = 0; + p->allocated = 0; +} + + +static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc) +{ + Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize); + if (!blocks) + return SZ_ERROR_MEM; + if (p->size != 0) + memcpy(blocks, p->blocks, p->size); + if (p->blocks) + ISzAlloc_Free(alloc, p->blocks); + p->blocks = blocks; + p->allocated = newSize; + return SZ_OK; +} + + +static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) +{ + UInt64 pos; + { + Byte buf[32]; + unsigned pos2 = Xz_WriteVarInt(buf, totalSize); + pos2 += Xz_WriteVarInt(buf + pos2, unpackSize); + pos = numBlocks * pos2; + } + + if (pos <= p->allocated - p->size) + return SZ_OK; + { + UInt64 newSize64 = p->size + pos; + size_t newSize = (size_t)newSize64; + if (newSize != newSize64) + return SZ_ERROR_MEM; + return XzEncIndex_ReAlloc(p, newSize, alloc); + } +} + + +static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) +{ + Byte buf[32]; + unsigned pos = Xz_WriteVarInt(buf, totalSize); + pos += Xz_WriteVarInt(buf + pos, unpackSize); + + if (pos > p->allocated - p->size) + { + size_t newSize = p->allocated * 2 + 16 * 2; + if (newSize < p->size + pos) + return SZ_ERROR_MEM; + RINOK(XzEncIndex_ReAlloc(p, newSize, alloc)); + } + memcpy(p->blocks + p->size, buf, pos); + p->size += pos; + p->numBlocks++; + return SZ_OK; +} + + +static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStream *s) +{ + Byte buf[32]; + UInt64 globalPos; + UInt32 crc = CRC_INIT_VAL; + unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); + + globalPos = pos; + buf[0] = 0; + RINOK(WriteBytesUpdateCrc(s, buf, pos, &crc)); + RINOK(WriteBytesUpdateCrc(s, p->blocks, p->size, &crc)); + globalPos += p->size; + + pos = XZ_GET_PAD_SIZE(globalPos); + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + globalPos += pos; + + crc = CrcUpdate(crc, buf + 4 - pos, pos); + SetUi32(buf + 4, CRC_GET_DIGEST(crc)); + + SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2)); + buf[8 + 8] = (Byte)(flags >> 8); + buf[8 + 9] = (Byte)(flags & 0xFF); + SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6)); + buf[8 + 10] = XZ_FOOTER_SIG_0; + buf[8 + 11] = XZ_FOOTER_SIG_1; + + return WriteBytes(s, buf + 4 - pos, pos + 4 + 12); +} + + + +/* ---------- CSeqCheckInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + ISeqInStream *realStream; + const Byte *data; + UInt64 limit; + UInt64 processed; + int realStreamFinished; + CXzCheck check; +} CSeqCheckInStream; + +static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode) +{ + p->limit = (UInt64)(Int64)-1; + p->processed = 0; + p->realStreamFinished = 0; + XzCheck_Init(&p->check, checkMode); +} + +static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) +{ + XzCheck_Final(&p->check, digest); +} + +static SRes SeqCheckInStream_Read(const ISeqInStream *pp, void *data, size_t *size) +{ + CSeqCheckInStream *p = CONTAINER_FROM_VTBL(pp, CSeqCheckInStream, vt); + size_t size2 = *size; + SRes res = SZ_OK; + + if (p->limit != (UInt64)(Int64)-1) + { + UInt64 rem = p->limit - p->processed; + if (size2 > rem) + size2 = (size_t)rem; + } + if (size2 != 0) + { + if (p->realStream) + { + res = ISeqInStream_Read(p->realStream, data, &size2); + p->realStreamFinished = (size2 == 0) ? 1 : 0; + } + else + memcpy(data, p->data + (size_t)p->processed, size2); + XzCheck_Update(&p->check, data, size2); + p->processed += size2; + } + *size = size2; + return res; +} + + +/* ---------- CSeqSizeOutStream ---------- */ + +typedef struct +{ + ISeqOutStream vt; + ISeqOutStream *realStream; + Byte *outBuf; + size_t outBufLimit; + UInt64 processed; +} CSeqSizeOutStream; + +static size_t SeqSizeOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) +{ + CSeqSizeOutStream *p = CONTAINER_FROM_VTBL(pp, CSeqSizeOutStream, vt); + if (p->realStream) + size = ISeqOutStream_Write(p->realStream, data, size); + else + { + if (size > p->outBufLimit - (size_t)p->processed) + return 0; + memcpy(p->outBuf + (size_t)p->processed, data, size); + } + p->processed += size; + return size; +} + + +/* ---------- CSeqInFilter ---------- */ + +#define FILTER_BUF_SIZE (1 << 20) + +typedef struct +{ + ISeqInStream p; + ISeqInStream *realStream; + IStateCoder StateCoder; + Byte *buf; + size_t curPos; + size_t endPos; + int srcWasFinished; +} CSeqInFilter; + + +SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc); + +static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc) +{ + if (!p->buf) + { + p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE); + if (!p->buf) + return SZ_ERROR_MEM; + } + p->curPos = p->endPos = 0; + p->srcWasFinished = 0; + RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, alloc)); + RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc)); + p->StateCoder.Init(p->StateCoder.p); + return SZ_OK; +} + + +static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size) +{ + CSeqInFilter *p = CONTAINER_FROM_VTBL(pp, CSeqInFilter, p); + size_t sizeOriginal = *size; + if (sizeOriginal == 0) + return SZ_OK; + *size = 0; + + for (;;) + { + if (!p->srcWasFinished && p->curPos == p->endPos) + { + p->curPos = 0; + p->endPos = FILTER_BUF_SIZE; + RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos)); + if (p->endPos == 0) + p->srcWasFinished = 1; + } + { + SizeT srcLen = p->endPos - p->curPos; + ECoderStatus status; + SRes res; + *size = sizeOriginal; + res = p->StateCoder.Code2(p->StateCoder.p, + (Byte *)data, size, + p->buf + p->curPos, &srcLen, + p->srcWasFinished, CODER_FINISH_ANY, + &status); + p->curPos += srcLen; + if (*size != 0 || srcLen == 0 || res != SZ_OK) + return res; + } + } +} + +static void SeqInFilter_Construct(CSeqInFilter *p) +{ + p->buf = NULL; + p->StateCoder.p = NULL; + p->p.Read = SeqInFilter_Read; +} + +static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) +{ + if (p->StateCoder.p) + { + p->StateCoder.Free(p->StateCoder.p, alloc); + p->StateCoder.p = NULL; + } + if (p->buf) + { + ISzAlloc_Free(alloc, p->buf); + p->buf = NULL; + } +} + + +/* ---------- CSbEncInStream ---------- */ + +#ifdef USE_SUBBLOCK + +typedef struct +{ + ISeqInStream vt; + ISeqInStream *inStream; + CSbEnc enc; +} CSbEncInStream; + +static SRes SbEncInStream_Read(const ISeqInStream *pp, void *data, size_t *size) +{ + CSbEncInStream *p = CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt); + size_t sizeOriginal = *size; + if (sizeOriginal == 0) + return SZ_OK; + + for (;;) + { + if (p->enc.needRead && !p->enc.readWasFinished) + { + size_t processed = p->enc.needReadSizeMax; + RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed)); + p->enc.readPos += processed; + if (processed == 0) + { + p->enc.readWasFinished = True; + p->enc.isFinalFinished = True; + } + p->enc.needRead = False; + } + + *size = sizeOriginal; + RINOK(SbEnc_Read(&p->enc, data, size)); + if (*size != 0 || !p->enc.needRead) + return SZ_OK; + } +} + +void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc) +{ + SbEnc_Construct(&p->enc, alloc); + p->vt.Read = SbEncInStream_Read; +} + +SRes SbEncInStream_Init(CSbEncInStream *p) +{ + return SbEnc_Init(&p->enc); +} + +void SbEncInStream_Free(CSbEncInStream *p) +{ + SbEnc_Free(&p->enc); +} + +#endif + + + +/* ---------- CXzProps ---------- */ + + +void XzFilterProps_Init(CXzFilterProps *p) +{ + p->id = 0; + p->delta = 0; + p->ip = 0; + p->ipDefined = False; +} + +void XzProps_Init(CXzProps *p) +{ + p->checkId = XZ_CHECK_CRC32; + p->blockSize = XZ_PROPS__BLOCK_SIZE__AUTO; + p->numBlockThreads_Reduced = -1; + p->numBlockThreads_Max = -1; + p->numTotalThreads = -1; + p->reduceSize = (UInt64)(Int64)-1; + p->forceWriteSizesInHeader = 0; + // p->forceWriteSizesInHeader = 1; + + XzFilterProps_Init(&p->filterProps); + Lzma2EncProps_Init(&p->lzma2Props); +} + + +static void XzEncProps_Normalize_Fixed(CXzProps *p) +{ + UInt64 fileSize; + int t1, t1n, t2, t2r, t3; + { + CLzma2EncProps tp = p->lzma2Props; + if (tp.numTotalThreads <= 0) + tp.numTotalThreads = p->numTotalThreads; + Lzma2EncProps_Normalize(&tp); + t1n = tp.numTotalThreads; + } + + t1 = p->lzma2Props.numTotalThreads; + t2 = p->numBlockThreads_Max; + t3 = p->numTotalThreads; + + if (t2 > MTCODER__THREADS_MAX) + t2 = MTCODER__THREADS_MAX; + + if (t3 <= 0) + { + if (t2 <= 0) + t2 = 1; + t3 = t1n * t2; + } + else if (t2 <= 0) + { + t2 = t3 / t1n; + if (t2 == 0) + { + t1 = 1; + t2 = t3; + } + if (t2 > MTCODER__THREADS_MAX) + t2 = MTCODER__THREADS_MAX; + } + else if (t1 <= 0) + { + t1 = t3 / t2; + if (t1 == 0) + t1 = 1; + } + else + t3 = t1n * t2; + + p->lzma2Props.numTotalThreads = t1; + + t2r = t2; + + fileSize = p->reduceSize; + + if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) + p->lzma2Props.lzmaProps.reduceSize = p->blockSize; + + Lzma2EncProps_Normalize(&p->lzma2Props); + + t1 = p->lzma2Props.numTotalThreads; + + { + if (t2 > 1 && fileSize != (UInt64)(Int64)-1) + { + UInt64 numBlocks = fileSize / p->blockSize; + if (numBlocks * p->blockSize != fileSize) + numBlocks++; + if (numBlocks < (unsigned)t2) + { + t2r = (unsigned)numBlocks; + if (t2r == 0) + t2r = 1; + t3 = t1 * t2r; + } + } + } + + p->numBlockThreads_Max = t2; + p->numBlockThreads_Reduced = t2r; + p->numTotalThreads = t3; +} + + +static void XzProps_Normalize(CXzProps *p) +{ + /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties. + Lzma2Enc_SetProps() will normalize lzma2Props later. */ + + if (p->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID) + { + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + p->numBlockThreads_Reduced = 1; + p->numBlockThreads_Max = 1; + if (p->lzma2Props.numTotalThreads <= 0) + p->lzma2Props.numTotalThreads = p->numTotalThreads; + return; + } + else + { + CLzma2EncProps *lzma2 = &p->lzma2Props; + if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) + { + // xz-auto + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + + if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) + { + // if (xz-auto && lzma2-solid) - we use solid for both + p->blockSize = XZ_PROPS__BLOCK_SIZE__SOLID; + p->numBlockThreads_Reduced = 1; + p->numBlockThreads_Max = 1; + if (p->lzma2Props.numTotalThreads <= 0) + p->lzma2Props.numTotalThreads = p->numTotalThreads; + } + else + { + // if (xz-auto && (lzma2-auto || lzma2-fixed_) + // we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block + CLzma2EncProps tp = p->lzma2Props; + if (tp.numTotalThreads <= 0) + tp.numTotalThreads = p->numTotalThreads; + + Lzma2EncProps_Normalize(&tp); + + p->blockSize = tp.blockSize; // fixed or solid + p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced; + p->numBlockThreads_Max = tp.numBlockThreads_Max; + if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) + lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID + if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) + lzma2->lzmaProps.reduceSize = tp.blockSize; + lzma2->numBlockThreads_Reduced = 1; + lzma2->numBlockThreads_Max = 1; + return; + } + } + else + { + // xz-fixed + // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize + + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + { + UInt64 r = p->reduceSize; + if (r > p->blockSize || r == (UInt64)(Int64)-1) + r = p->blockSize; + lzma2->lzmaProps.reduceSize = r; + } + if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) + lzma2->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; + else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) + lzma2->blockSize = p->blockSize; + + XzEncProps_Normalize_Fixed(p); + } + } +} + + +/* ---------- CLzma2WithFilters ---------- */ + +typedef struct +{ + CLzma2EncHandle lzma2; + CSeqInFilter filter; + + #ifdef USE_SUBBLOCK + CSbEncInStream sb; + #endif +} CLzma2WithFilters; + + +static void Lzma2WithFilters_Construct(CLzma2WithFilters *p) +{ + p->lzma2 = NULL; + SeqInFilter_Construct(&p->filter); + + #ifdef USE_SUBBLOCK + SbEncInStream_Construct(&p->sb, alloc); + #endif +} + + +static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc) +{ + if (!p->lzma2) + { + p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc); + if (!p->lzma2) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + + +static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc) +{ + #ifdef USE_SUBBLOCK + SbEncInStream_Free(&p->sb); + #endif + + SeqInFilter_Free(&p->filter, alloc); + if (p->lzma2) + { + Lzma2Enc_Destroy(p->lzma2); + p->lzma2 = NULL; + } +} + + +typedef struct +{ + UInt64 unpackSize; + UInt64 totalSize; + size_t headerSize; +} CXzEncBlockInfo; + + +static SRes Xz_CompressBlock( + CLzma2WithFilters *lzmaf, + + ISeqOutStream *outStream, + Byte *outBufHeader, + Byte *outBufData, size_t outBufDataLimit, + + ISeqInStream *inStream, + // UInt64 expectedSize, + const Byte *inBuf, // used if (!inStream) + size_t inBufSize, // used if (!inStream), it's block size, props->blockSize is ignored + + const CXzProps *props, + ICompressProgress *progress, + int *inStreamFinished, /* only for inStream version */ + CXzEncBlockInfo *blockSizes, + ISzAllocPtr alloc, + ISzAllocPtr allocBig) +{ + CSeqCheckInStream checkInStream; + CSeqSizeOutStream seqSizeOutStream; + CXzBlock block; + unsigned filterIndex = 0; + CXzFilter *filter = NULL; + const CXzFilterProps *fp = &props->filterProps; + if (fp->id == 0) + fp = NULL; + + *inStreamFinished = False; + + RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig)); + + RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props)); + + XzBlock_ClearFlags(&block); + XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0)); + + if (fp) + { + filter = &block.filters[filterIndex++]; + filter->id = fp->id; + filter->propsSize = 0; + + if (fp->id == XZ_ID_Delta) + { + filter->props[0] = (Byte)(fp->delta - 1); + filter->propsSize = 1; + } + else if (fp->ipDefined) + { + SetUi32(filter->props, fp->ip); + filter->propsSize = 4; + } + } + + { + CXzFilter *f = &block.filters[filterIndex++]; + f->id = XZ_ID_LZMA2; + f->propsSize = 1; + f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); + } + + seqSizeOutStream.vt.Write = SeqSizeOutStream_Write; + seqSizeOutStream.realStream = outStream; + seqSizeOutStream.outBuf = outBufData; + seqSizeOutStream.outBufLimit = outBufDataLimit; + seqSizeOutStream.processed = 0; + + /* + if (expectedSize != (UInt64)(Int64)-1) + { + block.unpackSize = expectedSize; + if (props->blockSize != (UInt64)(Int64)-1) + if (expectedSize > props->blockSize) + block.unpackSize = props->blockSize; + XzBlock_SetHasUnpackSize(&block); + } + */ + + if (outStream) + { + RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)); + } + + checkInStream.vt.Read = SeqCheckInStream_Read; + SeqCheckInStream_Init(&checkInStream, props->checkId); + + checkInStream.realStream = inStream; + checkInStream.data = inBuf; + checkInStream.limit = props->blockSize; + if (!inStream) + checkInStream.limit = inBufSize; + + if (fp) + { + #ifdef USE_SUBBLOCK + if (fp->id == XZ_ID_Subblock) + { + lzmaf->sb.inStream = &checkInStream.vt; + RINOK(SbEncInStream_Init(&lzmaf->sb)); + } + else + #endif + { + lzmaf->filter.realStream = &checkInStream.vt; + RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc)); + } + } + + { + SRes res; + Byte *outBuf = NULL; + size_t outSize = 0; + BoolInt useStream = (fp || inStream); + // useStream = True; + + if (!useStream) + { + XzCheck_Update(&checkInStream.check, inBuf, inBufSize); + checkInStream.processed = inBufSize; + } + + if (!outStream) + { + outBuf = seqSizeOutStream.outBuf; // + (size_t)seqSizeOutStream.processed; + outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed; + } + + res = Lzma2Enc_Encode2(lzmaf->lzma2, + outBuf ? NULL : &seqSizeOutStream.vt, + outBuf, + outBuf ? &outSize : NULL, + + useStream ? + (fp ? + ( + #ifdef USE_SUBBLOCK + (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt: + #endif + &lzmaf->filter.p) : + &checkInStream.vt) : NULL, + + useStream ? NULL : inBuf, + useStream ? 0 : inBufSize, + + progress); + + if (outBuf) + seqSizeOutStream.processed += outSize; + + RINOK(res); + blockSizes->unpackSize = checkInStream.processed; + } + { + Byte buf[4 + 64]; + unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed); + UInt64 packSize = seqSizeOutStream.processed; + + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + + SeqCheckInStream_GetDigest(&checkInStream, buf + 4); + RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId))); + + blockSizes->totalSize = seqSizeOutStream.processed - padSize; + + if (!outStream) + { + seqSizeOutStream.outBuf = outBufHeader; + seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX; + seqSizeOutStream.processed = 0; + + block.unpackSize = blockSizes->unpackSize; + XzBlock_SetHasUnpackSize(&block); + + block.packSize = packSize; + XzBlock_SetHasPackSize(&block); + + RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)); + + blockSizes->headerSize = (size_t)seqSizeOutStream.processed; + blockSizes->totalSize += seqSizeOutStream.processed; + } + } + + if (inStream) + *inStreamFinished = checkInStream.realStreamFinished; + else + { + *inStreamFinished = False; + if (checkInStream.processed != inBufSize) + return SZ_ERROR_FAIL; + } + + return SZ_OK; +} + + + +typedef struct +{ + ICompressProgress vt; + ICompressProgress *progress; + UInt64 inOffset; + UInt64 outOffset; +} CCompressProgress_XzEncOffset; + + +static SRes CompressProgress_XzEncOffset_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize) +{ + const CCompressProgress_XzEncOffset *p = CONTAINER_FROM_VTBL(pp, CCompressProgress_XzEncOffset, vt); + inSize += p->inOffset; + outSize += p->outOffset; + return ICompressProgress_Progress(p->progress, inSize, outSize); +} + + + + +typedef struct +{ + ISzAllocPtr alloc; + ISzAllocPtr allocBig; + + CXzProps xzProps; + UInt64 expectedDataSize; + + CXzEncIndex xzIndex; + + CLzma2WithFilters lzmaf_Items[MTCODER__THREADS_MAX]; + + size_t outBufSize; /* size of allocated outBufs[i] */ + Byte *outBufs[MTCODER__BLOCKS_MAX]; + + #ifndef _7ZIP_ST + unsigned checkType; + ISeqOutStream *outStream; + BoolInt mtCoder_WasConstructed; + CMtCoder mtCoder; + CXzEncBlockInfo EncBlocks[MTCODER__BLOCKS_MAX]; + #endif + +} CXzEnc; + + +static void XzEnc_Construct(CXzEnc *p) +{ + unsigned i; + + XzEncIndex_Construct(&p->xzIndex); + + for (i = 0; i < MTCODER__THREADS_MAX; i++) + Lzma2WithFilters_Construct(&p->lzmaf_Items[i]); + + #ifndef _7ZIP_ST + p->mtCoder_WasConstructed = False; + { + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + p->outBufs[i] = NULL; + p->outBufSize = 0; + } + #endif +} + + +static void XzEnc_FreeOutBufs(CXzEnc *p) +{ + unsigned i; + for (i = 0; i < MTCODER__BLOCKS_MAX; i++) + if (p->outBufs[i]) + { + ISzAlloc_Free(p->alloc, p->outBufs[i]); + p->outBufs[i] = NULL; + } + p->outBufSize = 0; +} + + +static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc) +{ + unsigned i; + + XzEncIndex_Free(&p->xzIndex, alloc); + + for (i = 0; i < MTCODER__THREADS_MAX; i++) + Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc); + + #ifndef _7ZIP_ST + if (p->mtCoder_WasConstructed) + { + MtCoder_Destruct(&p->mtCoder); + p->mtCoder_WasConstructed = False; + } + XzEnc_FreeOutBufs(p); + #endif +} + + +CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc)); + if (!p) + return NULL; + XzEnc_Construct(p); + XzProps_Init(&p->xzProps); + XzProps_Normalize(&p->xzProps); + p->expectedDataSize = (UInt64)(Int64)-1; + p->alloc = alloc; + p->allocBig = allocBig; + return p; +} + + +void XzEnc_Destroy(CXzEncHandle pp) +{ + CXzEnc *p = (CXzEnc *)pp; + XzEnc_Free(p, p->alloc); + ISzAlloc_Free(p->alloc, p); +} + + +SRes XzEnc_SetProps(CXzEncHandle pp, const CXzProps *props) +{ + CXzEnc *p = (CXzEnc *)pp; + p->xzProps = *props; + XzProps_Normalize(&p->xzProps); + return SZ_OK; +} + + +void XzEnc_SetDataSize(CXzEncHandle pp, UInt64 expectedDataSiize) +{ + CXzEnc *p = (CXzEnc *)pp; + p->expectedDataSize = expectedDataSiize; +} + + + + +#ifndef _7ZIP_ST + +static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished) +{ + CXzEnc *me = (CXzEnc *)pp; + SRes res; + CMtProgressThunk progressThunk; + + Byte *dest = me->outBufs[outBufIndex]; + + UNUSED_VAR(finished) + + { + CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; + bInfo->totalSize = 0; + bInfo->unpackSize = 0; + bInfo->headerSize = 0; + } + + if (!dest) + { + dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); + if (!dest) + return SZ_ERROR_MEM; + me->outBufs[outBufIndex] = dest; + } + + MtProgressThunk_CreateVTable(&progressThunk); + progressThunk.mtProgress = &me->mtCoder.mtProgress; + MtProgressThunk_Init(&progressThunk); + + { + CXzEncBlockInfo blockSizes; + int inStreamFinished; + + res = Xz_CompressBlock( + &me->lzmaf_Items[coderIndex], + + NULL, + dest, + dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX, + + NULL, + // srcSize, // expectedSize + src, srcSize, + + &me->xzProps, + &progressThunk.vt, + &inStreamFinished, + &blockSizes, + me->alloc, + me->allocBig); + + if (res == SZ_OK) + me->EncBlocks[outBufIndex] = blockSizes; + + return res; + } +} + + +static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex) +{ + CXzEnc *me = (CXzEnc *)pp; + + const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; + const Byte *data = me->outBufs[outBufIndex]; + + RINOK(WriteBytes(me->outStream, data, bInfo->headerSize)); + + { + UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize); + RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize)); + } + + return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc); +} + +#endif + + + +SRes XzEnc_Encode(CXzEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) +{ + CXzEnc *p = (CXzEnc *)pp; + + const CXzProps *props = &p->xzProps; + + XzEncIndex_Init(&p->xzIndex); + { + UInt64 numBlocks = 1; + UInt64 blockSize = props->blockSize; + + if (blockSize != XZ_PROPS__BLOCK_SIZE__SOLID + && props->reduceSize != (UInt64)(Int64)-1) + { + numBlocks = props->reduceSize / blockSize; + if (numBlocks * blockSize != props->reduceSize) + numBlocks++; + } + else + blockSize = (UInt64)1 << 62; + + RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc)); + } + + RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream)); + + + #ifndef _7ZIP_ST + if (props->numBlockThreads_Reduced > 1) + { + IMtCoderCallback2 vt; + + if (!p->mtCoder_WasConstructed) + { + p->mtCoder_WasConstructed = True; + MtCoder_Construct(&p->mtCoder); + } + + vt.Code = XzEnc_MtCallback_Code; + vt.Write = XzEnc_MtCallback_Write; + + p->checkType = props->checkId; + p->xzProps = *props; + + p->outStream = outStream; + + p->mtCoder.allocBig = p->allocBig; + p->mtCoder.progress = progress; + p->mtCoder.inStream = inStream; + p->mtCoder.inData = NULL; + p->mtCoder.inDataSize = 0; + p->mtCoder.mtCallback = &vt; + p->mtCoder.mtCallbackObject = p; + + if ( props->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID + || props->blockSize == XZ_PROPS__BLOCK_SIZE__AUTO) + return SZ_ERROR_FAIL; + + p->mtCoder.blockSize = (size_t)props->blockSize; + if (p->mtCoder.blockSize != props->blockSize) + return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ + + { + size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize); + if (destBlockSize < p->mtCoder.blockSize) + return SZ_ERROR_PARAM; + if (p->outBufSize != destBlockSize) + XzEnc_FreeOutBufs(p); + p->outBufSize = destBlockSize; + } + + p->mtCoder.numThreadsMax = props->numBlockThreads_Max; + p->mtCoder.expectedDataSize = p->expectedDataSize; + + RINOK(MtCoder_Code(&p->mtCoder)); + } + else + #endif + { + int writeStartSizes; + CCompressProgress_XzEncOffset progress2; + Byte *bufData = NULL; + size_t bufSize = 0; + + progress2.vt.Progress = CompressProgress_XzEncOffset_Progress; + progress2.inOffset = 0; + progress2.outOffset = 0; + progress2.progress = progress; + + writeStartSizes = 0; + + if (props->blockSize != XZ_PROPS__BLOCK_SIZE__SOLID) + { + writeStartSizes = (props->forceWriteSizesInHeader > 0); + + if (writeStartSizes) + { + size_t t2; + size_t t = (size_t)props->blockSize; + if (t != props->blockSize) + return SZ_ERROR_PARAM; + t = XZ_GET_MAX_BLOCK_PACK_SIZE(t); + if (t < props->blockSize) + return SZ_ERROR_PARAM; + t2 = XZ_BLOCK_HEADER_SIZE_MAX + t; + if (!p->outBufs[0] || t2 != p->outBufSize) + { + XzEnc_FreeOutBufs(p); + p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2); + if (!p->outBufs[0]) + return SZ_ERROR_MEM; + p->outBufSize = t2; + } + bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX; + bufSize = t; + } + } + + for (;;) + { + CXzEncBlockInfo blockSizes; + int inStreamFinished; + + /* + UInt64 rem = (UInt64)(Int64)-1; + if (props->reduceSize != (UInt64)(Int64)-1 + && props->reduceSize >= progress2.inOffset) + rem = props->reduceSize - progress2.inOffset; + */ + + blockSizes.headerSize = 0; // for GCC + + RINOK(Xz_CompressBlock( + &p->lzmaf_Items[0], + + writeStartSizes ? NULL : outStream, + writeStartSizes ? p->outBufs[0] : NULL, + bufData, bufSize, + + inStream, + // rem, + NULL, 0, + + props, + progress ? &progress2.vt : NULL, + &inStreamFinished, + &blockSizes, + p->alloc, + p->allocBig)); + + { + UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize); + + if (writeStartSizes) + { + RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize)); + RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize)); + } + + RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc)); + + progress2.inOffset += blockSizes.unpackSize; + progress2.outOffset += totalPackFull; + } + + if (inStreamFinished) + break; + } + } + + return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream); +} + + +#include "Alloc.h" + +SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, + const CXzProps *props, ICompressProgress *progress) +{ + SRes res; + CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc); + if (!xz) + return SZ_ERROR_MEM; + res = XzEnc_SetProps(xz, props); + if (res == SZ_OK) + res = XzEnc_Encode(xz, outStream, inStream, progress); + XzEnc_Destroy(xz); + return res; +} + + +SRes Xz_EncodeEmpty(ISeqOutStream *outStream) +{ + SRes res; + CXzEncIndex xzIndex; + XzEncIndex_Construct(&xzIndex); + res = Xz_WriteHeader((CXzStreamFlags)0, outStream); + if (res == SZ_OK) + res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream); + XzEncIndex_Free(&xzIndex, NULL); // g_Alloc + return res; +} diff --git a/lzma/XzEnc.h b/lzma/XzEnc.h new file mode 100644 index 0000000..529ac3f --- /dev/null +++ b/lzma/XzEnc.h @@ -0,0 +1,60 @@ +/* XzEnc.h -- Xz Encode +2017-06-27 : Igor Pavlov : Public domain */ + +#ifndef __XZ_ENC_H +#define __XZ_ENC_H + +#include "Lzma2Enc.h" + +#include "Xz.h" + +EXTERN_C_BEGIN + + +#define XZ_PROPS__BLOCK_SIZE__AUTO LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO +#define XZ_PROPS__BLOCK_SIZE__SOLID LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID + + +typedef struct +{ + UInt32 id; + UInt32 delta; + UInt32 ip; + int ipDefined; +} CXzFilterProps; + +void XzFilterProps_Init(CXzFilterProps *p); + + +typedef struct +{ + CLzma2EncProps lzma2Props; + CXzFilterProps filterProps; + unsigned checkId; + UInt64 blockSize; + int numBlockThreads_Reduced; + int numBlockThreads_Max; + int numTotalThreads; + int forceWriteSizesInHeader; + UInt64 reduceSize; +} CXzProps; + +void XzProps_Init(CXzProps *p); + + +typedef void * CXzEncHandle; + +CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); +void XzEnc_Destroy(CXzEncHandle p); +SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props); +void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize); +SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress); + +SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, + const CXzProps *props, ICompressProgress *progress); + +SRes Xz_EncodeEmpty(ISeqOutStream *outStream); + +EXTERN_C_END + +#endif diff --git a/lzma/XzIn.c b/lzma/XzIn.c new file mode 100644 index 0000000..792a617 --- /dev/null +++ b/lzma/XzIn.c @@ -0,0 +1,319 @@ +/* XzIn.c - Xz input +2018-07-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zCrc.h" +#include "CpuArch.h" +#include "Xz.h" + +/* +#define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0) +*/ +#define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1) + + +SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream) +{ + Byte sig[XZ_STREAM_HEADER_SIZE]; + RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE)); + if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) + return SZ_ERROR_NO_ARCHIVE; + return Xz_ParseHeader(p, sig); +} + +#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ + { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ + if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; } + +SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, BoolInt *isIndex, UInt32 *headerSizeRes) +{ + Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; + unsigned headerSize; + *headerSizeRes = 0; + RINOK(SeqInStream_ReadByte(inStream, &header[0])); + headerSize = (unsigned)header[0]; + if (headerSize == 0) + { + *headerSizeRes = 1; + *isIndex = True; + return SZ_OK; + } + + *isIndex = False; + headerSize = (headerSize << 2) + 4; + *headerSizeRes = headerSize; + RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1)); + return XzBlock_Parse(p, header); +} + +#define ADD_SIZE_CHECK(size, val) \ + { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } + +UInt64 Xz_GetUnpackSize(const CXzStream *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->numBlocks; i++) + ADD_SIZE_CHECK(size, p->blocks[i].unpackSize); + return size; +} + +UInt64 Xz_GetPackSize(const CXzStream *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->numBlocks; i++) + ADD_SIZE_CHECK(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3); + return size; +} + +/* +SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream) +{ + return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f)); +} +*/ + +static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc) +{ + size_t numBlocks, pos = 1; + UInt32 crc; + + if (size < 5 || buf[0] != 0) + return SZ_ERROR_ARCHIVE; + + size -= 4; + crc = CrcCalc(buf, size); + if (crc != GetUi32(buf + size)) + return SZ_ERROR_ARCHIVE; + + { + UInt64 numBlocks64; + READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64); + numBlocks = (size_t)numBlocks64; + if (numBlocks != numBlocks64 || numBlocks * 2 > size) + return SZ_ERROR_ARCHIVE; + } + + Xz_Free(p, alloc); + if (numBlocks != 0) + { + size_t i; + p->numBlocks = numBlocks; + p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); + if (!p->blocks) + return SZ_ERROR_MEM; + for (i = 0; i < numBlocks; i++) + { + CXzBlockSizes *block = &p->blocks[i]; + READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize); + READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize); + if (block->totalSize == 0) + return SZ_ERROR_ARCHIVE; + } + } + while ((pos & 3) != 0) + if (buf[pos++] != 0) + return SZ_ERROR_ARCHIVE; + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAllocPtr alloc) +{ + SRes res; + size_t size; + Byte *buf; + if (indexSize > ((UInt32)1 << 31)) + return SZ_ERROR_UNSUPPORTED; + size = (size_t)indexSize; + if (size != indexSize) + return SZ_ERROR_UNSUPPORTED; + buf = (Byte *)ISzAlloc_Alloc(alloc, size); + if (!buf) + return SZ_ERROR_MEM; + res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); + if (res == SZ_OK) + res = Xz_ReadIndex2(p, buf, size, alloc); + ISzAlloc_Free(alloc, buf); + return res; +} + +static SRes LookInStream_SeekRead_ForArc(ILookInStream *stream, UInt64 offset, void *buf, size_t size) +{ + RINOK(LookInStream_SeekTo(stream, offset)); + return LookInStream_Read(stream, buf, size); + /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */ +} + +static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAllocPtr alloc) +{ + UInt64 indexSize; + Byte buf[XZ_STREAM_FOOTER_SIZE]; + UInt64 pos = *startOffset; + + if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE) + return SZ_ERROR_NO_ARCHIVE; + + pos -= XZ_STREAM_FOOTER_SIZE; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)); + + if (!XZ_FOOTER_SIG_CHECK(buf + 10)) + { + UInt32 total = 0; + pos += XZ_STREAM_FOOTER_SIZE; + + for (;;) + { + size_t i; + #define TEMP_BUF_SIZE (1 << 10) + Byte temp[TEMP_BUF_SIZE]; + + i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos; + pos -= i; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i)); + total += (UInt32)i; + for (; i != 0; i--) + if (temp[i - 1] != 0) + break; + if (i != 0) + { + if ((i & 3) != 0) + return SZ_ERROR_NO_ARCHIVE; + pos += i; + break; + } + if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) + return SZ_ERROR_NO_ARCHIVE; + } + + if (pos < XZ_STREAM_FOOTER_SIZE) + return SZ_ERROR_NO_ARCHIVE; + pos -= XZ_STREAM_FOOTER_SIZE; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)); + if (!XZ_FOOTER_SIG_CHECK(buf + 10)) + return SZ_ERROR_NO_ARCHIVE; + } + + p->flags = (CXzStreamFlags)GetBe16(buf + 8); + + if (!XzFlags_IsSupported(p->flags)) + return SZ_ERROR_UNSUPPORTED; + + if (GetUi32(buf) != CrcCalc(buf + 4, 6)) + return SZ_ERROR_ARCHIVE; + + indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; + + if (pos < indexSize) + return SZ_ERROR_ARCHIVE; + + pos -= indexSize; + RINOK(LookInStream_SeekTo(stream, pos)); + RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)); + + { + UInt64 totalSize = Xz_GetPackSize(p); + if (totalSize == XZ_SIZE_OVERFLOW + || totalSize >= ((UInt64)1 << 63) + || pos < totalSize + XZ_STREAM_HEADER_SIZE) + return SZ_ERROR_ARCHIVE; + pos -= (totalSize + XZ_STREAM_HEADER_SIZE); + RINOK(LookInStream_SeekTo(stream, pos)); + *startOffset = pos; + } + { + CXzStreamFlags headerFlags; + CSecToRead secToRead; + SecToRead_CreateVTable(&secToRead); + secToRead.realStream = stream; + + RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt)); + return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; + } +} + + +/* ---------- Xz Streams ---------- */ + +void Xzs_Construct(CXzs *p) +{ + p->num = p->numAllocated = 0; + p->streams = 0; +} + +void Xzs_Free(CXzs *p, ISzAllocPtr alloc) +{ + size_t i; + for (i = 0; i < p->num; i++) + Xz_Free(&p->streams[i], alloc); + ISzAlloc_Free(alloc, p->streams); + p->num = p->numAllocated = 0; + p->streams = 0; +} + +UInt64 Xzs_GetNumBlocks(const CXzs *p) +{ + UInt64 num = 0; + size_t i; + for (i = 0; i < p->num; i++) + num += p->streams[i].numBlocks; + return num; +} + +UInt64 Xzs_GetUnpackSize(const CXzs *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->num; i++) + ADD_SIZE_CHECK(size, Xz_GetUnpackSize(&p->streams[i])); + return size; +} + +/* +UInt64 Xzs_GetPackSize(const CXzs *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->num; i++) + ADD_SIZE_CHECK(size, Xz_GetTotalSize(&p->streams[i])); + return size; +} +*/ + +SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAllocPtr alloc) +{ + Int64 endOffset = 0; + RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END)); + *startOffset = endOffset; + for (;;) + { + CXzStream st; + SRes res; + Xz_Construct(&st); + res = Xz_ReadBackward(&st, stream, startOffset, alloc); + st.startOffset = *startOffset; + RINOK(res); + if (p->num == p->numAllocated) + { + size_t newNum = p->num + p->num / 4 + 1; + Byte *data = (Byte *)ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream)); + if (!data) + return SZ_ERROR_MEM; + p->numAllocated = newNum; + if (p->num != 0) + memcpy(data, p->streams, p->num * sizeof(CXzStream)); + ISzAlloc_Free(alloc, p->streams); + p->streams = (CXzStream *)data; + } + p->streams[p->num++] = st; + if (*startOffset == 0) + break; + RINOK(LookInStream_SeekTo(stream, *startOffset)); + if (progress && ICompressProgress_Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK) + return SZ_ERROR_PROGRESS; + } + return SZ_OK; +} diff --git a/lzma/lzma.cpp b/lzma/lzma.cpp new file mode 100644 index 0000000..f002e9f --- /dev/null +++ b/lzma/lzma.cpp @@ -0,0 +1,81 @@ +#include + +#include "7zAlloc.c" +#include "7zArcIn.c" +#include "7zBuf.c" +#include "7zCrc.c" +#include "7zCrcOpt.c" +#include "7zDec.c" +#include "7zFile.c" +#include "7zStream.c" +#include "Bcj2.c" +#include "Bra.c" +#include "Bra86.c" +#include "BraIA64.c" +#include "CpuArch.c" +#include "Delta.c" +#undef kBitModelTotal +#undef kTopValue +#include "LzmaDec.c" +#include "Lzma2Dec.c" +#define kInputBufSize ((size_t)1 << 18) + +namespace LZMA { + +auto extract(string_view filename) -> vector { + vector result; + + static bool initialized = false; + if(!initialized) { + initialized = true; + CrcGenerateTable(); + } + + static ISzAlloc allocate = {SzAlloc, SzFree}; + static ISzAlloc allocateTemporary = {SzAllocTemp, SzFreeTemp}; + + CFileInStream archive; + #if defined(PLATFORM_WINDOWS) + if(InFile_OpenW(&archive.file, (const wchar_t*)utf16_t(filename)) != SZ_OK) return result; + #else + if(InFile_Open(&archive.file, (const char*)filename) != SZ_OK) return result; + #endif + FileInStream_CreateVTable(&archive); + + CLookToRead2 look; + LookToRead2_CreateVTable(&look, false); + look.buf = (Byte*)ISzAlloc_Alloc(&allocate, kInputBufSize); + look.bufSize = kInputBufSize; + look.realStream = &archive.vt; + LookToRead2_Init(&look); + + CSzArEx db; + SzArEx_Init(&db); + if(SzArEx_Open(&db, &look.vt, &allocate, &allocateTemporary) != SZ_OK || db.NumFiles == 0) { + SzArEx_Free(&db, &allocate); + return result; + } + + for(uint index : range(db.NumFiles)) { + if(SzArEx_IsDir(&db, index)) continue; + + UInt32 blockIndex = -1; + Byte* filedata = nullptr; + size_t filesize = 0; + size_t offset = 0; + size_t count = 0; + if(SzArEx_Extract(&db, &look.vt, index, &blockIndex, + &filedata, &filesize, &offset, &count, &allocate, &allocateTemporary + ) == SZ_OK) { + result.resize(filesize); + memory::copy(result.data(), filedata, filesize); + ISzAlloc_Free(&allocate, filedata); + break; + } + } + + SzArEx_Free(&db, &allocate); + return result; +} + +} diff --git a/lzma/lzma.hpp b/lzma/lzma.hpp new file mode 100644 index 0000000..a017882 --- /dev/null +++ b/lzma/lzma.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace LZMA { + +auto extract(string_view filename) -> vector; + +} diff --git a/nall/adaptive-array.hpp b/nall/adaptive-array.hpp new file mode 100644 index 0000000..9ca84e7 --- /dev/null +++ b/nall/adaptive-array.hpp @@ -0,0 +1,64 @@ +//deprecated + +#pragma once + +#include +#include + +namespace nall { + +template +struct adaptive_array { + auto capacity() const -> uint { return Capacity; } + auto size() const -> uint { return _size; } + + auto reset() -> void { + for(uint n : range(_size)) _pool.t[n].~T(); + _size = 0; + } + + auto operator[](uint index) -> T& { + #ifdef DEBUG + struct out_of_bounds {}; + if(index >= Capacity) throw out_of_bounds{}; + #endif + return _pool.t[index]; + } + + auto operator[](uint index) const -> const T& { + #ifdef DEBUG + struct out_of_bounds {}; + if(index >= Capacity) throw out_of_bounds{}; + #endif + return _pool.t[index]; + } + + auto append() -> T& { + new(_pool.t + _size) T; + return _pool.t[_size++]; + } + + auto append(const T& value) -> void { + new(_pool.t + _size++) T(value); + } + + auto append(T&& value) -> void { + new(_pool.t + _size++) T(move(value)); + } + + auto begin() { return &_pool.t[0]; } + auto end() { return &_pool.t[_size]; } + + auto begin() const { return &_pool.t[0]; } + auto end() const { return &_pool.t[_size]; } + +private: + union U { + U() {} + ~U() {} + T t[Capacity]; + } _pool; + uint _size = 0; +}; + +} diff --git a/nall/algorithm.hpp b/nall/algorithm.hpp new file mode 100755 index 0000000..34565f1 --- /dev/null +++ b/nall/algorithm.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +#undef min +#undef max + +namespace nall { + +template constexpr auto min(const T& t, const U& u) -> T { + return t < u ? t : (T)u; +} + +template constexpr auto min(const T& t, const U& u, P&&... p) -> T { + return t < u ? min(t, forward

    (p)...) : min(u, forward

    (p)...); +} + +template constexpr auto max(const T& t, const U& u) -> T { + return t > u ? t : (T)u; +} + +template constexpr auto max(const T& t, const U& u, P&&... p) -> T { + return t > u ? max(t, forward

    (p)...) : max(u, forward

    (p)...); +} + +} diff --git a/nall/any.hpp b/nall/any.hpp new file mode 100755 index 0000000..d7e789a --- /dev/null +++ b/nall/any.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include + +namespace nall { + +struct any { + any() = default; + any(const any& source) { operator=(source); } + any(any&& source) { operator=(move(source)); } + template any(const T& value) { operator=(value); } + ~any() { reset(); } + + explicit operator bool() const { return container; } + auto reset() -> void { if(container) { delete container; container = nullptr; } } + + auto type() const -> const std::type_info& { + return container ? container->type() : typeid(void); + } + + template auto is() const -> bool { + return type() == typeid(typename remove_reference::type); + } + + template auto get() -> T& { + if(!is()) throw; + return static_cast::type>*>(container)->value; + } + + template auto get() const -> const T& { + if(!is()) throw; + return static_cast::type>*>(container)->value; + } + + template auto get(const T& fallback) const -> const T& { + if(!is()) return fallback; + return static_cast::type>*>(container)->value; + } + + template auto operator=(const T& value) -> any& { + using auto_t = typename conditional::value, typename remove_extent::type>::type*, T>::type; + + 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; + } + + auto operator=(const any& source) -> any& { + if(container) { delete container; container = nullptr; } + if(source.container) container = source.container->copy(); + return *this; + } + + auto operator=(any&& source) -> any& { + if(container) delete container; + container = source.container; + source.container = nullptr; + return *this; + } + +private: + struct placeholder { + virtual ~placeholder() = default; + virtual auto type() const -> const std::type_info& = 0; + virtual auto copy() const -> placeholder* = 0; + }; + placeholder* container = nullptr; + + template struct holder : placeholder { + holder(const T& value) : value(value) {} + auto type() const -> const std::type_info& { return typeid(T); } + auto copy() const -> placeholder* { return new holder(value); } + T value; + }; +}; + +} diff --git a/nall/arguments.hpp b/nall/arguments.hpp new file mode 100644 index 0000000..6fb706d --- /dev/null +++ b/nall/arguments.hpp @@ -0,0 +1,161 @@ +#pragma once + +#include +#include +#include +#include + +namespace nall { + +struct Arguments { + Arguments(int argc, char** argv); + Arguments(vector arguments); + + explicit operator bool() const { return (bool)arguments; } + auto size() const -> uint { return arguments.size(); } + + auto operator[](uint index) -> string& { return arguments[index]; } + auto operator[](uint index) const -> const string& { return arguments[index]; } + + auto programPath() const -> string; + auto programName() const -> string; + auto programLocation() const -> string; + + auto find(string_view name) const -> bool; + auto find(string_view name, bool& argument) const -> bool; + auto find(string_view name, string& argument) const -> bool; + + auto begin() const { return arguments.begin(); } + auto end() const { return arguments.end(); } + + auto rbegin() const { return arguments.rbegin(); } + auto rend() const { return arguments.rend(); } + + auto take() -> string; + auto take(string_view name) -> bool; + auto take(string_view name, bool& argument) -> bool; + auto take(string_view name, string& argument) -> bool; + + auto begin() { return arguments.begin(); } + auto end() { return arguments.end(); } + + auto rbegin() { return arguments.rbegin(); } + auto rend() { return arguments.rend(); } + +private: + auto construct() -> void; + + string programArgument; + vector arguments; +}; + +inline auto Arguments::construct() -> void { + if(!arguments) return; + + //extract and pre-process program argument + programArgument = arguments.takeFirst(); + programArgument = {Path::real(programArgument), Location::file(programArgument)}; + + //normalize path and file arguments + for(auto& argument : arguments) { + if(directory::exists(argument)) argument.transform("\\", "/").trimRight("/").append("/"); + else if(file::exists(argument)) argument.transform("\\", "/").trimRight("/"); + } +} + +inline Arguments::Arguments(int argc, char** argv) { + #if defined(PLATFORM_WINDOWS) + utf8_arguments(argc, argv); + #endif + for(uint index : range(argc)) arguments.append(argv[index]); + construct(); +} + +inline Arguments::Arguments(vector arguments) { + this->arguments = arguments; + construct(); +} + +inline auto Arguments::programPath() const -> string { + return Location::path(programArgument); +} + +inline auto Arguments::programName() const -> string { + return Location::file(programArgument); +} + +inline auto Arguments::programLocation() const -> string { + return programArgument; +} + +inline auto Arguments::find(string_view name) const -> bool { + for(uint index : range(arguments.size())) { + if(arguments[index].match(name)) { + return true; + } + } + return false; +} + +inline auto Arguments::find(string_view name, bool& argument) const -> bool { + for(uint index : range(arguments.size())) { + if(arguments[index].match(name) && arguments.size() >= index + && (arguments[index + 1] == "true" || arguments[index + 1] == "false")) { + argument = arguments[index + 1] == "true"; + return true; + } + } + return false; +} + +inline auto Arguments::find(string_view name, string& argument) const -> bool { + for(uint index : range(arguments.size())) { + if(arguments[index].match(name) && arguments.size() >= index) { + argument = arguments[index + 1]; + return true; + } + } + return false; +} + +// + +inline auto Arguments::take() -> string { + if(!arguments) return {}; + return arguments.takeFirst(); +} + +inline auto Arguments::take(string_view name) -> bool { + for(uint index : range(arguments.size())) { + if(arguments[index].match(name)) { + arguments.remove(index); + return true; + } + } + return false; +} + +inline auto Arguments::take(string_view name, bool& argument) -> bool { + for(uint index : range(arguments.size())) { + if(arguments[index].match(name) && arguments.size() > index + 1 + && (arguments[index + 1] == "true" || arguments[index + 1] == "false")) { + arguments.remove(index); + argument = arguments.take(index) == "true"; + return true; + } + } + return false; +} + +inline auto Arguments::take(string_view name, string& argument) -> bool { + for(uint index : range(arguments.size())) { + if(arguments[index].match(name) && arguments.size() > index + 1) { + arguments.remove(index); + argument = arguments.take(index); + return true; + } + } + return false; +} + +} diff --git a/nall/arithmetic.hpp b/nall/arithmetic.hpp new file mode 100644 index 0000000..388370f --- /dev/null +++ b/nall/arithmetic.hpp @@ -0,0 +1,89 @@ +#pragma once + +//multi-precision arithmetic +//warning: each size is quadratically more expensive than the size before it! + +#include +#include +#include +#include + +#include + +namespace nall { + template struct ArithmeticNatural; + template<> struct ArithmeticNatural< 8> { using type = uint8_t; }; + template<> struct ArithmeticNatural< 16> { using type = uint16_t; }; + template<> struct ArithmeticNatural< 32> { using type = uint32_t; }; + template<> struct ArithmeticNatural< 64> { using type = uint64_t; }; + #if INTMAX_BITS >= 128 + template<> struct ArithmeticNatural<128> { using type = uint128_t; }; + #endif +} + +#if INTMAX_BITS < 128 +#define PairBits 128 +#define TypeBits 64 +#define HalfBits 32 +#include +#undef PairBits +#undef TypeBits +#undef HalfBits +#endif + +#define PairBits 256 +#define TypeBits 128 +#define HalfBits 64 +#include +#undef PairBits +#undef TypeBits +#undef HalfBits + +#define PairBits 512 +#define TypeBits 256 +#define HalfBits 128 +#include +#undef PairBits +#undef TypeBits +#undef HalfBits + +#define PairBits 1024 +#define TypeBits 512 +#define HalfBits 256 +#include +#undef PairBits +#undef TypeBits +#undef HalfBits + +#define PairBits 2048 +#define TypeBits 1024 +#define HalfBits 512 +#include +#undef PairBits +#undef TypeBits +#undef HalfBits + +#define PairBits 4096 +#define TypeBits 2048 +#define HalfBits 1024 +#include +#undef PairBits +#undef TypeBits +#undef HalfBits + +#define PairBits 8192 +#define TypeBits 4096 +#define HalfBits 2048 +#include +#undef PairBits +#undef TypeBits +#undef HalfBits + +namespace nall { + //TODO: these types are for expressing smaller bit ranges in class interfaces + //for instance, XChaCha20 taking a 192-bit nonce + //however, they still allow more bits than expressed ... + //some sort of wrapper needs to be devised to ensure these sizes are masked and wrap appropriately + + using uint192_t = uint256_t; +} diff --git a/nall/arithmetic/barrett.hpp b/nall/arithmetic/barrett.hpp new file mode 100644 index 0000000..ffbaf7c --- /dev/null +++ b/nall/arithmetic/barrett.hpp @@ -0,0 +1,28 @@ +#pragma once + +namespace nall { + +template struct BarrettReduction { + using type = typename ArithmeticNatural<1 * Bits>::type; + using pair = typename ArithmeticNatural<2 * Bits>::type; + + explicit BarrettReduction(type modulo) : modulo(modulo), factor(pair(1) + -pair(modulo) / modulo) {} + + //return => value % modulo + inline auto operator()(pair value) const -> type { + pair hi, lo; + mul(value, factor, hi, lo); + pair remainder = value - hi * modulo; + return remainder < modulo ? remainder : remainder - modulo; + } + +private: + const pair modulo; + const pair factor; +}; + +template auto operator%(T value, const BarrettReduction& modulo) { + return modulo(value); +} + +} diff --git a/nall/arithmetic/natural.hpp b/nall/arithmetic/natural.hpp new file mode 100644 index 0000000..fcc902b --- /dev/null +++ b/nall/arithmetic/natural.hpp @@ -0,0 +1,342 @@ +#define ConcatenateType(Size) uint##Size##_t +#define DeclareType(Size) ConcatenateType(Size) + +#define Pair DeclareType(PairBits) +#define Type DeclareType(TypeBits) +#define Half DeclareType(HalfBits) + +//pick the larger of two types to prevent unnecessary data clamping +#define Cast (typename conditional= sizeof(T), Pair, T>::type) + +namespace nall { +//namespace Arithmetic { + +struct Pair { + Pair() = default; + explicit constexpr Pair(const Pair& source) : hi(source.hi), lo(source.lo) {} + template constexpr Pair(const Hi& hi, const Lo& lo) : hi(hi), lo(lo) {} + template Pair(const T& source) { _set(*this, source); } + + explicit operator bool() const { return hi | lo; } + template operator T() const { T value; _get(*this, value); return value; } + + auto operator+() const -> Pair { return *this; } + auto operator-() const -> Pair { return Pair(0) - *this; } + auto operator~() const -> Pair { return {~hi, ~lo}; } + auto operator!() const -> bool { return !(hi || lo); } + + auto operator++() -> Pair& { lo++; hi += lo == 0; return *this; } + auto operator--() -> Pair& { hi -= lo == 0; lo--; return *this; } + + auto operator++(int) -> Pair { Pair r = *this; lo++; hi += lo == 0; return r; } + auto operator--(int) -> Pair { Pair r = *this; hi -= lo == 0; lo--; return r; } + + auto operator* (const Pair& rhs) const -> Pair { return mul(*this, rhs); } + auto operator/ (const Pair& rhs) const -> Pair { Pair q, r; div(*this, rhs, q, r); return q; } + auto operator% (const Pair& rhs) const -> Pair { Pair q, r; div(*this, rhs, q, r); return r; } + auto operator+ (const Pair& rhs) const -> Pair { return {hi + rhs.hi + (lo + rhs.lo < lo), lo + rhs.lo}; } + auto operator- (const Pair& rhs) const -> Pair { return {hi - rhs.hi - (lo - rhs.lo > lo), lo - rhs.lo}; } + auto operator<<(const Pair& rhs) const -> Pair { return shl(*this, rhs); } + auto operator>>(const Pair& rhs) const -> Pair { return shr(*this, rhs); } + auto operator& (const Pair& rhs) const -> Pair { return {hi & rhs.hi, lo & rhs.lo}; } + auto operator| (const Pair& rhs) const -> Pair { return {hi | rhs.hi, lo | rhs.lo}; } + auto operator^ (const Pair& rhs) const -> Pair { return {hi ^ rhs.hi, lo ^ rhs.lo}; } + auto operator==(const Pair& rhs) const -> bool { return hi == rhs.hi && lo == rhs.lo; } + auto operator!=(const Pair& rhs) const -> bool { return hi != rhs.hi || lo != rhs.lo; } + auto operator>=(const Pair& rhs) const -> bool { return hi > rhs.hi || (hi == rhs.hi && lo >= rhs.lo); } + auto operator<=(const Pair& rhs) const -> bool { return hi < rhs.hi || (hi == rhs.hi && lo <= rhs.lo); } + auto operator> (const Pair& rhs) const -> bool { return hi > rhs.hi || (hi == rhs.hi && lo > rhs.lo); } + auto operator< (const Pair& rhs) const -> bool { return hi < rhs.hi || (hi == rhs.hi && lo < rhs.lo); } + + template auto& operator*= (const T& rhs) { return *this = *this * Pair(rhs); } + template auto& operator/= (const T& rhs) { return *this = *this / Pair(rhs); } + template auto& operator%= (const T& rhs) { return *this = *this % Pair(rhs); } + template auto& operator+= (const T& rhs) { return *this = *this + Pair(rhs); } + template auto& operator-= (const T& rhs) { return *this = *this - Pair(rhs); } + template auto& operator<<=(const T& rhs) { return *this = *this << Pair(rhs); } + template auto& operator>>=(const T& rhs) { return *this = *this >> Pair(rhs); } + template auto& operator&= (const T& rhs) { return *this = *this & Pair(rhs); } + template auto& operator|= (const T& rhs) { return *this = *this | Pair(rhs); } + template auto& operator^= (const T& rhs) { return *this = *this ^ Pair(rhs); } + + template auto operator* (const T& rhs) const { return Cast(*this) * Cast(rhs); } + template auto operator/ (const T& rhs) const { return Cast(*this) / Cast(rhs); } + template auto operator% (const T& rhs) const { return Cast(*this) % Cast(rhs); } + template auto operator+ (const T& rhs) const { return Cast(*this) + Cast(rhs); } + template auto operator- (const T& rhs) const { return Cast(*this) - Cast(rhs); } + template auto operator<<(const T& rhs) const { return Cast(*this) << Cast(rhs); } + template auto operator>>(const T& rhs) const { return Cast(*this) >> Cast(rhs); } + template auto operator& (const T& rhs) const { return Cast(*this) & Cast(rhs); } + template auto operator| (const T& rhs) const { return Cast(*this) | Cast(rhs); } + template auto operator^ (const T& rhs) const { return Cast(*this) ^ Cast(rhs); } + + template auto operator==(const T& rhs) const -> bool { return Cast(*this) == Cast(rhs); } + template auto operator!=(const T& rhs) const -> bool { return Cast(*this) != Cast(rhs); } + template auto operator>=(const T& rhs) const -> bool { return Cast(*this) >= Cast(rhs); } + template auto operator<=(const T& rhs) const -> bool { return Cast(*this) <= Cast(rhs); } + template auto operator> (const T& rhs) const -> bool { return Cast(*this) > Cast(rhs); } + template auto operator< (const T& rhs) const -> bool { return Cast(*this) < Cast(rhs); } + +private: + Type lo; + Type hi; + + friend auto upper(const Pair&) -> Type; + friend auto lower(const Pair&) -> Type; + friend auto bits(Pair) -> uint; + friend auto square(const Pair&) -> Pair; + friend auto square(const Pair&, Pair&, Pair&) -> void; + friend auto mul(const Pair&, const Pair&) -> Pair; + friend auto mul(const Pair&, const Pair&, Pair&, Pair&) -> void; + friend auto div(const Pair&, const Pair&, Pair&, Pair&) -> void; + template friend auto shl(const Pair&, const T&) -> Pair; + template friend auto shr(const Pair&, const T&) -> Pair; +}; + +template<> struct ArithmeticNatural { + using type = Pair; +}; + +#define ConcatenateUDL(Size) _u##Size +#define DeclareUDL(Size) ConcatenateUDL(Size) + +alwaysinline auto operator"" DeclareUDL(PairBits)(const char* s) -> Pair { + Pair p = 0; + if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { + s += 2; + while(*s) { + auto c = *s++; + if(c == '\''); + else if(c >= '0' && c <= '9') p = (p << 4) + (c - '0'); + else if(c >= 'a' && c <= 'f') p = (p << 4) + (c - 'a' + 10); + else if(c >= 'A' && c <= 'F') p = (p << 4) + (c - 'A' + 10); + else break; + } + } else { + while(*s) { + auto c = *s++; + if(c == '\''); + else if(c >= '0' && c <= '9') p = (p << 3) + (p << 1) + (c - '0'); + else break; + } + } + return p; +} + +#undef ConcatenateUDL +#undef DeclareUDL + +template alwaysinline auto _set(Pair& lhs, const T& rhs) -> enable_if_t<(sizeof(Pair) == sizeof(T))> { + lhs = rhs; +} + +template alwaysinline auto _set(Pair& lhs, const T& rhs) -> enable_if_t<(sizeof(Pair) > sizeof(T))> { + lhs = {0, rhs}; +} + +template alwaysinline auto _set(Pair& lhs, const T& rhs) -> enable_if_t<(sizeof(Pair) < sizeof(T))> { + lhs = {lower(rhs) >> TypeBits, lower(rhs)}; +} + +template alwaysinline auto _get(const Pair& lhs, T& rhs) -> enable_if_t<(sizeof(T) == sizeof(Pair))> { + rhs = lhs; +} + +template alwaysinline auto _get(const Pair& lhs, T& rhs) -> enable_if_t<(sizeof(T) > sizeof(Pair))> { + rhs = {0, lhs}; +} + +template alwaysinline auto _get(const Pair& lhs, T& rhs) -> enable_if_t<(sizeof(T) < sizeof(Pair))> { + rhs = lower(lhs); +} + +alwaysinline auto upper(const Pair& value) -> Type { return value.hi; } +alwaysinline auto lower(const Pair& value) -> Type { return value.lo; } + +alwaysinline auto bits(Pair value) -> uint { + if(value.hi) { + uint bits = TypeBits; + while(value.hi) value.hi >>= 1, bits++; + return bits; + } else { + uint bits = 0; + while(value.lo) value.lo >>= 1, bits++; + return bits; + } +} + +//Bits * Bits => Bits +inline auto square(const Pair& lhs) -> Pair { + static const Type Mask = (Type(0) - 1) >> HalfBits; + Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask; + Type dd = square(d), dc = d * c, db = d * b, da = d * a; + Type cc = square(c), cb = c * b; + + Pair r0 = Pair(dd); + Pair r1 = Pair(dc) + Pair(dc) + Pair(r0 >> HalfBits); + Pair r2 = Pair(db) + Pair(cc) + Pair(db) + Pair(r1 >> HalfBits); + Pair r3 = Pair(da) + Pair(cb) + Pair(cb) + Pair(da) + Pair(r2 >> HalfBits); + + return {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)}; +} + +//Bits * Bits => 2 * Bits +inline auto square(const Pair& lhs, Pair& hi, Pair& lo) -> void { + static const Type Mask = (Type(0) - 1) >> HalfBits; + Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask; + Type dd = square(d), dc = d * c, db = d * b, da = d * a; + Type cc = square(c), cb = c * b, ca = c * a; + Type bb = square(b), ba = b * a; + Type aa = square(a); + + Pair r0 = Pair(dd); + Pair r1 = Pair(dc) + Pair(dc) + Pair(r0 >> HalfBits); + Pair r2 = Pair(db) + Pair(cc) + Pair(db) + Pair(r1 >> HalfBits); + Pair r3 = Pair(da) + Pair(cb) + Pair(cb) + Pair(da) + Pair(r2 >> HalfBits); + Pair r4 = Pair(ca) + Pair(bb) + Pair(ca) + Pair(r3 >> HalfBits); + Pair r5 = Pair(ba) + Pair(ba) + Pair(r4 >> HalfBits); + Pair r6 = Pair(aa) + Pair(r5 >> HalfBits); + Pair r7 = Pair(r6 >> HalfBits); + + hi = {(r7.lo & Mask) << HalfBits | (r6.lo & Mask), (r5.lo & Mask) << HalfBits | (r4.lo & Mask)}; + lo = {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)}; +} + +//Bits * Bits => Bits +alwaysinline auto mul(const Pair& lhs, const Pair& rhs) -> Pair { + static const Type Mask = (Type(0) - 1) >> HalfBits; + Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask; + Type e = rhs.hi >> HalfBits, f = rhs.hi & Mask, g = rhs.lo >> HalfBits, h = rhs.lo & Mask; + + Pair r0 = Pair(d * h); + Pair r1 = Pair(c * h) + Pair(d * g) + Pair(r0 >> HalfBits); + Pair r2 = Pair(b * h) + Pair(c * g) + Pair(d * f) + Pair(r1 >> HalfBits); + Pair r3 = Pair(a * h) + Pair(b * g) + Pair(c * f) + Pair(d * e) + Pair(r2 >> HalfBits); + + return {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)}; +} + +//Bits * Bits => 2 * Bits +alwaysinline auto mul(const Pair& lhs, const Pair& rhs, Pair& hi, Pair& lo) -> void { + static const Type Mask = (Type(0) - 1) >> HalfBits; + Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask; + Type e = rhs.hi >> HalfBits, f = rhs.hi & Mask, g = rhs.lo >> HalfBits, h = rhs.lo & Mask; + + Pair r0 = Pair(d * h); + Pair r1 = Pair(c * h) + Pair(d * g) + Pair(r0 >> HalfBits); + Pair r2 = Pair(b * h) + Pair(c * g) + Pair(d * f) + Pair(r1 >> HalfBits); + Pair r3 = Pair(a * h) + Pair(b * g) + Pair(c * f) + Pair(d * e) + Pair(r2 >> HalfBits); + Pair r4 = Pair(a * g) + Pair(b * f) + Pair(c * e) + Pair(r3 >> HalfBits); + Pair r5 = Pair(a * f) + Pair(b * e) + Pair(r4 >> HalfBits); + Pair r6 = Pair(a * e) + Pair(r5 >> HalfBits); + Pair r7 = Pair(r6 >> HalfBits); + + hi = {(r7.lo & Mask) << HalfBits | (r6.lo & Mask), (r5.lo & Mask) << HalfBits | (r4.lo & Mask)}; + lo = {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)}; +} + +alwaysinline auto div(const Pair& lhs, const Pair& rhs, Pair& quotient, Pair& remainder) -> void { + if(!rhs) throw std::runtime_error("division by zero"); + quotient = 0, remainder = lhs; + if(!lhs || lhs < rhs) return; + + auto count = bits(lhs) - bits(rhs); + Pair x = rhs << count; + Pair y = Pair(1) << count; + if(x > remainder) x >>= 1, y >>= 1; + while(remainder >= rhs) { + if(remainder >= x) remainder -= x, quotient |= y; + x >>= 1, y >>= 1; + } +} + +template alwaysinline auto shl(const Pair& lhs, const T& rhs) -> Pair { + if(!rhs) return lhs; + auto shift = (uint)rhs; + if(shift < TypeBits) { + return {lhs.hi << shift | lhs.lo >> (TypeBits - shift), lhs.lo << shift}; + } else { + return {lhs.lo << (shift - TypeBits), 0}; + } +} + +template alwaysinline auto shr(const Pair& lhs, const T& rhs) -> Pair { + if(!rhs) return lhs; + auto shift = (uint)rhs; + if(shift < TypeBits) { + return {lhs.hi >> shift, lhs.hi << (TypeBits - shift) | lhs.lo >> shift}; + } else { + return {0, lhs.hi >> (shift - TypeBits)}; + } +} + +template alwaysinline auto rol(const Pair& lhs, const T& rhs) -> Pair { + return lhs << rhs | lhs >> (PairBits - rhs); +} + +template alwaysinline auto ror(const Pair& lhs, const T& rhs) -> Pair { + return lhs >> rhs | lhs << (PairBits - rhs); +} + +#define EI enable_if_t::value> + +template auto& operator*= (T& lhs, const Pair& rhs) { return lhs = lhs * T(rhs); } +template auto& operator/= (T& lhs, const Pair& rhs) { return lhs = lhs / T(rhs); } +template auto& operator%= (T& lhs, const Pair& rhs) { return lhs = lhs % T(rhs); } +template auto& operator+= (T& lhs, const Pair& rhs) { return lhs = lhs + T(rhs); } +template auto& operator-= (T& lhs, const Pair& rhs) { return lhs = lhs - T(rhs); } +template auto& operator<<=(T& lhs, const Pair& rhs) { return lhs = lhs << T(rhs); } +template auto& operator>>=(T& lhs, const Pair& rhs) { return lhs = lhs >> T(rhs); } +template auto& operator&= (T& lhs, const Pair& rhs) { return lhs = lhs & T(rhs); } +template auto& operator|= (T& lhs, const Pair& rhs) { return lhs = lhs | T(rhs); } +template auto& operator^= (T& lhs, const Pair& rhs) { return lhs = lhs ^ T(rhs); } + +template auto operator* (const T& lhs, const Pair& rhs) { return Cast(lhs) * Cast(rhs); } +template auto operator/ (const T& lhs, const Pair& rhs) { return Cast(lhs) / Cast(rhs); } +template auto operator% (const T& lhs, const Pair& rhs) { return Cast(lhs) % Cast(rhs); } +template auto operator+ (const T& lhs, const Pair& rhs) { return Cast(lhs) + Cast(rhs); } +template auto operator- (const T& lhs, const Pair& rhs) { return Cast(lhs) - Cast(rhs); } +template auto operator<<(const T& lhs, const Pair& rhs) { return Cast(lhs) << Cast(rhs); } +template auto operator>>(const T& lhs, const Pair& rhs) { return Cast(lhs) >> Cast(rhs); } +template auto operator& (const T& lhs, const Pair& rhs) { return Cast(lhs) & Cast(rhs); } +template auto operator| (const T& lhs, const Pair& rhs) { return Cast(lhs) | Cast(rhs); } +template auto operator^ (const T& lhs, const Pair& rhs) { return Cast(lhs) ^ Cast(rhs); } + +template auto operator==(const T& lhs, const Pair& rhs) { return Cast(lhs) == Cast(rhs); } +template auto operator!=(const T& lhs, const Pair& rhs) { return Cast(lhs) != Cast(rhs); } +template auto operator>=(const T& lhs, const Pair& rhs) { return Cast(lhs) >= Cast(rhs); } +template auto operator<=(const T& lhs, const Pair& rhs) { return Cast(lhs) <= Cast(rhs); } +template auto operator> (const T& lhs, const Pair& rhs) { return Cast(lhs) > Cast(rhs); } +template auto operator< (const T& lhs, const Pair& rhs) { return Cast(lhs) < Cast(rhs); } + +#undef EI + +template<> struct stringify { + stringify(Pair source) { + char _output[1 + sizeof(Pair) * 3]; + auto p = (char*)&_output; + do { + Pair quotient, remainder; + div(source, 10, quotient, remainder); + *p++ = remainder + '0'; + source = quotient; + } while(source); + _size = p - _output; + *p = 0; + for(int x = _size - 1, y = 0; x >= 0 && y < _size; x--, y++) _data[x] = _output[y]; + } + + auto data() const -> const char* { return _data; } + auto size() const -> uint { return _size; } + char _data[1 + sizeof(Pair) * 3]; + uint _size; +}; + +} + +#undef ConcatenateType +#undef DeclareType +#undef Pair +#undef Type +#undef Half +#undef Cast diff --git a/nall/arithmetic/unsigned.hpp b/nall/arithmetic/unsigned.hpp new file mode 100644 index 0000000..5ed7ecd --- /dev/null +++ b/nall/arithmetic/unsigned.hpp @@ -0,0 +1,61 @@ +#pragma once + +namespace nall { + +template::value>> +inline auto upper(T value) -> T { + return value >> sizeof(T) * 4; +} + +template::value>> +inline auto lower(T value) -> T { + static const T Mask = ~T(0) >> sizeof(T) * 4; + return value & Mask; +} + +template::value>, enable_if_t::value>> +inline auto mul(T lhs, U rhs) -> uintmax { + return lhs * rhs; +} + +template::value>> +inline auto square(T value) -> uintmax { + return value * value; +} + +template +inline auto rol(T lhs, U rhs, enable_if_t::value>* = 0) -> T { + return lhs << rhs | lhs >> sizeof(T) * 8 - rhs; +} + +template +inline auto ror(T lhs, U rhs, enable_if_t::value>* = 0) -> T { + return lhs >> rhs | lhs << sizeof(T) * 8 - rhs; +} + +#if INTMAX_BITS >= 128 +inline auto operator"" _u128(const char* s) -> uint128_t { + uint128_t p = 0; + if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { + s += 2; + while(*s) { + auto c = *s++; + if(c == '\''); + else if(c >= '0' && c <= '9') p = (p << 4) + (c - '0'); + else if(c >= 'a' && c <= 'f') p = (p << 4) + (c - 'a' + 10); + else if(c >= 'A' && c <= 'F') p = (p << 4) + (c - 'A' + 10); + else break; + } + } else { + while(*s) { + auto c = *s++; + if(c == '\''); + else if(c >= '0' && c <= '9') p = (p << 3) + (p << 1) + (c - '0'); + else break; + } + } + return p; +} +#endif + +} diff --git a/nall/array-span.hpp b/nall/array-span.hpp new file mode 100644 index 0000000..96c791d --- /dev/null +++ b/nall/array-span.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include + +namespace nall { + +template struct array_span : array_view { + using type = array_span; + using super = array_view; + + inline array_span() { + super::_data = nullptr; + super::_size = 0; + } + + inline array_span(nullptr_t) { + super::_data = nullptr; + super::_size = 0; + } + + inline array_span(void* data, uint64_t size) { + super::_data = (T*)data; + super::_size = (int)size; + } + + inline operator T*() { return (T*)super::operator const T*(); } + + inline auto operator[](uint index) -> T& { return (T&)super::operator[](index); } + + template inline auto data() -> U* { return (U*)super::_data; } + + inline auto begin() -> iterator { return {(T*)super::_data, (uint)0}; } + inline auto end() -> iterator { return {(T*)super::_data, (uint)super::_size}; } + + inline auto rbegin() -> reverse_iterator { return {(T*)super::_data, (uint)super::_size - 1}; } + inline auto rend() -> reverse_iterator { return {(T*)super::_data, (uint)-1}; } + + auto write(T value) -> void { + operator[](0) = value; + super::_data++; + super::_size--; + } + + auto span(uint offset, uint length) const -> type { + #ifdef DEBUG + struct out_of_bounds {}; + if(offset + length >= super::_size) throw out_of_bounds{}; + #endif + return {super::_data + offset, length}; + } + + //array_span specializations + template auto writel(U value, uint size) -> void; + template auto writem(U value, uint size) -> void; + template auto writevn(U value, uint size) -> void; + template auto writevi(U value, uint size) -> void; +}; + +//array_span + +template<> inline auto array_span::write(uint8_t value) -> void { + operator[](0) = value; + _data++; + _size--; +} + +template<> template inline auto array_span::writel(U value, uint size) -> void { + for(uint byte : range(size)) write(value >> byte * 8); +} + +template<> template inline auto array_span::writem(U value, uint size) -> void { + for(uint byte : reverse(range(size))) write(value >> byte * 8); +} + +template<> template inline auto array_span::writevn(U value, uint size) -> void { + while(true) { + auto byte = value & 0x7f; + value >>= 7; + if(value == 0) return write(0x80 | byte); + write(byte); + value--; + } +} + +template<> template inline auto array_span::writevi(U value, uint size) -> void { + bool negate = value < 0; + if(negate) value = ~value; + value = value << 1 | negate; + writevn(value); +} + +} diff --git a/nall/array-view.hpp b/nall/array-view.hpp new file mode 100644 index 0000000..1c990b0 --- /dev/null +++ b/nall/array-view.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include +#include +#include + +namespace nall { + +template struct array_view { + using type = array_view; + + inline array_view() { + _data = nullptr; + _size = 0; + } + + inline array_view(nullptr_t) { + _data = nullptr; + _size = 0; + } + + inline array_view(const void* data, uint64_t size) { + _data = (const T*)data; + _size = (int)size; + } + + inline explicit operator bool() const { return _data && _size > 0; } + + inline operator const T*() const { + #ifdef DEBUG + struct out_of_bounds {}; + if(_size < 0) throw out_of_bounds{}; + #endif + return _data; + } + + inline auto operator++() -> type& { _data++; _size--; return *this; } + inline auto operator--() -> type& { _data--; _size++; return *this; } + + inline auto operator++(int) -> type { auto copy = *this; ++(*this); return copy; } + inline auto operator--(int) -> type { auto copy = *this; --(*this); return copy; } + + inline auto operator-=(int distance) -> type& { _data -= distance; _size += distance; return *this; } + inline auto operator+=(int distance) -> type& { _data += distance; _size -= distance; return *this; } + + inline auto operator[](uint index) const -> const T& { + #ifdef DEBUG + struct out_of_bounds {}; + if(index >= _size) throw out_of_bounds{}; + #endif + return _data[index]; + } + + inline auto operator()(uint index, const T& fallback = {}) const -> T { + if(index >= _size) return fallback; + return _data[index]; + } + + template inline auto data() const -> const U* { return (const U*)_data; } + template inline auto size() const -> uint64_t { return _size * sizeof(T) / sizeof(U); } + + inline auto begin() const -> iterator_const { return {_data, (uint)0}; } + inline auto end() const -> iterator_const { return {_data, (uint)_size}; } + + inline auto rbegin() const -> reverse_iterator_const { return {_data, (uint)_size - 1}; } + inline auto rend() const -> reverse_iterator_const { return {_data, (uint)-1}; } + + auto read() -> T { + auto value = operator[](0); + _data++; + _size--; + return value; + } + + auto view(uint offset, uint length) const -> type { + #ifdef DEBUG + struct out_of_bounds {}; + if(offset + length >= _size) throw out_of_bounds{}; + #endif + return {_data + offset, length}; + } + + //array_view specializations + template auto readl(U& value, uint size) -> U; + template auto readm(U& value, uint size) -> U; + template auto readvn(U& value, uint size) -> U; + template auto readvi(U& value, uint size) -> U; + + template auto readl(U& value, uint offset, uint size) -> U { return view(offset, size).readl(value, size); } + + template auto readl(uint size) -> U { U value; return readl(value, size); } + template auto readm(uint size) -> U { U value; return readm(value, size); } + template auto readvn(uint size) -> U { U value; return readvn(value, size); } + template auto readvi(uint size) -> U { U value; return readvi(value, size); } + + template auto readl(uint offset, uint size) -> U { U value; return readl(value, offset, size); } + +protected: + const T* _data; + int _size; +}; + +//array_view + +template<> template inline auto array_view::readl(U& value, uint size) -> U { + value = 0; + for(uint byte : range(size)) value |= (U)read() << byte * 8; + return value; +} + +template<> template inline auto array_view::readm(U& value, uint size) -> U { + value = 0; + for(uint byte : reverse(range(size))) value |= (U)read() << byte * 8; + return value; +} + +template<> template inline auto array_view::readvn(U& value, uint size) -> U { + value = 0; + uint shift = 1; + while(true) { + auto byte = read(); + value += (byte & 0x7f) * shift; + if(byte & 0x80) break; + shift <<= 7; + value += shift; + } + return value; +} + +template<> template inline auto array_view::readvi(U& value, uint size) -> U { + value = readvn(); + bool negate = value & 1; + value >>= 1; + if(negate) value = ~value; + return value; +} + +} diff --git a/nall/array.hpp b/nall/array.hpp new file mode 100644 index 0000000..2d70533 --- /dev/null +++ b/nall/array.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include +#include +#include +#include + +namespace nall { + +template struct array; + +//usage: int x[256] => array x +template struct array { + array() = default; + + array(const initializer_list& source) { + uint index = 0; + for(auto& value : source) { + operator[](index++) = value; + } + } + + operator array_span() { + return {data(), size()}; + } + + operator array_view() const { + return {data(), size()}; + } + + alwaysinline auto operator[](uint index) -> T& { + #ifdef DEBUG + struct out_of_bounds {}; + if(index >= Size) throw out_of_bounds{}; + #endif + return values[index]; + } + + alwaysinline auto operator[](uint index) const -> const T& { + #ifdef DEBUG + struct out_of_bounds {}; + if(index >= Size) throw out_of_bounds{}; + #endif + return values[index]; + } + + alwaysinline auto operator()(uint index, const T& fallback = {}) const -> const T& { + if(index >= Size) return fallback; + return values[index]; + } + + auto fill(const T& fill = {}) -> array& { + for(auto& value : values) value = fill; + return *this; + } + + auto data() -> T* { return values; } + auto data() const -> const T* { return values; } + auto size() const -> uint { return Size; } + + auto begin() -> T* { return &values[0]; } + auto end() -> T* { return &values[Size]; } + + auto begin() const -> const T* { return &values[0]; } + auto end() const -> const T* { return &values[Size]; } + +private: + T values[Size]; +}; + +template auto from_array(uint index) -> T { + static const array table{p...}; + struct out_of_bounds {}; + #if defined(DEBUG) + if(index >= sizeof...(p)) throw out_of_bounds{}; + #endif + return table[index]; +} + +template auto from_array(uint index) -> int64_t { + static const array table{p...}; + struct out_of_bounds {}; + #if defined(DEBUG) + if(index >= sizeof...(p)) throw out_of_bounds{}; + #endif + return table[index]; +} + +} diff --git a/nall/atoi.hpp b/nall/atoi.hpp new file mode 100755 index 0000000..d6fba25 --- /dev/null +++ b/nall/atoi.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include + +namespace nall { + +constexpr inline auto toBinary_(const char* s, uintmax sum = 0) -> uintmax { + return ( + *s == '0' || *s == '1' ? toBinary_(s + 1, (sum << 1) | *s - '0') : + *s == '\'' ? toBinary_(s + 1, sum) : + sum + ); +} + +constexpr inline auto toOctal_(const char* s, uintmax sum = 0) -> uintmax { + return ( + *s >= '0' && *s <= '7' ? toOctal_(s + 1, (sum << 3) | *s - '0') : + *s == '\'' ? toOctal_(s + 1, sum) : + sum + ); +} + +constexpr inline auto toDecimal_(const char* s, uintmax sum = 0) -> uintmax { + return ( + *s >= '0' && *s <= '9' ? toDecimal_(s + 1, (sum * 10) + *s - '0') : + *s == '\'' ? toDecimal_(s + 1, sum) : + sum + ); +} + +constexpr inline auto toHex_(const char* s, uintmax sum = 0) -> uintmax { + return ( + *s >= 'A' && *s <= 'F' ? toHex_(s + 1, (sum << 4) | *s - 'A' + 10) : + *s >= 'a' && *s <= 'f' ? toHex_(s + 1, (sum << 4) | *s - 'a' + 10) : + *s >= '0' && *s <= '9' ? toHex_(s + 1, (sum << 4) | *s - '0') : + *s == '\'' ? toHex_(s + 1, sum) : + sum + ); +} + +// + +constexpr inline auto toBinary(const char* s) -> uintmax { + return ( + *s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? toBinary_(s + 2) : + *s == '%' ? toBinary_(s + 1) : toBinary_(s) + ); +} + +constexpr inline auto toOctal(const char* s) -> uintmax { + return ( + *s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? toOctal_(s + 2) : + toOctal_(s) + ); +} + +constexpr inline auto toHex(const char* s) -> uintmax { + return ( + *s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? toHex_(s + 2) : + *s == '$' ? toHex_(s + 1) : toHex_(s) + ); +} + +// + +constexpr inline auto toNatural(const char* s) -> uintmax { + return ( + *s == '0' && (*(s + 1) == 'B' || *(s + 1) == 'b') ? toBinary_(s + 2) : + *s == '0' && (*(s + 1) == 'O' || *(s + 1) == 'o') ? toOctal_(s + 2) : + *s == '0' && (*(s + 1) == 'X' || *(s + 1) == 'x') ? toHex_(s + 2) : + *s == '%' ? toBinary_(s + 1) : *s == '$' ? toHex_(s + 1) : toDecimal_(s) + ); +} + +constexpr inline auto toInteger(const char* s) -> intmax { + return ( + *s == '+' ? +toNatural(s + 1) : *s == '-' ? -toNatural(s + 1) : toNatural(s) + ); +} + +// + +inline auto toReal(const char* s) -> double { + return atof(s); +} + +} diff --git a/nall/beat/archive/container.hpp b/nall/beat/archive/container.hpp new file mode 100644 index 0000000..bdfce1d --- /dev/null +++ b/nall/beat/archive/container.hpp @@ -0,0 +1,200 @@ +#pragma once + +#include + +namespace nall::Beat::Archive { + +struct Container { + Container(array_view = {}); + ~Container(); + + auto isCompressed() const -> bool { return (bool)compression.type; } + auto isSigned() const -> bool { return (bool)signature.type; } + auto isEncrypted() const -> bool { return (bool)encryption.type; } + + auto compressLZSA() -> void; + auto signEd25519(uint256_t privateKey) -> void; + auto encryptXChaCha20(uint256_t privateKey, uint192_t nonce = 0) -> void; + + auto validate() -> bool; + auto decryptXChaCha20(uint256_t privateKey) -> bool; + auto verifyEd25519(uint256_t publicKey) -> bool; + auto decompressLZSA() -> bool; + + auto append(string name, string location) -> shared_pointer; + auto appendPath(string name) -> shared_pointer; + auto appendFile(string name, array_view memory) -> shared_pointer; + auto remove(string name) -> bool; + auto find(string name) -> shared_pointer; + auto sort() -> void; + + auto begin() { return nodes.begin(); } + auto end() { return nodes.end(); } + + auto begin() const { return nodes.begin(); } + auto end() const { return nodes.end(); } + + auto rbegin() { return nodes.rbegin(); } + auto rend() { return nodes.rend(); } + + auto rbegin() const { return nodes.rbegin(); } + auto rend() const { return nodes.rend(); } + + vector> nodes; + vector memory; + string metadata; + + struct Compression { + string type; + } compression; + + struct Signature { + string type; + uint256_t privateKey = 0; + uint256_t publicKey = 0; + uint512_t value = 0; + } signature; + + struct Encryption { + string type; + uint256_t privateKey = 0; + uint192_t nonce = 0; + } encryption; +}; + +Container::Container(array_view memory) { + this->memory.resize(memory.size()); + nall::memory::copy(this->memory.data(), memory.data(), memory.size()); +} + +Container::~Container() { + metadata = {}; + signature = {}; + encryption = {}; +} + +// + +auto Container::compressLZSA() -> void { + compression.type = "lzsa"; +} + +auto Container::signEd25519(uint256_t privateKey) -> void { + signature.type = "ed25519"; + signature.privateKey = privateKey; +} + +auto Container::encryptXChaCha20(uint256_t privateKey, uint192_t nonce) -> void { + if(!nonce) { + CSPRNG::XChaCha20 csprng; + nonce = csprng.random(); + } + + encryption.type = "xchacha20"; + encryption.privateKey = privateKey; + encryption.nonce = nonce; +} + +// + +auto Container::validate() -> bool { + array_view memory = this->memory; + if(memory.size() < 44) return false; //8 (metadata size) + 32 (SHA256) + 4 (signature) + + if(memory[memory.size() - 4] != 'B') return false; + if(memory[memory.size() - 3] != 'P') return false; + if(memory[memory.size() - 2] != 'A') return false; + if(memory[memory.size() - 1] != '1') return false; + + auto sha256 = memory.readl(memory.size() - 36, 32); + if(Hash::SHA256({memory.data(), memory.size() - 36}).value() != sha256) return false; + + auto size = memory.readl(memory.size() - 44, 8); + + if(size & 1ull << 63) { + size -= 1ull << 63; + metadata = memory.view(memory.size() - 44 - size, size); + uint64_t offset = memory.size() - 44 - size; + for(auto& byte : metadata) byte ^= offset++; + } else { + metadata = memory.view(memory.size() - 44 - size, size); + } + + auto document = BML::unserialize(metadata); + + if(auto node = document["archive/encryption"]) { + if(node.text() == "xchacha20") { + encryption.type = node.text(); + encryption.nonce = Decode::Base<57, uint192_t>(node["nonce"].text()); + } + } + + if(auto node = document["archive/signature"]) { + if(node.text() == "ed25519") { + signature.type = node.text(); + signature.publicKey = Decode::Base<57, uint256_t>(node["publicKey"].text()); + signature.value = Decode::Base<57, uint512_t>(node["value"].text()); + } + } + + if(auto node = document["archive/compression"]) { + compression.type = node.text(); + } + + return true; +} + +auto Container::decryptXChaCha20(uint256_t privateKey) -> bool { + encryption.privateKey = privateKey; + Cipher::XChaCha20 xchacha20{encryption.privateKey, encryption.nonce}; + auto size = memory.readl(memory.size() - 44, 8); + memory = xchacha20.decrypt(memory.view(0, memory.size() - 44 - size)); + return true; +} + +auto Container::verifyEd25519(uint256_t publicKey) -> bool { + EllipticCurve::Ed25519 ed25519; + auto size = memory.readl(memory.size() - 44, 8); + return ed25519.verify(memory.view(0, memory.size() - 44 - size), signature.value, publicKey); +} + +auto Container::decompressLZSA() -> bool { + memory = Decode::LZSA(memory); + return (bool)memory; +} + +// + +auto Container::append(string name, string location) -> shared_pointer { + for(auto& node : nodes) if(node->name == name) return {}; + if(auto node = Node::create(name, location)) return nodes.append(node), node; + return {}; +} + +auto Container::appendPath(string name) -> shared_pointer { + for(auto& node : nodes) if(node->name == name) return {}; + if(auto node = Node::createPath(name)) return nodes.append(node), node; + return {}; +} + +auto Container::appendFile(string name, array_view memory) -> shared_pointer { + for(auto& node : nodes) if(node->name == name) return {}; + if(auto node = Node::createFile(name, memory)) return nodes.append(node), node; + return {}; +} + +auto Container::remove(string name) -> bool { + if(auto offset = nodes.find([&](auto& node) { return node->name == name; })) return nodes.remove(*offset), true; + return false; +} + +auto Container::find(string name) -> shared_pointer { + if(auto offset = nodes.find([&](auto& node) { return node->name == name; })) return nodes[*offset]; + return {}; +} + +auto Container::sort() -> void { + nodes.sort([&](auto& lhs, auto& rhs) { return string::icompare(lhs->name, rhs->name) < 0; }); +} + +} diff --git a/nall/beat/archive/create.hpp b/nall/beat/archive/create.hpp new file mode 100644 index 0000000..7014e48 --- /dev/null +++ b/nall/beat/archive/create.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include +#include + +namespace nall::Beat::Archive { + +auto create(Container& container, string name) -> vector { + auto& metadata = container.metadata; + metadata = {}; + metadata.append("archive: ", Location::file(name), "\n"); + + vector memory; + + container.sort(); + for(auto& node : container.nodes) { + if(node->isFile()) { + node->offset = memory.size(); + memory.append(node->memory); + } + metadata.append(node->metadata()); + } + + metadata.append(" size: ", memory.size(), "\n"); + + if(container.compression.type == "lzsa") { + memory = Encode::LZSA(memory); + metadata.append(" compression: lzsa\n"); + metadata.append(" size: ", memory.size(), "\n"); + } + + if(container.signature.type == "ed25519") { + EllipticCurve::Ed25519 ed25519; + container.signature.publicKey = ed25519.publicKey(container.signature.privateKey); + container.signature.value = ed25519.sign(memory, container.signature.privateKey); + + metadata.append(" signature: ed25519\n"); + metadata.append(" publicKey: ", Encode::Base<57>(container.signature.publicKey), "\n"); + metadata.append(" value: ", Encode::Base<57>(container.signature.value), "\n"); + } + + for(auto& byte : metadata) memory.append(byte); + memory.appendl((uint64_t)metadata.size(), 8); + + auto sha256 = Hash::SHA256(memory).value(); + memory.appendl((uint256_t)sha256, 32); + + memory.append('B'); + memory.append('P'); + memory.append('A'); + memory.append('1'); + + if(container.encryption.type == "xchacha20") { + Cipher::XChaCha20 xchacha20{container.encryption.privateKey, container.encryption.nonce}; + memory = xchacha20.encrypt(memory); + + metadata = {}; + metadata.append("archive\n"); + metadata.append(" encryption: xchacha20\n"); + metadata.append(" nonce: ", Encode::Base<57>(container.encryption.nonce), "\n"); + + if(container.signature.type == "ed25519") { + EllipticCurve::Ed25519 ed25519; + container.signature.value = ed25519.sign(memory, container.signature.privateKey); + + metadata.append(" signature: ed25519\n"); + //metadata.append(" publicKey: ", Encode::Base<57>(container.signature.publicKey), "\n"); + metadata.append(" value: ", Encode::Base<57>(container.signature.value), "\n"); + } + + for(auto& byte : metadata) memory.append(byte ^ memory.size()); + memory.appendl((uint64_t)metadata.size() | 1ull << 63, 8); + + auto sha256 = Hash::SHA256(memory).value(); + memory.appendl((uint256_t)sha256, 32); + + memory.append('B'); + memory.append('P'); + memory.append('A'); + memory.append('1'); + } + + return memory; +} + +} diff --git a/nall/beat/archive/extract.hpp b/nall/beat/archive/extract.hpp new file mode 100644 index 0000000..41e4889 --- /dev/null +++ b/nall/beat/archive/extract.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace nall::Beat::Archive { + +auto extract(Container& container) -> bool { + function extract = [&](auto metadata) { + if(metadata.name() != "path" && metadata.name() != "file") return; + shared_pointer node = new Node; + if(node->unserialize(container.memory, metadata)) { + container.nodes.append(node); + } + if(metadata.name() != "path") return; + for(auto node : metadata) extract(node); + }; + + container.nodes.reset(); + auto document = BML::unserialize(container.metadata); + for(auto node : document["archive"]) extract(node); + container.sort(); + + return true; +} + +} diff --git a/nall/beat/archive/node.hpp b/nall/beat/archive/node.hpp new file mode 100644 index 0000000..a8821ff --- /dev/null +++ b/nall/beat/archive/node.hpp @@ -0,0 +1,332 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nall::Beat::Archive { + +struct Node { + static auto create(string name, string location) -> shared_pointer; + static auto createPath(string name) -> shared_pointer; + static auto createFile(string name, array_view memory) -> shared_pointer; + + explicit operator bool() const { return (bool)name; } + auto isPath() const -> bool { return name.endsWith("/"); } + auto isFile() const -> bool { return !name.endsWith("/"); } + auto isCompressed() const -> bool { return (bool)compression.type; } + + auto metadata(bool indented = true) const -> string; + auto compressLZSA() -> bool; + + auto unserialize(array_view container, Markup::Node metadata) -> bool; + auto decompress() -> bool; + + auto getTimestamp(string) const -> uint64_t; + auto getPermissions() const -> uint; + auto getOwner() const -> string; + auto getGroup() const -> string; + + //files and paths + string name; + + bool timestamps = false; + struct Timestamp { + string created; + string modified; + string accessed; + } timestamp; + + bool permissions = false; + struct Permission { + struct Owner { + string name; + bool readable = false; + bool writable = false; + bool executable = false; + } owner; + struct Group { + string name; + bool readable = false; + bool writable = false; + bool executable = false; + } group; + struct Other { + bool readable = false; + bool writable = false; + bool executable = false; + } other; + } permission; + + //files only + vector memory; + uint64_t offset = 0; + + struct Compression { + string type; + uint size = 0; //decompressed size; memory.size() == compressed size + } compression; +}; + +auto Node::create(string name, string location) -> shared_pointer { + if(!inode::exists(location)) return {}; + shared_pointer node = new Node; + + node->name = name; + + node->timestamps = true; + node->timestamp.created = chrono::utc::datetime(inode::timestamp(location, inode::time::create)); + node->timestamp.modified = chrono::utc::datetime(inode::timestamp(location, inode::time::modify)); + node->timestamp.accessed = chrono::utc::datetime(inode::timestamp(location, inode::time::access)); + + uint mode = inode::mode(location); + node->permissions = true; + node->permission.owner.name = inode::owner(location); + node->permission.group.name = inode::group(location); + node->permission.owner.readable = mode & 0400; + node->permission.owner.writable = mode & 0200; + node->permission.owner.executable = mode & 0100; + node->permission.group.readable = mode & 0040; + node->permission.group.writable = mode & 0020; + node->permission.group.executable = mode & 0010; + node->permission.other.readable = mode & 0004; + node->permission.other.writable = mode & 0002; + node->permission.other.executable = mode & 0001; + + if(file::exists(location)) { + node->memory = file::read(location); + } + + return node; +} + +auto Node::createPath(string name) -> shared_pointer { + if(!name) return {}; + shared_pointer node = new Node; + node->name = name; + return node; +} + +auto Node::createFile(string name, array_view memory) -> shared_pointer { + if(!name) return {}; + shared_pointer node = new Node; + node->name = name; + node->memory.resize(memory.size()); + memory::copy(node->memory.data(), memory.data(), memory.size()); + return node; +} + +auto Node::metadata(bool indented) const -> string { + string metadata; + if(!name) return metadata; + + string indent; + if(indented) { + indent.append(" "); + auto bytes = string{name}.trimRight("/"); + for(auto& byte : bytes) { + if(byte == '/') indent.append(" "); + } + } + + if(isPath()) { + metadata.append(indent, "path: ", name, "\n"); + } + + if(isFile()) { + metadata.append(indent, "file: ", name, "\n"); + } + + if(timestamps) { + metadata.append(indent, " timestamp\n"); + if(timestamp.created != timestamp.modified) + metadata.append(indent, " created: ", timestamp.created, "\n"); + metadata.append(indent, " modified: ", timestamp.modified, "\n"); + if(timestamp.accessed != timestamp.modified) + metadata.append(indent, " accessed: ", timestamp.accessed, "\n"); + } + + if(permissions) { + metadata.append(indent, " permission\n"); + metadata.append(indent, " owner: ", permission.owner.name, "\n"); + if(permission.owner.readable) + metadata.append(indent, " readable\n"); + if(permission.owner.writable) + metadata.append(indent, " writable\n"); + if(permission.owner.executable) + metadata.append(indent, " executable\n"); + metadata.append(indent, " group: ", permission.group.name, "\n"); + if(permission.group.readable) + metadata.append(indent, " readable\n"); + if(permission.group.writable) + metadata.append(indent, " writable\n"); + if(permission.group.executable) + metadata.append(indent, " executable\n"); + metadata.append(indent, " other\n"); + if(permission.other.readable) + metadata.append(indent, " readable\n"); + if(permission.other.writable) + metadata.append(indent, " writable\n"); + if(permission.other.executable) + metadata.append(indent, " executable\n"); + } + + if(isFile()) { + metadata.append(indent, " offset: ", offset, "\n"); + if(!isCompressed()) { + metadata.append(indent, " size: ", memory.size(), "\n"); + } else { + metadata.append(indent, " size: ", compression.size, "\n"); + metadata.append(indent, " compression: ", compression.type, "\n"); + metadata.append(indent, " size: ", memory.size(), "\n"); + } + } + + return metadata; +} + +auto Node::unserialize(array_view container, Markup::Node metadata) -> bool { + *this = {}; + if(!metadata.text()) return false; + + name = metadata.text(); + + if(auto node = metadata["timestamp"]) { + timestamps = true; + if(auto created = node["created" ]) timestamp.created = created.text(); + if(auto modified = node["modified"]) timestamp.modified = modified.text(); + if(auto accessed = node["accessed"]) timestamp.accessed = accessed.text(); + } + + if(auto node = metadata["permission"]) { + permissions = true; + if(auto owner = node["owner"]) { + permission.owner.name = owner.text(); + permission.owner.readable = (bool)owner["readable"]; + permission.owner.writable = (bool)owner["writable"]; + permission.owner.executable = (bool)owner["executable"]; + } + if(auto group = node["group"]) { + permission.group.name = group.text(); + permission.group.readable = (bool)group["readable"]; + permission.group.writable = (bool)group["writable"]; + permission.group.executable = (bool)group["executable"]; + } + if(auto other = node["other"]) { + permission.other.readable = (bool)other["readable"]; + permission.other.writable = (bool)other["writable"]; + permission.other.executable = (bool)other["executable"]; + } + } + + if(isPath()) return true; + + uint offset = metadata["offset"].natural(); + uint size = metadata["size"].natural(); + + if(metadata["compression"]) { + size = metadata["compression/size"].natural(); + compression.type = metadata["compression"].text(); + } + + if(offset + size >= container.size()) return false; + + memory.reallocate(size); + nall::memory::copy(memory.data(), container.view(offset, size), size); + return true; +} + +auto Node::compressLZSA() -> bool { + if(!memory) return true; //don't compress empty files + if(isCompressed()) return true; //don't recompress files + + auto compressedMemory = Encode::LZSA(memory); + if(compressedMemory.size() >= memory.size()) return true; //can't compress smaller than original size + + compression.type = "lzsa"; + compression.size = memory.size(); + memory = move(compressedMemory); + return true; +} + +auto Node::decompress() -> bool { + if(!isCompressed()) return true; + + if(compression.type == "lzsa") { + compression = {}; + memory = Decode::LZSA(memory); + return (bool)memory; + } + + return false; +} + +auto Node::getTimestamp(string type) const -> uint64_t { + if(!timestamps) return time(nullptr); + + string value = chrono::utc::datetime(); + if(type == "created" ) value = timestamp.created; + if(type == "modified") value = timestamp.modified; + if(type == "accessed") value = timestamp.accessed; + + #if !defined(PLATFORM_WINDOWS) + struct tm timeInfo{}; + if(strptime(value, "%Y-%m-%d %H:%M:%S", &timeInfo) != nullptr) { + //todo: not thread safe ... + auto tz = getenv("TZ"); + setenv("TZ", "", 1); + timeInfo.tm_isdst = -1; + auto result = mktime(&timeInfo); + if(tz) setenv("TZ", tz, 1); + else unsetenv("TZ"); + if(result != -1) return result; + } + #endif + + return time(nullptr); +} + +auto Node::getPermissions() const -> uint { + if(!permissions) return 0755; + uint mode = 0; + if(permission.owner.readable ) mode |= 0400; + if(permission.owner.writable ) mode |= 0200; + if(permission.owner.executable) mode |= 0100; + if(permission.group.readable ) mode |= 0040; + if(permission.group.writable ) mode |= 0020; + if(permission.group.executable) mode |= 0010; + if(permission.other.readable ) mode |= 0004; + if(permission.other.writable ) mode |= 0002; + if(permission.other.executable) mode |= 0001; + return mode; +} + +auto Node::getOwner() const -> string { + if(!permissions || !permission.owner.name) { + #if !defined(PLATFORM_WINDOWS) + struct passwd* pwd = getpwuid(getuid()); + assert(pwd); + return pwd->pw_name; + #endif + } + return permission.owner.name; +} + +auto Node::getGroup() const -> string { + if(!permissions || !permission.group.name) { + #if !defined(PLATFORM_WINDOWS) + struct group* grp = getgrgid(getgid()); + assert(grp); + return grp->gr_name; + #endif + } + return permission.group.name; +} + +} diff --git a/nall/beat/single/apply.hpp b/nall/beat/single/apply.hpp new file mode 100644 index 0000000..cd81762 --- /dev/null +++ b/nall/beat/single/apply.hpp @@ -0,0 +1,88 @@ +#pragma once + +namespace nall::Beat::Single { + +inline auto apply(array_view source, array_view beat, maybe manifest = {}, maybe result = {}) -> maybe> { + #define error(text) { if(result) *result = {"error: ", text}; return {}; } + #define warning(text) { if(result) *result = {"warning: ", text}; return target; } + #define success() { if(result) *result = ""; return target; } + if(beat.size() < 19) error("beat size mismatch"); + + vector target; + + uint beatOffset = 0; + auto read = [&]() -> uint8_t { + return beat[beatOffset++]; + }; + + 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) { + target.append(data); + }; + + if(read() != 'B') error("beat header invalid"); + if(read() != 'P') error("beat header invalid"); + if(read() != 'S') error("beat header invalid"); + if(read() != '1') error("beat version mismatch"); + if(decode() != source.size()) error("source size mismatch"); + uint targetSize = decode(); + target.reserve(targetSize); + uint metadataSize = decode(); + for(uint n : range(metadataSize)) { + auto data = read(); + if(manifest) manifest->append((char)data); + } + + enum : uint { SourceRead, TargetRead, SourceCopy, TargetCopy }; + + uint sourceRelativeOffset = 0, targetRelativeOffset = 0; + while(beatOffset < beat.size() - 12) { + uint length = decode(); + uint mode = length & 3; + length = (length >> 2) + 1; + + if(mode == SourceRead) { + while(length--) write(source[target.size()]); + } else if(mode == TargetRead) { + while(length--) write(read()); + } else { + int offset = decode(); + offset = offset & 1 ? -(offset >> 1) : (offset >> 1); + if(mode == SourceCopy) { + sourceRelativeOffset += offset; + while(length--) write(source[sourceRelativeOffset++]); + } else { + targetRelativeOffset += offset; + while(length--) write(target[targetRelativeOffset++]); + } + } + } + + uint32_t sourceHash = 0, targetHash = 0, beatHash = 0; + for(uint shift : range(0, 32, 8)) sourceHash |= read() << shift; + for(uint shift : range(0, 32, 8)) targetHash |= read() << shift; + for(uint shift : range(0, 32, 8)) beatHash |= read() << shift; + + if(target.size() != targetSize) warning("target size mismatch"); + if(sourceHash != Hash::CRC32(source).value()) warning("source hash mismatch"); + if(targetHash != Hash::CRC32(target).value()) warning("target hash mismatch"); + if(beatHash != Hash::CRC32({beat.data(), beat.size() - 4}).value()) warning("beat hash mismatch"); + + success(); + #undef error + #undef warning + #undef success +} + +} diff --git a/nall/beat/single/create.hpp b/nall/beat/single/create.hpp new file mode 100644 index 0000000..940bdfc --- /dev/null +++ b/nall/beat/single/create.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include + +namespace nall::Beat::Single { + +inline auto create(array_view source, array_view target, string_view manifest = {}) -> vector { + vector beat; + + auto write = [&](uint8_t data) { + beat.append(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(source.size()), encode(target.size()), encode(manifest.size()); + for(auto& byte : manifest) write(byte); + + //generating lrcp() arrays for source requires O(4n) computations, and O(16m) memory, + //but it reduces find() complexity from O(n log m) to O(n + log m). and yet in practice, + //no matter how large n scales to, the O(n + log m) find() is paradoxically slower. + auto sourceArray = SuffixArray(source); + auto targetArray = SuffixArray(target).lpf(); + + enum : uint { SourceRead, TargetRead, SourceCopy, TargetCopy }; + uint outputOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0; + + uint targetReadLength = 0; + auto flush = [&] { + if(!targetReadLength) return; + encode(TargetRead | ((targetReadLength - 1) << 2)); + uint offset = outputOffset - targetReadLength; + while(targetReadLength) write(target[offset++]), targetReadLength--; + }; + + uint overlap = min(source.size(), target.size()); + while(outputOffset < target.size()) { + uint mode = TargetRead, longestLength = 3, longestOffset = 0; + int length = 0, offset = outputOffset; + + while(offset < overlap) { + if(source[offset] != target[offset]) break; + length++, offset++; + } + if(length > longestLength) { + mode = SourceRead, longestLength = length; + } + + sourceArray.find(length, offset, {target.data() + outputOffset, target.size() - outputOffset}); + if(length > longestLength) { + mode = SourceCopy, longestLength = length, longestOffset = offset; + } + + targetArray.previous(length, offset, outputOffset); + if(length > longestLength) { + mode = TargetCopy, longestLength = length, longestOffset = offset; + } + + if(mode == TargetRead) { + targetReadLength++; //queue writes to group sequential commands + outputOffset++; + } else { + flush(); + encode(mode | ((longestLength - 1) << 2)); + if(mode == SourceCopy) { + int relativeOffset = longestOffset - sourceRelativeOffset; + sourceRelativeOffset = longestOffset + longestLength; + encode(relativeOffset < 0 | abs(relativeOffset) << 1); + } + if(mode == TargetCopy) { + int relativeOffset = longestOffset - targetRelativeOffset; + targetRelativeOffset = longestOffset + longestLength; + encode(relativeOffset < 0 | abs(relativeOffset) << 1); + } + outputOffset += longestLength; + } + } + flush(); + + auto sourceHash = Hash::CRC32(source); + for(uint shift : range(0, 32, 8)) write(sourceHash.value() >> shift); + auto targetHash = Hash::CRC32(target); + for(uint shift : range(0, 32, 8)) write(targetHash.value() >> shift); + auto beatHash = Hash::CRC32(beat); + for(uint shift : range(0, 32, 8)) write(beatHash.value() >> shift); + + return beat; +} + +} diff --git a/nall/bit.hpp b/nall/bit.hpp new file mode 100755 index 0000000..c56ea4a --- /dev/null +++ b/nall/bit.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include + +namespace nall { + +template inline auto uclamp(const uintmax x) -> uintmax { + enum : uintmax { b = 1ull << (bits - 1), y = b * 2 - 1 }; + return y + ((x - y) & -(x < y)); //min(x, y); +} + +template inline auto uclip(const uintmax x) -> uintmax { + enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 }; + return (x & m); +} + +template inline auto sclamp(const intmax x) -> intmax { + enum : intmax { b = 1ull << (bits - 1), m = b - 1 }; + return (x > m) ? m : (x < -b) ? -b : x; +} + +template inline auto sclip(const intmax x) -> intmax { + enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 }; + return ((x & m) ^ b) - b; +} + +namespace bit { + constexpr inline auto mask(const char* s, uintmax sum = 0) -> uintmax { + return ( + *s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) : + *s == ' ' || *s == '_' ? mask(s + 1, sum) : + *s ? mask(s + 1, sum << 1) : + sum + ); + } + + constexpr inline auto test(const char* s, uintmax sum = 0) -> uintmax { + return ( + *s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) : + *s == ' ' || *s == '_' ? test(s + 1, sum) : + *s ? test(s + 1, sum << 1) : + sum + ); + } + + //lowest(0b1110) == 0b0010 + constexpr inline auto lowest(const uintmax x) -> uintmax { + return x & -x; + } + + //clear_lowest(0b1110) == 0b1100 + constexpr inline auto clearLowest(const uintmax x) -> uintmax { + return x & (x - 1); + } + + //set_lowest(0b0101) == 0b0111 + constexpr inline auto setLowest(const uintmax x) -> uintmax { + return x | (x + 1); + } + + //count number of bits set in a byte + constexpr inline auto count(uintmax x) -> uint { + uint count = 0; + while(x) x &= x - 1, count++; //clear the least significant bit + return count; + } + + //return index of the first bit set (or zero of no bits are set) + //first(0b1000) == 3 + constexpr inline auto first(uintmax x) -> uint { + uint first = 0; + while(x) { if(x & 1) break; x >>= 1; first++; } + return first; + } + + //round up to next highest single bit: + //round(15) == 16, round(16) == 16, round(17) == 32 + constexpr inline auto round(uintmax x) -> uintmax { + if((x & (x - 1)) == 0) return x; + while(x & (x - 1)) x &= x - 1; + return x << 1; + } +} + +} diff --git a/nall/cd.hpp b/nall/cd.hpp new file mode 100644 index 0000000..9fca9ab --- /dev/null +++ b/nall/cd.hpp @@ -0,0 +1,31 @@ +#pragma once + +/* CD-ROM sector functions. + * + * Implemented: + * eight-to-fourteen modulation (encoding and decoding) + * sync header creation and verification + * error detection code creation and verification + * reed-solomon product-code creation and verification + * sector scrambling and descrambling (currently unverified) + * + * Unimplemented: + * reed-solomon product-code correction + * cross-interleave reed-solomon creation, verification, and correction + * CD-ROM XA mode 2 forms 1 & 2 support + * subcode insertion and removal + * subcode decoding from CUE files + * channel frame expansion and reduction + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include diff --git a/nall/cd/crc16.hpp b/nall/cd/crc16.hpp new file mode 100644 index 0000000..d0b34b1 --- /dev/null +++ b/nall/cd/crc16.hpp @@ -0,0 +1,18 @@ +#pragma once + +//CRC-16/KERMIT + +namespace nall::CD { + +inline auto CRC16(array_view data) -> uint16_t { + uint16_t crc = 0; + while(data) { + crc ^= *data++ << 8; + for(uint bit : range(8)) { + crc = crc << 1 ^ (crc & 0x8000 ? 0x1021 : 0); + } + } + return ~crc; +} + +} diff --git a/nall/cd/edc.hpp b/nall/cd/edc.hpp new file mode 100644 index 0000000..bcc645a --- /dev/null +++ b/nall/cd/edc.hpp @@ -0,0 +1,65 @@ +#pragma once + +//error detection code + +namespace nall::CD::EDC { + +//polynomial(x) = (x^16 + x^15 + x^2 + 1) * (x^16 + x^2 + x + 1) +inline auto polynomial(uint8_t x) -> uint32_t { + static uint32_t lookup[256]{}; + static bool once = false; + if(!once) { once = true; + for(uint n : range(256)) { + uint32_t edc = n; + for(uint b : range(8)) edc = edc >> 1 ^ (edc & 1 ? 0xd8018001 : 0); + lookup[n] = edc; + } + } + return lookup[x]; +} + +// + +inline auto create(array_view input) -> uint32_t { + uint32_t sum = 0; + for(auto& byte : input) sum = sum >> 8 ^ polynomial(sum ^ byte); + return sum; +} + +inline auto create(array_view input, array_span output) -> bool { + if(output.size() != 4) return false; + auto sum = create(input); + output[0] = sum >> 0; + output[1] = sum >> 8; + output[2] = sum >> 16; + output[3] = sum >> 24; + return true; +} + +inline auto createMode1(array_span sector) -> bool { + if(sector.size() != 2352) return false; + return create({sector, 2064}, {sector + 2064, 4}); +} + +// + +inline auto verify(array_view input, uint32_t edc) -> bool { + return edc == create(input); +} + +inline auto verify(array_view input, array_view compare) -> bool { + if(compare.size() != 4) return false; + auto sum = create(input); + if(compare[0] != uint8_t(sum >> 0)) return false; + if(compare[1] != uint8_t(sum >> 8)) return false; + if(compare[2] != uint8_t(sum >> 16)) return false; + if(compare[3] != uint8_t(sum >> 24)) return false; + return true; +} + +inline auto verifyMode1(array_view sector) -> bool { + if(sector.size() != 2352) return false; + return verify({sector, 2064}, {sector + 2064, 4}); +} + +} diff --git a/nall/cd/efm.hpp b/nall/cd/efm.hpp new file mode 100644 index 0000000..ea4896a --- /dev/null +++ b/nall/cd/efm.hpp @@ -0,0 +1,68 @@ +#pragma once + +//eight-to-fourteen modulation: +//separates each 1-bit by at least two 0-bits and at most ten 0-bits + +namespace nall::CD::EFM { + +//the algorithm to generate this table is unknown +inline auto lookup(uint8_t index) -> uint16_t { + static const uint16_t lookup[256] = { + 0x1220, 0x2100, 0x2420, 0x2220, 0x1100, 0x0110, 0x0420, 0x0900, + 0x1240, 0x2040, 0x2440, 0x2240, 0x1040, 0x0040, 0x0440, 0x0840, + 0x2020, 0x2080, 0x2480, 0x0820, 0x1080, 0x0080, 0x0480, 0x0880, + 0x1210, 0x2010, 0x2410, 0x2210, 0x1010, 0x0210, 0x0410, 0x0810, + 0x0020, 0x2108, 0x0220, 0x0920, 0x1108, 0x0108, 0x1020, 0x0908, + 0x1248, 0x2048, 0x2448, 0x2248, 0x1048, 0x0048, 0x0448, 0x0848, + 0x0100, 0x2088, 0x2488, 0x2110, 0x1088, 0x0088, 0x0488, 0x0888, + 0x1208, 0x2008, 0x2408, 0x2208, 0x1008, 0x0208, 0x0408, 0x0808, + 0x1224, 0x2124, 0x2424, 0x2224, 0x1124, 0x0024, 0x0424, 0x0924, + 0x1244, 0x2044, 0x2444, 0x2244, 0x1044, 0x0044, 0x0444, 0x0844, + 0x2024, 0x2084, 0x2484, 0x0824, 0x1084, 0x0084, 0x0484, 0x0884, + 0x1204, 0x2004, 0x2404, 0x2204, 0x1004, 0x0204, 0x0404, 0x0804, + 0x1222, 0x2122, 0x2422, 0x2222, 0x1122, 0x0022, 0x1024, 0x0922, + 0x1242, 0x2042, 0x2442, 0x2242, 0x1042, 0x0042, 0x0442, 0x0842, + 0x2022, 0x2082, 0x2482, 0x0822, 0x1082, 0x0082, 0x0482, 0x0882, + 0x1202, 0x0248, 0x2402, 0x2202, 0x1002, 0x0202, 0x0402, 0x0802, + 0x1221, 0x2121, 0x2421, 0x2221, 0x1121, 0x0021, 0x0421, 0x0921, + 0x1241, 0x2041, 0x2441, 0x2241, 0x1041, 0x0041, 0x0441, 0x0841, + 0x2021, 0x2081, 0x2481, 0x0821, 0x1081, 0x0081, 0x0481, 0x0881, + 0x1201, 0x2090, 0x2401, 0x2201, 0x1090, 0x0201, 0x0401, 0x0890, + 0x0221, 0x2109, 0x1110, 0x0121, 0x1109, 0x0109, 0x1021, 0x0909, + 0x1249, 0x2049, 0x2449, 0x2249, 0x1049, 0x0049, 0x0449, 0x0849, + 0x0120, 0x2089, 0x2489, 0x0910, 0x1089, 0x0089, 0x0489, 0x0889, + 0x1209, 0x2009, 0x2409, 0x2209, 0x1009, 0x0209, 0x0409, 0x0809, + 0x1120, 0x2111, 0x2490, 0x0224, 0x1111, 0x0111, 0x0490, 0x0911, + 0x0241, 0x2101, 0x0244, 0x0240, 0x1101, 0x0101, 0x0090, 0x0901, + 0x0124, 0x2091, 0x2491, 0x2120, 0x1091, 0x0091, 0x0491, 0x0891, + 0x1211, 0x2011, 0x2411, 0x2211, 0x1011, 0x0211, 0x0411, 0x0811, + 0x1102, 0x0102, 0x2112, 0x0902, 0x1112, 0x0112, 0x1022, 0x0912, + 0x2102, 0x2104, 0x0249, 0x0242, 0x1104, 0x0104, 0x0422, 0x0904, + 0x0122, 0x2092, 0x2492, 0x0222, 0x1092, 0x0092, 0x0492, 0x0892, + 0x1212, 0x2012, 0x2412, 0x2212, 0x1012, 0x0212, 0x0412, 0x0812, + }; + return lookup[index]; +} + +// + +inline auto encode(uint8_t data) -> uint16_t { + return lookup(data); +} + +// + +inline auto decode(uint16_t data) -> maybe { + static uint16_t table[1 << 14]; + static bool once = true; + if(once) { + once = false; + for(uint n : range(1 << 14)) table[n] = 0xffff; + for(uint n : range(1 << 8)) table[lookup(n)] = n; + } + uint16_t result = table[data & 0x3fff]; + if(result == 0xffff) return {}; + return (uint8_t)result; +} + +} diff --git a/nall/cd/rspc.hpp b/nall/cd/rspc.hpp new file mode 100644 index 0000000..4f776dd --- /dev/null +++ b/nall/cd/rspc.hpp @@ -0,0 +1,128 @@ +#pragma once + +//reed-solomon product code + +namespace nall::CD::RSPC { + +inline auto encodeP(array_view input, array_span parity) -> bool { + ReedSolomon<26,24> s; + uint lo = 0, hi = 43 * 2; + for(uint x : range(43)) { + for(uint w : range(2)) { //16-bit words + uint z = 0; + for(uint y : range(24)) { + s[z++] = input[(y * 43 + x) * 2 + w]; + } + s.generateParity(); + parity[lo++] = s[z++]; + parity[hi++] = s[z++]; + } + } + return true; +} + +inline auto encodeQ(array_view input, array_span parity) -> bool { + ReedSolomon<45,43> s; + uint lo = 0, hi = 26 * 2; + for(uint y : range(26)) { + for(uint w : range(2)) { + uint z = 0; + for(uint x : range(43)) { + s[z++] = input[((x * 44 + y * 43) * 2 + w) % (26 * 43 * 2)]; + } + s.generateParity(); + parity[lo++] = s[z++]; + parity[hi++] = s[z++]; + } + } + return true; +} + +inline auto encodeMode1(array_span sector) -> bool { + if(sector.size() != 2352) return false; + if(!encodeP({sector + 12, 2064}, {sector + 2076, 172})) return false; + if(!encodeQ({sector + 12, 2236}, {sector + 2248, 104})) return false; + return true; +} + +// + +inline auto decodeP(array_span input, array_span parity) -> int { + bool success = false; + bool failure = false; + ReedSolomon<26,24> s; + uint lo = 0, hi = 43 * 2; + for(uint x : range(43)) { + for(uint w : range(2)) { + uint z = 0; + for(uint y : range(24)) { + s[z++] = input[(y * 43 + x) * 2 + w]; + } + s[z++] = parity[lo++]; + s[z++] = parity[hi++]; + auto count = s.correctErrors(); + if(count < 0) { + failure = true; + } + if(count > 0) { + success = true; + z = 0; + for(uint y : range(24)) { + input[(y * 43 + x) * 2 + w] = s[z++]; + } + parity[lo - 1] = s[z++]; + parity[hi - 1] = s[z++]; + } + } + } + if(!success && !failure) return 0; //no errors remaining + return success ? 1 : -1; //return success even if there are some failures +} + +inline auto decodeQ(array_span input, array_span parity) -> int { + bool success = false; + bool failure = false; + ReedSolomon<45,43> s; + uint lo = 0, hi = 26 * 2; + for(uint y : range(26)) { + for(uint w : range(2)) { + uint z = 0; + for(uint x : range(43)) { + s[z++] = input[((x * 44 + y * 43) * 2 + w) % (26 * 43 * 2)]; + } + s[z++] = parity[lo++]; + s[z++] = parity[hi++]; + auto count = s.correctErrors(); + if(count < 0) { + failure = true; + } + if(count > 0) { + success = true; + z = 0; + for(uint x : range(43)) { + input[((x * 44 + y * 43) * 2 + w) % (26 * 43 * 2)] = s[z++]; + } + parity[lo - 1] = s[z++]; + parity[hi - 1] = s[z++]; + } + } + } + if(!success && !failure) return 0; + return success ? 1 : -1; +} + +inline auto decodeMode1(array_span sector) -> bool { + if(sector.size() != 2352) return false; + //P corrections can allow Q corrections that previously failed to succeed, and vice versa. + //the more iterations, the more chances to correct errors, but the more computationally expensive it is. + //there must be a limit on the amount of retries, or this function may get stuck in an infinite loop. + for(uint attempt : range(4)) { + auto p = decodeP({sector + 12, 2064}, {sector + 2076, 172}); + auto q = decodeQ({sector + 12, 2236}, {sector + 2248, 104}); + if(p == 0 && q == 0) return true; //no errors remaining + if(p < 0 && q < 0) return false; //no more errors correctable + } + return false; //exhausted all retries with errors remaining +} + +} diff --git a/nall/cd/scrambler.hpp b/nall/cd/scrambler.hpp new file mode 100644 index 0000000..cf7380e --- /dev/null +++ b/nall/cd/scrambler.hpp @@ -0,0 +1,35 @@ +#pragma once + +namespace nall::CD::Scrambler { + +//polynomial(x) = x^15 + x + 1 +inline auto polynomial(uint x) -> uint8_t { + static uint8_t lookup[2340]{}; + static bool once = false; + if(!once) { once = true; + uint16_t shift = 0x0001; + for(uint n : range(2340)) { + lookup[n] = shift; + for(uint b : range(8)) { + bool carry = shift & 1 ^ shift >> 1 & 1; + shift = (carry << 15 | shift) >> 1; + } + } + } + return lookup[x]; +} + +// + +inline auto transform(array_span sector) -> bool { + if(sector.size() == 2352) sector += 12; //header is not scrambled + if(sector.size() != 2340) return false; //F1 frames only + + for(uint index : range(2340)) { + sector[index] ^= polynomial(index); + } + + return true; +} + +} diff --git a/nall/cd/session.hpp b/nall/cd/session.hpp new file mode 100644 index 0000000..4475926 --- /dev/null +++ b/nall/cd/session.hpp @@ -0,0 +1,478 @@ +#pragma once + +//subchannel processor +//note: this code is not tolerant to subchannel data that violates the Redbook standard + +namespace nall::CD { + +enum : int { InvalidLBA = 100 * 60 * 75 }; + +struct BCD { + static auto encode(uint8_t value) -> uint8_t { return value / 10 << 4 | value % 10; } + static auto decode(uint8_t value) -> uint8_t { return (value >> 4) * 10 + (value & 15); } +}; + +struct MSF { + uint8_t minute; //00-99 + uint8_t second; //00-59 + uint8_t frame = -1; //00-74 + + MSF() = default; + MSF(uint8_t m, uint8_t s, uint8_t f) : minute(m), second(s), frame(f) {} + MSF(int lba) { *this = fromLBA(lba); } + + explicit operator bool() const { + return minute <= 99 && second <= 59 && frame <= 74; + } + + static auto fromBCD(uint8_t minute, uint8_t second, uint8_t frame) -> MSF { + return {BCD::decode(minute), BCD::decode(second), BCD::decode(frame)}; + } + + static auto fromLBA(int lba) -> MSF { + if(lba < 0) lba = 100 * 60 * 75 + lba; + if(lba >= 100 * 60 * 75) return {}; + uint8_t minute = lba / 75 / 60 % 100; + uint8_t second = lba / 75 % 60; + uint8_t frame = lba % 75; + return {minute, second, frame}; + } + + auto toLBA() const -> int { + int lba = minute * 60 * 75 + second * 75 + frame; + if(minute < 90) return lba; + return -(100 * 60 * 75 - lba); + } + + //for debugging purposes + auto toString() const -> string { + if(!operator bool()) return "??:??:??"; + return {pad(minute, 2, '0'), ":", pad(second, 2, '0'), ":", pad(frame, 2, '0')}; + } +}; + +struct Index { + int lba = InvalidLBA; + int end = InvalidLBA; //inclusive range + + explicit operator bool() const { + return lba != InvalidLBA; + } + + auto inRange(int sector) const -> bool { + if(lba == InvalidLBA || end == InvalidLBA) return false; + return sector >= lba && sector <= end; + } +}; + +struct Track { + uint8_t control = 0b1111; //4-bit + uint8_t address = 0b1111; //4-bit + Index indices[100]; + uint8_t firstIndex = -1; + uint8_t lastIndex = -1; + + explicit operator bool() const { + return (bool)indices[1]; + } + + auto emphasis() const -> bool { + return control & 1; + } + + auto copyable() const -> bool { + return control & 2; + } + + auto channels() const -> uint { + if((control & 0b1100) == 0b0000) return 2; + if((control & 0b1100) == 0b1000) return 4; + return 0; //data track or reserved + } + + auto pregap() const -> int { + if(!indices[0] || !indices[1]) return InvalidLBA; + return indices[1].lba - indices[0].lba; + } + + auto isAudio() const -> bool { + return channels() != 0; + } + + auto isData() const -> bool { + return (control & 0b1100) == 0b0100; + } + + auto inIndex(int lba) const -> maybe { + for(uint8_t index : range(100)) { + if(indices[index].inRange(lba)) return index; + } + return {}; + } + + auto inRange(int lba) const -> bool { + if(firstIndex > 99 || lastIndex > 99) return false; + return lba >= indices[firstIndex].lba && lba <= indices[lastIndex].end; + } +}; + +struct Session { + Index leadIn; //00 + Track tracks[100]; //01-99 + Index leadOut; //aa + uint8_t firstTrack = -1; + uint8_t lastTrack = -1; + + auto inLeadIn(int lba) const -> bool { + return lba < 0; + } + + auto inTrack(int lba) const -> maybe { + for(uint8_t trackID : range(100)) { + auto& track = tracks[trackID]; + if(track && track.inRange(lba)) return trackID; + } + return {}; + } + + auto inLeadOut(int lba) const -> bool { + return lba >= leadOut.lba; + } + + auto encode(uint sectors) const -> vector { + if(sectors < abs(leadIn.lba) + leadOut.lba) return {}; //not enough sectors + + vector data; + data.resize(sectors * 96 + 96); //add one sector for P shift + + auto toP = [&](int lba) -> array_span { + //P is encoded one sector later than Q + return {&data[(lba + abs(leadIn.lba) + 1) * 96], 12}; + }; + + auto toQ = [&](int lba) -> array_span { + return {&data[(lba + abs(leadIn.lba)) * 96 + 12], 12}; + }; + + //lead-in + int lba = leadIn.lba; + while(lba < 0) { + //tracks + for(uint trackID : range(100)) { + for(uint repeat : range(3)) { + auto& track = tracks[trackID]; + if(!track) continue; + auto q = toQ(lba); + q[0] = track.control << 4 | track.address << 0; + q[1] = 0x00; + q[2] = BCD::encode(trackID); + auto msf = MSF(lba); + q[3] = BCD::encode(msf.minute); + q[4] = BCD::encode(msf.second); + q[5] = BCD::encode(msf.frame); + q[6] = 0x00; + msf = MSF(track.indices[1].lba); + q[7] = BCD::encode(msf.minute); + q[8] = BCD::encode(msf.second); + q[9] = BCD::encode(msf.frame); + auto crc16 = CRC16({q, 10}); + q[10] = crc16 >> 8; + q[11] = crc16 >> 0; + if(++lba >= 0) break; + }}if( lba >= 0) break; + + //first track + for(uint repeat : range(3)) { + auto q = toQ(lba); + q[0] = 0x01; //control value unverified; address = 1 + q[1] = 0x00; //track# = 00 (TOC) + q[2] = 0xa0; //first track + auto msf = MSF(lba); + q[3] = BCD::encode(msf.minute); + q[4] = BCD::encode(msf.second); + q[5] = BCD::encode(msf.frame); + q[6] = 0x00; + q[7] = BCD::encode(firstTrack); + q[8] = 0x00; + q[9] = 0x00; + auto crc16 = CRC16({q, 10}); + q[10] = crc16 >> 8; + q[11] = crc16 >> 0; + if(++lba >= 0) break; + } if( lba >= 0) break; + + //last track + for(uint repeat : range(3)) { + auto q = toQ(lba); + q[0] = 0x01; + q[1] = 0x00; + q[2] = 0xa1; //last track + auto msf = MSF(lba); + q[3] = BCD::encode(msf.minute); + q[4] = BCD::encode(msf.second); + q[5] = BCD::encode(msf.frame); + q[6] = 0x00; + q[7] = BCD::encode(lastTrack); + q[8] = 0x00; + q[9] = 0x00; + auto crc16 = CRC16({q, 10}); + q[10] = crc16 >> 8; + q[11] = crc16 >> 0; + if(++lba >= 0) break; + } if( lba >= 0) break; + + //lead-out point + for(uint repeat : range(3)) { + auto q = toQ(lba); + q[0] = 0x01; + q[1] = 0x00; + q[2] = 0xa2; //lead-out point + auto msf = MSF(lba); + q[3] = BCD::encode(msf.minute); + q[4] = BCD::encode(msf.second); + q[5] = BCD::encode(msf.frame); + q[6] = 0x00; + msf = MSF(leadOut.lba); + q[7] = BCD::encode(msf.minute); + q[8] = BCD::encode(msf.second); + q[9] = BCD::encode(msf.frame); + auto crc16 = CRC16({q, 10}); + q[10] = crc16 >> 8; + q[11] = crc16 >> 0; + if(++lba >= 0) break; + } if( lba >= 0) break; + } + + //tracks + int end = leadOut.lba; + for(uint8_t trackID : reverse(range(100))) { + auto& track = tracks[trackID]; + if(!track) continue; + + //indices + for(uint8_t indexID : reverse(range(100))) { + auto& index = track.indices[indexID]; + if(!index) continue; + + for(int lba = index.lba; lba < end; lba++) { + auto p = toP(lba); + uint8_t byte = indexID == 0 ? 0xff : 0x00; + for(uint index : range(12)) p[index] = byte; + + auto q = toQ(lba); + q[0] = track.control << 4 | track.address << 0; + q[1] = BCD::encode(trackID); + q[2] = BCD::encode(indexID); + auto msf = MSF(lba - track.indices[1].lba); + q[3] = BCD::encode(msf.minute); + q[4] = BCD::encode(msf.second); + q[5] = BCD::encode(msf.frame); + q[6] = 0x00; + msf = MSF(lba); + q[7] = BCD::encode(msf.minute); + q[8] = BCD::encode(msf.second); + q[9] = BCD::encode(msf.frame); + auto crc16 = CRC16({q, 10}); + q[10] = crc16 >> 8; + q[11] = crc16 >> 0; + } + + end = index.lba; + } + } + + //lead-out + for(int lba : range(sectors - abs(leadIn.lba) - leadOut.lba)) { + auto p = toP(leadOut.lba + lba); + uint8_t byte; + if(lba < 150) { + //2s start (standard specifies 2-3s start) + byte = 0x00; + } else { + //2hz duty cycle; rounded downward (standard specifies 2% tolerance) + byte = (lba - 150) / (75 >> 1) & 1 ? 0xff : 0x00; + } + for(uint index : range(12)) p[index] = byte; + + auto q = toQ(leadOut.lba + lba); + q[0] = 0x01; + q[1] = 0xaa; //lead-out track# + q[2] = 0x01; //lead-out index# + auto msf = MSF(lba); + q[3] = BCD::encode(msf.minute); + q[4] = BCD::encode(msf.second); + q[5] = BCD::encode(msf.frame); + q[6] = 0x00; + msf = MSF(leadOut.lba + lba); + q[7] = BCD::encode(msf.minute); + q[8] = BCD::encode(msf.second); + q[9] = BCD::encode(msf.frame); + auto crc16 = CRC16({q, 10}); + q[10] = crc16 >> 8; + q[11] = crc16 >> 0; + } + + data.resize(data.size() - 96); //remove padding for P shift + return data; + } + + auto decode(array_view data, uint size, uint leadOutSectors = 0) -> bool { + *this = {}; //reset session + //three data[] types supported: subcode Q only, subcode P-W only, data+subcode complete image + if(size != 12 && size != 96 && size != 2448) return false; + + //determine lead-in sector count + for(int lba : range(7500)) { //7500 max sectors scanned + uint offset = lba * size; + if(size == 96) offset += 12; + if(size == 2448) offset += 12 + 2352; + if(offset + 12 > data.size()) break; + auto q = array_view{&data[offset], 12}; + auto crc16 = CRC16({q, 10}); + if(q[10] != uint8_t(crc16 >> 8)) continue; + if(q[11] != uint8_t(crc16 >> 0)) continue; + + uint8_t control = q[0] >> 4; + uint8_t address = q[0] & 15; + uint8_t trackID = q[1]; + if(address != 1) continue; + if(trackID != 0) continue; + + auto msf = MSF::fromBCD(q[3], q[4], q[5]); + leadIn.lba = msf.toLBA() - lba; + break; + } + if(leadIn.lba == InvalidLBA || leadIn.lba >= 0) return false; + + auto toQ = [&](int lba) -> array_view { + uint offset = (lba + abs(leadIn.lba)) * size; + if(size == 96) offset += 12; + if(size == 2448) offset += 12 + 2352; + if(offset + 12 > data.size()) return {}; + return {&data[offset], 12}; + }; + + //lead-in + for(int lba = leadIn.lba; lba < 0; lba++) { + auto q = toQ(lba); + if(!q) break; + auto crc16 = CRC16({q, 10}); + if(q[10] != uint8_t(crc16 >> 8)) continue; + if(q[11] != uint8_t(crc16 >> 0)) continue; + + uint8_t control = q[0] >> 4; + uint8_t address = q[0] & 15; + uint8_t trackID = q[1]; + if(address != 1) continue; + if(trackID != 0) continue; + + trackID = BCD::decode(q[2]); + + if(trackID <= 99) { //00-99 + auto& track = tracks[trackID]; + track.control = control; + track.address = address; + track.indices[1].lba = MSF::fromBCD(q[7], q[8], q[9]).toLBA(); + } + + if(trackID == 100) { //a0 + firstTrack = BCD::decode(q[7]); + } + + if(trackID == 101) { //a1 + lastTrack = BCD::decode(q[7]); + } + + if(trackID == 102) { //a2 + leadOut.lba = MSF::fromBCD(q[7], q[8], q[9]).toLBA(); + } + } + if(leadOut.lba == InvalidLBA) return false; + + //tracks + for(int lba = 0; lba < leadOut.lba; lba++) { + auto q = toQ(lba); + if(!q) break; + auto crc16 = CRC16({q, 10}); + if(q[10] != uint8_t(crc16 >> 8)) continue; + if(q[11] != uint8_t(crc16 >> 0)) continue; + + uint8_t control = q[0] >> 4; + uint8_t address = q[0] & 15; + uint8_t trackID = BCD::decode(q[1]); + uint8_t indexID = BCD::decode(q[2]); + if(address != 1) continue; + if(trackID > 99) continue; + if(indexID > 99) continue; + + auto& track = tracks[trackID]; + if(!track) continue; //track not found? + auto& index = track.indices[indexID]; + if(index) continue; //index already decoded? + + index.lba = MSF::fromBCD(q[7], q[8], q[9]).toLBA(); + } + + synchronize(leadOutSectors); + return true; + } + + //calculates Index::end variables: + //needed for Session::isTrack() and Track::isIndex() to function. + auto synchronize(uint leadOutSectors = 0) -> void { + leadIn.end = -1; + int end = leadOut.lba - 1; + for(uint trackID : reverse(range(100))) { + auto& track = tracks[trackID]; + if(!track) continue; + + for(uint indexID : reverse(range(100))) { + auto& index = track.indices[indexID]; + if(!index) continue; + + index.end = end; + end = index.lba - 1; + } + + for(uint indexID : range(100)) { + auto& index = track.indices[indexID]; + if(index) { track.firstIndex = indexID; break; } + } + + for(uint indexID : reverse(range(100))) { + auto& index = track.indices[indexID]; + if(index) { track.lastIndex = indexID; break; } + } + } + leadOut.end = leadOut.lba + leadOutSectors - 1; + } + + //for diagnostic use only + auto serialize() const -> string { + string s; + s.append("session\n"); + s.append(" leadIn: "); + s.append(MSF(leadIn.lba).toString(), " - ", MSF(leadIn.end).toString(), "\n"); + for(uint trackID : range(100)) { + auto& track = tracks[trackID]; + if(!track) continue; + s.append(" track", pad(trackID, 2, '0')); + if(trackID == firstTrack) s.append(" first"); + if(trackID == lastTrack) s.append( " last"); + s.append("\n"); + s.append(" control: ", binary(track.control, 4, '0'), "\n"); + s.append(" address: ", binary(track.address, 4, '0'), "\n"); + for(uint indexID : range(100)) { + auto& index = track.indices[indexID]; + if(!index) continue; + s.append(" index", pad(indexID, 2, '0'), ": "); + s.append(MSF(index.lba).toString(), " - ", MSF(index.end).toString(), "\n"); + } + } + s.append(" leadout: "); + s.append(MSF(leadOut.lba).toString(), " - ", MSF(leadOut.end).toString(), "\n"); + return s; + } +}; + +} diff --git a/nall/cd/sync.hpp b/nall/cd/sync.hpp new file mode 100644 index 0000000..513db35 --- /dev/null +++ b/nall/cd/sync.hpp @@ -0,0 +1,27 @@ +#pragma once + +namespace nall::CD::Sync { + +inline auto create(array_span sector) -> bool { + if(sector.size() != 12 && sector.size() != 2352) return false; + + for(uint n : range(12)) { + sector[n] = (n == 0 || n == 11) ? 0x00 : 0xff; + } + + return true; +} + +// + +inline auto verify(array_view sector) -> bool { + if(sector.size() != 12 && sector.size() != 2352) return false; + + for(uint n : range(12)) { + if(sector[n] != (n == 0 || n == 11) ? 0x00 : 0xff) return false; + } + + return true; +} + +} diff --git a/nall/chrono.hpp b/nall/chrono.hpp new file mode 100644 index 0000000..b9c1162 --- /dev/null +++ b/nall/chrono.hpp @@ -0,0 +1,183 @@ +#pragma once + +#include +#include + +namespace nall::chrono { + +//passage of time functions (from unknown epoch) + +inline auto nanosecond() -> uint64_t { + timespec tv; + clock_gettime(CLOCK_MONOTONIC, &tv); + return tv.tv_sec * 1'000'000'000 + tv.tv_nsec; +} + +inline auto microsecond() -> uint64_t { return nanosecond() / 1'000; } +inline auto millisecond() -> uint64_t { return nanosecond() / 1'000'000; } +inline auto second() -> uint64_t { return nanosecond() / 1'000'000'000; } + +inline auto benchmark(const function& f, uint64_t times = 1) -> void { + auto start = nanosecond(); + while(times--) f(); + auto end = nanosecond(); + print("[chrono::benchmark] ", (double)(end - start) / 1'000'000'000.0, "s\n"); +} + +//exact date/time functions (from system epoch) + +struct timeinfo { + timeinfo( + uint year = 0, uint month = 0, uint day = 0, + uint hour = 0, uint minute = 0, uint second = 0, uint weekday = 0 + ) : year(year), month(month), day(day), + hour(hour), minute(minute), second(second), weekday(weekday) { + } + + inline explicit operator bool() const { return month; } + + uint year; //... + uint month; //1 - 12 + uint day; //1 - 31 + uint hour; //0 - 23 + uint minute; //0 - 59 + uint second; //0 - 60 + uint weekday; //0 - 6 +}; + +inline auto timestamp() -> uint64_t { + return ::time(nullptr); +} + +//0 = failure condition +inline auto timestamp(const string& datetime) -> uint64_t { + static const uint monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + uint64_t timestamp = 0; + if(datetime.match("??????????")) { + return datetime.natural(); + } + if(datetime.match("????*")) { + uint year = datetime.slice(0, 4).natural(); + if(year < 1970 || year > 2199) return 0; + for(uint y = 1970; y < year && y < 2999; y++) { + uint daysInYear = 365; + if(y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) daysInYear++; + timestamp += daysInYear * 24 * 60 * 60; + } + } + if(datetime.match("????-??*")) { + uint y = datetime.slice(0, 4).natural(); + uint month = datetime.slice(5, 2).natural(); + if(month < 1 || month > 12) return 0; + for(uint m = 1; m < month && m < 12; m++) { + uint daysInMonth = monthDays[m - 1]; + if(m == 2 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) daysInMonth++; + timestamp += daysInMonth * 24 * 60 * 60; + } + } + if(datetime.match("????-??-??*")) { + uint day = datetime.slice(8, 2).natural(); + if(day < 1 || day > 31) return 0; + timestamp += (day - 1) * 24 * 60 * 60; + } + if(datetime.match("????-??-?? ??*")) { + uint hour = datetime.slice(11, 2).natural(); + if(hour > 23) return 0; + timestamp += hour * 60 * 60; + } + if(datetime.match("????-??-?? ??:??*")) { + uint minute = datetime.slice(14, 2).natural(); + if(minute > 59) return 0; + timestamp += minute * 60; + } + if(datetime.match("????-??-?? ??:??:??*")) { + uint second = datetime.slice(17, 2).natural(); + if(second > 59) return 0; + timestamp += second; + } + return timestamp; +} + +namespace utc { + inline auto timeinfo(uint64_t time = 0) -> chrono::timeinfo { + auto stamp = time ? (time_t)time : (time_t)timestamp(); + auto info = gmtime(&stamp); + return { + (uint)info->tm_year + 1900, + (uint)info->tm_mon + 1, + (uint)info->tm_mday, + (uint)info->tm_hour, + (uint)info->tm_min, + (uint)info->tm_sec, + (uint)info->tm_wday + }; + } + + inline auto year(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).year, 4, '0'); } + inline auto month(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).month, 2, '0'); } + inline auto day(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).day, 2, '0'); } + inline auto hour(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).hour, 2, '0'); } + inline auto minute(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).minute, 2, '0'); } + inline auto second(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).second, 2, '0'); } + + inline auto date(uint64_t timestamp = 0) -> string { + auto t = timeinfo(timestamp); + return {pad(t.year, 4, '0'), "-", pad(t.month, 2, '0'), "-", pad(t.day, 2, '0')}; + } + + inline auto time(uint64_t timestamp = 0) -> string { + auto t = timeinfo(timestamp); + return {pad(t.hour, 2, '0'), ":", pad(t.minute, 2, '0'), ":", pad(t.second, 2, '0')}; + } + + inline auto datetime(uint64_t timestamp = 0) -> string { + auto t = timeinfo(timestamp); + return { + pad(t.year, 4, '0'), "-", pad(t.month, 2, '0'), "-", pad(t.day, 2, '0'), " ", + pad(t.hour, 2, '0'), ":", pad(t.minute, 2, '0'), ":", pad(t.second, 2, '0') + }; + } +} + +namespace local { + inline auto timeinfo(uint64_t time = 0) -> chrono::timeinfo { + auto stamp = time ? (time_t)time : (time_t)timestamp(); + auto info = localtime(&stamp); + return { + (uint)info->tm_year + 1900, + (uint)info->tm_mon + 1, + (uint)info->tm_mday, + (uint)info->tm_hour, + (uint)info->tm_min, + (uint)info->tm_sec, + (uint)info->tm_wday + }; + } + + inline auto year(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).year, 4, '0'); } + inline auto month(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).month, 2, '0'); } + inline auto day(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).day, 2, '0'); } + inline auto hour(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).hour, 2, '0'); } + inline auto minute(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).minute, 2, '0'); } + inline auto second(uint64_t timestamp = 0) -> string { return pad(timeinfo(timestamp).second, 2, '0'); } + + inline auto date(uint64_t timestamp = 0) -> string { + auto t = timeinfo(timestamp); + return {pad(t.year, 4, '0'), "-", pad(t.month, 2, '0'), "-", pad(t.day, 2, '0')}; + } + + inline auto time(uint64_t timestamp = 0) -> string { + auto t = timeinfo(timestamp); + return {pad(t.hour, 2, '0'), ":", pad(t.minute, 2, '0'), ":", pad(t.second, 2, '0')}; + } + + inline auto datetime(uint64_t timestamp = 0) -> string { + auto t = timeinfo(timestamp); + return { + pad(t.year, 4, '0'), "-", pad(t.month, 2, '0'), "-", pad(t.day, 2, '0'), " ", + pad(t.hour, 2, '0'), ":", pad(t.minute, 2, '0'), ":", pad(t.second, 2, '0') + }; + } +} + +} diff --git a/nall/cipher/chacha20.hpp b/nall/cipher/chacha20.hpp new file mode 100644 index 0000000..66b7166 --- /dev/null +++ b/nall/cipher/chacha20.hpp @@ -0,0 +1,109 @@ +#pragma once + +#include +#include + +namespace nall::Cipher { + +//64-bit nonce; 64-bit x 64-byte (256GB) counter +struct ChaCha20 { + ChaCha20(uint256_t key, uint64_t nonce, uint64_t counter = 0) { + static const uint128_t sigma = 0x6b20657479622d323320646e61707865_u128; //"expand 32-byte k" + + input[ 0] = sigma >> 0; + input[ 1] = sigma >> 32; + input[ 2] = sigma >> 64; + input[ 3] = sigma >> 96; + input[ 4] = key >> 0; + input[ 5] = key >> 32; + input[ 6] = key >> 64; + input[ 7] = key >> 96; + input[ 8] = key >> 128; + input[ 9] = key >> 160; + input[10] = key >> 192; + input[11] = key >> 224; + input[12] = counter >> 0; + input[13] = counter >> 32; + input[14] = nonce >> 0; + input[15] = nonce >> 32; + + offset = 0; + } + + auto encrypt(array_view input) -> vector { + vector output; + while(input) { + if(!offset) { + cipher(); + increment(); + } + auto byte = offset++; + output.append(*input++ ^ (block[byte >> 2] >> (byte & 3) * 8)); + offset &= 63; + } + return output; + } + + auto decrypt(array_view input) -> vector { + return encrypt(input); //reciprocal cipher + } + +//protected: + inline auto rol(uint32_t value, uint bits) -> uint32_t { + return value << bits | value >> 32 - bits; + } + + auto quarterRound(uint32_t x[16], uint a, uint b, uint c, uint d) -> void { + x[a] += x[b]; x[d] = rol(x[d] ^ x[a], 16); + x[c] += x[d]; x[b] = rol(x[b] ^ x[c], 12); + x[a] += x[b]; x[d] = rol(x[d] ^ x[a], 8); + x[c] += x[d]; x[b] = rol(x[b] ^ x[c], 7); + } + + auto cipher() -> void { + memory::copy(block, input, 64); + for(uint n : range(10)) { + quarterRound(block, 0, 4, 8, 12); + quarterRound(block, 1, 5, 9, 13); + quarterRound(block, 2, 6, 10, 14); + quarterRound(block, 3, 7, 11, 15); + quarterRound(block, 0, 5, 10, 15); + quarterRound(block, 1, 6, 11, 12); + quarterRound(block, 2, 7, 8, 13); + quarterRound(block, 3, 4, 9, 14); + } + } + + auto increment() -> void { + for(uint n : range(16)) { + block[n] += input[n]; + } + if(!++input[12]) ++input[13]; + } + + uint32_t input[16]; + uint32_t block[16]; + uint64_t offset; +}; + +struct HChaCha20 : protected ChaCha20 { + HChaCha20(uint256_t key, uint128_t nonce) : ChaCha20(key, nonce >> 64, nonce >> 0) { + cipher(); + } + + auto key() const -> uint256_t { + uint256_t key = 0; + for(uint n : range(4)) key |= (uint256_t)block[ 0 + n] << (n + 0) * 32; + for(uint n : range(4)) key |= (uint256_t)block[12 + n] << (n + 4) * 32; + return key; + } +}; + +//192-bit nonce; 64-bit x 64-byte (256GB) counter +struct XChaCha20 : ChaCha20 { + XChaCha20(uint256_t key, uint192_t nonce, uint64_t counter = 0): + ChaCha20(HChaCha20(key, nonce).key(), nonce >> 128, counter) { + } +}; + +} diff --git a/nall/counting-sort.hpp b/nall/counting-sort.hpp new file mode 100644 index 0000000..e4f7100 --- /dev/null +++ b/nall/counting-sort.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace nall { + +//counting sort by powers of two: used to implement radix sort +template +auto counting_sort(T* output, const T* input, uint size) -> void { + static_assert(Bits >= 1 && Bits <= 20, "must be between 1 and 20 bits"); + enum : uint { Base = 1 << Bits, Mask = Base - 1 }; + + uint64_t count[Base] = {}, last = 0; + for(uint n : range(size)) ++count[(input[n] >> Shift) & Mask]; + for(uint n : range(Base)) last += count[n], count[n] = last - count[n]; + for(uint n : range(size)) output[count[(input[n] >> Shift) & Mask]++] = input[n]; +} + +} diff --git a/nall/database/odbc.hpp b/nall/database/odbc.hpp new file mode 100644 index 0000000..bd3cba1 --- /dev/null +++ b/nall/database/odbc.hpp @@ -0,0 +1,299 @@ +#pragma once + +//legacy code; no longer used + +#include + +#include +#include +#include + +namespace nall::Database { + +struct ODBC { + struct Statement { + Statement(const Statement& source) = delete; + auto operator=(const Statement& source) -> Statement& = delete; + + Statement(SQLHANDLE statement) : _statement(statement) {} + Statement(Statement&& source) { operator=(move(source)); } + + auto operator=(Statement&& source) -> Statement& { + _statement = source._statement; + _output = source._output; + _values = move(source._values); + source._statement = nullptr; + source._output = 0; + return *this; + } + + auto columns() -> unsigned { + SQLSMALLINT columns = 0; + if(statement()) SQLNumResultCols(statement(), &columns); + return columns; + } + + auto integer(unsigned column) -> int64_t { + if(auto value = _values(column)) return value.get(0); + int64_t value = 0; + SQLGetData(statement(), 1 + column, SQL_C_SBIGINT, &value, 0, nullptr); + _values(column) = (int64_t)value; + return value; + } + + auto natural(unsigned column) -> uint64_t { + if(auto value = _values(column)) return value.get(0); + uint64_t value = 0; + SQLGetData(statement(), 1 + column, SQL_C_UBIGINT, &value, 0, nullptr); + _values(column) = (uint64_t)value; + return value; + } + + auto real(unsigned column) -> double { + if(auto value = _values(column)) return value.get(0.0); + double value = 0.0; + SQLGetData(statement(), 1 + column, SQL_C_DOUBLE, &value, 0, nullptr); + _values(column) = (double)value; + return value; + } + + auto text(unsigned column) -> string { + if(auto value = _values(column)) return value.get({}); + string value; + value.resize(65535); + SQLLEN size = 0; + SQLGetData(statement(), 1 + column, SQL_C_CHAR, value.get(), value.size(), &size); + value.resize(size); + _values(column) = (string)value; + return value; + } + + auto data(unsigned column) -> vector { + if(auto value = _values(column)) return value.get>({}); + vector value; + value.resize(65535); + SQLLEN size = 0; + SQLGetData(statement(), 1 + column, SQL_C_CHAR, value.data(), value.size(), &size); + value.resize(size); + _values(column) = (vector)value; + return value; + } + + auto integer() -> int64_t { return integer(_output++); } + auto natural() -> uint64_t { return natural(_output++); } + auto real() -> double { return real(_output++); } + auto text() -> string { return text(_output++); } + auto data() -> vector { return data(_output++); } + + protected: + virtual auto statement() -> SQLHANDLE { return _statement; } + + SQLHANDLE _statement = nullptr; + unsigned _output = 0; + vector _values; //some ODBC drivers (eg MS-SQL) do not allow the same column to be read more than once + }; + + struct Query : Statement { + Query(const Query& source) = delete; + auto operator=(const Query& source) -> Query& = delete; + + Query(SQLHANDLE statement) : Statement(statement) {} + Query(Query&& source) : Statement(source._statement) { operator=(move(source)); } + + ~Query() { + if(statement()) { + SQLFreeHandle(SQL_HANDLE_STMT, _statement); + _statement = nullptr; + } + } + + auto operator=(Query&& source) -> Query& { + Statement::operator=(move(source)); + _bindings = move(source._bindings); + _result = source._result; + _input = source._input; + _stepped = source._stepped; + source._result = SQL_SUCCESS; + source._input = 0; + source._stepped = false; + return *this; + } + + explicit operator bool() { + //this is likely not the best way to test if the query has returned data ... + //but I wasn't able to find an ODBC API for this seemingly simple task + return statement() && success(); + } + + //ODBC SQLBindParameter only holds pointers to data values + //if the bound paramters go out of scope before the query is executed, binding would reference dangling pointers + //so to work around this, we cache all parameters inside Query until the query is executed + + auto& bind(unsigned column, nullptr_t) { return _bindings.append({column, any{(nullptr_t)nullptr}}), *this; } + auto& bind(unsigned column, int32_t value) { return _bindings.append({column, any{(int32_t)value}}), *this; } + auto& bind(unsigned column, uint32_t value) { return _bindings.append({column, any{(uint32_t)value}}), *this; } + auto& bind(unsigned column, int64_t value) { return _bindings.append({column, any{(int64_t)value}}), *this; } + auto& bind(unsigned column, uint64_t value) { return _bindings.append({column, any{(uint64_t)value}}), *this; } + auto& bind(unsigned column, double value) { return _bindings.append({column, any{(double)value}}), *this; } + auto& bind(unsigned column, const string& value) { return _bindings.append({column, any{(string)value}}), *this; } + auto& bind(unsigned column, const vector& value) { return _bindings.append({column, any{(vector)value}}), *this; } + + auto& bind(nullptr_t) { return bind(_input++, nullptr); } + auto& bind(int32_t value) { return bind(_input++, value); } + auto& bind(uint32_t value) { return bind(_input++, value); } + auto& bind(int64_t value) { return bind(_input++, value); } + auto& bind(uint64_t value) { return bind(_input++, value); } + auto& bind(double value) { return bind(_input++, value); } + auto& bind(const string& value) { return bind(_input++, value); } + auto& bind(const vector& value) { return bind(_input++, value); } + + auto step() -> bool { + if(!_stepped) { + for(auto& binding : _bindings) { + if(binding.value.is()) { + SQLLEN length = SQL_NULL_DATA; + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC, 0, 0, nullptr, 0, &length); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + auto& value = binding.value.get(); + SQLLEN length = SQL_NTS; + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, value.size(), 0, (SQLPOINTER)value.data(), 0, &length); + } else if(binding.value.is>()) { + auto& value = binding.value.get>(); + SQLLEN length = value.size(); + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARBINARY, value.size(), 0, (SQLPOINTER)value.data(), 0, &length); + } + } + + _stepped = true; + _result = SQLExecute(_statement); + if(!success()) return false; + } + + _values.reset(); //clear previous row's cached read results + _result = SQLFetch(_statement); + _output = 0; + return success(); + } + + struct Iterator { + Iterator(Query& query, bool finished) : query(query), finished(finished) {} + auto operator*() -> Statement { return query._statement; } + auto operator!=(const Iterator& source) const -> bool { return finished != source.finished; } + auto operator++() -> Iterator& { finished = !query.step(); return *this; } + + protected: + Query& query; + bool finished = false; + }; + + auto begin() -> Iterator { return Iterator(*this, !step()); } + auto end() -> Iterator { return Iterator(*this, true); } + + private: + auto success() const -> bool { + return _result == SQL_SUCCESS || _result == SQL_SUCCESS_WITH_INFO; + } + + auto statement() -> SQLHANDLE override { + if(!_stepped) step(); + return _statement; + } + + struct Binding { + unsigned column; + any value; + }; + vector _bindings; + + SQLRETURN _result = SQL_SUCCESS; + unsigned _input = 0; + bool _stepped = false; + }; + + ODBC() { + _result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &_environment); + if(!success()) return; + + SQLSetEnvAttr(_environment, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); + } + + ODBC(const string& database, const string& username, const string& password) : ODBC() { + open(database, username, password); + } + + ~ODBC() { + if(_environment) { + close(); + SQLFreeHandle(SQL_HANDLE_ENV, _environment); + _environment = nullptr; + } + } + + explicit operator bool() const { return _connection; } + + auto open(const string& database, const string& username, const string& password) -> bool { + if(!_environment) return false; + close(); + + _result = SQLAllocHandle(SQL_HANDLE_DBC, _environment, &_connection); + if(!success()) return false; + + SQLSetConnectAttr(_connection, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0); + _result = SQLConnectA(_connection, + (SQLCHAR*)database.data(), SQL_NTS, + (SQLCHAR*)username.data(), SQL_NTS, + (SQLCHAR*)password.data(), SQL_NTS + ); + if(!success()) return close(), false; + + return true; + } + + auto close() -> void { + if(_connection) { + SQLDisconnect(_connection); + SQLFreeHandle(SQL_HANDLE_DBC, _connection); + _connection = nullptr; + } + } + + template auto execute(const string& statement, P&&... p) -> Query { + if(!_connection) return {nullptr}; + + SQLHANDLE _statement = nullptr; + _result = SQLAllocHandle(SQL_HANDLE_STMT, _connection, &_statement); + if(!success()) return {nullptr}; + + Query query{_statement}; + _result = SQLPrepareA(_statement, (SQLCHAR*)statement.data(), SQL_NTS); + if(!success()) return {nullptr}; + + bind(query, forward

    (p)...); + return query; + } + +private: + auto success() const -> bool { return _result == SQL_SUCCESS || _result == SQL_SUCCESS_WITH_INFO; } + + auto bind(Query&) -> void {} + template auto bind(Query& query, const T& value, P&&... p) -> void { + query.bind(value); + bind(query, forward

    (p)...); + } + + SQLHANDLE _environment = nullptr; + SQLHANDLE _connection = nullptr; + SQLRETURN _result = SQL_SUCCESS; +}; + +} diff --git a/nall/database/sqlite3.hpp b/nall/database/sqlite3.hpp new file mode 100644 index 0000000..10ab872 --- /dev/null +++ b/nall/database/sqlite3.hpp @@ -0,0 +1,218 @@ +#pragma once + +//SQLite3 C++ RAII wrapper for nall +//note: it is safe (no-op) to call sqlite3_* functions on null sqlite3 objects + +#include + +#include +#include + +namespace nall::Database { + +struct SQLite3 { + struct Statement { + Statement(const Statement& source) = delete; + auto operator=(const Statement& source) -> Statement& = delete; + + Statement(sqlite3_stmt* statement) : _statement(statement) {} + Statement(Statement&& source) { operator=(move(source)); } + + auto operator=(Statement&& source) -> Statement& { + _statement = source._statement; + _response = source._response; + _output = source._output; + source._statement = nullptr; + source._response = SQLITE_OK; + source._output = 0; + return *this; + } + + explicit operator bool() { + return sqlite3_data_count(statement()); + } + + auto columns() -> uint { + return sqlite3_column_count(statement()); + } + + auto boolean(uint column) -> bool { + return sqlite3_column_int64(statement(), column) != 0; + } + + auto integer(uint column) -> int64_t { + return sqlite3_column_int64(statement(), column); + } + + auto natural(uint column) -> uint64_t { + return sqlite3_column_int64(statement(), column); + } + + auto real(uint column) -> double { + return sqlite3_column_double(statement(), column); + } + + auto string(uint column) -> nall::string { + nall::string result; + if(auto text = sqlite3_column_text(statement(), column)) { + result.resize(sqlite3_column_bytes(statement(), column)); + memory::copy(result.get(), text, result.size()); + } + return result; + } + + auto data(uint column) -> vector { + vector result; + if(auto data = sqlite3_column_blob(statement(), column)) { + result.resize(sqlite3_column_bytes(statement(), column)); + memory::copy(result.data(), data, result.size()); + } + return result; + } + + auto boolean() -> bool { return boolean(_output++); } + auto integer() -> int64_t { return integer(_output++); } + auto natural() -> uint64_t { return natural(_output++); } + auto real() -> double { return real(_output++); } + auto string() -> nall::string { return string(_output++); } + auto data() -> vector { return data(_output++); } + + protected: + virtual auto statement() -> sqlite3_stmt* { return _statement; } + + sqlite3_stmt* _statement = nullptr; + int _response = SQLITE_OK; + uint _output = 0; + }; + + struct Query : Statement { + Query(const Query& source) = delete; + auto operator=(const Query& source) -> Query& = delete; + + Query(sqlite3_stmt* statement) : Statement(statement) {} + Query(Query&& source) : Statement(source._statement) { operator=(move(source)); } + + ~Query() { + sqlite3_finalize(statement()); + _statement = nullptr; + } + + auto operator=(Query&& source) -> Query& { + _statement = source._statement; + _input = source._input; + source._statement = nullptr; + source._input = 0; + return *this; + } + + auto& bind(uint column, nullptr_t) { sqlite3_bind_null(_statement, 1 + column); return *this; } + auto& bind(uint column, bool value) { sqlite3_bind_int(_statement, 1 + column, value); return *this; } + auto& bind(uint column, int32_t value) { sqlite3_bind_int(_statement, 1 + column, value); return *this; } + auto& bind(uint column, uint32_t value) { sqlite3_bind_int(_statement, 1 + column, value); return *this; } + auto& bind(uint column, int64_t value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; } + auto& bind(uint column, uint64_t value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; } + auto& bind(uint column, intmax value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; } + auto& bind(uint column, uintmax value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; } + auto& bind(uint column, nall::boolean value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; } + auto& bind(uint column, nall::integer value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; } + auto& bind(uint column, nall::natural value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; } + auto& bind(uint column, double value) { sqlite3_bind_double(_statement, 1 + column, value); return *this; } + auto& bind(uint column, const nall::string& value) { sqlite3_bind_text(_statement, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; } + auto& bind(uint column, const vector& value) { sqlite3_bind_blob(_statement, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; } + + auto& bind(nullptr_t) { return bind(_input++, nullptr); } + auto& bind(bool value) { return bind(_input++, value); } + auto& bind(int32_t value) { return bind(_input++, value); } + auto& bind(uint32_t value) { return bind(_input++, value); } + auto& bind(int64_t value) { return bind(_input++, value); } + auto& bind(uint64_t value) { return bind(_input++, value); } + auto& bind(intmax value) { return bind(_input++, value); } + auto& bind(uintmax value) { return bind(_input++, value); } + auto& bind(nall::boolean value) { return bind(_input++, value); } + auto& bind(nall::integer value) { return bind(_input++, value); } + auto& bind(nall::natural value) { return bind(_input++, value); } + auto& bind(double value) { return bind(_input++, value); } + auto& bind(const nall::string& value) { return bind(_input++, value); } + auto& bind(const vector& value) { return bind(_input++, value); } + + auto step() -> bool { + _stepped = true; + return sqlite3_step(_statement) == SQLITE_ROW; + } + + struct Iterator { + Iterator(Query& query, bool finished) : query(query), finished(finished) {} + auto operator*() -> Statement { return query._statement; } + auto operator!=(const Iterator& source) const -> bool { return finished != source.finished; } + auto operator++() -> Iterator& { finished = !query.step(); return *this; } + + protected: + Query& query; + bool finished = false; + }; + + auto begin() -> Iterator { return Iterator(*this, !step()); } + auto end() -> Iterator { return Iterator(*this, true); } + + private: + auto statement() -> sqlite3_stmt* override { + if(!_stepped) step(); + return _statement; + } + + uint _input = 0; + bool _stepped = false; + }; + + SQLite3() = default; + SQLite3(const string& filename) { open(filename); } + ~SQLite3() { close(); } + + explicit operator bool() const { return _database; } + + auto open(const string& filename) -> bool { + close(); + sqlite3_open(filename, &_database); + return _database; + } + + auto close() -> void { + sqlite3_close(_database); + _database = nullptr; + } + + template auto execute(const string& statement, P&&... p) -> Query { + if(!_database) return {nullptr}; + + sqlite3_stmt* _statement = nullptr; + sqlite3_prepare_v2(_database, statement.data(), statement.size(), &_statement, nullptr); + if(!_statement) { + if(_debug) print("[sqlite3_prepare_v2] ", sqlite3_errmsg(_database), "\n"); + return {nullptr}; + } + + Query query{_statement}; + bind(query, forward

    (p)...); + return query; + } + + auto lastInsertID() const -> uint64_t { + return _database ? sqlite3_last_insert_rowid(_database) : 0; + } + + auto setDebug(bool debug = true) -> void { + _debug = debug; + } + +protected: + auto bind(Query&) -> void {} + template auto bind(Query& query, const T& value, P&&... p) -> void { + query.bind(value); + bind(query, forward

    (p)...); + } + + bool _debug = false; + sqlite3* _database = nullptr; +}; + +} diff --git a/nall/decode/base.hpp b/nall/decode/base.hpp new file mode 100644 index 0000000..d20f1a5 --- /dev/null +++ b/nall/decode/base.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +namespace nall::Decode { + +template inline auto Base(const string& value) -> T { + static const string format = + Bits == 2 ? "01" + : Bits == 8 ? "01234567" + : Bits == 10 ? "0123456789" + : Bits == 16 ? "0123456789abcdef" + : Bits == 32 ? "0123456789abcdefghijklmnopqrstuv" + : Bits == 34 ? "023456789abcdefghijkmnopqrstuvwxyz" //1l + : Bits == 36 ? "0123456789abcdefghijklmnopqrstuvwxyz" + : Bits == 57 ? "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" //01IOl + : Bits == 62 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + : Bits == 64 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{}" + : Bits == 85 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%()+,-.:;=@[]^_`{|}~" //\ "&'*/<>? + : ""; + static bool initialized = false; + static uint8_t lookup[256] = {0}; + if(!initialized) { + initialized = true; + for(uint n : range(format.size())) { + lookup[format[n]] = n; + } + } + + T result = 0; + for(auto byte : value) { + result = result * Bits + lookup[byte]; + } + return result; +} + +} diff --git a/nall/decode/base64.hpp b/nall/decode/base64.hpp new file mode 100644 index 0000000..a613d34 --- /dev/null +++ b/nall/decode/base64.hpp @@ -0,0 +1,47 @@ +#pragma once + +namespace nall::Decode { + +inline auto Base64(const string& text) -> vector { + static bool initialized = false; + static uint8_t lookup[256] = {0}; + if(!initialized) { + initialized = true; + for(uint n : range(26)) lookup['A' + n] = n; + for(uint n : range(26)) lookup['a' + n] = n + 26; + for(uint n : range(10)) lookup['0' + n] = n + 52; + lookup['+'] = lookup['-'] = 62; + lookup['/'] = lookup['_'] = 63; + } + + vector result; + uint8_t buffer, output; + for(uint n : range(text.size())) { + uint8_t buffer = lookup[text[n]]; + + switch(n & 3) { + case 0: + output = buffer << 2; + break; + + case 1: + result.append(output | buffer >> 4); + output = (buffer & 15) << 4; + break; + + case 2: + result.append(output | buffer >> 2); + output = (buffer & 3) << 6; + break; + + case 3: + result.append(output | buffer); + break; + } + } + + if(text.size() & 3) result.append(output | buffer); + return result; +} + +} diff --git a/nall/decode/bmp.hpp b/nall/decode/bmp.hpp new file mode 100644 index 0000000..8aa725a --- /dev/null +++ b/nall/decode/bmp.hpp @@ -0,0 +1,76 @@ +#pragma once + +namespace nall::Decode { + +struct BMP { + BMP() = default; + BMP(const string& filename) { load(filename); } + BMP(const uint8_t* data, uint size) { load(data, size); } + + explicit operator bool() const { return _data; } + + auto reset() -> void { + if(_data) { delete[] _data; _data = nullptr; } + } + + auto data() -> uint32_t* { return _data; } + auto data() const -> const uint32_t* { return _data; } + auto width() const -> uint { return _width; } + auto height() const -> uint { return _height; } + + auto load(const string& filename) -> bool { + auto buffer = file::read(filename); + return load(buffer.data(), buffer.size()); + } + + auto load(const uint8_t* data, uint size) -> bool { + if(size < 0x36) return false; + const uint8_t* p = data; + if(read(p, 2) != 0x4d42) return false; //signature + read(p, 8); + uint offset = read(p, 4); + if(read(p, 4) != 40) return false; //DIB size + int width = read(p, 4); + if(width < 0) return false; + int height = read(p, 4); + bool flip = height < 0; + if(flip) height = -height; + read(p, 2); + uint bitsPerPixel = read(p, 2); + if(bitsPerPixel != 24 && bitsPerPixel != 32) return false; + if(read(p, 4) != 0) return false; //compression type + + _width = width; + _height = height; + _data = new uint32_t[width * height]; + + uint bytesPerPixel = bitsPerPixel / 8; + uint alignedWidth = width * bytesPerPixel; + uint paddingLength = 0; + while(alignedWidth % 4) alignedWidth++, paddingLength++; + + p = data + offset; + for(auto y : range(height)) { + uint32_t* output = flip ? _data + (height - 1 - y) * width : _data + y * width; + for(auto x : range(width)) { + *output++ = read(p, bytesPerPixel) | (bitsPerPixel == 24 ? 255u << 24 : 0); + } + if(paddingLength) read(p, paddingLength); + } + + return true; + } + +private: + uint32_t* _data = nullptr; + uint _width = 0; + uint _height = 0; + + auto read(const uint8_t*& buffer, uint length) -> uintmax { + uintmax result = 0; + for(auto n : range(length)) result |= (uintmax)*buffer++ << (n << 3); + return result; + } +}; + +} diff --git a/nall/decode/bwt.hpp b/nall/decode/bwt.hpp new file mode 100644 index 0000000..5aeb1f8 --- /dev/null +++ b/nall/decode/bwt.hpp @@ -0,0 +1,47 @@ +#pragma once + +//burrows-wheeler transform + +#include + +namespace nall::Decode { + +inline auto BWT(array_view input) -> vector { + vector output; + + uint size = 0; + for(uint byte : range(8)) size |= *input++ << byte * 8; + output.resize(size); + + uint I = 0; + for(uint byte : range(8)) I |= *input++ << byte * 8; + + auto suffixes = SuffixArray(input); + + auto L = input; + auto F = new uint8_t[size]; + for(uint offset : range(size)) F[offset] = L[suffixes[offset + 1]]; + + uint64_t K[256] = {}; + auto C = new int[size]; + for(uint i : range(size)) { + C[i] = K[L[i]]; + K[L[i]]++; + } + + int M[256]; + memory::fill(M, 256, -1); + for(uint i : range(size)) { + if(M[F[i]] == -1) M[F[i]] = i; + } + + uint i = I; + for(uint j : reverse(range(size))) { + output[j] = L[i]; + i = C[i] + M[L[i]]; + } + + return output; +} + +} diff --git a/nall/decode/gzip.hpp b/nall/decode/gzip.hpp new file mode 100755 index 0000000..20f754c --- /dev/null +++ b/nall/decode/gzip.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include +#include + +namespace nall::Decode { + +struct GZIP { + inline ~GZIP(); + + inline auto decompress(const string& filename) -> bool; + inline auto decompress(const uint8_t* data, uint size) -> bool; + + string filename; + uint8_t* data = nullptr; + uint size = 0; +}; + +GZIP::~GZIP() { + if(data) delete[] data; +} + +auto GZIP::decompress(const string& filename) -> bool { + if(auto memory = file::read(filename)) { + return decompress(memory.data(), memory.size()); + } + return false; +} + +auto GZIP::decompress(const uint8_t* data, uint size) -> bool { + if(size < 18) return false; + if(data[0] != 0x1f) return false; + if(data[1] != 0x8b) return false; + uint cm = data[2]; + uint flg = data[3]; + uint mtime = data[4]; + mtime |= data[5] << 8; + mtime |= data[6] << 16; + mtime |= data[7] << 24; + uint xfl = data[8]; + uint os = data[9]; + uint p = 10; + uint isize = data[size - 4]; + isize |= data[size - 3] << 8; + isize |= data[size - 2] << 16; + isize |= data[size - 1] << 24; + filename = ""; + + if(flg & 0x04) { //FEXTRA + uint xlen = data[p + 0]; + xlen |= data[p + 1] << 8; + p += 2 + xlen; + } + + if(flg & 0x08) { //FNAME + char buffer[PATH_MAX]; + for(uint 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); +} + +} diff --git a/nall/decode/html.hpp b/nall/decode/html.hpp new file mode 100644 index 0000000..ccec3e8 --- /dev/null +++ b/nall/decode/html.hpp @@ -0,0 +1,40 @@ +#pragma once + +namespace nall::Decode { + +inline auto HTML(const string& input) -> string { + string output; + for(uint n = 0; n < input.size();) { + if(input[n] == '&') { + if(input(n + 1) == 'a' && input(n + 2) == 'm' && input(n + 3) == 'p' && input(n + 4) == ';') { + output.append('&'); + n += 5; + continue; + } + if(input(n + 1) == 'l' && input(n + 2) == 't' && input(n + 3) == ';') { + output.append('<'); + n += 4; + continue; + } + if(input(n + 1) == 'g' && input(n + 2) == 't' && input(n + 3) == ';') { + output.append('>'); + n += 4; + continue; + } + if(input(n + 1) == 'q' && input(n + 2) == 'u' && input(n + 3) == 'o' && input(n + 4) == 't' && input(n + 5) == ';') { + output.append('"'); + n += 6; + continue; + } + if(input(n + 1) == 'a' && input(n + 2) == 'p' && input(n + 3) == 'o' && input(n + 4) == 's' && input(n + 5) == ';') { + output.append('\''); + n += 6; + continue; + } + } + output.append(input[n++]); + } + return output; +} + +} diff --git a/nall/decode/huffman.hpp b/nall/decode/huffman.hpp new file mode 100644 index 0000000..cb8c392 --- /dev/null +++ b/nall/decode/huffman.hpp @@ -0,0 +1,36 @@ +#pragma once + +namespace nall::Decode { + +inline auto Huffman(array_view input) -> vector { + vector output; + + uint size = 0; + for(uint byte : range(8)) size |= *input++ << byte * 8; + output.reserve(size); + + uint byte = 0, bits = 0; + auto read = [&]() -> bool { + if(bits == 0) bits = 8, byte = *input++; + return byte >> --bits & 1; + }; + + uint nodes[256][2] = {}; + for(uint offset : range(256)) { + for(uint index : range(9)) nodes[offset][0] = nodes[offset][0] << 1 | read(); + for(uint index : range(9)) nodes[offset][1] = nodes[offset][1] << 1 | read(); + } + + uint node = 511; + while(output.size() < size) { + node = nodes[node - 256][read()]; + if(node < 256) { + output.append(node); + node = 511; + } + } + + return output; +} + +} diff --git a/nall/decode/inflate.hpp b/nall/decode/inflate.hpp new file mode 100755 index 0000000..0f659b7 --- /dev/null +++ b/nall/decode/inflate.hpp @@ -0,0 +1,349 @@ +#pragma once + +//a bad implementation of inflate from zlib/minizip +//todo: replace with Talarubi's version + +#include + +namespace nall::Decode { + +namespace puff { + inline auto puff( + unsigned char* dest, unsigned long* destlen, + unsigned char* source, unsigned long* sourcelen + ) -> int; +} + +inline auto inflate( + uint8_t* target, uint targetLength, + const uint8_t* source, uint sourceLength +) -> bool { + unsigned long tl = targetLength, sl = sourceLength; + int result = puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl); + return result == 0; +} + +namespace puff { + +enum : uint { + 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 auto bits(state* s, int need) -> int { + 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 auto stored(state* s) -> int { + uint 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 != nullptr) { + 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 auto decode(state* s, huffman* h) -> int { + 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 auto construct(huffman* h, short* length, int n) -> int { + 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 auto codes(state* s, huffman* lencode, huffman* distcode) -> int { + int symbol, len; + uint 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 != nullptr) { + 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 != nullptr) { + 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 auto fixed(state* s) -> int { + 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 auto dynamic(state* s) -> int { + 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 auto puff( + unsigned char* dest, unsigned long* destlen, + unsigned char* source, unsigned long* sourcelen +) -> int { + 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; +} + +} + +} diff --git a/nall/decode/lzsa.hpp b/nall/decode/lzsa.hpp new file mode 100644 index 0000000..a0e9c9c --- /dev/null +++ b/nall/decode/lzsa.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include + +namespace nall::Decode { + +inline auto LZSA(array_view input) -> vector { + vector output; + uint index = 0; + + uint size = 0; + for(uint byte : range(8)) size |= *input++ << byte * 8; + output.resize(size); + + auto load = [&]() -> vector { + uint size = 0; + for(uint byte : range(8)) size |= *input++ << byte * 8; + vector buffer; + buffer.reserve(size); + while(size--) buffer.append(*input++); + return buffer; + }; + + auto flags = Decode::Huffman(load()); + auto literals = Decode::Huffman(load()); + auto lengths = Decode::Huffman(load()); + auto offsets = Decode::Huffman(load()); + + auto flagData = flags.data(); + uint byte = 0, bits = 0; + auto flagRead = [&]() -> bool { + if(bits == 0) bits = 8, byte = *flagData++; + return byte >> --bits & 1; + }; + + auto literalData = literals.data(); + auto literalRead = [&]() -> uint8_t { + return *literalData++; + }; + + auto lengthData = lengths.data(); + auto lengthRead = [&]() -> uint64_t { + uint byte = *lengthData++, bytes = 1; + while(!(byte & 1)) byte >>= 1, bytes++; + uint length = byte >> 1, shift = 8 - bytes; + while(--bytes) length |= *lengthData++ << shift, shift += 8; + return length; + }; + + auto offsetData = offsets.data(); + auto offsetRead = [&]() -> uint { + uint offset = 0; + offset |= *offsetData++ << 0; if(index < 1 << 8) return offset; + offset |= *offsetData++ << 8; if(index < 1 << 16) return offset; + offset |= *offsetData++ << 16; if(index < 1 << 24) return offset; + offset |= *offsetData++ << 24; return offset; + }; + + while(index < size) { + if(!flagRead()) { + output[index++] = literalRead(); + } else { + uint length = lengthRead() + 6; + uint offset = index - offsetRead(); + while(length--) output[index++] = output[offset++]; + } + } + + return output; +} + +} diff --git a/nall/decode/mtf.hpp b/nall/decode/mtf.hpp new file mode 100644 index 0000000..d70e168 --- /dev/null +++ b/nall/decode/mtf.hpp @@ -0,0 +1,25 @@ +#pragma once + +//move to front + +namespace nall::Decode { + +inline auto MTF(array_view input) -> vector { + vector output; + output.resize(input.size()); + + uint8_t order[256]; + for(uint n : range(256)) order[n] = n; + + for(uint offset : range(input.size())) { + uint data = input[offset]; + uint value = order[data]; + output[offset] = value; + memory::move(&order[1], &order[0], data); + order[0] = value; + } + + return output; +} + +} diff --git a/nall/decode/png.hpp b/nall/decode/png.hpp new file mode 100755 index 0000000..f5c2eed --- /dev/null +++ b/nall/decode/png.hpp @@ -0,0 +1,332 @@ +#pragma once + +#include +#include + +namespace nall::Decode { + +struct PNG { + inline PNG(); + inline ~PNG(); + + inline auto load(const string& filename) -> bool; + inline auto load(const uint8_t* sourceData, uint sourceSize) -> bool; + inline auto readbits(const uint8_t*& data) -> uint; + + struct Info { + uint width; + uint height; + uint bitDepth; + //colorType: + //0 = L (luma) + //2 = R,G,B + //3 = P (palette) + //4 = L,A + //6 = R,G,B,A + uint colorType; + uint compressionMethod; + uint filterType; + uint interlaceMethod; + + uint bytesPerPixel; + uint pitch; + + uint8_t palette[256][3]; + } info; + + uint8_t* data = nullptr; + uint size = 0; + + uint bitpos = 0; + +protected: + enum class FourCC : uint { + IHDR = 0x49484452, + PLTE = 0x504c5445, + IDAT = 0x49444154, + IEND = 0x49454e44, + }; + + inline auto interlace(uint pass, uint index) -> uint; + inline auto inflateSize() -> uint; + inline auto deinterlace(const uint8_t*& inputData, uint pass) -> bool; + inline auto filter(uint8_t* outputData, const uint8_t* inputData, uint width, uint height) -> bool; + inline auto read(const uint8_t* data, uint length) -> uint; +}; + +PNG::PNG() { +} + +PNG::~PNG() { + if(data) delete[] data; +} + +auto PNG::load(const string& filename) -> bool { + if(auto memory = file::read(filename)) { + return load(memory.data(), memory.size()); + } + return false; +} + +auto PNG::load(const uint8_t* sourceData, uint sourceSize) -> bool { + if(sourceSize < 8) return false; + if(read(sourceData + 0, 4) != 0x89504e47) return false; + if(read(sourceData + 4, 4) != 0x0d0a1a0a) return false; + + uint8_t* compressedData = nullptr; + uint compressedSize = 0; + + uint offset = 8; + while(offset < sourceSize) { + uint length = read(sourceData + offset + 0, 4); + uint fourCC = read(sourceData + offset + 4, 4); + uint checksum = read(sourceData + offset + 8 + length, 4); + + if(fourCC == (uint)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 == (uint)FourCC::PLTE) { + if(length % 3) return false; + for(uint 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 == (uint)FourCC::IDAT) { + compressedData = (uint8_t*)realloc(compressedData, compressedSize + length); + memcpy(compressedData + compressedSize, sourceData + offset + 8, length); + compressedSize += length; + } + + if(fourCC == (uint)FourCC::IEND) { + break; + } + + offset += 4 + 4 + length + 4; + } + + uint interlacedSize = inflateSize(); + auto interlacedData = new uint8_t[interlacedSize]; + + bool result = inflate(interlacedData, interlacedSize, compressedData + 2, compressedSize - 6); + free(compressedData); + + if(result == false) { + delete[] interlacedData; + return false; + } + + size = info.width * info.height * info.bytesPerPixel; + data = new uint8_t[size]; + + if(info.interlaceMethod == 0) { + if(filter(data, interlacedData, info.width, info.height) == false) { + delete[] interlacedData; + delete[] data; + data = nullptr; + return false; + } + } else { + const uint8_t* passData = interlacedData; + for(uint pass = 0; pass < 7; pass++) { + if(deinterlace(passData, pass) == false) { + delete[] interlacedData; + delete[] data; + data = nullptr; + return false; + } + } + } + + delete[] interlacedData; + return true; +} + +auto PNG::interlace(uint pass, uint index) -> uint { + static const uint 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]; +} + +auto PNG::inflateSize() -> uint { + if(info.interlaceMethod == 0) { + return info.width * info.height * info.bytesPerPixel + info.height; + } + + uint size = 0; + for(uint pass = 0; pass < 7; pass++) { + uint xd = interlace(pass, 0), yd = interlace(pass, 1); + uint xo = interlace(pass, 2), yo = interlace(pass, 3); + uint width = (info.width + (xd - xo - 1)) / xd; + uint height = (info.height + (yd - yo - 1)) / yd; + if(width == 0 || height == 0) continue; + size += width * height * info.bytesPerPixel + height; + } + return size; +} + +auto PNG::deinterlace(const uint8_t*& inputData, uint pass) -> bool { + uint xd = interlace(pass, 0), yd = interlace(pass, 1); + uint xo = interlace(pass, 2), yo = interlace(pass, 3); + uint width = (info.width + (xd - xo - 1)) / xd; + uint height = (info.height + (yd - yo - 1)) / yd; + if(width == 0 || height == 0) return true; + + uint outputSize = width * height * info.bytesPerPixel; + auto outputData = new uint8_t[outputSize]; + bool result = filter(outputData, inputData, width, height); + + const uint8_t* rd = outputData; + for(uint y = yo; y < info.height; y += yd) { + uint8_t* wr = data + y * info.pitch; + for(uint x = xo; x < info.width; x += xd) { + for(uint b = 0; b < info.bytesPerPixel; b++) { + wr[x * info.bytesPerPixel + b] = *rd++; + } + } + } + + inputData += outputSize + height; + delete[] outputData; + return result; +} + +auto PNG::filter(uint8_t* outputData, const uint8_t* inputData, uint width, uint height) -> bool { + 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; + + auto 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; +} + +auto PNG::read(const uint8_t* data, uint length) -> uint { + uint result = 0; + while(length--) result = (result << 8) | (*data++); + return result; +} + +auto PNG::readbits(const uint8_t*& data) -> uint { + uint 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; +} + +} diff --git a/nall/decode/rle.hpp b/nall/decode/rle.hpp new file mode 100644 index 0000000..4a6c67c --- /dev/null +++ b/nall/decode/rle.hpp @@ -0,0 +1,44 @@ +#pragma once + +namespace nall::Decode { + +template //S = word size; M = match length +inline auto RLE(array_view input) -> vector { + vector output; + + auto load = [&]() -> uint8_t { + return input ? *input++ : 0; + }; + + uint base = 0; + uint64_t size = 0; + for(uint byte : range(8)) size |= load() << byte * 8; + output.resize(size); + + auto read = [&]() -> uint64_t { + uint64_t value = 0; + for(uint byte : range(S)) value |= load() << byte * 8; + return value; + }; + + auto write = [&](uint64_t value) -> void { + if(base >= size) return; + for(uint byte : range(S)) output[base++] = value >> byte * 8; + }; + + while(base < size) { + auto byte = load(); + if(byte < 128) { + byte++; + while(byte--) write(read()); + } else { + auto value = read(); + byte = (byte & 127) + M; + while(byte--) write(value); + } + } + + return output; +} + +} diff --git a/nall/decode/url.hpp b/nall/decode/url.hpp new file mode 100644 index 0000000..56526c9 --- /dev/null +++ b/nall/decode/url.hpp @@ -0,0 +1,39 @@ +#pragma once + +namespace nall::Decode { + +//returns empty string on malformed content +inline auto URL(string_view input) -> string { + string output; + for(uint n = 0; n < input.size();) { + char c = input[n]; + + //unreserved characters + if(c >= 'A' && c <= 'Z') { output.append(c); n++; continue; } + if(c >= 'a' && c <= 'z') { output.append(c); n++; continue; } + if(c >= '0' && c <= '9') { output.append(c); n++; continue; } + if(c == '-' || c == '_' || c == '.' || c == '~') { output.append(c); n++; continue; } + + //special characters + if(c == '+') { output.append(' '); n++; continue; } + + //reserved characters + if(c != '%' || n + 2 >= input.size()) return ""; + char hi = input[n + 1]; + char lo = input[n + 2]; + if(hi >= '0' && hi <= '9') hi -= '0'; + else if(hi >= 'A' && hi <= 'F') hi -= 'A' - 10; + else if(hi >= 'a' && hi <= 'f') hi -= 'a' - 10; + else return ""; + if(lo >= '0' && lo <= '9') lo -= '0'; + else if(lo >= 'A' && lo <= 'F') lo -= 'A' - 10; + else if(lo >= 'a' && lo <= 'f') lo -= 'a' - 10; + else return ""; + char byte = hi * 16 + lo; + output.append(byte); + n += 3; + } + return output; +} + +} diff --git a/nall/decode/zip.hpp b/nall/decode/zip.hpp new file mode 100755 index 0000000..316009d --- /dev/null +++ b/nall/decode/zip.hpp @@ -0,0 +1,136 @@ +#pragma once + +#include +#include +#include +#include + +namespace nall::Decode { + +struct ZIP { + struct File { + string name; + const uint8_t* data; + uint size; + uint csize; + uint cmode; //0 = uncompressed, 8 = deflate + uint crc32; + time_t timestamp; + }; + + ~ZIP() { + close(); + } + + auto open(const string& filename) -> bool { + close(); + if(fm.open(filename, file::mode::read) == false) return false; + if(open(fm.data(), fm.size()) == false) { + fm.close(); + return false; + } + return true; + } + + auto open(const uint8_t* data, uint size) -> bool { + if(size < 22) return false; + + filedata = data; + filesize = size; + + file.reset(); + + const uint8_t* footer = data + size - 22; + while(true) { + if(footer <= data + 22) return false; + if(read(footer, 4) == 0x06054b50) { + uint commentlength = read(footer + 20, 2); + if(footer + 22 + commentlength == data + size) break; + } + footer--; + } + const uint8_t* directory = data + read(footer + 16, 4); + + while(true) { + uint 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); + + uint16_t dosTime = read(directory + 12, 2); + uint16_t dosDate = read(directory + 14, 2); + tm info = {}; + info.tm_sec = (dosTime >> 0 & 31) << 1; + info.tm_min = (dosTime >> 5 & 63); + info.tm_hour = (dosTime >> 11 & 31); + info.tm_mday = (dosDate >> 0 & 31); + info.tm_mon = (dosDate >> 5 & 15) - 1; + info.tm_year = (dosDate >> 9 & 127) + 80; + info.tm_isdst = -1; + file.timestamp = mktime(&info); + + uint namelength = read(directory + 28, 2); + uint extralength = read(directory + 30, 2); + uint commentlength = read(directory + 32, 2); + + char* filename = new char[namelength + 1]; + memcpy(filename, directory + 46, namelength); + filename[namelength] = 0; + file.name = filename; + delete[] filename; + + uint offset = read(directory + 42, 4); + uint offsetNL = read(data + offset + 26, 2); + uint offsetEL = read(data + offset + 28, 2); + file.data = data + offset + 30 + offsetNL + offsetEL; + + directory += 46 + namelength + extralength + commentlength; + + this->file.append(file); + } + + return true; + } + + auto extract(File& file) -> vector { + vector buffer; + + if(file.cmode == 0) { + buffer.resize(file.size); + memcpy(buffer.data(), file.data, file.size); + } + + if(file.cmode == 8) { + buffer.resize(file.size); + if(inflate(buffer.data(), buffer.size(), file.data, file.csize) == false) { + buffer.reset(); + } + } + + return buffer; + } + + auto close() -> void { + if(fm) fm.close(); + } + +protected: + file_map fm; + const uint8_t* filedata; + uint filesize; + + auto read(const uint8_t* data, uint size) -> uint { + uint result = 0, shift = 0; + while(size--) { result |= *data++ << shift; shift += 8; } + return result; + } + +public: + vector file; +}; + +} diff --git a/nall/directory.hpp b/nall/directory.hpp new file mode 100755 index 0000000..126ec66 --- /dev/null +++ b/nall/directory.hpp @@ -0,0 +1,348 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_WINDOWS) + #include +#else + #include + #include + #include +#endif + +namespace nall { + +struct directory : inode { + directory() = delete; + + static auto copy(const string& source, const string& target) -> bool; //recursive + static auto create(const string& pathname, uint permissions = 0755) -> bool; //recursive + static auto remove(const string& pathname) -> bool; //recursive + static auto exists(const string& pathname) -> bool; + + static auto folders(const string& pathname, const string& pattern = "*") -> vector { + auto folders = directory::ufolders(pathname, pattern); + folders.sort(); + for(auto& folder : folders) folder.append("/"); //must append after sorting + return folders; + } + + static auto files(const string& pathname, const string& pattern = "*") -> vector { + auto files = directory::ufiles(pathname, pattern); + files.sort(); + return files; + } + + static auto contents(const string& pathname, const string& pattern = "*") -> vector { + auto folders = directory::ufolders(pathname); //pattern search of contents should only filter files + folders.sort(); + for(auto& folder : folders) folder.append("/"); //must append after sorting + auto files = directory::ufiles(pathname, pattern); + files.sort(); + for(auto& file : files) folders.append(file); + return folders; + } + + static auto ifolders(const string& pathname, const string& pattern = "*") -> vector { + auto folders = ufolders(pathname, pattern); + folders.isort(); + for(auto& folder : folders) folder.append("/"); //must append after sorting + return folders; + } + + static auto ifiles(const string& pathname, const string& pattern = "*") -> vector { + auto files = ufiles(pathname, pattern); + files.isort(); + return files; + } + + static auto icontents(const string& pathname, const string& pattern = "*") -> vector { + auto folders = directory::ufolders(pathname); //pattern search of contents should only filter files + folders.isort(); + for(auto& folder : folders) folder.append("/"); //must append after sorting + auto files = directory::ufiles(pathname, pattern); + files.isort(); + for(auto& file : files) folders.append(file); + return folders; + } + + static auto rcontents(const string& pathname, const string& pattern = "*") -> vector { + vector contents; + function + recurse = [&](const string& basename, const string& pathname, const string& pattern) { + for(auto& folder : directory::ufolders(pathname)) { + contents.append(string{pathname, folder, "/"}.trimLeft(basename, 1L)); + recurse(basename, {pathname, folder, "/"}, pattern); + } + for(auto& file : directory::ufiles(pathname, pattern)) { + contents.append(string{pathname, file}.trimLeft(basename, 1L)); + } + }; + for(auto& folder : directory::ufolders(pathname)) { + contents.append({folder, "/"}); + recurse(pathname, {pathname, folder, "/"}, pattern); + } + for(auto& file : directory::ufiles(pathname, pattern)) { + contents.append(file); + } + contents.sort(); + return contents; + } + + static auto ircontents(const string& pathname, const string& pattern = "*") -> vector { + vector contents; + function + recurse = [&](const string& basename, const string& pathname, const string& pattern) { + for(auto& folder : directory::ufolders(pathname)) { + contents.append(string{pathname, folder, "/"}.trimLeft(basename, 1L)); + recurse(basename, {pathname, folder, "/"}, pattern); + } + for(auto& file : directory::ufiles(pathname, pattern)) { + contents.append(string{pathname, file}.trimLeft(basename, 1L)); + } + }; + for(auto& folder : directory::ufolders(pathname)) { + contents.append({folder, "/"}); + recurse(pathname, {pathname, folder, "/"}, pattern); + } + for(auto& file : directory::ufiles(pathname, pattern)) { + contents.append(file); + } + contents.isort(); + return contents; + } + + static auto rfolders(const string& pathname, const string& pattern = "*") -> vector { + vector folders; + for(auto& folder : rcontents(pathname, pattern)) { + if(directory::exists({pathname, folder})) folders.append(folder); + } + return folders; + } + + static auto irfolders(const string& pathname, const string& pattern = "*") -> vector { + vector folders; + for(auto& folder : ircontents(pathname, pattern)) { + if(directory::exists({pathname, folder})) folders.append(folder); + } + return folders; + } + + static auto rfiles(const string& pathname, const string& pattern = "*") -> vector { + vector files; + for(auto& file : rcontents(pathname, pattern)) { + if(file::exists({pathname, file})) files.append(file); + } + return files; + } + + static auto irfiles(const string& pathname, const string& pattern = "*") -> vector { + vector files; + for(auto& file : ircontents(pathname, pattern)) { + if(file::exists({pathname, file})) files.append(file); + } + return files; + } + +private: + //internal functions; these return unsorted lists + static auto ufolders(const string& pathname, const string& pattern = "*") -> vector; + static auto ufiles(const string& pathname, const string& pattern = "*") -> vector; +}; + +inline auto directory::copy(const string& source, const string& target) -> bool { + bool result = true; + if(!directory::create(target)) return result = false; + for(auto& name : directory::folders(source)) { + if(!directory::copy({source, name}, {target, name})) result = false; + } + for(auto& name : directory::files(source)) { + if(!file::copy({source, name}, {target, name})) result = false; + } + return result; +} + +#if defined(PLATFORM_WINDOWS) + inline auto directory::create(const string& pathname, uint permissions) -> bool { + string path; + auto list = string{pathname}.transform("\\", "/").trimRight("/").split("/"); + bool result = true; + for(auto& part : list) { + path.append(part, "/"); + if(directory::exists(path)) continue; + result &= (_wmkdir(utf16_t(path)) == 0); + } + return result; + } + + inline auto directory::remove(const string& pathname) -> bool { + auto list = directory::contents(pathname); + for(auto& name : list) { + if(name.endsWith("/")) directory::remove({pathname, name}); + else file::remove({pathname, name}); + } + return _wrmdir(utf16_t(pathname)) == 0; + } + + inline auto directory::exists(const string& pathname) -> bool { + string name = pathname; + name.trim("\"", "\""); + DWORD result = GetFileAttributes(utf16_t(name)); + if(result == INVALID_FILE_ATTRIBUTES) return false; + return (result & FILE_ATTRIBUTE_DIRECTORY); + } + + inline auto directory::ufolders(const string& pathname, const string& pattern) -> vector { + if(!pathname) { + //special root pseudo-folder (return list of drives) + wchar_t drives[PATH_MAX] = {0}; + GetLogicalDriveStrings(PATH_MAX, drives); + wchar_t* p = drives; + while(*p || *(p + 1)) { + if(!*p) *p = ';'; + *p++; + } + return string{(const char*)utf8_t(drives)}.replace("\\", "/").split(";"); + } + + vector list; + string path = pathname; + path.transform("/", "\\"); + if(!path.endsWith("\\")) 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(name.match(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(name.match(pattern)) list.append(name); + } + } + } + FindClose(handle); + } + return list; + } + + inline auto directory::ufiles(const string& pathname, const string& pattern) -> vector { + if(!pathname) return {}; + + vector list; + string path = pathname; + path.transform("/", "\\"); + if(!path.endsWith("\\")) 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(name.match(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(name.match(pattern)) list.append(name); + } + } + FindClose(handle); + } + return list; + } +#else + inline auto directoryIsFolder(DIR* dp, struct dirent* ep) -> bool { + if(ep->d_type == DT_DIR) return true; + if(ep->d_type == DT_LNK || ep->d_type == DT_UNKNOWN) { + //symbolic links must be resolved to determine type + struct stat sp = {0}; + fstatat(dirfd(dp), ep->d_name, &sp, 0); + return S_ISDIR(sp.st_mode); + } + return false; + } + + inline auto directory::create(const string& pathname, uint permissions) -> bool { + string path; + auto list = string{pathname}.trimRight("/").split("/"); + bool result = true; + for(auto& part : list) { + path.append(part, "/"); + if(directory::exists(path)) continue; + result &= (mkdir(path, permissions) == 0); + } + return result; + } + + inline auto directory::remove(const string& pathname) -> bool { + auto list = directory::contents(pathname); + for(auto& name : list) { + if(name.endsWith("/")) directory::remove({pathname, name}); + else file::remove({pathname, name}); + } + return rmdir(pathname) == 0; + } + + inline auto directory::exists(const string& pathname) -> bool { + struct stat data; + if(stat(pathname, &data) != 0) return false; + return S_ISDIR(data.st_mode); + } + + inline auto directory::ufolders(const string& pathname, const string& pattern) -> vector { + if(!pathname) return vector{"/"}; + + vector 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(!directoryIsFolder(dp, ep)) continue; + string name{ep->d_name}; + if(name.match(pattern)) list.append(std::move(name)); + } + closedir(dp); + } + return list; + } + + inline auto directory::ufiles(const string& pathname, const string& pattern) -> vector { + if(!pathname) return {}; + + vector 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(directoryIsFolder(dp, ep)) continue; + string name{ep->d_name}; + if(name.match(pattern)) list.append(std::move(name)); + } + closedir(dp); + } + return list; + } +#endif + +} diff --git a/nall/dl.hpp b/nall/dl.hpp new file mode 100755 index 0000000..8116d34 --- /dev/null +++ b/nall/dl.hpp @@ -0,0 +1,126 @@ +#pragma once + +//dynamic linking support + +#include +#include +#include +#include +#include + +#if defined(PLATFORM_WINDOWS) + #include +#else + #include +#endif + +namespace nall { + +struct library { + library() = default; + ~library() { close(); } + + library& operator=(const library&) = delete; + library(const library&) = delete; + + explicit operator bool() const { return open(); } + auto open() const -> bool { return handle; } + auto open(const string&, const string& = "") -> bool; + auto openAbsolute(const string&) -> bool; + auto sym(const string&) -> void*; + auto close() -> void; + +private: + uintptr handle = 0; +}; + +#if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) +inline auto library::open(const string& name, const string& path) -> bool { + if(handle) close(); + if(path) handle = (uintptr)dlopen(string(path, "lib", name, ".so"), RTLD_LAZY); + if(!handle) handle = (uintptr)dlopen(string(Path::user(), ".local/lib/lib", name, ".so"), RTLD_LAZY); + if(!handle) handle = (uintptr)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY); + if(!handle) handle = (uintptr)dlopen(string("lib", name, ".so"), RTLD_LAZY); + return handle; +} + +inline auto library::openAbsolute(const string& name) -> bool { + if(handle) close(); + handle = (uintptr)dlopen(name, RTLD_LAZY); + return handle; +} + +inline auto library::sym(const string& name) -> void* { + if(!handle) return nullptr; + return dlsym((void*)handle, name); +} + +inline auto library::close() -> void { + if(!handle) return; + dlclose((void*)handle); + handle = 0; +} +#elif defined(PLATFORM_MACOS) +inline auto library::open(const string& name, const string& path) -> bool { + if(handle) close(); + if(path) handle = (uintptr)dlopen(string(path, "lib", name, ".dylib"), RTLD_LAZY); + if(!handle) handle = (uintptr)dlopen(string(Path::user(), ".local/lib/lib", name, ".dylib"), RTLD_LAZY); + if(!handle) handle = (uintptr)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY); + if(!handle) handle = (uintptr)dlopen(string("lib", name, ".dylib"), RTLD_LAZY); + return handle; +} + +inline auto library::openAbsolute(const string& name) -> bool { + if(handle) close(); + handle = (uintptr)dlopen(name, RTLD_LAZY); + return handle; +} + +inline auto library::sym(const string& name) -> void* { + if(!handle) return nullptr; + return dlsym((void*)handle, name); +} + +inline auto library::close() -> void { + if(!handle) return; + dlclose((void*)handle); + handle = 0; +} +#elif defined(PLATFORM_WINDOWS) +inline auto library::open(const string& name, const string& path) -> bool { + if(handle) close(); + if(path) { + string filepath = {path, name, ".dll"}; + handle = (uintptr)LoadLibraryW(utf16_t(filepath)); + } + if(!handle) { + string filepath = {name, ".dll"}; + handle = (uintptr)LoadLibraryW(utf16_t(filepath)); + } + return handle; +} + +inline auto library::openAbsolute(const string& name) -> bool { + if(handle) close(); + handle = (uintptr)LoadLibraryW(utf16_t(name)); + return handle; +} + +inline auto library::sym(const string& name) -> void* { + if(!handle) return nullptr; + return (void*)GetProcAddress((HMODULE)handle, name); +} + +inline auto library::close() -> void { + if(!handle) return; + FreeLibrary((HMODULE)handle); + handle = 0; +} +#else +inline auto library::open(const string&, const string&) -> bool { return false; } +inline auto library::openAbsolute(const string&) -> bool { return false; } +inline auto library::sym(const string&) -> void* { return nullptr; } +inline auto library::close() -> void {} +#endif + +} diff --git a/nall/dsp/dsp.hpp b/nall/dsp/dsp.hpp new file mode 100644 index 0000000..f8bf82e --- /dev/null +++ b/nall/dsp/dsp.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace nall::DSP { + +} diff --git a/nall/dsp/iir/biquad.hpp b/nall/dsp/iir/biquad.hpp new file mode 100644 index 0000000..becd2c6 --- /dev/null +++ b/nall/dsp/iir/biquad.hpp @@ -0,0 +1,164 @@ +#pragma once + +#include + +//transposed direct form II biquadratic second-order IIR filter + +namespace nall::DSP::IIR { + +struct Biquad { + enum class Type : uint { + LowPass, + HighPass, + BandPass, + Notch, + Peak, + LowShelf, + HighShelf, + }; + + inline auto reset(Type type, double cutoffFrequency, double samplingFrequency, double quality, double gain = 0.0) -> void; + inline auto process(double in) -> double; //normalized sample (-1.0 to +1.0) + + inline static auto shelf(double gain, double slope) -> double; + inline static auto butterworth(uint order, uint phase) -> double; + +private: + Type type; + double cutoffFrequency; + double samplingFrequency; + double quality; //frequency response quality + double gain; //peak gain + double a0, a1, a2, b1, b2; //coefficients + double z1, z2; //second-order IIR +}; + +auto Biquad::reset(Type type, double cutoffFrequency, double samplingFrequency, double quality, double gain) -> void { + this->type = type; + this->cutoffFrequency = cutoffFrequency; + this->samplingFrequency = samplingFrequency; + this->quality = quality; + this->gain = gain; + + z1 = 0.0; + z2 = 0.0; + + double v = pow(10, fabs(gain) / 20.0); + double k = tan(Math::Pi * cutoffFrequency / samplingFrequency); + double q = quality; + double n = 0.0; + + switch(type) { + + case Type::LowPass: + n = 1 / (1 + k / q + k * k); + a0 = k * k * n; + a1 = 2 * a0; + a2 = a0; + b1 = 2 * (k * k - 1) * n; + b2 = (1 - k / q + k * k) * n; + break; + + case Type::HighPass: + n = 1 / (1 + k / q + k * k); + a0 = 1 * n; + a1 = -2 * a0; + a2 = a0; + b1 = 2 * (k * k - 1) * n; + b2 = (1 - k / q + k * k) * n; + break; + + case Type::BandPass: + n = 1 / (1 + k / q + k * k); + a0 = k / q * n; + a1 = 0; + a2 = -a0; + b1 = 2 * (k * k - 1) * n; + b2 = (1 - k / q + k * k) * n; + break; + + case Type::Notch: + n = 1 / (1 + k / q + k * k); + a0 = (1 + k * k) * n; + a1 = 2 * (k * k - 1) * n; + a2 = a0; + b1 = a1; + b2 = (1 - k / q + k * k) * n; + break; + + case Type::Peak: + if(gain >= 0) { + n = 1 / (1 + 1 / q * k + k * k); + a0 = (1 + v / q * k + k * k) * n; + a1 = 2 * (k * k - 1) * n; + a2 = (1 - v / q * k + k * k) * n; + b1 = a1; + b2 = (1 - 1 / q * k + k * k) * n; + } else { + n = 1 / (1 + v / q * k + k * k); + a0 = (1 + 1 / q * k + k * k) * n; + a1 = 2 * (k * k - 1) * n; + a2 = (1 - 1 / q * k + k * k) * n; + b1 = a1; + b2 = (1 - v / q * k + k * k) * n; + } + break; + + case Type::LowShelf: + if(gain >= 0) { + n = 1 / (1 + k / q + k * k); + a0 = (1 + sqrt(v) / q * k + v * k * k) * n; + a1 = 2 * (v * k * k - 1) * n; + a2 = (1 - sqrt(v) / q * k + v * k * k) * n; + b1 = 2 * (k * k - 1) * n; + b2 = (1 - k / q + k * k) * n; + } else { + n = 1 / (1 + sqrt(v) / q * k + v * k * k); + a0 = (1 + k / q + k * k) * n; + a1 = 2 * (k * k - 1) * n; + a2 = (1 - k / q + k * k) * n; + b1 = 2 * (v * k * k - 1) * n; + b2 = (1 - sqrt(v) / q * k + v * k * k) * n; + } + break; + + case Type::HighShelf: + if(gain >= 0) { + n = 1 / (1 + k / q + k * k); + a0 = (v + sqrt(v) / q * k + k * k) * n; + a1 = 2 * (k * k - v) * n; + a2 = (v - sqrt(v) / q * k + k * k) * n; + b1 = 2 * (k * k - 1) * n; + b2 = (1 - k / q + k * k) * n; + } else { + n = 1 / (v + sqrt(v) / q * k + k * k); + a0 = (1 + k / q + k * k) * n; + a1 = 2 * (k * k - 1) * n; + a2 = (1 - k / q + k * k) * n; + b1 = 2 * (k * k - v) * n; + b2 = (v - sqrt(v) / q * k + k * k) * n; + } + break; + + } +} + +auto Biquad::process(double in) -> double { + double out = in * a0 + z1; + z1 = in * a1 + z2 - b1 * out; + z2 = in * a2 - b2 * out; + return out; +} + +//compute Q values for low-shelf and high-shelf filtering +auto Biquad::shelf(double gain, double slope) -> double { + double a = pow(10, gain / 40); + return 1 / sqrt((a + 1 / a) * (1 / slope - 1) + 2); +} + +//compute Q values for Nth-order butterworth filtering +auto Biquad::butterworth(uint order, uint phase) -> double { + return -0.5 / cos(Math::Pi * (phase + order + 0.5) / order); +} + +} diff --git a/nall/dsp/iir/dc-removal.hpp b/nall/dsp/iir/dc-removal.hpp new file mode 100644 index 0000000..3fdbf3a --- /dev/null +++ b/nall/dsp/iir/dc-removal.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +//DC offset removal IIR filter + +namespace nall::DSP::IIR { + +struct DCRemoval { + inline auto reset() -> void; + inline auto process(double in) -> double; //normalized sample (-1.0 to +1.0) + +private: + double x; + double y; +}; + +auto DCRemoval::reset() -> void { + x = 0.0; + y = 0.0; +} + +auto DCRemoval::process(double in) -> double { + x = 0.999 * x + in - y; + y = in; + return x; +} + +} diff --git a/nall/dsp/iir/one-pole.hpp b/nall/dsp/iir/one-pole.hpp new file mode 100644 index 0000000..a2f6d98 --- /dev/null +++ b/nall/dsp/iir/one-pole.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +//one-pole first-order IIR filter + +namespace nall::DSP::IIR { + +struct OnePole { + enum class Type : uint { + LowPass, + HighPass, + }; + + inline auto reset(Type type, double cutoffFrequency, double samplingFrequency) -> void; + inline auto process(double in) -> double; //normalized sample (-1.0 to +1.0) + +private: + Type type; + double cutoffFrequency; + double samplingFrequency; + double a0, b1; //coefficients + double z1; //first-order IIR +}; + +auto OnePole::reset(Type type, double cutoffFrequency, double samplingFrequency) -> void { + this->type = type; + this->cutoffFrequency = cutoffFrequency; + this->samplingFrequency = samplingFrequency; + + z1 = 0.0; + double x = cos(2.0 * Math::Pi * cutoffFrequency / samplingFrequency); + if(type == Type::LowPass) { + b1 = +2.0 - x - sqrt((+2.0 - x) * (+2.0 - x) - 1); + a0 = 1.0 - b1; + } else { + b1 = -2.0 - x + sqrt((-2.0 - x) * (-2.0 - x) - 1); + a0 = 1.0 + b1; + } +} + +auto OnePole::process(double in) -> double { + return z1 = in * a0 + z1 * b1; +} + +} diff --git a/nall/dsp/resampler/cubic.hpp b/nall/dsp/resampler/cubic.hpp new file mode 100644 index 0000000..eaa4aaf --- /dev/null +++ b/nall/dsp/resampler/cubic.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include + +namespace nall::DSP::Resampler { + +struct Cubic { + inline auto inputFrequency() const -> double { return _inputFrequency; } + inline auto outputFrequency() const -> double { return _outputFrequency; } + + inline auto reset(double inputFrequency, double outputFrequency = 0, uint queueSize = 0) -> void; + inline auto setInputFrequency(double inputFrequency) -> void; + inline auto pending() const -> bool; + inline auto read() -> double; + inline auto write(double sample) -> void; + inline auto serialize(serializer&) -> void; + +private: + double _inputFrequency; + double _outputFrequency; + + double _ratio; + double _fraction; + double _history[4]; + queue _samples; +}; + +auto Cubic::reset(double inputFrequency, double outputFrequency, uint queueSize) -> void { + _inputFrequency = inputFrequency; + _outputFrequency = outputFrequency ? outputFrequency : _inputFrequency; + + _ratio = _inputFrequency / _outputFrequency; + _fraction = 0.0; + for(auto& sample : _history) sample = 0.0; + _samples.resize(queueSize ? queueSize : _outputFrequency * 0.02); //default to 20ms max queue size +} + +auto Cubic::setInputFrequency(double inputFrequency) -> void { + _inputFrequency = inputFrequency; + _ratio = _inputFrequency / _outputFrequency; +} + +auto Cubic::pending() const -> bool { + return _samples.pending(); +} + +auto Cubic::read() -> double { + return _samples.read(); +} + +auto Cubic::write(double sample) -> void { + auto& mu = _fraction; + auto& s = _history; + + s[0] = s[1]; + s[1] = s[2]; + s[2] = s[3]; + s[3] = sample; + + while(mu <= 1.0) { + double A = s[3] - s[2] - s[0] + s[1]; + double B = s[0] - s[1] - A; + double C = s[2] - s[0]; + double D = s[1]; + + _samples.write(A * mu * mu * mu + B * mu * mu + C * mu + D); + mu += _ratio; + } + + mu -= 1.0; +} + +auto Cubic::serialize(serializer& s) -> void { + s.real(_inputFrequency); + s.real(_outputFrequency); + s.real(_ratio); + s.real(_fraction); + s.array(_history); + _samples.serialize(s); +} + +} diff --git a/nall/elliptic-curve/curve25519.hpp b/nall/elliptic-curve/curve25519.hpp new file mode 100644 index 0000000..194efdd --- /dev/null +++ b/nall/elliptic-curve/curve25519.hpp @@ -0,0 +1,57 @@ +#pragma once + +#if defined(EC_REFERENCE) + #include +#else + #include +#endif + +namespace nall::EllipticCurve { + +struct Curve25519 { + auto sharedKey(uint256_t secretKey, uint256_t basepoint = 9) const -> uint256_t { + secretKey &= (1_u256 << 254) - 8; + secretKey |= (1_u256 << 254); + basepoint &= ~0_u256 >> 1; + + point p = scalarMultiply(basepoint % P, secretKey); + field k = p.x * reciprocal(p.z); + return k(); + } + +private: + using field = Modulo25519; + struct point { field x, z; }; + const BarrettReduction<256> P = BarrettReduction<256>{EllipticCurve::P}; + + inline auto montgomeryDouble(point p) const -> point { + field a = square(p.x + p.z); + field b = square(p.x - p.z); + field c = a - b; + field d = a + c * 121665; + return {a * b, c * d}; + } + + inline auto montgomeryAdd(point p, point q, field b) const -> point { + return { + square(p.x * q.x - p.z * q.z), + square(p.x * q.z - p.z * q.x) * b + }; + } + + inline auto scalarMultiply(field b, uint256_t exponent) const -> point { + point p{1, 0}, q{b, 1}; + for(uint bit : reverse(range(255))) { + bool condition = exponent >> bit & 1; + cswap(condition, p.x, q.x); + cswap(condition, p.z, q.z); + q = montgomeryAdd(p, q, b); + p = montgomeryDouble(p); + cswap(condition, p.x, q.x); + cswap(condition, p.z, q.z); + } + return p; + } +}; + +} diff --git a/nall/elliptic-curve/ed25519.hpp b/nall/elliptic-curve/ed25519.hpp new file mode 100644 index 0000000..afce41b --- /dev/null +++ b/nall/elliptic-curve/ed25519.hpp @@ -0,0 +1,144 @@ +#pragma once + +#include +#if defined(EC_REFERENCE) + #include +#else + #include +#endif + +namespace nall::EllipticCurve { + +static const uint256_t L = (1_u256 << 252) + 27742317777372353535851937790883648493_u256; + +struct Ed25519 { + auto publicKey(uint256_t privateKey) const -> uint256_t { + return compress(scalarMultiply(B, clamp(hash(privateKey)) % L)); + } + + auto sign(array_view message, uint256_t privateKey) const -> uint512_t { + uint512_t H = hash(privateKey); + uint256_t a = clamp(H) % L; + uint256_t A = compress(scalarMultiply(B, a)); + + uint512_t r = hash(upper(H), message) % L; + uint256_t R = compress(scalarMultiply(B, r)); + + uint512_t k = hash(R, A, message) % L; + uint256_t S = (k * a + r) % L; + + return uint512_t(S) << 256 | R; + } + + auto verify(array_view message, uint512_t signature, uint256_t publicKey) const -> bool { + auto R = decompress(lower(signature)); + auto A = decompress(publicKey); + if(!R || !A) return false; + + uint256_t S = upper(signature) % L; + uint512_t r = hash(lower(signature), publicKey, message) % L; + + auto p = scalarMultiply(B, S); + auto q = edwardsAdd(R(), scalarMultiply(A(), r)); + if(!onCurve(p) || !onCurve(q)) return false; + if(p.x * q.z - q.x * p.z) return false; + if(p.y * q.z - q.y * p.z) return false; + return true; + } + +private: + using field = Modulo25519; + struct point { field x, y, z, t; }; + const field D = -field(121665) * reciprocal(field(121666)); + const point B = *decompress((field(4) * reciprocal(field(5)))()); + const BarrettReduction<256> L = BarrettReduction<256>{EllipticCurve::L}; + + inline auto input(Hash::SHA512&) const -> void {} + + template inline auto input(Hash::SHA512& hash, uint256_t value, P&&... p) const -> void { + for(uint byte : range(32)) hash.input(uint8_t(value >> byte * 8)); + input(hash, forward

    (p)...); + } + + template inline auto input(Hash::SHA512& hash, array_view value, P&&... p) const -> void { + hash.input(value); + input(hash, forward

    (p)...); + } + + template inline auto hash(P&&... p) const -> uint512_t { + Hash::SHA512 hash; + input(hash, forward

    (p)...); + uint512_t result; + for(auto byte : reverse(hash.output())) result = result << 8 | byte; + return result; + } + + inline auto clamp(uint256_t p) const -> uint256_t { + p &= (1_u256 << 254) - 8; + p |= (1_u256 << 254); + return p; + } + + inline auto onCurve(point p) const -> bool { + if(!p.z) return false; + if(p.x * p.y - p.z * p.t) return false; + if(square(p.y) - square(p.x) - square(p.z) - square(p.t) * D) return false; + return true; + } + + inline auto decompress(uint256_t c) const -> maybe { + field y = c & ~0_u256 >> 1; + field x = squareRoot((square(y) - 1) * reciprocal(D * square(y) + 1)); + if(c >> 255) x = -x; + point p{x, y, 1, x * y}; + if(!onCurve(p)) return nothing; + return p; + } + + inline auto compress(point p) const -> uint256_t { + field r = reciprocal(p.z); + field x = p.x * r; + field y = p.y * r; + return (x & 1) << 255 | (y & ~0_u256 >> 1); + } + + inline auto edwardsDouble(point p) const -> point { + field a = square(p.x); + field b = square(p.y); + field c = square(p.z); + field d = -a; + field e = square(p.x + p.y) - a - b; + field g = d + b; + field f = g - (c + c); + field h = d - b; + return {e * f, g * h, f * g, e * h}; + } + + inline auto edwardsAdd(point p, point q) const -> point { + field a = (p.y - p.x) * (q.y - q.x); + field b = (p.y + p.x) * (q.y + q.x); + field c = (p.t + p.t) * q.t * D; + field d = (p.z + p.z) * q.z; + field e = b - a; + field f = d - c; + field g = d + c; + field h = b + a; + return {e * f, g * h, f * g, e * h}; + } + + inline auto scalarMultiply(point q, uint256_t exponent) const -> point { + point p{0, 1, 1, 0}, c; + for(uint bit : reverse(range(253))) { + p = edwardsDouble(p); + c = edwardsAdd(p, q); + bool condition = exponent >> bit & 1; + cmove(condition, p.x, c.x); + cmove(condition, p.y, c.y); + cmove(condition, p.z, c.z); + cmove(condition, p.t, c.t); + } + return p; + } +}; + +} diff --git a/nall/elliptic-curve/modulo25519-optimized.hpp b/nall/elliptic-curve/modulo25519-optimized.hpp new file mode 100644 index 0000000..4d2ec01 --- /dev/null +++ b/nall/elliptic-curve/modulo25519-optimized.hpp @@ -0,0 +1,218 @@ +#pragma once + +#include + +namespace nall::EllipticCurve { + +static const uint256_t P = (1_u256 << 255) - 19; + +#define Mask ((1ull << 51) - 1) + +struct Modulo25519 { + inline Modulo25519() = default; + inline Modulo25519(const Modulo25519&) = default; + inline Modulo25519(uint64_t a, uint64_t b = 0, uint64_t c = 0, uint64_t d = 0, uint64_t e = 0) : l{a, b, c, d, e} {} + inline Modulo25519(uint256_t n); + + inline explicit operator bool() const { return (bool)operator()(); } + inline auto operator[](uint index) -> uint64_t& { return l[index]; } + inline auto operator[](uint index) const -> uint64_t { return l[index]; } + inline auto operator()() const -> uint256_t; + +private: + uint64_t l[5]; //51-bits per limb; 255-bits total +}; + +inline Modulo25519::Modulo25519(uint256_t n) { + l[0] = n >> 0 & Mask; + l[1] = n >> 51 & Mask; + l[2] = n >> 102 & Mask; + l[3] = n >> 153 & Mask; + l[4] = n >> 204 & Mask; +} + +inline auto Modulo25519::operator()() const -> uint256_t { + Modulo25519 o = *this; + + o[1] += (o[0] >> 51); o[0] &= Mask; + o[2] += (o[1] >> 51); o[1] &= Mask; + o[3] += (o[2] >> 51); o[2] &= Mask; + o[4] += (o[3] >> 51); o[3] &= Mask; + o[0] += 19 * (o[4] >> 51); o[4] &= Mask; + + o[1] += (o[0] >> 51); o[0] &= Mask; + o[2] += (o[1] >> 51); o[1] &= Mask; + o[3] += (o[2] >> 51); o[2] &= Mask; + o[4] += (o[3] >> 51); o[3] &= Mask; + o[0] += 19 * (o[4] >> 51); o[4] &= Mask; + + o[0] += 19; + o[1] += (o[0] >> 51); o[0] &= Mask; + o[2] += (o[1] >> 51); o[1] &= Mask; + o[3] += (o[2] >> 51); o[2] &= Mask; + o[4] += (o[3] >> 51); o[3] &= Mask; + o[0] += 19 * (o[4] >> 51); o[4] &= Mask; + + o[0] += Mask - 18; + o[1] += Mask; + o[2] += Mask; + o[3] += Mask; + o[4] += Mask; + + o[1] += o[0] >> 51; o[0] &= Mask; + o[2] += o[1] >> 51; o[1] &= Mask; + o[3] += o[2] >> 51; o[2] &= Mask; + o[4] += o[3] >> 51; o[3] &= Mask; + o[4] &= Mask; + + return (uint256_t)o[0] << 0 | (uint256_t)o[1] << 51 | (uint256_t)o[2] << 102 | (uint256_t)o[3] << 153 | (uint256_t)o[4] << 204; +} + +inline auto cmove(bool move, Modulo25519& l, const Modulo25519& r) -> void { + uint64_t mask = -move; + l[0] ^= mask & (l[0] ^ r[0]); + l[1] ^= mask & (l[1] ^ r[1]); + l[2] ^= mask & (l[2] ^ r[2]); + l[3] ^= mask & (l[3] ^ r[3]); + l[4] ^= mask & (l[4] ^ r[4]); +} + +inline auto cswap(bool swap, Modulo25519& l, Modulo25519& r) -> void { + uint64_t mask = -swap, x; + x = mask & (l[0] ^ r[0]); l[0] ^= x; r[0] ^= x; + x = mask & (l[1] ^ r[1]); l[1] ^= x; r[1] ^= x; + x = mask & (l[2] ^ r[2]); l[2] ^= x; r[2] ^= x; + x = mask & (l[3] ^ r[3]); l[3] ^= x; r[3] ^= x; + x = mask & (l[4] ^ r[4]); l[4] ^= x; r[4] ^= x; +} + +inline auto operator-(const Modulo25519& l) -> Modulo25519 { //P - l + Modulo25519 o; + uint64_t c; + o[0] = 0xfffffffffffda - l[0]; c = o[0] >> 51; o[0] &= Mask; + o[1] = 0xffffffffffffe - l[1] + c; c = o[1] >> 51; o[1] &= Mask; + o[2] = 0xffffffffffffe - l[2] + c; c = o[2] >> 51; o[2] &= Mask; + o[3] = 0xffffffffffffe - l[3] + c; c = o[3] >> 51; o[3] &= Mask; + o[4] = 0xffffffffffffe - l[4] + c; c = o[4] >> 51; o[4] &= Mask; + o[0] += c * 19; + return o; +} + +inline auto operator+(const Modulo25519& l, const Modulo25519& r) -> Modulo25519 { + Modulo25519 o; + uint64_t c; + o[0] = l[0] + r[0]; c = o[0] >> 51; o[0] &= Mask; + o[1] = l[1] + r[1] + c; c = o[1] >> 51; o[1] &= Mask; + o[2] = l[2] + r[2] + c; c = o[2] >> 51; o[2] &= Mask; + o[3] = l[3] + r[3] + c; c = o[3] >> 51; o[3] &= Mask; + o[4] = l[4] + r[4] + c; c = o[4] >> 51; o[4] &= Mask; + o[0] += c * 19; + return o; +} + +inline auto operator-(const Modulo25519& l, const Modulo25519& r) -> Modulo25519 { + Modulo25519 o; + uint64_t c; + o[0] = l[0] + 0x1fffffffffffb4 - r[0]; c = o[0] >> 51; o[0] &= Mask; + o[1] = l[1] + 0x1ffffffffffffc - r[1] + c; c = o[1] >> 51; o[1] &= Mask; + o[2] = l[2] + 0x1ffffffffffffc - r[2] + c; c = o[2] >> 51; o[2] &= Mask; + o[3] = l[3] + 0x1ffffffffffffc - r[3] + c; c = o[3] >> 51; o[3] &= Mask; + o[4] = l[4] + 0x1ffffffffffffc - r[4] + c; c = o[4] >> 51; o[4] &= Mask; + o[0] += c * 19; + return o; +} + +inline auto operator*(const Modulo25519& l, uint64_t scalar) -> Modulo25519 { + Modulo25519 o; + uint128_t a; + a = (uint128_t)l[0] * scalar; o[0] = a & Mask; + a = (uint128_t)l[1] * scalar + (a >> 51 & Mask); o[1] = a & Mask; + a = (uint128_t)l[2] * scalar + (a >> 51 & Mask); o[2] = a & Mask; + a = (uint128_t)l[3] * scalar + (a >> 51 & Mask); o[3] = a & Mask; + a = (uint128_t)l[4] * scalar + (a >> 51 & Mask); o[4] = a & Mask; + o[0] += (a >> 51) * 19; + return o; +} + +inline auto operator*(const Modulo25519& l, Modulo25519 r) -> Modulo25519 { + uint128_t t[] = { + (uint128_t)r[0] * l[0], + (uint128_t)r[0] * l[1] + (uint128_t)r[1] * l[0], + (uint128_t)r[0] * l[2] + (uint128_t)r[1] * l[1] + (uint128_t)r[2] * l[0], + (uint128_t)r[0] * l[3] + (uint128_t)r[1] * l[2] + (uint128_t)r[2] * l[1] + (uint128_t)r[3] * l[0], + (uint128_t)r[0] * l[4] + (uint128_t)r[1] * l[3] + (uint128_t)r[2] * l[2] + (uint128_t)r[3] * l[1] + (uint128_t)r[4] * l[0] + }; + + r[1] *= 19, r[2] *= 19, r[3] *= 19, r[4] *= 19; + + t[0] += (uint128_t)r[4] * l[1] + (uint128_t)r[3] * l[2] + (uint128_t)r[2] * l[3] + (uint128_t)r[1] * l[4]; + t[1] += (uint128_t)r[4] * l[2] + (uint128_t)r[3] * l[3] + (uint128_t)r[2] * l[4]; + t[2] += (uint128_t)r[4] * l[3] + (uint128_t)r[3] * l[4]; + t[3] += (uint128_t)r[4] * l[4]; + + uint64_t c; r[0] = t[0] & Mask; c = (uint64_t)(t[0] >> 51); + t[1] += c; r[1] = t[1] & Mask; c = (uint64_t)(t[1] >> 51); + t[2] += c; r[2] = t[2] & Mask; c = (uint64_t)(t[2] >> 51); + t[3] += c; r[3] = t[3] & Mask; c = (uint64_t)(t[3] >> 51); + t[4] += c; r[4] = t[4] & Mask; c = (uint64_t)(t[4] >> 51); + + r[0] += c * 19; c = r[0] >> 51; r[0] &= Mask; + r[1] += c; c = r[1] >> 51; r[1] &= Mask; + r[2] += c; + return r; +} + +inline auto operator&(const Modulo25519& lhs, uint256_t rhs) -> uint256_t { + return lhs() & rhs; +} + +inline auto square(const Modulo25519& lhs) -> Modulo25519 { + Modulo25519 r{lhs}; + Modulo25519 d{r[0] * 2, r[1] * 2, r[2] * 2 * 19, r[4] * 19, r[4] * 19 * 2}; + + uint128_t t[5]; + t[0] = (uint128_t)r[0] * r[0] + (uint128_t)d[4] * r[1] + (uint128_t)d[2] * r[3]; + t[1] = (uint128_t)d[0] * r[1] + (uint128_t)d[4] * r[2] + (uint128_t)r[3] * r[3] * 19; + t[2] = (uint128_t)d[0] * r[2] + (uint128_t)r[1] * r[1] + (uint128_t)d[4] * r[3]; + t[3] = (uint128_t)d[0] * r[3] + (uint128_t)d[1] * r[2] + (uint128_t)r[4] * d[3]; + t[4] = (uint128_t)d[0] * r[4] + (uint128_t)d[1] * r[3] + (uint128_t)r[2] * r[2]; + + uint64_t c; r[0] = t[0] & Mask; c = (uint64_t)(t[0] >> 51); + t[1] += c; r[1] = t[1] & Mask; c = (uint64_t)(t[1] >> 51); + t[2] += c; r[2] = t[2] & Mask; c = (uint64_t)(t[2] >> 51); + t[3] += c; r[3] = t[3] & Mask; c = (uint64_t)(t[3] >> 51); + t[4] += c; r[4] = t[4] & Mask; c = (uint64_t)(t[4] >> 51); + + r[0] += c * 19; c = r[0] >> 51; r[0] &= Mask; + r[1] += c; c = r[1] >> 51; r[1] &= Mask; + r[2] += c; + return r; +} + +inline auto exponentiate(const Modulo25519& lhs, uint256_t exponent) -> Modulo25519 { + Modulo25519 x = 1, y; + for(uint bit : reverse(range(256))) { + x = square(x); + y = x * lhs; + cmove(exponent >> bit & 1, x, y); + } + return x; +} + +inline auto reciprocal(const Modulo25519& lhs) -> Modulo25519 { + return exponentiate(lhs, P - 2); +} + +inline auto squareRoot(const Modulo25519& lhs) -> Modulo25519 { + static const Modulo25519 I = exponentiate(Modulo25519(2), P - 1 >> 2); //I == sqrt(-1) + Modulo25519 x = exponentiate(lhs, P + 3 >> 3); + Modulo25519 y = x * I; + cmove(bool(square(x) - lhs), x, y); + y = -x; + cmove(x & 1, x, y); + return x; +} + +#undef Mask + +} diff --git a/nall/elliptic-curve/modulo25519-reference.hpp b/nall/elliptic-curve/modulo25519-reference.hpp new file mode 100644 index 0000000..f9eb485 --- /dev/null +++ b/nall/elliptic-curve/modulo25519-reference.hpp @@ -0,0 +1,84 @@ +#pragma once + +//warning: this implementation leaks side-channel information +//use modulo25519-optimized.hpp in production + +#include + +namespace nall::EllipticCurve { + +static const uint256_t P = (1_u256 << 255) - 19; + +struct Modulo25519 { + inline Modulo25519() = default; + inline Modulo25519(const Modulo25519& source) : value(source.value) {} + template inline Modulo25519(const T& value) : value(value) {} + inline explicit operator bool() const { return (bool)value; } + inline auto operator()() const -> uint256_t { return value; } + +private: + uint256_t value; +}; + +inline auto operator-(const Modulo25519& lhs) -> Modulo25519 { + return P - lhs(); +} + +inline auto operator+(const Modulo25519& lhs, const Modulo25519& rhs) -> Modulo25519 { + uint512_t value = (uint512_t)lhs() + rhs(); + if(value >= P) value -= P; + return value; +} + +inline auto operator-(const Modulo25519& lhs, const Modulo25519& rhs) -> Modulo25519 { + uint512_t value = (uint512_t)lhs(); + if(value < rhs()) value += P; + return uint256_t(value - rhs()); +} + +inline auto operator*(const Modulo25519& lhs, const Modulo25519& rhs) -> Modulo25519 { + static const BarrettReduction<256> P{EllipticCurve::P}; + uint256_t hi, lo; + mul(lhs(), rhs(), hi, lo); + return uint512_t{hi, lo} % P; +} + +inline auto operator&(const Modulo25519& lhs, uint256_t rhs) -> uint256_t { + return lhs() & rhs; +} + +inline auto square(const Modulo25519& lhs) -> Modulo25519 { + static const BarrettReduction<256> P{EllipticCurve::P}; + uint256_t hi, lo; + square(lhs(), hi, lo); + return uint512_t{hi, lo} % P; +} + +inline auto exponentiate(const Modulo25519& lhs, uint256_t exponent) -> Modulo25519 { + if(exponent == 0) return 1; + Modulo25519 value = square(exponentiate(lhs, exponent >> 1)); + if(exponent & 1) value = value * lhs; + return value; +} + +inline auto reciprocal(const Modulo25519& lhs) -> Modulo25519 { + return exponentiate(lhs, P - 2); +} + +inline auto squareRoot(const Modulo25519& lhs) -> Modulo25519 { + static const Modulo25519 I = exponentiate(Modulo25519(2), P - 1 >> 2); //I = sqrt(-1) + Modulo25519 value = exponentiate(lhs, P + 3 >> 3); + if(square(value) - lhs) value = value * I; + if(value & 1) value = -value; + return value; +} + +inline auto cmove(bool condition, Modulo25519& lhs, const Modulo25519& rhs) -> void { + if(condition) lhs = rhs; +} + +inline auto cswap(bool condition, Modulo25519& lhs, Modulo25519& rhs) -> void { + if(condition) swap(lhs, rhs); +} + +} diff --git a/nall/emulation/21fx.hpp b/nall/emulation/21fx.hpp new file mode 100644 index 0000000..1625e74 --- /dev/null +++ b/nall/emulation/21fx.hpp @@ -0,0 +1,140 @@ +#pragma once + +#include +#include +using namespace nall; + +using int8 = Integer< 8>; +using int16 = Integer<16>; +using int24 = Integer<24>; +using int32 = Integer<32>; +using int64 = Integer<64>; + +using uint8 = Natural< 8>; +using uint16 = Natural<16>; +using uint24 = Natural<24>; +using uint32 = Natural<32>; +using uint64 = Natural<64>; + +struct FX { + auto open(Arguments& arguments) -> bool; + auto close() -> void; + auto readable() -> bool; + auto read() -> uint8_t; + auto writable() -> bool; + auto write(uint8_t data) -> void; + + auto read(uint offset, uint length) -> vector; + auto write(uint offset, const void* buffer, uint length) -> void; + auto write(uint offset, const vector& buffer) -> void { write(offset, buffer.data(), buffer.size()); } + auto execute(uint offset) -> void; + + auto read(uint offset) -> uint8_t; + auto write(uint offset, uint8_t data) -> void; + + serial device; +}; + +auto FX::open(Arguments& arguments) -> bool { + //device name override support + string name; + arguments.take("--device", name); + if(!device.open(name)) { + print("[21fx] error: unable to open hardware device\n"); + return false; + } + + //flush the device (to clear floating inputs) + while(true) { + while(readable()) read(); + auto iplrom = read(0x2184, 122); + auto sha256 = Hash::SHA256(iplrom).digest(); + if(sha256 == "41b79712a4a2d16d39894ae1b38cde5c41dad22eadc560df631d39f13df1e4b9") break; + } + + return true; +} + +auto FX::close() -> void { + device.close(); +} + +auto FX::readable() -> bool { + return device.readable(); +} + +//1000ns delay avoids burning CPU core at 100%; does not slow down max transfer rate at all +auto FX::read() -> uint8_t { + while(!readable()) usleep(1000); + uint8_t buffer[1] = {0}; + device.read(buffer, 1); + return buffer[0]; +} + +auto FX::writable() -> bool { + return device.writable(); +} + +auto FX::write(uint8_t data) -> void { + while(!writable()) usleep(1000); + uint8_t buffer[1] = {data}; + device.write(buffer, 1); +} + +// + +auto FX::read(uint offset, uint length) -> vector { + write(0x21); + write(0x66); + write(0x78); + write(offset >> 16); + write(offset >> 8); + write(offset >> 0); + write(0x01); + write(length >> 8); + write(length >> 0); + write(0x00); + + vector buffer; + while(length--) buffer.append(read()); + return buffer; +} + +auto FX::write(uint offset, const void* data, uint length) -> void { + write(0x21); + write(0x66); + write(0x78); + write(offset >> 16); + write(offset >> 8); + write(offset >> 0); + write(0x01); + write(length >> 8); + write(length >> 0); + write(0x01); + + auto buffer = (uint8_t*)data; + for(auto n : range(length)) write(buffer[n]); + write(0x00); +} + +auto FX::execute(uint offset) -> void { + write(0x21); + write(0x66); + write(0x78); + write(offset >> 16); + write(offset >> 8); + write(offset >> 0); + write(0x00); +} + +// + +auto FX::read(uint offset) -> uint8_t { + auto buffer = read(offset, 1); + return buffer[0]; +} + +auto FX::write(uint offset, uint8_t data) -> void { + vector buffer = {data}; + write(offset, buffer); +} diff --git a/nall/encode/base.hpp b/nall/encode/base.hpp new file mode 100644 index 0000000..ac55486 --- /dev/null +++ b/nall/encode/base.hpp @@ -0,0 +1,38 @@ +#pragma once + +//required bytes: ceil(bits / log2(base)) +//base57 => 128=22, 256=44, 512=88 +//base62 => 128=22, 256=43, 512=86 +//base64 => 128=22, 256=43, 512=86 + +#include + +namespace nall::Encode { + +template inline auto Base(T value) -> string { + static const string format = + Bits == 2 ? "01" + : Bits == 8 ? "01234567" + : Bits == 10 ? "0123456789" + : Bits == 16 ? "0123456789abcdef" + : Bits == 32 ? "0123456789abcdefghijklmnopqrstuv" + : Bits == 34 ? "023456789abcdefghijkmnopqrstuvwxyz" //1l + : Bits == 36 ? "0123456789abcdefghijklmnopqrstuvwxyz" + : Bits == 57 ? "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" //01IOl + : Bits == 62 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + : Bits == 64 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{}" + : Bits == 85 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%()+,-.:;=@[]^_`{|}~" //\ "&'*/<>? + : ""; + static const uint size = ceil(sizeof(T) * 8 / log2(Bits)); + + string result; + result.resize(size); + char* data = result.get() + size; + for(auto byte : result) { + *--data = format[value % Bits]; + value /= Bits; + } + return result; +} + +} diff --git a/nall/encode/base64.hpp b/nall/encode/base64.hpp new file mode 100644 index 0000000..a1d518c --- /dev/null +++ b/nall/encode/base64.hpp @@ -0,0 +1,68 @@ +#pragma once + +namespace nall::Encode { + +inline auto Base64(const void* vdata, uint size, const string& format = "MIME") -> string { + static bool initialized = false; + static char lookup[65] = {0}; + if(!initialized) { + initialized = true; + for(uint n : range(26)) lookup[n + 0] = 'A' + n; + for(uint n : range(26)) lookup[n + 26] = 'a' + n; + for(uint n : range(10)) lookup[n + 52] = '0' + n; + } + + if(format == "MIME") { + lookup[62] = '+'; + lookup[63] = '/'; + lookup[64] = '='; + } else if(format == "URI") { + lookup[62] = '-'; + lookup[63] = '_'; + lookup[64] = 0; + } else return ""; + + auto data = (const uint8_t*)vdata; + uint overflow = (3 - (size % 3)) % 3; //bytes to round to nearest multiple of 3 + string result; + uint8_t buffer; + for(uint n : range(size)) { + switch(n % 3) { + case 0: + buffer = data[n] >> 2; + result.append(lookup[buffer]); + buffer = (data[n] & 3) << 4; + break; + + case 1: + buffer |= data[n] >> 4; + result.append(lookup[buffer]); + buffer = (data[n] & 15) << 2; + break; + + case 2: + buffer |= data[n] >> 6; + result.append(lookup[buffer]); + buffer = (data[n] & 63); + result.append(lookup[buffer]); + break; + } + } + + if(overflow) result.append(lookup[buffer]); + if(lookup[64]) { + while(result.size() % 4) result.append(lookup[64]); + } + + return result; +} + +inline auto Base64(const vector& buffer, const string& format = "MIME") -> string { + return Base64(buffer.data(), buffer.size(), format); +} + +inline auto Base64(const string& text, const string& format = "MIME") -> string { + return Base64(text.data(), text.size(), format); +} + +} diff --git a/nall/encode/bmp.hpp b/nall/encode/bmp.hpp new file mode 100644 index 0000000..1ccc930 --- /dev/null +++ b/nall/encode/bmp.hpp @@ -0,0 +1,47 @@ +#pragma once + +namespace nall::Encode { + +struct BMP { + static auto create(const string& filename, const void* data, uint pitch, uint width, uint height, bool alpha) -> bool { + auto fp = file::open(filename, file::mode::write); + if(!fp) return false; + + uint bitsPerPixel = alpha ? 32 : 24; + uint bytesPerPixel = bitsPerPixel / 8; + uint alignedWidth = width * bytesPerPixel; + uint paddingLength = 0; + uint imageSize = alignedWidth * height; + uint fileSize = 0x36 + imageSize; + while(alignedWidth % 4) alignedWidth++, paddingLength++; + + fp.writel(0x4d42, 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 + + pitch >>= 2; + for(auto y : range(height)) { + auto p = (const uint32_t*)data + y * pitch; + for(auto x : range(width)) fp.writel(*p++, bytesPerPixel); + if(paddingLength) fp.writel(0, paddingLength); + } + + return true; + } +}; + +} diff --git a/nall/encode/bwt.hpp b/nall/encode/bwt.hpp new file mode 100644 index 0000000..84e00d9 --- /dev/null +++ b/nall/encode/bwt.hpp @@ -0,0 +1,86 @@ +#pragma once + +//burrows-wheeler transform + +#include + +namespace nall::Encode { + +/* + A standard suffix array cannot produce a proper burrows-wheeler transform, due to rotations. + + Take the input string, "nall", this gives us: + nall + alln + llna + lnal + + If we suffix sort this, we produce: + all => alln + l => lnal + ll => llna + nall => nall + + If we sort this, we produce: + alln + llna + lnal + nall + + Thus, suffix sorting gives us "nlal" as the last column instead of "nall". + This is because BWT rotates the input string, whereas suffix arrays sort the input string. + + Adding a 256th character terminator before sorting will not produce the desired result, either. + A more complicated string such as "mississippi" will sort as "ssmppissiii" with terminator=256, + and as "ipssmpissii" with terminator=0, alphabet=1..256, whereas we want "pssmipissii". + + Performing a merge sort to use a specialized comparison function that wraps suffixes is too slow at O(n log n). + + Producing a custom induced sort to handle rotations would be incredibly complicated, + owing to the recursive nature of induced sorting, among other things. + + So instead, a temporary array is produced that contains the input suffix twice. + This is then fed into the suffix array sort, and the doubled matches are filtered out. + After this point, suffixes are sorted in their mirrored form, and the correct result can be derived + + The result of this is an O(2n) algorithm, which vastly outperforms a naive O(n log n) algorithm, + but is still far from ideal. However, this will have to do until a better solution is devised. + + Although to be fair, BWT is inferior to the bijective BWT anyway, so it may not be worth the effort. +*/ + +inline auto BWT(array_view input) -> vector { + auto size = input.size(); + vector output; + output.reserve(8 + 8 + size); + for(uint byte : range(8)) output.append(size >> byte * 8); + for(uint byte : range(8)) output.append(0x00); + + vector buffer; + buffer.reserve(2 * size); + for(uint offset : range(size)) buffer.append(input[offset]); + for(uint offset : range(size)) buffer.append(input[offset]); + + auto suffixes = SuffixArray(buffer); + + vector prefixes; + prefixes.reserve(size); + + for(uint offset : range(2 * size + 1)) { + uint suffix = suffixes[offset]; + if(suffix >= size) continue; //beyond the bounds of the original input string + prefixes.append(suffix); + } + + uint64_t root = 0; + for(uint offset : range(size)) { + uint suffix = prefixes[offset]; + if(suffix == 0) root = offset, suffix = size; + output.append(input[--suffix]); + } + for(uint byte : range(8)) output[8 + byte] = root >> byte * 8; + + return output; +} + +} diff --git a/nall/encode/html.hpp b/nall/encode/html.hpp new file mode 100644 index 0000000..6e4fd04 --- /dev/null +++ b/nall/encode/html.hpp @@ -0,0 +1,18 @@ +#pragma once + +namespace nall::Encode { + +inline auto HTML(const string& input) -> string { + string output; + for(char c : input) { + if(c == '&' ) { output.append("&" ); continue; } + if(c == '<' ) { output.append("<" ); continue; } + if(c == '>' ) { output.append(">" ); continue; } + if(c == '"' ) { output.append("""); continue; } + if(c == '\'') { output.append("'"); continue; } + output.append(c); + } + return output; +} + +} diff --git a/nall/encode/huffman.hpp b/nall/encode/huffman.hpp new file mode 100644 index 0000000..18aa25f --- /dev/null +++ b/nall/encode/huffman.hpp @@ -0,0 +1,84 @@ +#pragma once + +namespace nall::Encode { + +inline auto Huffman(array_view input) -> vector { + vector output; + for(uint byte : range(8)) output.append(input.size() >> byte * 8); + + struct Node { + uint frequency = 0; + uint parent = 0; + uint lhs = 0; + uint rhs = 0; + }; + array nodes; + for(uint offset : range(input.size())) nodes[input[offset]].frequency++; + + uint count = 0; + for(uint offset : range(511)) { + if(nodes[offset].frequency) count++; + else nodes[offset].parent = 511; + } + + auto minimum = [&] { + uint frequency = ~0, minimum = 511; + for(uint index : range(511)) { + if(!nodes[index].parent && nodes[index].frequency && nodes[index].frequency < frequency) { + frequency = nodes[index].frequency; + minimum = index; + } + } + return minimum; + }; + + //group the least two frequently used nodes until only one node remains + uint index = 256; + for(uint remaining = max(2, count); remaining >= 2; remaining--) { + uint lhs = minimum(); + nodes[lhs].parent = index; + uint rhs = minimum(); + nodes[rhs].parent = index; + if(remaining == 2) index = nodes[lhs].parent = nodes[rhs].parent = 511; + nodes[index].lhs = lhs; + nodes[index].rhs = rhs; + nodes[index].parent = 0; + nodes[index].frequency = nodes[lhs].frequency + nodes[rhs].frequency; + index++; + } + + uint byte = 0, bits = 0; + auto write = [&](bool bit) { + byte = byte << 1 | bit; + if(++bits == 8) output.append(byte), bits = 0; + }; + + //only the upper half of the table is needed for decompression + //the first 256 nodes are always treated as leaf nodes + for(uint offset : range(256)) { + for(uint index : reverse(range(9))) write(nodes[256 + offset].lhs >> index & 1); + for(uint index : reverse(range(9))) write(nodes[256 + offset].rhs >> index & 1); + } + + for(uint byte : input) { + uint node = byte, length = 0; + uint256_t sequence = 0; + //traversing the array produces the bitstream in reverse order + do { + uint parent = nodes[node].parent; + bool bit = nodes[nodes[node].parent].rhs == node; + sequence = sequence << 1 | bit; + length++; + node = parent; + } while(node != 511); + //output the generated bits in the correct order + for(uint index : range(length)) { + write(sequence >> index & 1); + } + } + while(bits) write(0); + + return output; +} + +} diff --git a/nall/encode/lzsa.hpp b/nall/encode/lzsa.hpp new file mode 100644 index 0000000..2ca59b6 --- /dev/null +++ b/nall/encode/lzsa.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace nall::Encode { + +inline auto LZSA(array_view input) -> vector { + vector output; + for(uint byte : range(8)) output.append(input.size() >> byte * 8); + + auto suffixArray = SuffixArray(input).lpf(); + uint index = 0; + vector flags; + vector literals; + vector stringLengths; + vector stringOffsets; + + uint byte = 0, bits = 0; + auto flagWrite = [&](bool bit) { + byte = byte << 1 | bit; + if(++bits == 8) flags.append(byte), bits = 0; + }; + + auto literalWrite = [&](uint8_t literal) { + literals.append(literal); + }; + + auto lengthWrite = [&](uint64_t length) { + if(length < 1 << 7) length = length << 1 | 0b1; + else if(length < 1 << 14) length = length << 2 | 0b10; + else if(length < 1 << 21) length = length << 3 | 0b100; + else if(length < 1 << 28) length = length << 4 | 0b1000; + else /*length < 1 << 35*/length = length << 5 | 0b10000; + while(length) stringLengths.append(length), length >>= 8; + }; + + auto offsetWrite = [&](uint offset) { + stringOffsets.append(offset >> 0); if(index < 1 << 8) return; + stringOffsets.append(offset >> 8); if(index < 1 << 16) return; + stringOffsets.append(offset >> 16); if(index < 1 << 24) return; + stringOffsets.append(offset >> 24); + }; + + while(index < input.size()) { + int length, offset; + suffixArray.previous(length, offset, index); + +/* for(uint ahead = 1; ahead <= 2; ahead++) { + int aheadLength, aheadOffset; + suffixArray.previous(aheadLength, aheadOffset, index + ahead); + if(aheadLength > length && aheadOffset >= 0) { + length = 0; + break; + } + } */ + + if(length < 6 || offset < 0) { + flagWrite(0); + literalWrite(input[index++]); + } else { + flagWrite(1); + lengthWrite(length - 6); + offsetWrite(index - offset); + index += length; + } + } + while(bits) flagWrite(0); + + auto save = [&](const vector& buffer) { + for(uint byte : range(8)) output.append(buffer.size() >> byte * 8); + output.append(buffer); + }; + + save(Encode::Huffman(flags)); + save(Encode::Huffman(literals)); + save(Encode::Huffman(stringLengths)); + save(Encode::Huffman(stringOffsets)); + + return output; +} + +} diff --git a/nall/encode/mtf.hpp b/nall/encode/mtf.hpp new file mode 100644 index 0000000..42f24b1 --- /dev/null +++ b/nall/encode/mtf.hpp @@ -0,0 +1,30 @@ +#pragma once + +//move to front + +namespace nall::Encode { + +inline auto MTF(array_view input) -> vector { + vector output; + output.resize(input.size()); + + uint8_t order[256]; + for(uint n : range(256)) order[n] = n; + + for(uint offset : range(input.size())) { + uint data = input[offset]; + for(uint index : range(256)) { + uint value = order[index]; + if(value == data) { + output[offset] = index; + memory::move(&order[1], &order[0], index); + order[0] = value; + break; + } + } + } + + return output; +} + +} diff --git a/nall/encode/rle.hpp b/nall/encode/rle.hpp new file mode 100644 index 0000000..da88fff --- /dev/null +++ b/nall/encode/rle.hpp @@ -0,0 +1,56 @@ +#pragma once + +namespace nall::Encode { + +template //S = word size; M = match length +inline auto RLE(array_view input) -> vector { + vector output; + for(uint byte : range(8)) output.append(input.size() >> byte * 8); + + uint base = 0; + uint skip = 0; + + auto load = [&](uint offset) -> uint8_t { + return input(offset); + }; + + auto read = [&](uint offset) -> uint64_t { + uint64_t value = 0; + for(uint byte : range(S)) value |= load(offset + byte) << byte * 8; + return value; + }; + + auto write = [&](uint64_t value) -> void { + for(uint byte : range(S)) output.append(value >> byte * 8); + }; + + auto flush = [&] { + output.append(skip - 1); + do { + write(read(base)); + base += S; + } while(--skip); + }; + + while(base + S * skip < input.size()) { + uint same = 1; + for(uint offset = base + S * (skip + 1); offset < input.size(); offset += S) { + if(read(offset) != read(base + S * skip)) break; + if(++same == 127 + M) break; + } + + if(same < M) { + if(++skip == 128) flush(); + } else { + if(skip) flush(); + output.append(128 | same - M); + write(read(base)); + base += S * same; + } + } + if(skip) flush(); + + return output; +} + +} diff --git a/nall/encode/url.hpp b/nall/encode/url.hpp new file mode 100644 index 0000000..1f422e5 --- /dev/null +++ b/nall/encode/url.hpp @@ -0,0 +1,27 @@ +#pragma once + +namespace nall::Encode { + +inline auto URL(string_view input) -> string { + string output; + for(auto c : input) { + //unreserved characters + if(c >= 'A' && c <= 'Z') { output.append(c); continue; } + if(c >= 'a' && c <= 'z') { output.append(c); continue; } + if(c >= '0' && c <= '9') { output.append(c); continue; } + if(c == '-' || c == '_' || c == '.' || c == '~') { output.append(c); continue; } + + //special characters + if(c == ' ') { output.append('+'); continue; } + + //reserved characters + uint hi = (c >> 4) & 15; + uint lo = (c >> 0) & 15; + output.append('%'); + output.append((char)(hi < 10 ? ('0' + hi) : ('a' + hi - 10))); + output.append((char)(lo < 10 ? ('0' + lo) : ('a' + lo - 10))); + } + return output; +} + +} diff --git a/nall/encode/wav.hpp b/nall/encode/wav.hpp new file mode 100644 index 0000000..1b42485 --- /dev/null +++ b/nall/encode/wav.hpp @@ -0,0 +1,52 @@ +#pragma once + +namespace nall::Encode { + +struct WAV { + static auto stereo_16bit(const string& filename, array_view left, array_view right, uint frequency) -> bool { + if(left.size() != right.size()) return false; + static uint channels = 2; + static uint bits = 16; + static uint samples = left.size(); + + file_buffer fp; + if(!fp.open(filename, file::mode::write)) return false; + + fp.write('R'); + fp.write('I'); + fp.write('F'); + fp.write('F'); + fp.writel(4 + (8 + 16) + (8 + samples * 4), 4); + + fp.write('W'); + fp.write('A'); + fp.write('V'); + fp.write('E'); + + fp.write('f'); + fp.write('m'); + fp.write('t'); + fp.write(' '); + fp.writel(16, 4); + fp.writel(1, 2); + fp.writel(channels, 2); + fp.writel(frequency, 4); + fp.writel(frequency * channels * bits, 4); + fp.writel(channels * bits, 2); + fp.writel(bits, 2); + + fp.write('d'); + fp.write('a'); + fp.write('t'); + fp.write('a'); + fp.writel(samples * 4, 4); + for(uint sample : range(samples)) { + fp.writel(left[sample], 2); + fp.writel(right[sample], 2); + } + + return true; + } +}; + +} diff --git a/nall/encode/zip.hpp b/nall/encode/zip.hpp new file mode 100755 index 0000000..b98376d --- /dev/null +++ b/nall/encode/zip.hpp @@ -0,0 +1,101 @@ +#pragma once + +//creates uncompressed ZIP archives + +#include +#include + +namespace nall::Encode { + +struct ZIP { + ZIP(const string& filename) { + fp.open(filename, file::mode::write); + timestamp = time(nullptr); + } + + //append path: append("path/"); + //append file: append("path/file", data, size); + auto append(string filename, const uint8_t* data = nullptr, uint size = 0u, time_t timestamp = 0) -> void { + filename.transform("\\", "/"); + if(!timestamp) timestamp = this->timestamp; + uint32_t checksum = Hash::CRC32({data, size}).digest().hex(); + directory.append({filename, timestamp, checksum, size, (uint32_t)fp.offset()}); + + fp.writel(0x04034b50, 4); //signature + fp.writel(0x0014, 2); //minimum version (2.0) + fp.writel(0x0000, 2); //general purpose bit flags + fp.writel(0x0000, 2); //compression method (0 = uncompressed) + fp.writel(makeTime(timestamp), 2); + fp.writel(makeDate(timestamp), 2); + fp.writel(checksum, 4); + fp.writel(size, 4); //compressed size + fp.writel(size, 4); //uncompressed size + fp.writel(filename.length(), 2); //file name length + fp.writel(0x0000, 2); //extra field length + fp.print(filename); //file name + + fp.write({data, size}); //file data + } + + ~ZIP() { + //central directory + uint baseOffset = fp.offset(); + for(auto& entry : directory) { + fp.writel(0x02014b50, 4); //signature + fp.writel(0x0014, 2); //version made by (2.0) + fp.writel(0x0014, 2); //version needed to extract (2.0) + fp.writel(0x0000, 2); //general purpose bit flags + fp.writel(0x0000, 2); //compression method (0 = uncompressed) + fp.writel(makeTime(entry.timestamp), 2); + fp.writel(makeDate(entry.timestamp), 2); + fp.writel(entry.checksum, 4); + fp.writel(entry.size, 4); //compressed size + fp.writel(entry.size, 4); //uncompressed size + fp.writel(entry.filename.length(), 2); //file name length + fp.writel(0x0000, 2); //extra field length + fp.writel(0x0000, 2); //file comment length + fp.writel(0x0000, 2); //disk number start + fp.writel(0x0000, 2); //internal file attributes + fp.writel(0x00000000, 4); //external file attributes + fp.writel(entry.offset, 4); //relative offset of file header + fp.print(entry.filename); + } + uint finishOffset = fp.offset(); + + //end of central directory + fp.writel(0x06054b50, 4); //signature + fp.writel(0x0000, 2); //number of this disk + fp.writel(0x0000, 2); //disk where central directory starts + fp.writel(directory.size(), 2); //number of central directory records on this disk + fp.writel(directory.size(), 2); //total number of central directory records + fp.writel(finishOffset - baseOffset, 4); //size of central directory + fp.writel(baseOffset, 4); //offset of central directory + fp.writel(0x0000, 2); //comment length + + fp.close(); + } + +protected: + auto makeTime(time_t timestamp) -> uint16_t { + tm* info = localtime(×tamp); + return (info->tm_hour << 11) | (info->tm_min << 5) | (info->tm_sec >> 1); + } + + auto makeDate(time_t timestamp) -> uint16_t { + tm* info = localtime(×tamp); + return ((info->tm_year - 80) << 9) | ((1 + info->tm_mon) << 5) + (info->tm_mday); + } + + file_buffer fp; + time_t timestamp; + struct entry_t { + string filename; + time_t timestamp; + uint32_t checksum; + uint32_t size; + uint32_t offset; + }; + vector directory; +}; + +} diff --git a/nall/endian.hpp b/nall/endian.hpp new file mode 100755 index 0000000..7a01b9a --- /dev/null +++ b/nall/endian.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#if defined(ENDIAN_LSB) + //little-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x04030201 + #define order_lsb1(a) a + #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_msb1(a) a + #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_lsb1(a) a + #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_msb1(a) 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 diff --git a/nall/file-buffer.hpp b/nall/file-buffer.hpp new file mode 100644 index 0000000..6dcf905 --- /dev/null +++ b/nall/file-buffer.hpp @@ -0,0 +1,249 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nall { + +//on Windows (at least for 7 and earlier), FILE* is not buffered +//thus, reading/writing one byte at a time will be dramatically slower +//on all other OSes, FILE* is buffered +//in order to ensure good performance, file_buffer implements its own buffer +//this speeds up Windows substantially, without harming performance elsewhere much + +struct file_buffer { + struct mode { enum : uint { read, write, modify, append }; }; + struct index { enum : uint { absolute, relative }; }; + + file_buffer(const file_buffer&) = delete; + auto operator=(const file_buffer&) -> file_buffer& = delete; + + file_buffer() = default; + file_buffer(const string& filename, uint mode) { open(filename, mode); } + + file_buffer(file_buffer&& source) { operator=(move(source)); } + + ~file_buffer() { close(); } + + auto operator=(file_buffer&& source) -> file_buffer& { + buffer = source.buffer; + bufferOffset = source.bufferOffset; + bufferDirty = source.bufferDirty; + fileHandle = source.fileHandle; + fileOffset = source.fileOffset; + fileSize = source.fileSize; + fileMode = source.fileMode; + + source.bufferOffset = -1; + source.bufferDirty = false; + source.fileHandle = nullptr; + source.fileOffset = 0; + source.fileSize = 0; + source.fileMode = mode::read; + + return *this; + } + + explicit operator bool() const { + return (bool)fileHandle; + } + + auto read() -> uint8_t { + if(!fileHandle) return 0; //file not open + if(fileMode == mode::write) return 0; //reads not permitted + if(fileOffset >= fileSize) return 0; //cannot read past end of file + bufferSynchronize(); + return buffer[fileOffset++ & buffer.size() - 1]; + } + + template auto readl(uint length = 1) -> T { + T data = 0; + for(uint n : range(length)) { + data |= (T)read() << n * 8; + } + return data; + } + + template auto readm(uint length = 1) -> T { + T data = 0; + while(length--) { + data <<= 8; + data |= read(); + } + return data; + } + + auto reads(uint length) -> string { + string result; + result.resize(length); + for(auto& byte : result) byte = read(); + return result; + } + + auto read(array_span memory) -> void { + for(auto& byte : memory) byte = read(); + } + + auto write(uint8_t data) -> void { + if(!fileHandle) return; //file not open + if(fileMode == mode::read) return; //writes not permitted + bufferSynchronize(); + buffer[fileOffset++ & buffer.size() - 1] = data; + bufferDirty = true; + if(fileOffset > fileSize) fileSize = fileOffset; + } + + template auto writel(T data, uint length = 1) -> void { + while(length--) { + write(uint8_t(data)); + data >>= 8; + } + } + + template auto writem(T data, uint length = 1) -> void { + for(uint n : reverse(range(length))) { + write(uint8_t(data >> n * 8)); + } + } + + auto writes(const string& s) -> void { + for(auto& byte : s) write(byte); + } + + auto write(array_view memory) -> void { + for(auto& byte : memory) write(byte); + } + + template auto print(P&&... p) -> void { + string s{forward

    (p)...}; + for(auto& byte : s) write(byte); + } + + auto flush() -> void { + bufferFlush(); + fflush(fileHandle); + } + + auto seek(int64_t offset, uint index_ = index::absolute) -> void { + if(!fileHandle) return; + bufferFlush(); + + int64_t seekOffset = fileOffset; + switch(index_) { + case index::absolute: seekOffset = offset; break; + case index::relative: seekOffset += offset; break; + } + + if(seekOffset < 0) seekOffset = 0; //cannot seek before start of file + if(seekOffset > fileSize) { + if(fileMode == mode::read) { //cannot seek past end of file + seekOffset = fileSize; + } else { //pad file to requested location + fileOffset = fileSize; + while(fileSize < seekOffset) write(0); + } + } + + fileOffset = seekOffset; + } + + auto offset() const -> uint64_t { + if(!fileHandle) return 0; + return fileOffset; + } + + auto size() const -> uint64_t { + if(!fileHandle) return 0; + return fileSize; + } + + auto truncate(uint64_t size) -> bool { + if(!fileHandle) return false; + #if defined(API_POSIX) + return ftruncate(fileno(fileHandle), size) == 0; + #elif defined(API_WINDOWS) + return _chsize(fileno(fileHandle), size) == 0; + #endif + } + + auto end() const -> bool { + if(!fileHandle) return true; + return fileOffset >= fileSize; + } + + auto open(const string& filename, uint mode_) -> bool { + close(); + + switch(fileMode = mode_) { + #if defined(API_POSIX) + case mode::read: fileHandle = fopen(filename, "rb" ); break; + case mode::write: fileHandle = fopen(filename, "wb+"); break; //need read permission for buffering + case mode::modify: fileHandle = fopen(filename, "rb+"); break; + case mode::append: fileHandle = fopen(filename, "wb+"); break; + #elif defined(API_WINDOWS) + case mode::read: fileHandle = _wfopen(utf16_t(filename), L"rb" ); break; + case mode::write: fileHandle = _wfopen(utf16_t(filename), L"wb+"); break; + case mode::modify: fileHandle = _wfopen(utf16_t(filename), L"rb+"); break; + case mode::append: fileHandle = _wfopen(utf16_t(filename), L"wb+"); break; + #endif + } + if(!fileHandle) return false; + + bufferOffset = -1; + fileOffset = 0; + fseek(fileHandle, 0, SEEK_END); + fileSize = ftell(fileHandle); + fseek(fileHandle, 0, SEEK_SET); + return true; + } + + auto close() -> void { + if(!fileHandle) return; + bufferFlush(); + fclose(fileHandle); + fileHandle = nullptr; + } + +private: + array buffer; + int bufferOffset = -1; + bool bufferDirty = false; + FILE* fileHandle = nullptr; + uint64_t fileOffset = 0; + uint64_t fileSize = 0; + uint fileMode = mode::read; + + auto bufferSynchronize() -> void { + if(!fileHandle) return; + if(bufferOffset == (fileOffset & ~(buffer.size() - 1))) return; + + bufferFlush(); + bufferOffset = fileOffset & ~(buffer.size() - 1); + fseek(fileHandle, bufferOffset, SEEK_SET); + uint64_t length = bufferOffset + buffer.size() <= fileSize ? buffer.size() : fileSize & buffer.size() - 1; + if(length) (void)fread(buffer.data(), 1, length, fileHandle); + } + + auto bufferFlush() -> void { + if(!fileHandle) return; //file not open + if(fileMode == mode::read) return; //buffer cannot be written to + if(bufferOffset < 0) return; //buffer unused + if(!bufferDirty) return; //buffer unmodified since read + + fseek(fileHandle, bufferOffset, SEEK_SET); + uint64_t length = bufferOffset + buffer.size() <= fileSize ? buffer.size() : fileSize & buffer.size() - 1; + if(length) (void)fwrite(buffer.data(), 1, length, fileHandle); + bufferOffset = -1; + bufferDirty = false; + } +}; + +} diff --git a/nall/file-map.hpp b/nall/file-map.hpp new file mode 100755 index 0000000..647a823 --- /dev/null +++ b/nall/file-map.hpp @@ -0,0 +1,225 @@ +#pragma once + +#include +#include + +#include +#include +#if defined(PLATFORM_WINDOWS) + #include +#else + #include + #include + #include + #include + #include +#endif + +#if !defined(MAP_NORESERVE) + //not supported on FreeBSD; flag removed in 11.0 + #define MAP_NORESERVE 0 +#endif + +namespace nall { + +struct file_map { + struct mode { enum : uint { read, write, modify, append }; }; + + file_map(const file_map&) = delete; + auto operator=(const file_map&) = delete; + + file_map() = default; + file_map(file_map&& source) { operator=(move(source)); } + file_map(const string& filename, uint mode) { open(filename, mode); } + + ~file_map() { close(); } + + explicit operator bool() const { return _open; } + auto size() const -> uint64_t { return _size; } + auto data() -> uint8_t* { return _data; } + auto data() const -> const uint8_t* { return _data; } + +//auto operator=(file_map&& source) -> file_map&; +//auto open(const string& filename, uint mode) -> bool; +//auto close() -> void; + +private: + bool _open = false; //zero-byte files return _data = nullptr, _size = 0 + uint8_t* _data = nullptr; + uint64_t _size = 0; + + #if defined(API_WINDOWS) + + HANDLE _file = INVALID_HANDLE_VALUE; + HANDLE _map = INVALID_HANDLE_VALUE; + +public: + auto operator=(file_map&& source) -> file_map& { + _open = source._open; + _data = source._data; + _size = source._size; + _file = source._file; + _map = source._map; + + source._open = false; + source._data = nullptr; + source._size = 0; + source._file = INVALID_HANDLE_VALUE; + source._map = INVALID_HANDLE_VALUE; + + return *this; + } + + auto open(const string& filename, uint mode_) -> bool { + close(); + if(file::exists(filename) && file::size(filename) == 0) return _open = true; + + int desiredAccess, creationDisposition, protection, mapAccess; + + switch(mode_) { + default: return false; + case mode::read: + desiredAccess = GENERIC_READ; + creationDisposition = OPEN_EXISTING; + protection = PAGE_READONLY; + mapAccess = FILE_MAP_READ; + break; + case mode::write: + //write access requires read access + desiredAccess = GENERIC_WRITE; + creationDisposition = CREATE_ALWAYS; + protection = PAGE_READWRITE; + mapAccess = FILE_MAP_ALL_ACCESS; + break; + case mode::modify: + desiredAccess = GENERIC_READ | GENERIC_WRITE; + creationDisposition = OPEN_EXISTING; + protection = PAGE_READWRITE; + mapAccess = FILE_MAP_ALL_ACCESS; + break; + case mode::append: + desiredAccess = GENERIC_READ | GENERIC_WRITE; + creationDisposition = CREATE_NEW; + protection = PAGE_READWRITE; + mapAccess = FILE_MAP_ALL_ACCESS; + break; + } + + _file = CreateFileW(utf16_t(filename), desiredAccess, FILE_SHARE_READ, nullptr, + creationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr); + if(_file == INVALID_HANDLE_VALUE) return false; + + _size = GetFileSize(_file, nullptr); + + _map = CreateFileMapping(_file, nullptr, protection, 0, _size, nullptr); + if(_map == INVALID_HANDLE_VALUE) { + CloseHandle(_file); + _file = INVALID_HANDLE_VALUE; + return false; + } + + _data = (uint8_t*)MapViewOfFile(_map, mapAccess, 0, 0, _size); + return _open = true; + } + + auto close() -> void { + if(_data) { + UnmapViewOfFile(_data); + _data = nullptr; + } + + if(_map != INVALID_HANDLE_VALUE) { + CloseHandle(_map); + _map = INVALID_HANDLE_VALUE; + } + + if(_file != INVALID_HANDLE_VALUE) { + CloseHandle(_file); + _file = INVALID_HANDLE_VALUE; + } + + _open = false; + } + + #else + + int _fd = -1; + +public: + auto operator=(file_map&& source) -> file_map& { + _open = source._open; + _data = source._data; + _size = source._size; + _fd = source._fd; + + source._open = false; + source._data = nullptr; + source._size = 0; + source._fd = -1; + + return *this; + } + + auto open(const string& filename, uint mode_) -> bool { + close(); + if(file::exists(filename) && file::size(filename) == 0) return _open = true; + + int openFlags = 0; + int mmapFlags = 0; + + switch(mode_) { + default: return false; + case mode::read: + openFlags = O_RDONLY; + mmapFlags = PROT_READ; + break; + case mode::write: + openFlags = O_RDWR | O_CREAT; //mmap() requires read access + mmapFlags = PROT_WRITE; + break; + case mode::modify: + openFlags = O_RDWR; + mmapFlags = PROT_READ | PROT_WRITE; + break; + case mode::append: + openFlags = O_RDWR | O_CREAT; + mmapFlags = PROT_READ | PROT_WRITE; + break; + } + + _fd = ::open(filename, openFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if(_fd < 0) return false; + + struct stat _stat; + fstat(_fd, &_stat); + _size = _stat.st_size; + + _data = (uint8_t*)mmap(nullptr, _size, mmapFlags, MAP_SHARED | MAP_NORESERVE, _fd, 0); + if(_data == MAP_FAILED) { + _data = nullptr; + ::close(_fd); + _fd = -1; + return false; + } + + return _open = true; + } + + auto close() -> void { + if(_data) { + munmap(_data, _size); + _data = nullptr; + } + + if(_fd >= 0) { + ::close(_fd); + _fd = -1; + } + + _open = false; + } + + #endif +}; + +} diff --git a/nall/file.hpp b/nall/file.hpp new file mode 100755 index 0000000..fc4284e --- /dev/null +++ b/nall/file.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include + +namespace nall { + +struct file : inode { + struct mode { enum : uint { read, write, modify, append }; }; + struct index { enum : uint { absolute, relative }; }; + + file() = delete; + + static auto open(const string& filename, uint mode) -> file_buffer { + return file_buffer{filename, mode}; + } + + static auto copy(const string& sourcename, const string& targetname) -> bool { + if(sourcename == targetname) return true; + if(auto reader = file::open(sourcename, mode::read)) { + if(auto writer = file::open(targetname, mode::write)) { + for(uint64_t n : range(reader.size())) writer.write(reader.read()); + return true; + } + } + return false; + } + + //attempt to rename file first + //this will fail if paths point to different file systems; fall back to copy+remove in this case + static auto move(const string& sourcename, const string& targetname) -> bool { + if(sourcename == targetname) return true; + if(rename(sourcename, targetname)) return true; + if(!writable(sourcename)) return false; + if(copy(sourcename, targetname)) return remove(sourcename), true; + return false; + } + + static auto truncate(const string& filename, uint64_t size) -> bool { + #if defined(API_POSIX) + return truncate(filename, size) == 0; + #elif defined(API_WINDOWS) + if(auto fp = _wfopen(utf16_t(filename), L"rb+")) { + bool result = _chsize(fileno(fp), size) == 0; + fclose(fp); + return result; + } + return false; + #endif + } + + //returns false if specified filename is a directory + static auto exists(const string& filename) -> bool { + #if defined(API_POSIX) + struct stat data; + if(stat(filename, &data) != 0) return false; + #elif defined(API_WINDOWS) + struct __stat64 data; + if(_wstat64(utf16_t(filename), &data) != 0) return false; + #endif + return !(data.st_mode & S_IFDIR); + } + + static auto size(const string& filename) -> uint64_t { + #if defined(API_POSIX) + struct stat data; + stat(filename, &data); + #elif defined(API_WINDOWS) + struct __stat64 data; + _wstat64(utf16_t(filename), &data); + #endif + return S_ISREG(data.st_mode) ? data.st_size : 0u; + } + + static auto read(const string& filename) -> vector { + vector memory; + if(auto fp = file::open(filename, mode::read)) { + memory.resize(fp.size()); + fp.read(memory); + } + return memory; + } + + static auto read(const string& filename, array_span memory) -> bool { + if(auto fp = file::open(filename, mode::read)) return fp.read(memory), true; + return false; + } + + static auto write(const string& filename, array_view memory) -> bool { + if(auto fp = file::open(filename, mode::write)) return fp.write(memory), true; + return false; + } + + //create an empty file (will replace existing files) + static auto create(const string& filename) -> bool { + if(auto fp = file::open(filename, mode::write)) return true; + return false; + } + + static auto sha256(const string& filename) -> string { + return Hash::SHA256(read(filename)).digest(); + } +}; + +} diff --git a/nall/function.hpp b/nall/function.hpp new file mode 100755 index 0000000..3b59e05 --- /dev/null +++ b/nall/function.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include + +namespace nall { + +template struct function; + +template struct function R> { + using cast = auto (*)(P...) -> R; + + //value = true if auto L::operator()(P...) -> R exists + template struct is_compatible { + template static auto exists(T*) -> const typename is_same().operator()(declval

    ()...))>::type; + template static auto exists(...) -> const false_type; + static constexpr bool value = decltype(exists(0))::value; + }; + + function() {} + function(const function& source) { operator=(source); } + function(auto (*function)(P...) -> R) { callback = new global(function); } + template function(auto (C::*function)(P...) -> R, C* object) { callback = new member(function, object); } + template function(auto (C::*function)(P...) const -> R, C* object) { callback = new member((auto (C::*)(P...) -> R)function, object); } + template::value>> function(const L& object) { callback = new lambda(object); } + explicit function(void* function) { if(function) callback = new global((auto (*)(P...) -> R)function); } + ~function() { if(callback) delete callback; } + + explicit operator bool() const { return callback; } + auto operator()(P... p) const -> R { return (*callback)(forward

    (p)...); } + auto reset() -> void { if(callback) { delete callback; callback = nullptr; } } + + auto operator=(const function& source) -> function& { + if(this != &source) { + if(callback) { delete callback; callback = nullptr; } + if(source.callback) callback = source.callback->copy(); + } + return *this; + } + + auto operator=(void* source) -> function& { + if(callback) { delete callback; callback = nullptr; } + callback = new global((auto (*)(P...) -> R)source); + return *this; + } + +private: + struct container { + virtual auto operator()(P... p) const -> R = 0; + virtual auto copy() const -> container* = 0; + virtual ~container() = default; + }; + + container* callback = nullptr; + + struct global : container { + auto (*function)(P...) -> R; + auto operator()(P... p) const -> R { return function(forward

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

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

    (p)...); } + auto copy() const -> container* { return new lambda(object); } + lambda(const L& object) : object(object) {} + }; +}; + +} diff --git a/nall/galois-field.hpp b/nall/galois-field.hpp new file mode 100644 index 0000000..38f2269 --- /dev/null +++ b/nall/galois-field.hpp @@ -0,0 +1,70 @@ +#pragma once + +//table-driven galois field modulo 2 +//do not use with GF(2^17) or larger + +namespace nall { + +template +struct GaloisField { + using type = GaloisField; + + GaloisField(uint x = 0) : x(x) {} + operator field() const { return x; } + + auto operator^(field y) const -> type { return x ^ y; } + auto operator+(field y) const -> type { return x ^ y; } + auto operator-(field y) const -> type { return x ^ y; } + auto operator*(field y) const -> type { return x && y ? exp(log(x) + log(y)) : 0; } + auto operator/(field y) const -> type { return x && y ? exp(log(x) + Elements - log(y)) : 0; } + + auto& operator =(field y) { return x = y, *this; } + auto& operator^=(field y) { return x = operator^(y), *this; } + auto& operator+=(field y) { return x = operator^(y), *this; } + auto& operator-=(field y) { return x = operator^(y), *this; } + auto& operator*=(field y) { return x = operator*(y), *this; } + auto& operator/=(field y) { return x = operator/(y), *this; } + + auto pow(field y) const -> type { return exp(log(x) * y); } + auto inv() const -> type { return exp(Elements - log(x)); } // 1/x + + static auto log(uint x) -> uint { + enum : uint { Size = bit::round(Elements), Mask = Size - 1 }; + static array log = [] { + uint shift = 0, polynomial = Polynomial; + while(polynomial >>= 1) shift++; + shift--; + + array log; + field x = 1; + for(uint n : range(Elements)) { + log[x] = n; + x = x << 1 ^ (x >> shift ? Polynomial : 0); + } + log[0] = 0; //-inf (undefined) + return log; + }(); + return log[x & Mask]; + } + + static auto exp(uint x) -> uint { + static array exp = [] { + uint shift = 0, polynomial = Polynomial; + while(polynomial >>= 1) shift++; + shift--; + + array exp; + field x = 1; + for(uint n : range(Elements)) { + exp[n] = x; + x = x << 1 ^ (x >> shift ? Polynomial : 0); + } + return exp; + }(); + return exp[x % Elements]; + } + + field x; +}; + +} diff --git a/nall/hash/crc16.hpp b/nall/hash/crc16.hpp new file mode 100755 index 0000000..8058a40 --- /dev/null +++ b/nall/hash/crc16.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include + +namespace nall::Hash { + +struct CRC16 : Hash { + using Hash::input; + + CRC16(array_view buffer = {}) { + reset(); + input(buffer); + } + + auto reset() -> void override { + checksum = ~0; + } + + auto input(uint8_t value) -> void override { + checksum = (checksum >> 8) ^ table(checksum ^ value); + } + + auto output() const -> vector override { + vector result; + for(auto n : reverse(range(2))) result.append(~checksum >> n * 8); + return result; + } + + auto value() const -> uint16_t { + return ~checksum; + } + +private: + static auto table(uint8_t index) -> uint16_t { + static uint16_t table[256] = {0}; + static bool initialized = false; + + if(!initialized) { + initialized = true; + for(auto index : range(256)) { + uint16_t crc = index; + for(auto bit : range(8)) { + crc = (crc >> 1) ^ (crc & 1 ? 0x8408 : 0); + } + table[index] = crc; + } + } + + return table[index]; + } + + uint16_t checksum = 0; +}; + +} diff --git a/nall/hash/crc32.hpp b/nall/hash/crc32.hpp new file mode 100755 index 0000000..3931871 --- /dev/null +++ b/nall/hash/crc32.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include + +namespace nall::Hash { + +struct CRC32 : Hash { + using Hash::input; + + CRC32(array_view buffer = {}) { + reset(); + input(buffer); + } + + auto reset() -> void override { + checksum = ~0; + } + + auto input(uint8_t value) -> void override { + checksum = (checksum >> 8) ^ table(checksum ^ value); + } + + auto output() const -> vector { + vector result; + for(auto n : reverse(range(4))) result.append(~checksum >> n * 8); + return result; + } + + auto value() const -> uint32_t { + return ~checksum; + } + +private: + static auto table(uint8_t index) -> uint32_t { + static uint32_t table[256] = {0}; + static bool initialized = false; + + if(!initialized) { + initialized = true; + for(auto index : range(256)) { + uint32_t crc = index; + for(auto bit : range(8)) { + crc = (crc >> 1) ^ (crc & 1 ? 0xedb8'8320 : 0); + } + table[index] = crc; + } + } + + return table[index]; + } + + uint32_t checksum = 0; +}; + +} diff --git a/nall/hash/crc64.hpp b/nall/hash/crc64.hpp new file mode 100644 index 0000000..7364b0d --- /dev/null +++ b/nall/hash/crc64.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include + +namespace nall::Hash { + +struct CRC64 : Hash { + using Hash::input; + + CRC64(array_view buffer = {}) { + reset(); + input(buffer); + } + + auto reset() -> void override { + checksum = ~0; + } + + auto input(uint8_t value) -> void override { + checksum = (checksum >> 8) ^ table(checksum ^ value); + } + + auto output() const -> vector { + vector result; + for(auto n : reverse(range(8))) result.append(~checksum >> n * 8); + return result; + } + + auto value() const -> uint64_t { + return ~checksum; + } + +private: + static auto table(uint8_t index) -> uint64_t { + static uint64_t table[256] = {0}; + static bool initialized = false; + + if(!initialized) { + initialized = true; + for(auto index : range(256)) { + uint64_t crc = index; + for(auto bit : range(8)) { + crc = (crc >> 1) ^ (crc & 1 ? 0xc96c'5795'd787'0f42 : 0); + } + table[index] = crc; + } + } + + return table[index]; + } + + uint64_t checksum = 0; +}; + +} diff --git a/nall/hash/hash.hpp b/nall/hash/hash.hpp new file mode 100644 index 0000000..4565fe3 --- /dev/null +++ b/nall/hash/hash.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include + +//cannot use constructor inheritance due to needing to call virtual reset(); +//instead, define a macro to reduce boilerplate code in every Hash subclass +#define nallHash(Name) \ + Name() { reset(); } \ + Name(const void* data, uint64_t size) : Name() { input(data, size); } \ + Name(const vector& data) : Name() { input(data); } \ + Name(const string& data) : Name() { input(data); } \ + using Hash::input; \ + +namespace nall::Hash { + +struct Hash { + virtual auto reset() -> void = 0; + virtual auto input(uint8_t data) -> void = 0; + virtual auto output() const -> vector = 0; + + auto input(array_view data) -> void { + for(auto byte : data) input(byte); + } + + auto input(const void* data, uint64_t size) -> void { + auto p = (const uint8_t*)data; + while(size--) input(*p++); + } + + auto input(const vector& data) -> void { + for(auto byte : data) input(byte); + } + + auto input(const string& data) -> void { + for(auto byte : data) input(byte); + } + + auto digest() const -> string { + string result; + for(auto n : output()) result.append(hex(n, 2L)); + return result; + } +}; + +} diff --git a/nall/hash/sha224.hpp b/nall/hash/sha224.hpp new file mode 100644 index 0000000..6bcf785 --- /dev/null +++ b/nall/hash/sha224.hpp @@ -0,0 +1,106 @@ +#pragma once + +#include + +namespace nall::Hash { + +struct SHA224 : Hash { + using Hash::input; + + SHA224(array_view buffer = {}) { + reset(); + input(buffer); + } + + auto reset() -> void override { + for(auto& n : queue) n = 0; + for(auto& n : w) n = 0; + for(auto n : range(8)) h[n] = square(n); + queued = length = 0; + } + + auto input(uint8_t value) -> void override { + byte(value); + length++; + } + + auto output() const -> vector override { + SHA224 self(*this); + self.finish(); + vector result; + for(auto h : range(7)) { + for(auto n : reverse(range(4))) result.append(self.h[h] >> n * 8); + } + return result; + } + + auto value() const -> uint256_t { + uint256_t value = 0; + for(auto byte : output()) value = value << 8 | byte; + return value; + } + +private: + auto byte(uint8_t value) -> void { + uint32_t shift = (3 - (queued & 3)) * 8; + queue[queued >> 2] &= ~(0xff << shift); + queue[queued >> 2] |= (value << shift); + if(++queued == 64) block(), queued = 0; + } + + auto block() -> void { + for(auto n : range(16)) w[n] = queue[n]; + for(auto n : range(16, 64)) { + uint32_t a = ror(w[n - 15], 7) ^ ror(w[n - 15], 18) ^ (w[n - 15] >> 3); + uint32_t b = ror(w[n - 2], 17) ^ ror(w[n - 2], 19) ^ (w[n - 2] >> 10); + w[n] = w[n - 16] + w[n - 7] + a + b; + } + uint32_t t[8]; + for(auto n : range(8)) t[n] = h[n]; + for(auto n : range(64)) { + uint32_t a = ror(t[0], 2) ^ ror(t[0], 13) ^ ror(t[0], 22); + uint32_t b = ror(t[4], 6) ^ ror(t[4], 11) ^ ror(t[4], 25); + uint32_t c = (t[0] & t[1]) ^ (t[0] & t[2]) ^ (t[1] & t[2]); + uint32_t d = (t[4] & t[5]) ^ (~t[4] & t[6]); + uint32_t e = t[7] + w[n] + cube(n) + b + d; + t[7] = t[6]; t[6] = t[5]; t[5] = t[4]; t[4] = t[3] + e; + t[3] = t[2]; t[2] = t[1]; t[1] = t[0]; t[0] = a + c + e; + } + for(auto n : range(8)) h[n] += t[n]; + } + + auto finish() -> void { + byte(0x80); + while(queued != 56) byte(0x00); + for(auto n : range(8)) byte(length * 8 >> (7 - n) * 8); + } + + auto square(uint n) -> uint32_t { + static const uint32_t value[8] = { + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4, + }; + return value[n]; + } + + auto cube(uint n) -> uint32_t { + static const uint32_t value[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, + }; + return value[n]; + } + + uint32_t queue[16] = {0}; + uint32_t w[64] = {0}; + uint32_t h[8] = {0}; + uint32_t queued = 0; + uint64_t length = 0; +}; + +} diff --git a/nall/hash/sha256.hpp b/nall/hash/sha256.hpp new file mode 100755 index 0000000..27f42a0 --- /dev/null +++ b/nall/hash/sha256.hpp @@ -0,0 +1,106 @@ +#pragma once + +#include + +namespace nall::Hash { + +struct SHA256 : Hash { + using Hash::input; + + SHA256(array_view buffer = {}) { + reset(); + input(buffer); + } + + auto reset() -> void override { + for(auto& n : queue) n = 0; + for(auto& n : w) n = 0; + for(auto n : range(8)) h[n] = square(n); + queued = length = 0; + } + + auto input(uint8_t value) -> void override { + byte(value); + length++; + } + + auto output() const -> vector override { + SHA256 self(*this); + self.finish(); + vector result; + for(auto h : self.h) { + for(auto n : reverse(range(4))) result.append(h >> n * 8); + } + return result; + } + + auto value() const -> uint256_t { + uint256_t value = 0; + for(auto byte : output()) value = value << 8 | byte; + return value; + } + +private: + auto byte(uint8_t value) -> void { + uint32_t shift = (3 - (queued & 3)) * 8; + queue[queued >> 2] &= ~(0xff << shift); + queue[queued >> 2] |= (value << shift); + if(++queued == 64) block(), queued = 0; + } + + auto block() -> void { + for(auto n : range(16)) w[n] = queue[n]; + for(auto n : range(16, 64)) { + uint32_t a = ror(w[n - 15], 7) ^ ror(w[n - 15], 18) ^ (w[n - 15] >> 3); + uint32_t b = ror(w[n - 2], 17) ^ ror(w[n - 2], 19) ^ (w[n - 2] >> 10); + w[n] = w[n - 16] + w[n - 7] + a + b; + } + uint32_t t[8]; + for(auto n : range(8)) t[n] = h[n]; + for(auto n : range(64)) { + uint32_t a = ror(t[0], 2) ^ ror(t[0], 13) ^ ror(t[0], 22); + uint32_t b = ror(t[4], 6) ^ ror(t[4], 11) ^ ror(t[4], 25); + uint32_t c = (t[0] & t[1]) ^ (t[0] & t[2]) ^ (t[1] & t[2]); + uint32_t d = (t[4] & t[5]) ^ (~t[4] & t[6]); + uint32_t e = t[7] + w[n] + cube(n) + b + d; + t[7] = t[6]; t[6] = t[5]; t[5] = t[4]; t[4] = t[3] + e; + t[3] = t[2]; t[2] = t[1]; t[1] = t[0]; t[0] = a + c + e; + } + for(auto n : range(8)) h[n] += t[n]; + } + + auto finish() -> void { + byte(0x80); + while(queued != 56) byte(0x00); + for(auto n : range(8)) byte(length * 8 >> (7 - n) * 8); + } + + auto square(uint n) -> uint32_t { + static const uint32_t value[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, + }; + return value[n]; + } + + auto cube(uint n) -> uint32_t { + static const uint32_t value[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, + }; + return value[n]; + } + + uint32_t queue[16] = {0}; + uint32_t w[64] = {0}; + uint32_t h[8] = {0}; + uint32_t queued = 0; + uint64_t length = 0; +}; + +} diff --git a/nall/hash/sha384.hpp b/nall/hash/sha384.hpp new file mode 100644 index 0000000..09dbbdb --- /dev/null +++ b/nall/hash/sha384.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include + +namespace nall::Hash { + +struct SHA384 : Hash { + using Hash::input; + + SHA384(array_view buffer = {}) { + reset(); + input(buffer); + } + + auto reset() -> void override { + for(auto& n : queue) n = 0; + for(auto& n : w) n = 0; + for(auto n : range(8)) h[n] = square(n); + queued = length = 0; + } + + auto input(uint8_t data) -> void override { + byte(data); + length++; + } + + auto output() const -> vector override { + SHA384 self(*this); + self.finish(); + vector result; + for(auto h : range(6)) { + for(auto n : reverse(range(8))) result.append(self.h[h] >> n * 8); + } + return result; + } + + auto value() const -> uint512_t { + uint512_t value = 0; + for(auto byte : output()) value = value << 8 | byte; + return value; + } + +private: + auto byte(uint8_t data) -> void { + uint64_t shift = (7 - (queued & 7)) * 8; + queue[queued >> 3] &=~((uint64_t)0xff << shift); + queue[queued >> 3] |= ((uint64_t)data << shift); + if(++queued == 128) block(), queued = 0; + } + + auto block() -> void { + for(auto n : range(16)) w[n] = queue[n]; + for(auto n : range(16, 80)) { + uint64_t a = ror(w[n - 15], 1) ^ ror(w[n - 15], 8) ^ (w[n - 15] >> 7); + uint64_t b = ror(w[n - 2], 19) ^ ror(w[n - 2], 61) ^ (w[n - 2] >> 6); + w[n] = w[n - 16] + w[n - 7] + a + b; + } + uint64_t t[8]; + for(auto n : range(8)) t[n] = h[n]; + for(auto n : range(80)) { + uint64_t a = ror(t[0], 28) ^ ror(t[0], 34) ^ ror(t[0], 39); + uint64_t b = ror(t[4], 14) ^ ror(t[4], 18) ^ ror(t[4], 41); + uint64_t c = (t[0] & t[1]) ^ (t[0] & t[2]) ^ (t[1] & t[2]); + uint64_t d = (t[4] & t[5]) ^ (~t[4] & t[6]); + uint64_t e = t[7] + w[n] + cube(n) + b + d; + t[7] = t[6]; t[6] = t[5]; t[5] = t[4]; t[4] = t[3] + e; + t[3] = t[2]; t[2] = t[1]; t[1] = t[0]; t[0] = a + c + e; + } + for(auto n : range(8)) h[n] += t[n]; + } + + auto finish() -> void { + byte(0x80); + while(queued != 112) byte(0x00); + for(auto n : range(16)) byte(length * 8 >> (15 - n) * 8); + } + + auto square(uint n) -> uint64_t { + static const uint64_t data[8] = { + 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, + 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4, + }; + return data[n]; + } + + auto cube(uint n) -> uint64_t { + static const uint64_t data[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, + }; + return data[n]; + } + + uint64_t queue[16] = {0}; + uint64_t w[80] = {0}; + uint64_t h[8] = {0}; + uint64_t queued = 0; + uint128_t length = 0; +}; + +} diff --git a/nall/hash/sha512.hpp b/nall/hash/sha512.hpp new file mode 100644 index 0000000..f76d2d5 --- /dev/null +++ b/nall/hash/sha512.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include + +namespace nall::Hash { + +struct SHA512 : Hash { + using Hash::input; + + SHA512(array_view buffer = {}) { + reset(); + input(buffer); + } + + auto reset() -> void override { + for(auto& n : queue) n = 0; + for(auto& n : w) n = 0; + for(auto n : range(8)) h[n] = square(n); + queued = length = 0; + } + + auto input(uint8_t data) -> void override { + byte(data); + length++; + } + + auto output() const -> vector override { + SHA512 self(*this); + self.finish(); + vector result; + for(auto h : self.h) { + for(auto n : reverse(range(8))) result.append(h >> n * 8); + } + return result; + } + + auto value() const -> uint512_t { + uint512_t value = 0; + for(auto byte : output()) value = value << 8 | byte; + return value; + } + +private: + auto byte(uint8_t data) -> void { + uint64_t shift = (7 - (queued & 7)) * 8; + queue[queued >> 3] &=~((uint64_t)0xff << shift); + queue[queued >> 3] |= ((uint64_t)data << shift); + if(++queued == 128) block(), queued = 0; + } + + auto block() -> void { + for(auto n : range(16)) w[n] = queue[n]; + for(auto n : range(16, 80)) { + uint64_t a = ror(w[n - 15], 1) ^ ror(w[n - 15], 8) ^ (w[n - 15] >> 7); + uint64_t b = ror(w[n - 2], 19) ^ ror(w[n - 2], 61) ^ (w[n - 2] >> 6); + w[n] = w[n - 16] + w[n - 7] + a + b; + } + uint64_t t[8]; + for(auto n : range(8)) t[n] = h[n]; + for(auto n : range(80)) { + uint64_t a = ror(t[0], 28) ^ ror(t[0], 34) ^ ror(t[0], 39); + uint64_t b = ror(t[4], 14) ^ ror(t[4], 18) ^ ror(t[4], 41); + uint64_t c = (t[0] & t[1]) ^ (t[0] & t[2]) ^ (t[1] & t[2]); + uint64_t d = (t[4] & t[5]) ^ (~t[4] & t[6]); + uint64_t e = t[7] + w[n] + cube(n) + b + d; + t[7] = t[6]; t[6] = t[5]; t[5] = t[4]; t[4] = t[3] + e; + t[3] = t[2]; t[2] = t[1]; t[1] = t[0]; t[0] = a + c + e; + } + for(auto n : range(8)) h[n] += t[n]; + } + + auto finish() -> void { + byte(0x80); + while(queued != 112) byte(0x00); + for(auto n : range(16)) byte(length * 8 >> (15 - n) * 8); + } + + auto square(uint n) -> uint64_t { + static const uint64_t data[8] = { + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, + }; + return data[n]; + } + + auto cube(uint n) -> uint64_t { + static const uint64_t data[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, + }; + return data[n]; + } + + uint64_t queue[16] = {0}; + uint64_t w[80] = {0}; + uint64_t h[8] = {0}; + uint64_t queued = 0; + uint128_t length = 0; +}; + +} diff --git a/nall/hashset.hpp b/nall/hashset.hpp new file mode 100755 index 0000000..6812eaf --- /dev/null +++ b/nall/hashset.hpp @@ -0,0 +1,133 @@ +#pragma once + +//hashset +// +//search: O(1) average; O(n) worst +//insert: O(1) average; O(n) worst +//remove: O(1) average; O(n) worst +// +//requirements: +// auto T::hash() const -> uint; +// auto T::operator==(const T&) const -> bool; + +namespace nall { + +template +struct hashset { + hashset() = default; + hashset(uint length) : length(bit::round(length)) {} + hashset(const hashset& source) { operator=(source); } + hashset(hashset&& source) { operator=(move(source)); } + ~hashset() { reset(); } + + auto operator=(const hashset& source) -> hashset& { + reset(); + if(source.pool) { + for(uint n : range(source.count)) { + insert(*source.pool[n]); + } + } + return *this; + } + + auto operator=(hashset&& source) -> hashset& { + reset(); + pool = source.pool; + length = source.length; + count = source.count; + source.pool = nullptr; + source.length = 8; + source.count = 0; + return *this; + } + + explicit operator bool() const { return count; } + auto capacity() const -> uint { return length; } + auto size() const -> uint { return count; } + + auto reset() -> void { + if(pool) { + for(uint n : range(length)) { + if(pool[n]) { + delete pool[n]; + pool[n] = nullptr; + } + } + delete pool; + pool = nullptr; + } + length = 8; + count = 0; + } + + auto reserve(uint size) -> void { + //ensure all items will fit into pool (with <= 50% load) and amortize growth + size = bit::round(max(size, count << 1)); + T** copy = new T*[size](); + + if(pool) { + for(uint n : range(length)) { + if(pool[n]) { + uint hash = (*pool[n]).hash() & (size - 1); + while(copy[hash]) if(++hash >= size) hash = 0; + copy[hash] = pool[n]; + pool[n] = nullptr; + } + } + } + + delete pool; + pool = copy; + length = size; + } + + auto find(const T& value) -> maybe { + if(!pool) return nothing; + + uint hash = value.hash() & (length - 1); + while(pool[hash]) { + if(value == *pool[hash]) return *pool[hash]; + if(++hash >= length) hash = 0; + } + + return nothing; + } + + auto insert(const T& value) -> maybe { + if(!pool) pool = new T*[length](); + + //double pool size when load is >= 50% + if(count >= (length >> 1)) reserve(length << 1); + count++; + + uint hash = value.hash() & (length - 1); + while(pool[hash]) if(++hash >= length) hash = 0; + pool[hash] = new T(value); + + return *pool[hash]; + } + + auto remove(const T& value) -> bool { + if(!pool) return false; + + uint hash = value.hash() & (length - 1); + while(pool[hash]) { + if(value == *pool[hash]) { + delete pool[hash]; + pool[hash] = nullptr; + count--; + return true; + } + if(++hash >= length) hash = 0; + } + + return false; + } + +protected: + T** pool = nullptr; + uint length = 8; //length of pool + uint count = 0; //number of objects inside of the pool +}; + +} diff --git a/nall/hid.hpp b/nall/hid.hpp new file mode 100755 index 0000000..e002c65 --- /dev/null +++ b/nall/hid.hpp @@ -0,0 +1,121 @@ +#pragma once + +#include +#include +#include +#include + +namespace nall::HID { + +struct Input { + Input(const string& name) : _name(name) {} + + auto name() const -> string { return _name; } + auto value() const -> int16_t { return _value; } + auto setValue(int16_t value) -> void { _value = value; } + +private: + string _name; + int16_t _value = 0; + friend class Group; +}; + +struct Group : vector { + Group(const string& name) : _name(name) {} + + auto name() const -> string { return _name; } + auto input(uint id) -> Input& { return operator[](id); } + auto append(const string& name) -> void { vector::append(Input{name}); } + + auto find(const string& name) const -> maybe { + for(auto id : range(size())) { + if(operator[](id)._name == name) return id; + } + return nothing; + } + +private: + string _name; + friend class Device; +}; + +struct Device : vector { + Device(const string& name) : _name(name) {} + + //id => {pathID}-{vendorID}-{productID} + auto pathID() const -> uint32_t { return (uint32_t)(_id >> 32); } //32-63 + auto vendorID() const -> uint16_t { return (uint16_t)(_id >> 16); } //16-31 + auto productID() const -> uint16_t { return (uint16_t)(_id >> 0); } // 0-15 + + auto setPathID (uint32_t pathID ) -> void { _id = (uint64_t)pathID << 32 | vendorID() << 16 | productID() << 0; } + auto setVendorID (uint16_t vendorID ) -> void { _id = (uint64_t)pathID() << 32 | vendorID << 16 | productID() << 0; } + auto setProductID(uint16_t productID) -> void { _id = (uint64_t)pathID() << 32 | vendorID() << 16 | productID << 0; } + + virtual auto isNull() const -> bool { return false; } + virtual auto isKeyboard() const -> bool { return false; } + virtual auto isMouse() const -> bool { return false; } + virtual auto isJoypad() const -> bool { return false; } + + auto name() const -> string { return _name; } + auto id() const -> uint64_t { return _id; } + auto setID(uint64_t id) -> void { _id = id; } + auto group(uint id) -> Group& { return operator[](id); } + auto append(const string& name) -> void { vector::append(Group{name}); } + + auto find(const string& name) const -> maybe { + for(auto id : range(size())) { + if(operator[](id)._name == name) return id; + } + return nothing; + } + +private: + string _name; + uint64_t _id = 0; +}; + +struct Null : Device { + enum : uint16_t { GenericVendorID = 0x0000, GenericProductID = 0x0000 }; + + Null() : Device("Null") {} + auto isNull() const -> bool { return true; } +}; + +struct Keyboard : Device { + enum : uint16_t { GenericVendorID = 0x0000, GenericProductID = 0x0001 }; + enum GroupID : uint { Button }; + + Keyboard() : Device("Keyboard") { append("Button"); } + auto isKeyboard() const -> bool { return true; } + auto buttons() -> Group& { return group(GroupID::Button); } +}; + +struct Mouse : Device { + enum : uint16_t { GenericVendorID = 0x0000, GenericProductID = 0x0002 }; + enum GroupID : uint { Axis, Button }; + + Mouse() : Device("Mouse") { append("Axis"), append("Button"); } + auto isMouse() const -> bool { return true; } + auto axes() -> Group& { return group(GroupID::Axis); } + auto buttons() -> Group& { return group(GroupID::Button); } +}; + +struct Joypad : Device { + enum : uint16_t { GenericVendorID = 0x0000, GenericProductID = 0x0003 }; + enum GroupID : uint { Axis, Hat, Trigger, Button }; + + Joypad() : Device("Joypad") { append("Axis"), append("Hat"), append("Trigger"), append("Button"); } + auto isJoypad() const -> bool { return true; } + auto axes() -> Group& { return group(GroupID::Axis); } + auto hats() -> Group& { return group(GroupID::Hat); } + auto triggers() -> Group& { return group(GroupID::Trigger); } + auto buttons() -> Group& { return group(GroupID::Button); } + + auto rumble() const -> bool { return _rumble; } + auto setRumble(bool rumble) -> void { _rumble = rumble; } + +private: + bool _rumble = false; +}; + +} diff --git a/nall/http/client.hpp b/nall/http/client.hpp new file mode 100755 index 0000000..17a6a43 --- /dev/null +++ b/nall/http/client.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include + +namespace nall::HTTP { + +struct Client : Role { + inline auto open(const string& hostname, uint port = 80) -> bool; + inline auto upload(const Request& request) -> bool; + inline auto download(const Request& request) -> Response; + inline auto close() -> void; + ~Client() { close(); } + +private: + int fd = -1; + addrinfo* info = nullptr; +}; + +auto Client::open(const string& hostname, uint port) -> bool { + addrinfo hint = {0}; + hint.ai_family = AF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + hint.ai_flags = AI_ADDRCONFIG; + + if(getaddrinfo(hostname, string{port}, &hint, &info) != 0) return close(), false; + + fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol); + if(fd < 0) return close(), false; + + if(connect(fd, info->ai_addr, info->ai_addrlen) < 0) return close(), false; + return true; +} + +auto Client::upload(const Request& request) -> bool { + return Role::upload(fd, request); +} + +auto Client::download(const Request& request) -> Response { + Response response(request); + Role::download(fd, response); + return response; +} + +auto Client::close() -> void { + if(fd) { + ::close(fd); + fd = -1; + } + + if(info) { + freeaddrinfo(info); + info = nullptr; + } +} + +} diff --git a/nall/http/message.hpp b/nall/http/message.hpp new file mode 100755 index 0000000..e4c543d --- /dev/null +++ b/nall/http/message.hpp @@ -0,0 +1,104 @@ +#pragma once + +//httpMessage: base class for httpRequest and httpResponse +//provides shared functionality + +namespace nall::HTTP { + +struct Variable { + string name; + string value; +}; + +struct SharedVariable { + SharedVariable(const nall::string& name = "", const nall::string& value = "") : shared(new Variable{name, value}) {} + + explicit operator bool() const { return (bool)shared->name; } + auto operator()() const { return shared->value; } + auto& operator=(const nall::string& value) { shared->value = value; return *this; } + + auto name() const { return shared->name; } + auto value() const { return shared->value; } + auto string() const { return nall::string{shared->value}.strip().replace("\r", ""); } + auto boolean() const { return string() == "true"; } + auto integer() const { return string().integer(); } + auto natural() const { return string().natural(); } + auto real() const { return string().real(); } + + auto& setName(const nall::string& name) { shared->name = name; return *this; } + auto& setValue(const nall::string& value = "") { shared->value = value; return *this; } + + shared_pointer shared; +}; + +struct Variables { + auto operator[](const string& name) const -> SharedVariable { + for(auto& variable : variables) { + if(variable.shared->name.iequals(name)) return variable; + } + return {}; + } + + auto operator()(const string& name) -> SharedVariable { + for(auto& variable : variables) { + if(variable.shared->name.iequals(name)) return variable; + } + return append(name); + } + + auto find(const string& name) const -> vector { + vector result; + for(auto& variable : variables) { + if(variable.shared->name.iequals(name)) result.append(variable); + } + return result; + } + + auto assign(const string& name, const string& value = "") -> SharedVariable { + for(auto& variable : variables) { + if(variable.shared->name.iequals(name)) { + variable.shared->value = value; + return variable; + } + } + return append(name, value); + } + + auto append(const string& name, const string& value = "") -> SharedVariable { + SharedVariable variable{name, value}; + variables.append(variable); + return variable; + } + + auto remove(const string& name) -> void { + for(auto n : reverse(range(variables.size()))) { + if(variables[n].shared->name.iequals(name)) variables.remove(n); + } + } + + auto size() const { return variables.size(); } + auto begin() const { return variables.begin(); } + auto end() const { return variables.end(); } + auto begin() { return variables.begin(); } + auto end() { return variables.end(); } + + vector variables; +}; + +struct Message { + using type = Message; + + virtual auto head(const function& callback) const -> bool = 0; + virtual auto setHead() -> bool = 0; + + virtual auto body(const function& callback) const -> bool = 0; + virtual auto setBody() -> bool = 0; + + Variables header; + +//private: + string _head; + string _body; +}; + +} diff --git a/nall/http/request.hpp b/nall/http/request.hpp new file mode 100755 index 0000000..081c1c7 --- /dev/null +++ b/nall/http/request.hpp @@ -0,0 +1,184 @@ +#pragma once + +#include +#include +#include + +namespace nall::HTTP { + +struct Request : Message { + using type = Request; + + enum class RequestType : uint { None, Head, Get, Post }; + + explicit operator bool() const { return requestType() != RequestType::None; } + + inline auto head(const function& callback) const -> bool override; + inline auto setHead() -> bool override; + + inline auto body(const function& callback) const -> bool override; + inline auto setBody() -> bool override; + + auto ipv4() const -> bool { return _ipv6 == false; } + auto ipv6() const -> bool { return _ipv6 == true; } + auto ip() const -> string { return _ip; } + + auto requestType() const -> RequestType { return _requestType; } + auto setRequestType(RequestType value) -> void { _requestType = value; } + + auto path() const -> string { return _path; } + auto setPath(const string& value) -> void { _path = value; } + + Variables cookie; + Variables get; + Variables post; + +//private: + bool _ipv6 = false; + string _ip; + RequestType _requestType = RequestType::None; + string _path; +}; + +auto Request::head(const function& callback) const -> bool { + if(!callback) return false; + string output; + + string request = path(); + if(get.size()) { + request.append("?"); + for(auto& variable : get) { + request.append(Encode::URL(variable.name()), "=", Encode::URL(variable.value()), "&"); + } + request.trimRight("&", 1L); + } + + switch(requestType()) { + case RequestType::Head: output.append("HEAD ", request, " HTTP/1.1\r\n"); break; + case RequestType::Get : output.append("GET ", request, " HTTP/1.1\r\n"); break; + case RequestType::Post: output.append("POST ", request, " HTTP/1.1\r\n"); break; + default: return false; + } + + for(auto& variable : header) { + output.append(variable.name(), ": ", variable.value(), "\r\n"); + } + output.append("\r\n"); + + return callback(output.data(), output.size()); +} + +auto Request::setHead() -> bool { + auto headers = _head.split("\n"); + string request = headers.takeLeft().trimRight("\r", 1L); + string requestHost; + + if(request.iendsWith(" HTTP/1.0")) request.itrimRight(" HTTP/1.0", 1L); + else if(request.iendsWith(" HTTP/1.1")) request.itrimRight(" HTTP/1.1", 1L); + else return false; + + if(request.ibeginsWith("HEAD ")) request.itrimLeft("HEAD ", 1L), setRequestType(RequestType::Head); + else if(request.ibeginsWith("GET " )) request.itrimLeft("GET ", 1L), setRequestType(RequestType::Get ); + else if(request.ibeginsWith("POST ")) request.itrimLeft("POST ", 1L), setRequestType(RequestType::Post); + else return false; + + //decode absolute URIs + request.strip().itrimLeft("http://", 1L); + if(!request.beginsWith("/")) { + auto components = request.split("/", 1L); + requestHost = components(0); + request = {"/", components(1)}; + } + + auto components = request.split("?", 1L); + setPath(components(0)); + + if(auto queryString = components(1)) { + for(auto& block : queryString.split("&")) { + auto p = block.split("=", 1L); + auto name = Decode::URL(p(0)); + auto value = Decode::URL(p(1)); + if(name) get.append(name, value); + } + } + + for(auto& header : headers) { + if(header.beginsWith(" ") || header.beginsWith("\t")) continue; + auto part = header.split(":", 1L).strip(); + if(!part[0] || part.size() != 2) continue; + this->header.append(part[0], part[1]); + + if(part[0].iequals("Cookie")) { + for(auto& block : part[1].split(";")) { + auto p = block.split("=", 1L).strip(); + auto name = p(0); + auto value = p(1).trim("\"", "\"", 1L); + if(name) cookie.append(name, value); + } + } + } + + if(requestHost) header.assign("Host", requestHost); //request URI overrides host header + return true; +} + +auto Request::body(const function& callback) const -> bool { + if(!callback) return false; + + if(_body) { + return callback(_body.data(), _body.size()); + } + + return true; +} + +auto Request::setBody() -> bool { + if(requestType() == RequestType::Post) { + auto contentType = header["Content-Type"].value(); + if(contentType.iequals("application/x-www-form-urlencoded")) { + for(auto& block : _body.split("&")) { + auto p = block.trimRight("\r").split("=", 1L); + auto name = Decode::URL(p(0)); + auto value = Decode::URL(p(1)); + if(name) post.append(name, value); + } + } else if(contentType.imatch("multipart/form-data; boundary=?*")) { + auto boundary = contentType.itrimLeft("multipart/form-data; boundary=", 1L).trim("\"", "\"", 1L); + auto blocks = _body.split({"--", boundary}, 1024L); //limit blocks to prevent memory exhaustion + for(auto& block : blocks) block.trim("\r\n", "\r\n", 1L); + if(blocks.size() < 2 || (blocks.takeLeft(), !blocks.takeRight().beginsWith("--"))) return false; + for(auto& block : blocks) { + string name; + string filename; + string contentType; + + auto segments = block.split("\r\n\r\n", 1L); + for(auto& segment : segments(0).split("\r\n")) { + auto statement = segment.split(":", 1L); + if(statement(0).ibeginsWith("Content-Disposition")) { + for(auto& component : statement(1).split(";")) { + auto part = component.split("=", 1L).strip(); + if(part(0).iequals("name")) { + name = part(1).trim("\"", "\"", 1L); + } else if(part(0).iequals("filename")) { + filename = part(1).trim("\"", "\"", 1L); + } + } + } else if(statement(0).ibeginsWith("Content-Type")) { + contentType = statement(1).strip(); + } + } + + if(name) { + post.append(name, segments(1)); + post.append({name, ".filename"}, filename); + post.append({name, ".content-type"}, contentType); + } + } + } + } + + return true; +} + +} diff --git a/nall/http/response.hpp b/nall/http/response.hpp new file mode 100755 index 0000000..a55d870 --- /dev/null +++ b/nall/http/response.hpp @@ -0,0 +1,273 @@ +#pragma once + +#include + +namespace nall::HTTP { + +struct Response : Message { + using type = Response; + + Response() = default; + Response(const Request& request) { setRequest(request); } + + explicit operator bool() const { return responseType() != 0; } + auto operator()(uint responseType) -> type& { return setResponseType(responseType); } + + inline auto head(const function& callback) const -> bool override; + inline auto setHead() -> bool override; + + inline auto body(const function& callback) const -> bool override; + inline auto setBody() -> bool override; + + auto request() const -> const Request* { return _request; } + auto setRequest(const Request& value) -> type& { _request = &value; return *this; } + + auto responseType() const -> uint { return _responseType; } + auto setResponseType(uint value) -> type& { _responseType = value; return *this; } + + auto hasData() const -> bool { return (bool)_data; } + auto data() const -> const vector& { return _data; } + inline auto setData(const vector& value) -> type&; + + auto hasFile() const -> bool { return (bool)_file; } + auto file() const -> const string& { return _file; } + inline auto setFile(const string& value) -> type&; + + auto hasText() const -> bool { return (bool)_text; } + auto text() const -> const string& { return _text; } + inline auto setText(const string& value) -> type&; + + inline auto hasBody() const -> bool; + inline auto findContentLength() const -> uint; + inline auto findContentType() const -> string; + inline auto findContentType(const string& suffix) const -> string; + inline auto findResponseType() const -> string; + inline auto setFileETag() -> void; + + const Request* _request = nullptr; + uint _responseType = 0; + vector _data; + string _file; + string _text; +}; + +auto Response::head(const function& callback) const -> bool { + if(!callback) return false; + string output; + + if(auto request = this->request()) { + if(auto eTag = header["ETag"]) { + if(eTag.value() == request->header["If-None-Match"].value()) { + output.append("HTTP/1.1 304 Not Modified\r\n"); + output.append("Connection: close\r\n"); + output.append("\r\n"); + return callback(output.data(), output.size()); + } + } + } + + output.append("HTTP/1.1 ", findResponseType(), "\r\n"); + for(auto& variable : header) { + output.append(variable.name(), ": ", variable.value(), "\r\n"); + } + if(hasBody()) { + if(!header["Content-Length"] && !header["Transfer-Encoding"].value().iequals("chunked")) { + output.append("Content-Length: ", findContentLength(), "\r\n"); + } + if(!header["Content-Type"]) { + output.append("Content-Type: ", findContentType(), "\r\n"); + } + } + if(!header["Connection"]) { + output.append("Connection: close\r\n"); + } + output.append("\r\n"); + + return callback(output.data(), output.size()); +} + +auto Response::setHead() -> bool { + auto headers = _head.split("\n"); + string response = headers.takeLeft().trimRight("\r"); + + if(response.ibeginsWith("HTTP/1.0 ")) response.itrimLeft("HTTP/1.0 ", 1L); + else if(response.ibeginsWith("HTTP/1.1 ")) response.itrimLeft("HTTP/1.1 ", 1L); + else return false; + + setResponseType(response.natural()); + + for(auto& header : headers) { + if(header.beginsWith(" ") || header.beginsWith("\t")) continue; + auto variable = header.split(":", 1L).strip(); + if(variable.size() != 2) continue; + this->header.append(variable[0], variable[1]); + } + + return true; +} + +auto Response::body(const function& callback) const -> bool { + if(!callback) return false; + if(!hasBody()) return true; + bool chunked = header["Transfer-Encoding"].value() == "chunked"; + + if(chunked) { + string prefix = {hex(findContentLength()), "\r\n"}; + if(!callback(prefix.data(), prefix.size())) return false; + } + + if(_body) { + if(!callback(_body.data(), _body.size())) return false; + } else if(hasData()) { + if(!callback(data().data(), data().size())) return false; + } else if(hasFile()) { + file_map map(file(), file_map::mode::read); + if(!callback(map.data(), map.size())) return false; + } else if(hasText()) { + if(!callback(text().data(), text().size())) return false; + } else { + string response = findResponseType(); + if(!callback(response.data(), response.size())) return false; + } + + if(chunked) { + string suffix = {"\r\n0\r\n\r\n"}; + if(!callback(suffix.data(), suffix.size())) return false; + } + + return true; +} + +auto Response::setBody() -> bool { + return true; +} + +auto Response::hasBody() const -> bool { + if(auto request = this->request()) { + if(request->requestType() == Request::RequestType::Head) return false; + } + if(responseType() == 301) return false; + if(responseType() == 302) return false; + if(responseType() == 303) return false; + if(responseType() == 304) return false; + if(responseType() == 307) return false; + return true; +} + +auto Response::findContentLength() const -> uint { + if(auto contentLength = header["Content-Length"]) return contentLength.value().natural(); + if(_body) return _body.size(); + if(hasData()) return data().size(); + if(hasFile()) return file::size(file()); + if(hasText()) return text().size(); + return findResponseType().size(); +} + +auto Response::findContentType() const -> string { + if(auto contentType = header["Content-Type"]) return contentType.value(); + if(hasData()) return "application/octet-stream"; + if(hasFile()) return findContentType(Location::suffix(file())); + return "text/html; charset=utf-8"; +} + +auto Response::findContentType(const string& s) const -> string { + if(s == ".7z" ) return "application/x-7z-compressed"; + if(s == ".avi" ) return "video/avi"; + if(s == ".bml" ) return "text/plain; charset=utf-8"; + if(s == ".bz2" ) return "application/x-bzip2"; + if(s == ".css" ) return "text/css; charset=utf-8"; + if(s == ".gif" ) return "image/gif"; + if(s == ".gz" ) return "application/gzip"; + if(s == ".htm" ) return "text/html; charset=utf-8"; + if(s == ".html") return "text/html; charset=utf-8"; + if(s == ".ico" ) return "image/x-icon"; + if(s == ".jpg" ) return "image/jpeg"; + if(s == ".jpeg") return "image/jpeg"; + if(s == ".js" ) return "application/javascript"; + if(s == ".mka" ) return "audio/x-matroska"; + if(s == ".mkv" ) return "video/x-matroska"; + if(s == ".mp3" ) return "audio/mpeg"; + if(s == ".mp4" ) return "video/mp4"; + if(s == ".mpeg") return "video/mpeg"; + if(s == ".mpg" ) return "video/mpeg"; + if(s == ".ogg" ) return "audio/ogg"; + if(s == ".pdf" ) return "application/pdf"; + if(s == ".png" ) return "image/png"; + if(s == ".rar" ) return "application/x-rar-compressed"; + if(s == ".svg" ) return "image/svg+xml"; + if(s == ".tar" ) return "application/x-tar"; + if(s == ".txt" ) return "text/plain; charset=utf-8"; + if(s == ".wav" ) return "audio/vnd.wave"; + if(s == ".webm") return "video/webm"; + if(s == ".xml" ) return "text/xml; charset=utf-8"; + if(s == ".xz" ) return "application/x-xz"; + if(s == ".zip" ) return "application/zip"; + return "application/octet-stream"; //binary +} + +auto Response::findResponseType() const -> string { + switch(responseType()) { + case 200: return "200 OK"; + case 301: return "301 Moved Permanently"; + case 302: return "302 Found"; + case 303: return "303 See Other"; + case 304: return "304 Not Modified"; + case 307: return "307 Temporary Redirect"; + case 400: return "400 Bad Request"; + case 403: return "403 Forbidden"; + case 404: return "404 Not Found"; + case 500: return "500 Internal Server Error"; + case 501: return "501 Not Implemented"; + case 503: return "503 Service Unavailable"; + } + return "501 Not Implemented"; +} + +auto Response::setData(const vector& value) -> type& { + _data = value; + header.assign("Content-Length", value.size()); + return *this; +} + +auto Response::setFile(const string& value) -> type& { + //block path escalation exploits ("../" and "..\" in the file location) + bool valid = true; + for(uint n : range(value.size())) { + if(value(n + 0, '\0') != '.') continue; + if(value(n + 1, '\0') != '.') continue; + if(value(n + 2, '\0') != '/' && value(n + 2, '\0') != '\\') continue; + valid = false; + break; + } + if(!valid) return *this; + + //cache images for seven days + auto suffix = Location::suffix(value); + uint maxAge = 0; + if(suffix == ".svg" + || suffix == ".ico" + || suffix == ".png" + || suffix == ".gif" + || suffix == ".jpg" + || suffix == ".jpeg") { + maxAge = 7 * 24 * 60 * 60; + } + + _file = value; + header.assign("Content-Length", file::size(value)); + header.assign("ETag", {"\"", chrono::utc::datetime(file::timestamp(value, file::time::modify)), "\""}); + if(maxAge == 0) { + header.assign("Cache-Control", {"public"}); + } else { + header.assign("Cache-Control", {"public, max-age=", maxAge}); + } + return *this; +} + +auto Response::setText(const string& value) -> type& { + _text = value; + header.assign("Content-Length", value.size()); + return *this; +} + +} diff --git a/nall/http/role.hpp b/nall/http/role.hpp new file mode 100755 index 0000000..5a9abcf --- /dev/null +++ b/nall/http/role.hpp @@ -0,0 +1,158 @@ +#pragma once + +//Role: base class for Client and Server +//provides shared functionality + +#include +#include + +namespace nall::HTTP { + +struct Role { + struct Settings { + int connectionLimit = 1 * 1024; //server + int headSizeLimit = 16 * 1024; //client, server + int bodySizeLimit = 65536 * 1024; //client, server + int chunkSize = 32 * 1024; //client, server + int threadStackSize = 128 * 1024; //server + int timeoutReceive = 15 * 1000; //server + int timeoutSend = 15 * 1000; //server + } settings; + + inline auto configure(const string& parameters) -> bool; + inline auto download(int fd, Message& message) -> bool; + inline auto upload(int fd, const Message& message) -> bool; +}; + +auto Role::configure(const string& parameters) -> bool { + auto document = BML::unserialize(parameters); + for(auto parameter : document) { + auto name = parameter.name(); + auto value = parameter.integer(); + + if(0); + else if(name == "connectionLimit") settings.connectionLimit = value; + else if(name == "headSizeLimit") settings.headSizeLimit = value; + else if(name == "bodySizeLimit") settings.bodySizeLimit = value; + else if(name == "chunkSize") settings.chunkSize = value; + else if(name == "threadStackSize") settings.threadStackSize = value; + else if(name == "timeoutReceive") settings.timeoutReceive = value; + else if(name == "timeoutSend") settings.timeoutSend = value; + } + return true; +} + +auto Role::download(int fd, Message& message) -> bool { + auto& head = message._head; + auto& body = message._body; + string chunk; + uint8_t packet[settings.chunkSize], *p = nullptr; + + head.reset(), head.reserve(4095); + body.reset(), body.reserve(4095); + + bool headReceived = false; + bool chunked = false; + bool chunkReceived = false; + bool chunkFooterReceived = true; + int length = 0; + int chunkLength = 0; + int contentLength = 0; + + while(true) { + if(auto limit = settings.headSizeLimit) if(head.size() >= limit) return false; + if(auto limit = settings.bodySizeLimit) if(body.size() >= limit) return false; + + if(headReceived && !chunked && body.size() >= contentLength) { + body.resize(contentLength); + break; + } + + if(length == 0) { + length = recv(fd, packet, settings.chunkSize, MSG_NOSIGNAL); + if(length <= 0) return false; + p = packet; + } + + if(!headReceived) { + head.append((char)*p++); + --length; + + if(head.endsWith("\r\n\r\n") || head.endsWith("\n\n")) { + headReceived = true; + if(!message.setHead()) return false; + chunked = message.header["Transfer-Encoding"].value().iequals("chunked"); + contentLength = message.header["Content-Length"].value().natural(); + } + + continue; + } + + if(chunked && !chunkReceived) { + char n = *p++; + --length; + + if(!chunkFooterReceived) { + if(n == '\n') chunkFooterReceived = true; + continue; + } + + chunk.append(n); + + if(chunk.endsWith("\r\n") || chunk.endsWith("\n")) { + chunkReceived = true; + chunkLength = chunk.hex(); + if(chunkLength == 0) break; + chunk.reset(); + } + + continue; + } + + if(!chunked) { + body.resize(body.size() + length); + memory::copy(body.get() + body.size() - length, p, length); + + p += length; + length = 0; + } else { + int transferLength = min(length, chunkLength); + body.resize(body.size() + transferLength); + memory::copy(body.get() + body.size() - transferLength, p, transferLength); + + p += transferLength; + length -= transferLength; + chunkLength -= transferLength; + + if(chunkLength == 0) { + chunkReceived = false; + chunkFooterReceived = false; + } + } + } + + if(!message.setBody()) return false; + return true; +} + +auto Role::upload(int fd, const Message& message) -> bool { + auto transfer = [&](const uint8_t* data, uint size) -> bool { + while(size) { + int length = send(fd, data, min(size, settings.chunkSize), MSG_NOSIGNAL); + if(length < 0) return false; + data += length; + size -= length; + } + return true; + }; + + if(message.head([&](const uint8_t* data, uint size) -> bool { return transfer(data, size); })) { + if(message.body([&](const uint8_t* data, uint size) -> bool { return transfer(data, size); })) { + return true; + } + } + + return false; +} + +} diff --git a/nall/http/server.hpp b/nall/http/server.hpp new file mode 100755 index 0000000..3454ccf --- /dev/null +++ b/nall/http/server.hpp @@ -0,0 +1,226 @@ +#pragma once + +#include +#include + +namespace nall::HTTP { + +struct Server : Role, service { + inline auto open(uint port = 8080, const string& serviceName = "", const string& command = "") -> bool; + inline auto main(const function& function = {}) -> void; + inline auto scan() -> string; + inline auto close() -> void; + ~Server() { close(); } + +private: + function callback; + std::atomic connections{0}; + + int fd4 = -1; + int fd6 = -1; + struct sockaddr_in addrin4 = {0}; + struct sockaddr_in6 addrin6 = {0}; + + auto ipv4() const -> bool { return fd4 >= 0; } + auto ipv6() const -> bool { return fd6 >= 0; } + + auto ipv4_close() -> void { if(fd4 >= 0) ::close(fd4); fd4 = -1; } + auto ipv6_close() -> void { if(fd6 >= 0) ::close(fd6); fd6 = -1; } + + auto ipv4_scan() -> bool; + auto ipv6_scan() -> bool; +}; + +auto Server::open(uint port, const string& serviceName, const string& command) -> bool { + if(serviceName) { + if(!service::command(serviceName, command)) return false; + } + + fd4 = socket(AF_INET, SOCK_STREAM, 0); + fd6 = socket(AF_INET6, SOCK_STREAM, 0); + if(!ipv4() && !ipv6()) return false; + + { + #if defined(SO_RCVTIMEO) + if(settings.timeoutReceive) { + struct timeval rcvtimeo; + rcvtimeo.tv_sec = settings.timeoutReceive / 1000; + rcvtimeo.tv_usec = settings.timeoutReceive % 1000 * 1000; + if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval)); + if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval)); + } + #endif + + #if defined(SO_SNDTIMEO) + if(settings.timeoutSend) { + struct timeval sndtimeo; + sndtimeo.tv_sec = settings.timeoutSend / 1000; + sndtimeo.tv_usec = settings.timeoutSend % 1000 * 1000; + if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval)); + if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval)); + } + #endif + + #if defined(SO_NOSIGPIPE) //BSD, OSX + int nosigpipe = 1; + if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(int)); + if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(int)); + #endif + + #if defined(SO_REUSEADDR) //BSD, Linux, OSX + int reuseaddr = 1; + if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)); + if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)); + #endif + + #if defined(SO_REUSEPORT) //BSD, OSX + int reuseport = 1; + if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(int)); + if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(int)); + #endif + } + + addrin4.sin_family = AF_INET; + addrin4.sin_addr.s_addr = htonl(INADDR_ANY); + addrin4.sin_port = htons(port); + + addrin6.sin6_family = AF_INET6; + addrin6.sin6_addr = in6addr_any; + addrin6.sin6_port = htons(port); + + if(bind(fd4, (struct sockaddr*)&addrin4, sizeof(addrin4)) < 0 || listen(fd4, SOMAXCONN) < 0) ipv4_close(); + if(bind(fd6, (struct sockaddr*)&addrin6, sizeof(addrin6)) < 0 || listen(fd6, SOMAXCONN) < 0) ipv6_close(); + return ipv4() || ipv6(); +} + +auto Server::main(const function& function) -> void { + callback = function; +} + +auto Server::scan() -> string { + if(auto command = service::receive()) return command; + if(connections >= settings.connectionLimit) return "busy"; + if(ipv4() && ipv4_scan()) return "ok"; + if(ipv6() && ipv6_scan()) return "ok"; + return "idle"; +} + +auto Server::ipv4_scan() -> bool { + struct pollfd query = {0}; + query.fd = fd4; + query.events = POLLIN; + poll(&query, 1, 0); + + if(query.fd == fd4 && query.revents & POLLIN) { + ++connections; + + thread::create([&](uintptr) { + thread::detach(); + + int clientfd = -1; + struct sockaddr_in settings = {0}; + socklen_t socklen = sizeof(sockaddr_in); + + clientfd = accept(fd4, (struct sockaddr*)&settings, &socklen); + if(clientfd < 0) return; + + uint32_t ip = ntohl(settings.sin_addr.s_addr); + + Request request; + request._ipv6 = false; + request._ip = { + (uint8_t)(ip >> 24), ".", + (uint8_t)(ip >> 16), ".", + (uint8_t)(ip >> 8), ".", + (uint8_t)(ip >> 0) + }; + + if(download(clientfd, request) && callback) { + auto response = callback(request); + upload(clientfd, response); + } else { + upload(clientfd, Response()); //"501 Not Implemented" + } + + ::close(clientfd); + --connections; + }, 0, settings.threadStackSize); + + return true; + } + + return false; +} + +auto Server::ipv6_scan() -> bool { + struct pollfd query = {0}; + query.fd = fd6; + query.events = POLLIN; + poll(&query, 1, 0); + + if(query.fd == fd6 && query.revents & POLLIN) { + ++connections; + + thread::create([&](uintptr) { + thread::detach(); + + int clientfd = -1; + struct sockaddr_in6 settings = {0}; + socklen_t socklen = sizeof(sockaddr_in6); + + clientfd = accept(fd6, (struct sockaddr*)&settings, &socklen); + if(clientfd < 0) return; + + uint8_t* ip = settings.sin6_addr.s6_addr; + uint16_t ipSegment[8]; + for(auto n : range(8)) ipSegment[n] = ip[n * 2 + 0] * 256 + ip[n * 2 + 1]; + + Request request; + request._ipv6 = true; + //RFC5952 IPv6 encoding: the first longest 2+ consecutive zero-sequence is compressed to "::" + int zeroOffset = -1; + int zeroLength = 0; + int zeroCounter = 0; + for(auto n : range(8)) { + uint16_t value = ipSegment[n]; + if(value == 0) zeroCounter++; + if(zeroCounter > zeroLength) { + zeroLength = zeroCounter; + zeroOffset = 1 + n - zeroLength; + } + if(value != 0) zeroCounter = 0; + } + if(zeroLength == 1) zeroOffset = -1; + for(uint n = 0; n < 8;) { + if(n == zeroOffset) { + request._ip.append(n == 0 ? "::" : ":"); + n += zeroLength; + } else { + uint16_t value = ipSegment[n]; + request._ip.append(hex(value), n++ != 7 ? ":" : ""); + } + } + + if(download(clientfd, request) && callback) { + auto response = callback(request); + upload(clientfd, response); + } else { + upload(clientfd, Response()); //"501 Not Implemented" + } + + ::close(clientfd); + --connections; + }, 0, settings.threadStackSize); + + return true; + } + + return false; +} + +auto Server::close() -> void { + ipv4_close(); + ipv6_close(); +} + +} diff --git a/nall/image.hpp b/nall/image.hpp new file mode 100755 index 0000000..3124e73 --- /dev/null +++ b/nall/image.hpp @@ -0,0 +1,169 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace nall { + +struct image { + enum class blend : uint { + add, + sourceAlpha, //color = sourceColor * sourceAlpha + targetColor * (1 - sourceAlpha) + sourceColor, //color = sourceColor + targetAlpha, //color = targetColor * targetAlpha + sourceColor * (1 - targetAlpha) + targetColor, //color = targetColor + }; + + struct channel { + channel(uint64_t mask, uint depth, uint shift) : _mask(mask), _depth(depth), _shift(shift) { + } + + auto operator==(const channel& source) const -> bool { + return _mask == source._mask && _depth == source._depth && _shift == source._shift; + } + + auto operator!=(const channel& source) const -> bool { + return !operator==(source); + } + + alwaysinline auto mask() const { return _mask; } + alwaysinline auto depth() const { return _depth; } + alwaysinline auto shift() const { return _shift; } + + private: + uint64_t _mask; + uint _depth; + uint _shift; + }; + + //core.hpp + inline image(const image& source); + inline image(image&& source); + inline image(bool endian, uint depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask); + inline image(const string& filename); + inline image(const void* data, uint size); + inline image(const vector& buffer); + template inline image(const uint8_t (&Name)[Size]); + inline image(); + inline ~image(); + + inline auto operator=(const image& source) -> image&; + inline auto operator=(image&& source) -> image&; + + inline explicit operator bool() const; + inline auto operator==(const image& source) const -> bool; + inline auto operator!=(const image& source) const -> bool; + + inline auto read(const uint8_t* data) const -> uint64_t; + inline auto write(uint8_t* data, uint64_t value) const -> void; + + inline auto free() -> void; + inline auto load(const string& filename) -> bool; + inline auto copy(const void* data, uint pitch, uint width, uint height) -> void; + inline auto allocate(uint width, uint height) -> void; + + //fill.hpp + inline auto fill(uint64_t color = 0) -> void; + inline auto gradient(uint64_t a, uint64_t b, uint64_t c, uint64_t d) -> void; + inline auto gradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY, function callback) -> void; + inline auto crossGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void; + inline auto diamondGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void; + inline auto horizontalGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void; + inline auto radialGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void; + inline auto sphericalGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void; + inline auto squareGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void; + inline auto verticalGradient(uint64_t a, uint64_t b, int radiusX, int radiusY, int centerX, int centerY) -> void; + + //scale.hpp + inline auto scale(uint width, uint height, bool linear = true) -> void; + + //blend.hpp + inline auto impose(blend mode, uint targetX, uint targetY, image source, uint x, uint y, uint width, uint height) -> void; + + //utility.hpp + inline auto shrink(uint64_t transparentColor = 0) -> void; + inline auto crop(uint x, uint y, uint width, uint height) -> bool; + inline auto alphaBlend(uint64_t alphaColor) -> void; + inline auto alphaMultiply() -> void; + inline auto transform(const image& source = {}) -> void; + inline auto transform(bool endian, uint depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask) -> void; + + //static.hpp + static inline auto bitDepth(uint64_t color) -> uint; + static inline auto bitShift(uint64_t color) -> uint; + static inline auto normalize(uint64_t color, uint sourceDepth, uint targetDepth) -> uint64_t; + + //access + alwaysinline auto data() { return _data; } + alwaysinline auto data() const { return _data; } + alwaysinline auto width() const { return _width; } + alwaysinline auto height() const { return _height; } + + alwaysinline auto endian() const { return _endian; } + alwaysinline auto depth() const { return _depth; } + alwaysinline auto stride() const { return (_depth + 7) >> 3; } + + alwaysinline auto pitch() const { return _width * stride(); } + alwaysinline auto size() const { return _height * pitch(); } + + alwaysinline auto alpha() const { return _alpha; } + alwaysinline auto red() const { return _red; } + alwaysinline auto green() const { return _green; } + alwaysinline auto blue() const { return _blue; } + +private: + //core.hpp + inline auto allocate(uint width, uint height, uint stride) -> uint8_t*; + + //scale.hpp + inline auto scaleLinearWidth(uint width) -> void; + inline auto scaleLinearHeight(uint height) -> void; + inline auto scaleLinear(uint width, uint height) -> void; + inline auto scaleNearest(uint width, uint height) -> void; + + //load.hpp + inline auto loadBMP(const string& filename) -> bool; + inline auto loadBMP(const uint8_t* data, uint size) -> bool; + inline auto loadPNG(const string& filename) -> bool; + inline auto loadPNG(const uint8_t* data, uint size) -> bool; + + //interpolation.hpp + alwaysinline auto isplit(uint64_t* component, uint64_t color) -> void; + alwaysinline auto imerge(const uint64_t* component) -> uint64_t; + alwaysinline auto interpolate1f(uint64_t a, uint64_t b, double x) -> uint64_t; + alwaysinline auto interpolate1f(uint64_t a, uint64_t b, uint64_t c, uint64_t d, double x, double y) -> uint64_t; + alwaysinline auto interpolate1i(int64_t a, int64_t b, uint32_t x) -> uint64_t; + alwaysinline auto interpolate1i(int64_t a, int64_t b, int64_t c, int64_t d, uint32_t x, uint32_t y) -> uint64_t; + inline auto interpolate4f(uint64_t a, uint64_t b, double x) -> uint64_t; + inline auto interpolate4f(uint64_t a, uint64_t b, uint64_t c, uint64_t d, double x, double y) -> uint64_t; + inline auto interpolate4i(uint64_t a, uint64_t b, uint32_t x) -> uint64_t; + inline auto interpolate4i(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint32_t x, uint32_t y) -> uint64_t; + + uint8_t* _data = nullptr; + uint _width = 0; + uint _height = 0; + + bool _endian = 0; //0 = lsb, 1 = msb + uint _depth = 32; + + channel _alpha{255u << 24, 8, 24}; + channel _red {255u << 16, 8, 16}; + channel _green{255u << 8, 8, 8}; + channel _blue {255u << 0, 8, 0}; +}; + +} + +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/nall/image/blend.hpp b/nall/image/blend.hpp new file mode 100755 index 0000000..298d6e1 --- /dev/null +++ b/nall/image/blend.hpp @@ -0,0 +1,71 @@ +#pragma once + +namespace nall { + +auto image::impose(blend mode, unsigned targetX, unsigned targetY, image source, unsigned sourceX, unsigned sourceY, unsigned sourceWidth, unsigned sourceHeight) -> void { + source.transform(_endian, _depth, _alpha.mask(), _red.mask(), _green.mask(), _blue.mask()); + + for(unsigned y = 0; y < sourceHeight; y++) { + const uint8_t* sp = source._data + source.pitch() * (sourceY + y) + source.stride() * sourceX; + uint8_t* dp = _data + pitch() * (targetY + y) + stride() * targetX; + for(unsigned x = 0; x < sourceWidth; x++) { + uint64_t sourceColor = source.read(sp); + uint64_t targetColor = read(dp); + + int64_t sa = (sourceColor & _alpha.mask()) >> _alpha.shift(); + int64_t sr = (sourceColor & _red.mask() ) >> _red.shift(); + int64_t sg = (sourceColor & _green.mask()) >> _green.shift(); + int64_t sb = (sourceColor & _blue.mask() ) >> _blue.shift(); + + int64_t da = (targetColor & _alpha.mask()) >> _alpha.shift(); + int64_t dr = (targetColor & _red.mask() ) >> _red.shift(); + int64_t dg = (targetColor & _green.mask()) >> _green.shift(); + int64_t db = (targetColor & _blue.mask() ) >> _blue.shift(); + + uint64_t a, r, g, b; + + switch(mode) { + case blend::add: + a = max(sa, da); + r = min(_red.mask() >> _red.shift(), ((sr * sa) >> _alpha.depth()) + ((dr * da) >> _alpha.depth())); + g = min(_green.mask() >> _green.shift(), ((sg * sa) >> _alpha.depth()) + ((dg * da) >> _alpha.depth())); + b = min(_blue.mask() >> _blue.shift(), ((sb * sa) >> _alpha.depth()) + ((db * da) >> _alpha.depth())); + break; + + case blend::sourceAlpha: + a = max(sa, da); + r = dr + (((sr - dr) * sa) >> _alpha.depth()); + g = dg + (((sg - dg) * sa) >> _alpha.depth()); + b = db + (((sb - db) * sa) >> _alpha.depth()); + break; + + case blend::sourceColor: + a = sa; + r = sr; + g = sg; + b = sb; + break; + + case blend::targetAlpha: + a = max(sa, da); + r = sr + (((dr - sr) * da) >> _alpha.depth()); + g = sg + (((dg - sg) * da) >> _alpha.depth()); + b = sb + (((db - sb) * da) >> _alpha.depth()); + break; + + case blend::targetColor: + a = da; + r = dr; + g = dg; + b = db; + break; + } + + write(dp, (a << _alpha.shift()) | (r << _red.shift()) | (g << _green.shift()) | (b << _blue.shift())); + sp += source.stride(); + dp += stride(); + } + } +} + +} diff --git a/nall/image/core.hpp b/nall/image/core.hpp new file mode 100755 index 0000000..c2fae6b --- /dev/null +++ b/nall/image/core.hpp @@ -0,0 +1,173 @@ +#pragma once + +namespace nall { + +image::image(const image& source) { + operator=(source); +} + +image::image(image&& source) { + operator=(forward(source)); +} + +image::image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask) { + _endian = endian; + _depth = depth; + + _alpha = {alphaMask, bitDepth(alphaMask), bitShift(alphaMask)}; + _red = {redMask, bitDepth(redMask), bitShift(redMask )}; + _green = {greenMask, bitDepth(greenMask), bitShift(greenMask)}; + _blue = {blueMask, bitDepth(blueMask), bitShift(blueMask )}; +} + +image::image(const string& filename) { + load(filename); +} + +image::image(const void* data_, uint size) { + auto data = (const uint8_t*)data_; + if(size < 4); + else if(data[0] == 'B' && data[1] == 'M') loadBMP(data, size); + else if(data[1] == 'P' && data[2] == 'N' && data[3] == 'G') loadPNG(data, size); +} + +image::image(const vector& buffer) : image(buffer.data(), buffer.size()) { +} + +template image::image(const uint8_t (&Name)[Size]) : image(Name, Size) { +} + +image::image() { +} + +image::~image() { + free(); +} + +auto image::operator=(const image& source) -> image& { + if(this == &source) return *this; + free(); + + _width = source._width; + _height = source._height; + + _endian = source._endian; + _depth = source._depth; + + _alpha = source._alpha; + _red = source._red; + _green = source._green; + _blue = source._blue; + + _data = allocate(_width, _height, stride()); + memory::copy(_data, source._data, source.size()); + return *this; +} + +auto image::operator=(image&& source) -> image& { + if(this == &source) return *this; + free(); + + _width = source._width; + _height = source._height; + + _endian = source._endian; + _depth = source._depth; + + _alpha = source._alpha; + _red = source._red; + _green = source._green; + _blue = source._blue; + + _data = source._data; + source._data = nullptr; + return *this; +} + +image::operator bool() const { + return _data && _width && _height; +} + +auto image::operator==(const image& source) const -> bool { + if(_width != source._width) return false; + if(_height != source._height) return false; + + if(_endian != source._endian) return false; + if(_depth != source._depth) return false; + + if(_alpha != source._alpha) return false; + if(_red != source._red) return false; + if(_green != source._green) return false; + if(_blue != source._blue) return false; + + return memory::compare(_data, source._data, size()) == 0; +} + +auto image::operator!=(const image& source) const -> bool { + return !operator==(source); +} + +auto image::read(const uint8_t* data) const -> uint64_t { + uint64_t result = 0; + if(_endian == 0) { + for(signed n = stride() - 1; n >= 0; n--) result = (result << 8) | data[n]; + } else { + for(signed n = 0; n < stride(); n++) result = (result << 8) | data[n]; + } + return result; +} + +auto image::write(uint8_t* data, uint64_t value) const -> void { + if(_endian == 0) { + for(signed n = 0; n < stride(); n++) { + data[n] = value; + value >>= 8; + } + } else { + for(signed n = stride() - 1; n >= 0; n--) { + data[n] = value; + value >>= 8; + } + } +} + +auto image::free() -> void { + if(_data) delete[] _data; + _data = nullptr; +} + +auto image::load(const string& filename) -> bool { + if(loadBMP(filename) == true) return true; + if(loadPNG(filename) == true) return true; + return false; +} + +//assumes image and data are in the same format; pitch is adapted to image +auto image::copy(const void* data, uint pitch, uint width, uint height) -> void { + allocate(width, height); + for(uint y : range(height)) { + auto input = (const uint8_t*)data + y * pitch; + auto output = (uint8_t*)_data + y * this->pitch(); + memory::copy(output, input, width * stride()); + } +} + +auto image::allocate(unsigned width, unsigned height) -> void { + if(_data && _width == width && _height == height) return; + free(); + _width = width; + _height = height; + _data = allocate(_width, _height, stride()); +} + +//private +auto image::allocate(unsigned width, unsigned height, unsigned stride) -> uint8_t* { + //allocate 1x1 larger than requested; so that linear interpolation does not require bounds-checking + unsigned size = width * height * stride; + unsigned padding = width * stride + stride; + auto data = new uint8_t[size + padding]; + memory::fill(data + size, padding); + return data; +} + +} diff --git a/nall/image/fill.hpp b/nall/image/fill.hpp new file mode 100755 index 0000000..8ff1f88 --- /dev/null +++ b/nall/image/fill.hpp @@ -0,0 +1,84 @@ +#pragma once + +namespace nall { + +auto image::fill(uint64_t color) -> void { + for(unsigned y = 0; y < _height; y++) { + uint8_t* dp = _data + pitch() * y; + for(unsigned x = 0; x < _width; x++) { + write(dp, color); + dp += stride(); + } + } +} + +auto image::gradient(uint64_t a, uint64_t b, uint64_t c, uint64_t d) -> void { + for(unsigned y = 0; y < _height; y++) { + uint8_t* dp = _data + pitch() * y; + double muY = (double)y / (double)_height; + for(unsigned x = 0; x < _width; x++) { + double muX = (double)x / (double)_width; + write(dp, interpolate4f(a, b, c, d, muX, muY)); + dp += stride(); + } + } +} + +auto image::gradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY, function callback) -> void { + for(signed y = 0; y < _height; y++) { + uint8_t* dp = _data + pitch() * y; + double py = max(-radiusY, min(+radiusY, y - centerY)) * 1.0 / radiusY; + for(signed x = 0; x < _width; x++) { + double px = max(-radiusX, min(+radiusX, x - centerX)) * 1.0 / radiusX; + double mu = max(0.0, min(1.0, callback(px, py))); + if(mu != mu) mu = 1.0; //NaN + write(dp, interpolate4f(a, b, mu)); + dp += stride(); + } + } +} + +auto image::crossGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) -> void { + return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { + x = fabs(x), y = fabs(y); + return min(x, y) * min(x, y); + }); +} + +auto image::diamondGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) -> void { + return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { + return fabs(x) + fabs(y); + }); +} + +auto image::horizontalGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) -> void { + return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { + return fabs(x); + }); +} + +auto image::radialGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) -> void { + return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { + return sqrt(x * x + y * y); + }); +} + +auto image::sphericalGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) -> void { + return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { + return x * x + y * y; + }); +} + +auto image::squareGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) -> void { + return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { + return max(fabs(x), fabs(y)); + }); +} + +auto image::verticalGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) -> void { + return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double { + return fabs(y); + }); +} + +} diff --git a/nall/image/interpolation.hpp b/nall/image/interpolation.hpp new file mode 100755 index 0000000..c839f6c --- /dev/null +++ b/nall/image/interpolation.hpp @@ -0,0 +1,62 @@ +#pragma once + +namespace nall { + +auto image::isplit(uint64_t* c, uint64_t color) -> void { + c[0] = (color & _alpha.mask()) >> _alpha.shift(); + c[1] = (color & _red.mask() ) >> _red.shift(); + c[2] = (color & _green.mask()) >> _green.shift(); + c[3] = (color & _blue.mask() ) >> _blue.shift(); +} + +auto image::imerge(const uint64_t* c) -> uint64_t { + return c[0] << _alpha.shift() | c[1] << _red.shift() | c[2] << _green.shift() | c[3] << _blue.shift(); +} + +auto image::interpolate1f(uint64_t a, uint64_t b, double x) -> uint64_t { + return a * (1.0 - x) + b * x; +} + +auto image::interpolate1f(uint64_t a, uint64_t b, uint64_t c, uint64_t d, double x, double y) -> uint64_t { + return a * (1.0 - x) * (1.0 - y) + b * x * (1.0 - y) + c * (1.0 - x) * y + d * x * y; +} + +auto image::interpolate1i(int64_t a, int64_t b, uint32_t x) -> uint64_t { + return a + (((b - a) * x) >> 32); //a + (b - a) * x +} + +auto image::interpolate1i(int64_t a, int64_t b, int64_t c, int64_t d, uint32_t x, uint32_t y) -> uint64_t { + a = a + (((b - a) * x) >> 32); //a + (b - a) * x + c = c + (((d - c) * x) >> 32); //c + (d - c) * x + return a + (((c - a) * y) >> 32); //a + (c - a) * y +} + +auto image::interpolate4f(uint64_t a, uint64_t b, double x) -> uint64_t { + uint64_t o[4], pa[4], pb[4]; + isplit(pa, a), isplit(pb, b); + for(unsigned n = 0; n < 4; n++) o[n] = interpolate1f(pa[n], pb[n], x); + return imerge(o); +} + +auto image::interpolate4f(uint64_t a, uint64_t b, uint64_t c, uint64_t d, double x, double y) -> uint64_t { + uint64_t o[4], pa[4], pb[4], pc[4], pd[4]; + isplit(pa, a), isplit(pb, b), isplit(pc, c), isplit(pd, d); + for(unsigned n = 0; n < 4; n++) o[n] = interpolate1f(pa[n], pb[n], pc[n], pd[n], x, y); + return imerge(o); +} + +auto image::interpolate4i(uint64_t a, uint64_t b, uint32_t x) -> uint64_t { + uint64_t o[4], pa[4], pb[4]; + isplit(pa, a), isplit(pb, b); + for(unsigned n = 0; n < 4; n++) o[n] = interpolate1i(pa[n], pb[n], x); + return imerge(o); +} + +auto image::interpolate4i(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint32_t x, uint32_t y) -> uint64_t { + uint64_t o[4], pa[4], pb[4], pc[4], pd[4]; + isplit(pa, a), isplit(pb, b), isplit(pc, c), isplit(pd, d); + for(unsigned n = 0; n < 4; n++) o[n] = interpolate1i(pa[n], pb[n], pc[n], pd[n], x, y); + return imerge(o); +} + +} diff --git a/nall/image/load.hpp b/nall/image/load.hpp new file mode 100755 index 0000000..cf40f5e --- /dev/null +++ b/nall/image/load.hpp @@ -0,0 +1,99 @@ +#pragma once + +namespace nall { + +auto image::loadBMP(const string& filename) -> bool { + if(!file::exists(filename)) return false; + auto buffer = file::read(filename); + return loadBMP(buffer.data(), buffer.size()); +} + +auto image::loadBMP(const uint8_t* bmpData, unsigned bmpSize) -> bool { + Decode::BMP source; + if(!source.load(bmpData, bmpSize)) return false; + + allocate(source.width(), source.height()); + const uint32_t* sp = source.data(); + uint8_t* dp = _data; + + for(unsigned y = 0; y < _height; y++) { + for(unsigned x = 0; x < _width; x++) { + uint32_t color = *sp++; + uint64_t a = normalize((uint8_t)(color >> 24), 8, _alpha.depth()); + uint64_t r = normalize((uint8_t)(color >> 16), 8, _red.depth()); + uint64_t g = normalize((uint8_t)(color >> 8), 8, _green.depth()); + uint64_t b = normalize((uint8_t)(color >> 0), 8, _blue.depth()); + write(dp, (a << _alpha.shift()) | (r << _red.shift()) | (g << _green.shift()) | (b << _blue.shift())); + dp += stride(); + } + } + + return true; +} + +auto image::loadPNG(const string& filename) -> bool { + if(!file::exists(filename)) return false; + auto buffer = file::read(filename); + return loadPNG(buffer.data(), buffer.size()); +} + +auto image::loadPNG(const uint8_t* pngData, unsigned pngSize) -> bool { + Decode::PNG source; + if(!source.load(pngData, pngSize)) return false; + + allocate(source.info.width, source.info.height); + const uint8_t* sp = source.data; + uint8_t* dp = _data; + + auto decode = [&]() -> uint64_t { + uint64_t p, r, g, b, a; + + switch(source.info.colorType) { + case 0: //L + r = g = b = source.readbits(sp); + a = (1 << source.info.bitDepth) - 1; + break; + case 2: //R,G,B + r = source.readbits(sp); + g = source.readbits(sp); + b = source.readbits(sp); + a = (1 << source.info.bitDepth) - 1; + break; + case 3: //P + p = source.readbits(sp); + r = source.info.palette[p][0]; + g = source.info.palette[p][1]; + b = source.info.palette[p][2]; + a = (1 << source.info.bitDepth) - 1; + break; + case 4: //L,A + r = g = b = source.readbits(sp); + a = source.readbits(sp); + break; + case 6: //R,G,B,A + r = source.readbits(sp); + g = source.readbits(sp); + b = source.readbits(sp); + a = source.readbits(sp); + break; + } + + a = normalize(a, source.info.bitDepth, _alpha.depth()); + r = normalize(r, source.info.bitDepth, _red.depth()); + g = normalize(g, source.info.bitDepth, _green.depth()); + b = normalize(b, source.info.bitDepth, _blue.depth()); + + return (a << _alpha.shift()) | (r << _red.shift()) | (g << _green.shift()) | (b << _blue.shift()); + }; + + for(unsigned y = 0; y < _height; y++) { + for(unsigned x = 0; x < _width; x++) { + write(dp, decode()); + dp += stride(); + } + } + + return true; +} + +} diff --git a/nall/image/scale.hpp b/nall/image/scale.hpp new file mode 100755 index 0000000..3ea63d1 --- /dev/null +++ b/nall/image/scale.hpp @@ -0,0 +1,177 @@ +#pragma once + +namespace nall { + +auto image::scale(unsigned outputWidth, unsigned outputHeight, bool linear) -> void { + if(!_data) return; + if(_width == outputWidth && _height == outputHeight) return; //no scaling necessary + if(linear == false) return scaleNearest(outputWidth, outputHeight); + + if(_width == outputWidth ) return scaleLinearHeight(outputHeight); + if(_height == outputHeight) return scaleLinearWidth(outputWidth); + + //find fastest scaling method, based on number of interpolation operations required + //magnification usually benefits from two-pass linear interpolation + //minification usually benefits from one-pass bilinear interpolation + unsigned d1wh = ((_width * outputWidth ) + (outputWidth * outputHeight)) * 1; + unsigned d1hw = ((_height * outputHeight) + (outputWidth * outputHeight)) * 1; + unsigned d2wh = (outputWidth * outputHeight) * 3; + + if(d1wh <= d1hw && d1wh <= d2wh) return scaleLinearWidth(outputWidth), scaleLinearHeight(outputHeight); + if(d1hw <= d2wh) return scaleLinearHeight(outputHeight), scaleLinearWidth(outputWidth); + return scaleLinear(outputWidth, outputHeight); +} + +auto image::scaleLinearWidth(unsigned outputWidth) -> void { + uint8_t* outputData = allocate(outputWidth, _height, stride()); + unsigned outputPitch = outputWidth * stride(); + uint64_t xstride = ((uint64_t)(_width - 1) << 32) / max(1u, outputWidth - 1); + + for(unsigned y = 0; y < _height; y++) { + uint64_t xfraction = 0; + + const uint8_t* sp = _data + pitch() * y; + uint8_t* dp = outputData + outputPitch * y; + + uint64_t a = read(sp); + uint64_t b = read(sp + stride()); + sp += stride(); + + unsigned x = 0; + while(true) { + while(xfraction < 0x100000000 && x++ < outputWidth) { + write(dp, interpolate4i(a, b, xfraction)); + dp += stride(); + xfraction += xstride; + } + if(x >= outputWidth) break; + + sp += stride(); + a = b; + b = read(sp); + xfraction -= 0x100000000; + } + } + + free(); + _data = outputData; + _width = outputWidth; +} + +auto image::scaleLinearHeight(unsigned outputHeight) -> void { + uint8_t* outputData = allocate(_width, outputHeight, stride()); + uint64_t ystride = ((uint64_t)(_height - 1) << 32) / max(1u, outputHeight - 1); + + for(unsigned x = 0; x < _width; x++) { + uint64_t yfraction = 0; + + const uint8_t* sp = _data + stride() * x; + uint8_t* dp = outputData + stride() * x; + + uint64_t a = read(sp); + uint64_t b = read(sp + pitch()); + sp += pitch(); + + unsigned y = 0; + while(true) { + while(yfraction < 0x100000000 && y++ < outputHeight) { + write(dp, interpolate4i(a, b, yfraction)); + dp += pitch(); + yfraction += ystride; + } + if(y >= outputHeight) break; + + sp += pitch(); + a = b; + b = read(sp); + yfraction -= 0x100000000; + } + } + + free(); + _data = outputData; + _height = outputHeight; +} + +auto image::scaleLinear(unsigned outputWidth, unsigned outputHeight) -> void { + uint8_t* outputData = allocate(outputWidth, outputHeight, stride()); + unsigned outputPitch = outputWidth * stride(); + + uint64_t xstride = ((uint64_t)(_width - 1) << 32) / max(1u, outputWidth - 1); + uint64_t ystride = ((uint64_t)(_height - 1) << 32) / max(1u, outputHeight - 1); + + for(unsigned y = 0; y < outputHeight; y++) { + uint64_t yfraction = ystride * y; + uint64_t xfraction = 0; + + const uint8_t* sp = _data + pitch() * (yfraction >> 32); + uint8_t* dp = outputData + outputPitch * y; + + uint64_t a = read(sp); + uint64_t b = read(sp + stride()); + uint64_t c = read(sp + pitch()); + uint64_t d = read(sp + pitch() + stride()); + sp += stride(); + + unsigned x = 0; + while(true) { + while(xfraction < 0x100000000 && x++ < outputWidth) { + write(dp, interpolate4i(a, b, c, d, xfraction, yfraction)); + dp += stride(); + xfraction += xstride; + } + if(x >= outputWidth) break; + + sp += stride(); + a = b; + c = d; + b = read(sp); + d = read(sp + pitch()); + xfraction -= 0x100000000; + } + } + + free(); + _data = outputData; + _width = outputWidth; + _height = outputHeight; +} + +auto image::scaleNearest(unsigned outputWidth, unsigned outputHeight) -> void { + uint8_t* outputData = allocate(outputWidth, outputHeight, stride()); + unsigned outputPitch = outputWidth * stride(); + + uint64_t xstride = ((uint64_t)_width << 32) / outputWidth; + uint64_t ystride = ((uint64_t)_height << 32) / outputHeight; + + for(unsigned y = 0; y < outputHeight; y++) { + uint64_t yfraction = ystride * y; + uint64_t xfraction = 0; + + const uint8_t* sp = _data + pitch() * (yfraction >> 32); + uint8_t* dp = outputData + outputPitch * y; + + uint64_t a = read(sp); + + unsigned x = 0; + while(true) { + while(xfraction < 0x100000000 && x++ < outputWidth) { + write(dp, a); + dp += stride(); + xfraction += xstride; + } + if(x >= outputWidth) break; + + sp += stride(); + a = read(sp); + xfraction -= 0x100000000; + } + } + + free(); + _data = outputData; + _width = outputWidth; + _height = outputHeight; +} + +} diff --git a/nall/image/static.hpp b/nall/image/static.hpp new file mode 100755 index 0000000..7dc0d84 --- /dev/null +++ b/nall/image/static.hpp @@ -0,0 +1,28 @@ +#pragma once + +namespace nall { + +auto image::bitDepth(uint64_t color) -> unsigned { + unsigned depth = 0; + if(color) while((color & 1) == 0) color >>= 1; + while((color & 1) == 1) { color >>= 1; depth++; } + return depth; +} + +auto image::bitShift(uint64_t color) -> unsigned { + unsigned shift = 0; + if(color) while((color & 1) == 0) { color >>= 1; shift++; } + return shift; +} + +auto image::normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth) -> uint64_t { + if(sourceDepth == 0 || targetDepth == 0) return 0; + while(sourceDepth < targetDepth) { + color = (color << sourceDepth) | color; + sourceDepth += sourceDepth; + } + if(targetDepth < sourceDepth) color >>= (sourceDepth - targetDepth); + return color; +} + +} diff --git a/nall/image/utility.hpp b/nall/image/utility.hpp new file mode 100755 index 0000000..7c0ddd4 --- /dev/null +++ b/nall/image/utility.hpp @@ -0,0 +1,179 @@ +#pragma once + +namespace nall { + +//scan all four sides of the image for fully transparent pixels, and then crop them +//imagine an icon centered on a transparent background: this function removes the bordering +//this certainly won't win any speed awards, but nall::image is meant to be correct and simple, not fast +auto image::shrink(uint64_t transparentColor) -> void { + //top + { uint padding = 0; + for(uint y : range(_height)) { + const uint8_t* sp = _data + pitch() * y; + bool found = false; + for(uint x : range(_width)) { + if(read(sp) != transparentColor) { found = true; break; } + sp += stride(); + } + if(found) break; + padding++; + } + crop(0, padding, _width, _height - padding); + } + + //bottom + { uint padding = 0; + for(uint y : reverse(range(_height))) { + const uint8_t* sp = _data + pitch() * y; + bool found = false; + for(uint x : range(_width)) { + if(read(sp) != transparentColor) { found = true; break; } + sp += stride(); + } + if(found) break; + padding++; + } + crop(0, 0, _width, _height - padding); + } + + //left + { uint padding = 0; + for(uint x : range(_width)) { + const uint8_t* sp = _data + stride() * x; + bool found = false; + for(uint y : range(_height)) { + if(read(sp) != transparentColor) { found = true; break; } + sp += pitch(); + } + if(found) break; + padding++; + } + crop(padding, 0, _width - padding, _height); + } + + //right + { uint padding = 0; + for(uint x : reverse(range(_width))) { + const uint8_t* sp = _data + stride() * x; + bool found = false; + for(uint y : range(_height)) { + if(read(sp) != transparentColor) { found = true; break; } + sp += pitch(); + } + if(found) break; + padding++; + } + crop(0, 0, _width - padding, _height); + } +} + +auto image::crop(unsigned outputX, unsigned outputY, unsigned outputWidth, unsigned outputHeight) -> bool { + if(outputX + outputWidth > _width) return false; + if(outputY + outputHeight > _height) return false; + + uint8_t* outputData = allocate(outputWidth, outputHeight, stride()); + unsigned outputPitch = outputWidth * stride(); + + for(unsigned y = 0; y < outputHeight; y++) { + const uint8_t* sp = _data + pitch() * (outputY + y) + stride() * outputX; + uint8_t* dp = outputData + outputPitch * y; + for(unsigned x = 0; x < outputWidth; x++) { + write(dp, read(sp)); + sp += stride(); + dp += stride(); + } + } + + delete[] _data; + _data = outputData; + _width = outputWidth; + _height = outputHeight; + return true; +} + +auto image::alphaBlend(uint64_t alphaColor) -> void { + uint64_t alphaR = (alphaColor & _red.mask() ) >> _red.shift(); + uint64_t alphaG = (alphaColor & _green.mask()) >> _green.shift(); + uint64_t alphaB = (alphaColor & _blue.mask() ) >> _blue.shift(); + + for(unsigned y = 0; y < _height; y++) { + uint8_t* dp = _data + pitch() * y; + for(unsigned x = 0; x < _width; x++) { + uint64_t color = read(dp); + + uint64_t colorA = (color & _alpha.mask()) >> _alpha.shift(); + uint64_t colorR = (color & _red.mask() ) >> _red.shift(); + uint64_t colorG = (color & _green.mask()) >> _green.shift(); + uint64_t colorB = (color & _blue.mask() ) >> _blue.shift(); + double alphaScale = (double)colorA / (double)((1 << _alpha.depth()) - 1); + + colorA = (1 << _alpha.depth()) - 1; + colorR = (colorR * alphaScale) + (alphaR * (1.0 - alphaScale)); + colorG = (colorG * alphaScale) + (alphaG * (1.0 - alphaScale)); + colorB = (colorB * alphaScale) + (alphaB * (1.0 - alphaScale)); + + write(dp, (colorA << _alpha.shift()) | (colorR << _red.shift()) | (colorG << _green.shift()) | (colorB << _blue.shift())); + dp += stride(); + } + } +} + +auto image::alphaMultiply() -> void { + unsigned divisor = (1 << _alpha.depth()) - 1; + + for(unsigned y = 0; y < _height; y++) { + uint8_t* dp = _data + pitch() * y; + for(unsigned x = 0; x < _width; x++) { + uint64_t color = read(dp); + + uint64_t colorA = (color & _alpha.mask()) >> _alpha.shift(); + uint64_t colorR = (color & _red.mask() ) >> _red.shift(); + uint64_t colorG = (color & _green.mask()) >> _green.shift(); + uint64_t colorB = (color & _blue.mask() ) >> _blue.shift(); + + colorR = (colorR * colorA) / divisor; + colorG = (colorG * colorA) / divisor; + colorB = (colorB * colorA) / divisor; + + write(dp, (colorA << _alpha.shift()) | (colorR << _red.shift()) | (colorG << _green.shift()) | (colorB << _blue.shift())); + dp += stride(); + } + } +} + +auto image::transform(const image& source) -> void { + return transform(source._endian, source._depth, source._alpha.mask(), source._red.mask(), source._green.mask(), source._blue.mask()); +} + +auto image::transform(bool outputEndian, unsigned outputDepth, uint64_t outputAlphaMask, uint64_t outputRedMask, uint64_t outputGreenMask, uint64_t outputBlueMask) -> void { + if(_endian == outputEndian && _depth == outputDepth && _alpha.mask() == outputAlphaMask && _red.mask() == outputRedMask && _green.mask() == outputGreenMask && _blue.mask() == outputBlueMask) return; + + image output(outputEndian, outputDepth, outputAlphaMask, outputRedMask, outputGreenMask, outputBlueMask); + output.allocate(_width, _height); + + for(unsigned y = 0; y < _height; y++) { + const uint8_t* sp = _data + pitch() * y; + uint8_t* dp = output._data + output.pitch() * y; + for(unsigned x = 0; x < _width; x++) { + uint64_t color = read(sp); + sp += stride(); + + uint64_t a = (color & _alpha.mask()) >> _alpha.shift(); + uint64_t r = (color & _red.mask() ) >> _red.shift(); + uint64_t g = (color & _green.mask()) >> _green.shift(); + uint64_t b = (color & _blue.mask() ) >> _blue.shift(); + + a = normalize(a, _alpha.depth(), output._alpha.depth()); + r = normalize(r, _red.depth(), output._red.depth()); + g = normalize(g, _green.depth(), output._green.depth()); + b = normalize(b, _blue.depth(), output._blue.depth()); + + output.write(dp, (a << output._alpha.shift()) | (r << output._red.shift()) | (g << output._green.shift()) | (b << output._blue.shift())); + dp += output.stride(); + } + } + + operator=(move(output)); +} + +} diff --git a/nall/induced-sort.hpp b/nall/induced-sort.hpp new file mode 100644 index 0000000..c544a89 --- /dev/null +++ b/nall/induced-sort.hpp @@ -0,0 +1,176 @@ +#pragma once + +//suffix array construction via induced sorting +//many thanks to Screwtape for the thorough explanation of this algorithm +//this implementation would not be possible without his help + +namespace nall { + +//note that induced_sort will return an array of size+1 characters, +//where the first character is the empty suffix, equal to size + +template +inline auto induced_sort(array_view data, const uint characters = 256) -> vector { + const uint size = data.size(); + if(size == 0) return vector{0}; //required to avoid out-of-bounds accesses + if(size == 1) return vector{1, 0}; //not strictly necessary; but more performant + + vector types; //0 = S-suffix (sort before next suffix), 1 = L-suffix (sort after next suffix) + types.resize(size + 1); + + types[size - 0] = 0; //empty suffix is always S-suffix + types[size - 1] = 1; //last suffix is always L-suffix compared to empty suffix + for(uint n : reverse(range(size - 1))) { + if(data[n] < data[n + 1]) { + types[n] = 0; //this suffix is smaller than the one after it + } else if(data[n] > data[n + 1]) { + types[n] = 1; //this suffix is larger than the one after it + } else { + types[n] = types[n + 1]; //this suffix will be the same as the one after it + } + } + + //left-most S-suffix + auto isLMS = [&](int n) -> bool { + if(n == 0) return 0; //no character to the left of the first suffix + return !types[n] && types[n - 1]; //true if this is the start of a new S-suffix + }; + + //test if two LMS-substrings are equal + auto isEqual = [&](int lhs, int rhs) -> bool { + if(lhs == size || rhs == size) return false; //no other suffix can be equal to the empty suffix + + for(uint n = 0;; n++) { + bool lhsLMS = isLMS(lhs + n); + bool rhsLMS = isLMS(rhs + n); + if(n && lhsLMS && rhsLMS) return true; //substrings are identical + if(lhsLMS != rhsLMS) return false; //length mismatch: substrings cannot be identical + if(data[lhs + n] != data[rhs + n]) return false; //character mismatch: substrings are different + } + }; + + //determine the sizes of each bucket: one bucket per character + vector counts; + counts.resize(characters); + for(uint n : range(size)) counts[data[n]]++; + + //bucket sorting start offsets + vector heads; + heads.resize(characters); + + uint headOffset; + auto getHeads = [&] { + headOffset = 1; + for(uint n : range(characters)) { + heads[n] = headOffset; + headOffset += counts[n]; + } + }; + + //bucket sorting end offsets + vector tails; + tails.resize(characters); + + uint tailOffset; + auto getTails = [&] { + tailOffset = 1; + for(uint n : range(characters)) { + tailOffset += counts[n]; + tails[n] = tailOffset - 1; + } + }; + + //inaccurate LMS bucket sort + vector suffixes; + suffixes.resize(size + 1, (int)-1); + + getTails(); + for(uint n : range(size)) { + if(!isLMS(n)) continue; //skip non-LMS-suffixes + suffixes[tails[data[n]]--] = n; //advance from the tail of the bucket + } + + suffixes[0] = size; //the empty suffix is always an LMS-suffix, and is the first suffix + + //sort all L-suffixes to the left of LMS-suffixes + auto sortL = [&] { + getHeads(); + for(uint n : range(size + 1)) { + if(suffixes[n] == -1) continue; //offsets may not be known yet here ... + auto l = suffixes[n] - 1; + if(l < 0 || !types[l]) continue; //skip S-suffixes + suffixes[heads[data[l]]++] = l; //advance from the head of the bucket + } + }; + + auto sortS = [&] { + getTails(); + for(uint n : reverse(range(size + 1))) { + auto l = suffixes[n] - 1; + if(l < 0 || types[l]) continue; //skip L-suffixes + suffixes[tails[data[l]]--] = l; //advance from the tail of the bucket + } + }; + + sortL(); + sortS(); + + //analyze data for the summary suffix array + vector names; + names.resize(size + 1, (int)-1); + + uint currentName = 0; //keep a count to tag each unique LMS-substring with unique IDs + auto lastLMSOffset = suffixes[0]; //location in the original data of the last checked LMS suffix + names[lastLMSOffset] = currentName; //the first LMS-substring is always the empty suffix entry, at position 0 + + for(uint n : range(1, size + 1)) { + auto offset = suffixes[n]; + if(!isLMS(offset)) continue; //only LMS suffixes are important + + //if this LMS suffix starts with a different LMS substring than the last suffix observed ... + if(!isEqual(lastLMSOffset, offset)) currentName++; //then it gets a new name + lastLMSOffset = offset; //keep track of the new most-recent LMS suffix + names[lastLMSOffset] = currentName; //store the LMS suffix name where the suffix appears at in the original data + } + + vector summaryOffsets; + vector summaryData; + for(uint n : range(size + 1)) { + if(names[n] == -1) continue; + summaryOffsets.append(n); + summaryData.append(names[n]); + } + uint summaryCharacters = currentName + 1; //zero-indexed, so the total unique characters is currentName + 1 + + //make the summary suffix array + vector summaries; + if(summaryData.size() == summaryCharacters) { + //simple bucket sort when every character in summaryData appears only once + summaries.resize(summaryData.size() + 1, (int)-1); + summaries[0] = summaryData.size(); //always include the empty suffix at the beginning + for(int x : range(summaryData.size())) { + int y = summaryData[x]; + summaries[y + 1] = x; + } + } else { + //recurse until every character in summaryData is unique ... + summaries = induced_sort({summaryData.data(), summaryData.size()}, summaryCharacters); + } + + suffixes.fill(-1); //reuse existing buffer for accurate sort + + //accurate LMS sort + getTails(); + for(uint n : reverse(range(2, summaries.size()))) { + auto index = summaryOffsets[summaries[n]]; + suffixes[tails[data[index]]--] = index; //advance from the tail of the bucket + } + suffixes[0] = size; //always include the empty suffix at the beginning + + sortL(); + sortS(); + + return suffixes; +} + +} diff --git a/nall/inline-if.hpp b/nall/inline-if.hpp new file mode 100644 index 0000000..b7b7a86 --- /dev/null +++ b/nall/inline-if.hpp @@ -0,0 +1,11 @@ +#pragma once +#warning "these defines break if statements with multiple parameters to templates" + +#define if1(statement) if(statement) +#define if2(condition, false) ([&](auto&& value) -> decltype(condition) { \ + return (bool)value ? value : (decltype(condition))false; \ +})(condition) +#define if3(condition, true, false) ((condition) ? (true) : (decltype(true))(false)) +#define if4(type, condition, true, false) ((condition) ? (type)(true) : (type)(false)) +#define if_(_1, _2, _3, _4, name, ...) name +#define if(...) if_(__VA_ARGS__, if4, if3, if2, if1)(__VA_ARGS__) diff --git a/nall/inode.hpp b/nall/inode.hpp new file mode 100755 index 0000000..89bebb2 --- /dev/null +++ b/nall/inode.hpp @@ -0,0 +1,163 @@ +#pragma once + +//generic abstraction layer for common storage operations against both files and directories +//these functions are not recursive; use directory::create() and directory::remove() for recursion + +#include +#include + +namespace nall { + +struct inode { + enum class time : uint { create, modify, access }; + + inode() = delete; + inode(const inode&) = delete; + auto operator=(const inode&) -> inode& = delete; + + static auto exists(const string& name) -> bool { + return access(name, F_OK) == 0; + } + + static auto readable(const string& name) -> bool { + return access(name, R_OK) == 0; + } + + static auto writable(const string& name) -> bool { + return access(name, W_OK) == 0; + } + + static auto executable(const string& name) -> bool { + return access(name, X_OK) == 0; + } + + static auto hidden(const string& name) -> bool { + #if defined(PLATFORM_WINDOWS) + auto attributes = GetFileAttributes(utf16_t(name)); + return attributes & FILE_ATTRIBUTE_HIDDEN; + #else + //todo: is this really the best way to do this? stat doesn't have S_ISHIDDEN ... + return name.split("/").last().beginsWith("."); + #endif + } + + static auto mode(const string& name) -> uint { + struct stat data{}; + stat(name, &data); + return data.st_mode; + } + + static auto uid(const string& name) -> uint { + struct stat data{}; + stat(name, &data); + return data.st_uid; + } + + static auto gid(const string& name) -> uint { + struct stat data{}; + stat(name, &data); + return data.st_gid; + } + + static auto owner(const string& name) -> string { + #if !defined(PLATFORM_WINDOWS) + struct passwd* pw = getpwuid(uid(name)); + if(pw && pw->pw_name) return pw->pw_name; + #endif + return {}; + } + + static auto group(const string& name) -> string { + #if !defined(PLATFORM_WINDOWS) + struct group* gr = getgrgid(gid(name)); + if(gr && gr->gr_name) return gr->gr_name; + #endif + return {}; + } + + static auto timestamp(const string& name, time mode = time::modify) -> uint64_t { + struct stat data{}; + stat(name, &data); + switch(mode) { + #if defined(PLATFORM_WINDOWS) + //on Windows, the last status change time (ctime) holds the file creation time instead + case time::create: return data.st_ctime; + #elif defined(PLATFORM_BSD) || defined(PLATFORM_MACOS) + //st_birthtime may return -1 or st_atime if it is not supported by the file system + //the best that can be done in this case is to return st_mtime if it's older + case time::create: return min((uint)data.st_birthtime, (uint)data.st_mtime); + #else + //Linux simply doesn't support file creation time at all + //this is also our fallback case for unsupported operating systems + case time::create: return data.st_mtime; + #endif + case time::modify: return data.st_mtime; + //for performance reasons, last access time is usually not enabled on various filesystems + //ensure that the last access time is not older than the last modify time (eg for NTFS) + case time::access: return max((uint)data.st_atime, data.st_mtime); + } + return 0; + } + + static auto setMode(const string& name, uint mode) -> bool { + #if !defined(PLATFORM_WINDOWS) + return chmod(name, mode) == 0; + #else + return _wchmod(utf16_t(name), (mode & 0400 ? _S_IREAD : 0) | (mode & 0200 ? _S_IWRITE : 0)) == 0; + #endif + } + + static auto setOwner(const string& name, const string& owner) -> bool { + #if !defined(PLATFORM_WINDOWS) + struct passwd* pwd = getpwnam(owner); + if(!pwd) return false; + return chown(name, pwd->pw_uid, inode::gid(name)) == 0; + #else + return true; + #endif + } + + static auto setGroup(const string& name, const string& group) -> bool { + #if !defined(PLATFORM_WINDOWS) + struct group* grp = getgrnam(group); + if(!grp) return false; + return chown(name, inode::uid(name), grp->gr_gid) == 0; + #else + return true; + #endif + } + + static auto setTimestamp(const string& name, uint64_t value, time mode = time::modify) -> bool { + struct utimbuf timeBuffer; + timeBuffer.modtime = mode == time::modify ? value : inode::timestamp(name, time::modify); + timeBuffer.actime = mode == time::access ? value : inode::timestamp(name, time::access); + return utime(name, &timeBuffer) == 0; + } + + //returns true if 'name' already exists + static auto create(const string& name, uint permissions = 0755) -> bool { + if(exists(name)) return true; + if(name.endsWith("/")) return mkdir(name, permissions) == 0; + int fd = open(name, O_CREAT | O_EXCL, permissions); + if(fd < 0) return false; + return close(fd), true; + } + + //returns false if 'name' and 'targetname' are on different file systems (requires copy) + static auto rename(const string& name, const string& targetname) -> bool { + return ::rename(name, targetname) == 0; + } + + //returns false if 'name' is a directory that is not empty + static auto remove(const string& name) -> bool { + #if defined(PLATFORM_WINDOWS) + if(name.endsWith("/")) return _wrmdir(utf16_t(name)) == 0; + return _wunlink(utf16_t(name)) == 0; + #else + if(name.endsWith("/")) return rmdir(name) == 0; + return unlink(name) == 0; + #endif + } +}; + +} diff --git a/nall/instance.hpp b/nall/instance.hpp new file mode 100644 index 0000000..a3cbced --- /dev/null +++ b/nall/instance.hpp @@ -0,0 +1,39 @@ +#pragma once + +namespace nall { + +template +struct Instance { + ~Instance() { + destruct(); + } + + auto operator()() -> T& { + return instance.object; + } + + template + auto construct(P&&... p) { + if(constructed) return; + constructed = true; + new((void*)(&instance.object)) T(forward

    (p)...); + } + + auto destruct() -> void { + if(!constructed) return; + constructed = false; + instance.object.~T(); + } + +private: + bool constructed = false; + union Union { + Union() {} + ~Union() {} + + T object; + char storage[sizeof(T)]; + } instance; +}; + +} diff --git a/nall/interpolation.hpp b/nall/interpolation.hpp new file mode 100755 index 0000000..007f2ec --- /dev/null +++ b/nall/interpolation.hpp @@ -0,0 +1,56 @@ +#pragma once + +namespace nall { + +struct Interpolation { + static inline auto Nearest(double mu, double a, double b, double c, double d) -> double { + return (mu <= 0.5 ? b : c); + } + + static inline auto Sublinear(double mu, double a, double b, double c, double d) -> double { + mu = ((mu - 0.5) * 2.0) + 0.5; + if(mu < 0) mu = 0; + if(mu > 1) mu = 1; + return b * (1.0 - mu) + c * mu; + } + + static inline auto Linear(double mu, double a, double b, double c, double d) -> double { + return b * (1.0 - mu) + c * mu; + } + + static inline auto Cosine(double mu, double a, double b, double c, double d) -> double { + mu = (1.0 - cos(mu * Math::Pi)) / 2.0; + return b * (1.0 - mu) + c * mu; + } + + static inline auto Cubic(double mu, double a, double b, double c, double d) -> double { + double A = d - c - a + b; + double B = a - b - A; + double C = c - a; + double D = b; + return A * (mu * mu * mu) + B * (mu * mu) + C * mu + D; + } + + static inline auto Hermite(double mu1, double a, double b, double c, double d) -> double { + const double tension = 0.0; //-1 = low, 0 = normal, +1 = high + const double bias = 0.0; //-1 = left, 0 = even, +1 = right + double mu2, mu3, m0, m1, a0, a1, a2, a3; + + 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; + + return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); + } +}; + +} diff --git a/nall/intrinsics.hpp b/nall/intrinsics.hpp new file mode 100755 index 0000000..d4c7164 --- /dev/null +++ b/nall/intrinsics.hpp @@ -0,0 +1,174 @@ +#pragma once + +namespace nall { + using uint = unsigned; + + enum class Compiler : uint { Clang, GCC, Microsoft, Unknown }; + enum class Platform : uint { Windows, MacOS, Linux, BSD, Android, Unknown }; + enum class API : uint { Windows, Posix, Unknown }; + enum class DisplayServer : uint { Windows, Quartz, Xorg, Unknown }; + enum class Architecture : uint { x86, amd64, ARM32, ARM64, PPC32, PPC64, Unknown }; + enum class Endian : uint { LSB, MSB, Unknown }; + enum class Build : uint { Debug, Stable, Size, Release, Performance }; + + static inline constexpr auto compiler() -> Compiler; + static inline constexpr auto platform() -> Platform; + static inline constexpr auto api() -> API; + static inline constexpr auto display() -> DisplayServer; + static inline constexpr auto architecture() -> Architecture; + static inline constexpr auto endian() -> Endian; + static inline constexpr auto build() -> Build; +} + +/* Compiler detection */ + +namespace nall { + +#if defined(__clang__) + #define COMPILER_CLANG + constexpr auto compiler() -> Compiler { return Compiler::Clang; } + + #pragma clang diagnostic warning "-Wreturn-type" + #pragma clang diagnostic ignored "-Wunused-result" + #pragma clang diagnostic ignored "-Wunknown-pragmas" + #pragma clang diagnostic ignored "-Wempty-body" + #pragma clang diagnostic ignored "-Wparentheses" + #pragma clang diagnostic ignored "-Wswitch" + #pragma clang diagnostic ignored "-Wswitch-bool" + #pragma clang diagnostic ignored "-Wtautological-compare" + #pragma clang diagnostic ignored "-Wabsolute-value" + #pragma clang diagnostic ignored "-Wshift-count-overflow" + #pragma clang diagnostic ignored "-Wtrigraphs" + + //temporary + #pragma clang diagnostic ignored "-Winconsistent-missing-override" +//#pragma clang diagnostic error "-Wdeprecated-declarations" +#elif defined(__GNUC__) + #define COMPILER_GCC + constexpr auto compiler() -> Compiler { return Compiler::GCC; } + + #pragma GCC diagnostic warning "-Wreturn-type" + #pragma GCC diagnostic ignored "-Wunused-result" + #pragma GCC diagnostic ignored "-Wunknown-pragmas" + #pragma GCC diagnostic ignored "-Wpragmas" + #pragma GCC diagnostic ignored "-Wswitch-bool" + #pragma GCC diagnostic ignored "-Wtrigraphs" +#elif defined(_MSC_VER) + #define COMPILER_MICROSOFT + constexpr auto compiler() -> Compiler { return Compiler::Microsoft; } + + #pragma warning(disable:4996) //libc "deprecation" warnings +#else + #warning "unable to detect compiler" + #define COMPILER_UNKNOWN + constexpr auto compiler() -> Compiler { return Compiler::Unknown; } +#endif + +} + +/* Platform detection */ + +namespace nall { + +#if defined(_WIN32) + #define PLATFORM_WINDOWS + #define API_WINDOWS + #define DISPLAY_WINDOWS + constexpr auto platform() -> Platform { return Platform::Windows; } + constexpr auto api() -> API { return API::Windows; } + constexpr auto display() -> DisplayServer { return DisplayServer::Windows; } +#elif defined(__APPLE__) + #define PLATFORM_MACOS + #define API_POSIX + #define DISPLAY_QUARTZ + constexpr auto platform() -> Platform { return Platform::MacOS; } + constexpr auto api() -> API { return API::Posix; } + constexpr auto display() -> DisplayServer { return DisplayServer::Quartz; } +#elif defined(__ANDROID__) + #define PLATFORM_ANDROID + #define API_POSIX + #define DISPLAY_UNKNOWN + constexpr auto platform() -> Platform { return Platform::Android; } + constexpr auto api() -> API { return API::Posix; } + constexpr auto display() -> DisplayServer { return DisplayServer::Unknown; } +#elif defined(linux) || defined(__linux__) + #define PLATFORM_LINUX + #define API_POSIX + #define DISPLAY_XORG + constexpr auto platform() -> Platform { return Platform::Linux; } + constexpr auto api() -> API { return API::Posix; } + constexpr auto display() -> DisplayServer { return DisplayServer::Xorg; } +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) + #define PLATFORM_BSD + #define API_POSIX + #define DISPLAY_XORG + constexpr auto platform() -> Platform { return Platform::BSD; } + constexpr auto api() -> API { return API::Posix; } + constexpr auto display() -> DisplayServer { return DisplayServer::Xorg; } +#else + #warning "unable to detect platform" + #define PLATFORM_UNKNOWN + #define API_UNKNOWN + #define DISPLAY_UNKNOWN + constexpr auto platform() -> Platform { return Platform::Unknown; } + constexpr auto api() -> API { return API::Unknown; } + constexpr auto display() -> DisplayServer { return DisplayServer::Unknown; } +#endif + +} + +#if defined(PLATFORM_MACOS) + #include +#elif defined(PLATFORM_LINUX) + #include +#elif defined(PLATFORM_BSD) + #include +#endif + +/* Architecture detection */ + +namespace nall { + +#if defined(__i386__) || defined(_M_IX86) + #define ARCHITECTURE_X86 + constexpr auto architecture() -> Architecture { return Architecture::x86; } +#elif defined(__amd64__) || defined(_M_AMD64) + #define ARCHITECTURE_AMD64 + constexpr auto architecture() -> Architecture { return Architecture::amd64; } +#elif defined(__aarch64__) + #define ARCHITECTURE_ARM64 + constexpr auto architecture() -> Architecture { return Architecture::ARM64; } +#elif defined(__arm__) + #define ARCHITECTURE_ARM32 + constexpr auto architecture() -> Architecture { return Architecture::ARM32; } +#elif defined(__ppc64__) || defined(_ARCH_PPC64) + #define ARCHITECTURE_PPC64 + constexpr auto architecture() -> Architecture { return Architecture::PPC64; } +#elif defined(__ppc__) || defined(_ARCH_PPC) || defined(_M_PPC) + #define ARCHITECTURE_PPC32 + constexpr auto architecture() -> Architecture { return Architecture::PPC32; } +#else + #warning "unable to detect architecture" + #define ARCHITECTURE_UNKNOWN + constexpr auto architecture() -> Architecture { return Architecture::Unknown; } +#endif + +} + +/* Endian detection */ + +namespace nall { + +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN__) || defined(__i386__) || defined(__amd64__) || defined(_M_IX86) || defined(_M_AMD64) + #define ENDIAN_LSB + constexpr auto endian() -> Endian { return Endian::LSB; } +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(__powerpc__) || defined(_M_PPC) + #define ENDIAN_MSB + constexpr auto endian() -> Endian { return Endian::MSB; } +#else + #warning "unable to detect endian" + #define ENDIAN_UNKNOWN + constexpr auto endian() -> Endian { return Endian::Unknown; } +#endif + +} diff --git a/nall/iterator.hpp b/nall/iterator.hpp new file mode 100644 index 0000000..6c2625e --- /dev/null +++ b/nall/iterator.hpp @@ -0,0 +1,79 @@ +#pragma once + +namespace nall { + +template struct iterator { + iterator(T* self, uint64_t offset) : _self(self), _offset(offset) {} + auto operator*() -> T& { return _self[_offset]; } + auto operator!=(const iterator& source) const -> bool { return _offset != source._offset; } + auto operator++() -> iterator& { return _offset++, *this; } + auto offset() const -> uint64_t { return _offset; } + +private: + T* _self; + uint64_t _offset; +}; + +template struct iterator_const { + iterator_const(const T* self, uint64_t offset) : _self(self), _offset(offset) {} + auto operator*() -> const T& { return _self[_offset]; } + auto operator!=(const iterator_const& source) const -> bool { return _offset != source._offset; } + auto operator++() -> iterator_const& { return _offset++, *this; } + auto offset() const -> uint64_t { return _offset; } + +private: + const T* _self; + uint64_t _offset; +}; + +template struct reverse_iterator { + reverse_iterator(T* self, uint64_t offset) : _self(self), _offset(offset) {} + auto operator*() -> T& { return _self[_offset]; } + auto operator!=(const reverse_iterator& source) const -> bool { return _offset != source._offset; } + auto operator++() -> reverse_iterator& { return _offset--, *this; } + auto offset() const -> uint64_t { return _offset; } + +private: + T* _self; + uint64_t _offset; +}; + +template struct reverse_iterator_const { + reverse_iterator_const(const T* self, uint64_t offset) : _self(self), _offset(offset) {} + auto operator*() -> const T& { return _self[_offset]; } + auto operator!=(const reverse_iterator_const& source) const -> bool { return _offset != source._offset; } + auto operator++() -> reverse_iterator_const& { return _offset--, *this; } + auto offset() const -> uint64_t { return _offset; } + +private: + const T* _self; + uint64_t _offset; +}; + +//std::rbegin(), std::rend() is missing from GCC 4.9; which I still target + +template auto rbegin(T (&array)[Size]) { return reverse_iterator{array, Size - 1}; } +template auto rend(T (&array)[Size]) { return reverse_iterator{array, (uint64_t)-1}; } + +template auto rbegin(T& self) { return self.rbegin(); } +template auto rend(T& self) { return self.rend(); } + +template struct reverse_wrapper { + auto begin() { return rbegin(_self); } + auto end() { return rend(_self); } + + auto begin() const { return rbegin(_self); } + auto end() const { return rend(_self); } + + T _self; +}; + +template auto reverse(T& object) -> reverse_wrapper { + return {object}; +} + +template auto reverse(T&& object) -> reverse_wrapper { + return {object}; +} + +} diff --git a/nall/literals.hpp b/nall/literals.hpp new file mode 100644 index 0000000..304823b --- /dev/null +++ b/nall/literals.hpp @@ -0,0 +1,20 @@ +#pragma once + +namespace nall { + +inline constexpr auto operator"" _Kibit(unsigned long long value) { return value * 1024 / 8; } +inline constexpr auto operator"" _Mibit(unsigned long long value) { return value * 1024 * 1024 / 8; } +inline constexpr auto operator"" _Gibit(unsigned long long value) { return value * 1024 * 1024 * 1024 / 8; } +inline constexpr auto operator"" _Tibit(unsigned long long value) { return value * 1024 * 1024 * 1024 * 1024 / 8; } + +inline constexpr auto operator"" _KiB(unsigned long long value) { return value * 1024; } +inline constexpr auto operator"" _MiB(unsigned long long value) { return value * 1024 * 1024; } +inline constexpr auto operator"" _GiB(unsigned long long value) { return value * 1024 * 1024 * 1024; } +inline constexpr auto operator"" _TiB(unsigned long long value) { return value * 1024 * 1024 * 1024 * 1024; } + +inline constexpr auto operator"" _KHz(unsigned long long value) { return value * 1000; } +inline constexpr auto operator"" _MHz(unsigned long long value) { return value * 1000 * 1000; } +inline constexpr auto operator"" _GHz(unsigned long long value) { return value * 1000 * 1000 * 1000; } +inline constexpr auto operator"" _THz(unsigned long long value) { return value * 1000 * 1000 * 1000 * 1000; } + +} diff --git a/nall/locale.hpp b/nall/locale.hpp new file mode 100644 index 0000000..6fb9f17 --- /dev/null +++ b/nall/locale.hpp @@ -0,0 +1,87 @@ +#pragma once + +namespace nall { + +struct Locale { + struct Dictionary { + string location; + string language; + Markup::Node document; + }; + + auto scan(string pathname) -> void { + dictionaries.reset(); + selected.reset(); + for(auto filename : directory::icontents(pathname, "*.bml")) { + Dictionary dictionary; + dictionary.location = {pathname, filename}; + dictionary.document = BML::unserialize(string::read(dictionary.location)); + dictionary.language = dictionary.document["locale/language"].text(); + dictionaries.append(dictionary); + } + } + + auto available() const -> vector { + vector result; + for(auto& dictionary : dictionaries) { + result.append(dictionary.language); + } + return result; + } + + auto select(string option) -> bool { + selected.reset(); + for(auto& dictionary : dictionaries) { + if(option == Location::prefix(dictionary.location) || option == dictionary.language) { + selected = dictionary; + return true; + } + } + return false; + } + + template + auto operator()(string ns, string input, P&&... p) const -> string { + vector arguments{forward

    (p)...}; + if(selected) { + for(auto node : selected().document) { + if(node.name() == "namespace" && node.text() == ns) { + for(auto map : node) { + if(map.name() == "map" && map["input"].text() == input) { + input = map["value"].text(); + break; + } + } + } + } + } + for(uint index : range(arguments.size())) { + input.replace({"{", index, "}"}, arguments[index]); + } + return input; + } + + struct Namespace { + Namespace(Locale& _locale, string _namespace) : _locale(_locale), _namespace(_namespace) {} + + template + auto operator()(string input, P&&... p) const -> string { + return _locale(_namespace, input, forward

    (p)...); + } + + template + auto tr(string input, P&&... p) const -> string { + return _locale(_namespace, input, forward

    (p)...); + } + + private: + Locale& _locale; + string _namespace; + }; + +private: + vector dictionaries; + maybe selected; +}; + +} diff --git a/nall/location.hpp b/nall/location.hpp new file mode 100755 index 0000000..7aeb8b0 --- /dev/null +++ b/nall/location.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include + +namespace nall::Location { + +// (/parent/child.type/) +// (/parent/child.type/)name.type +inline auto path(string_view self) -> string { + const char* p = self.data() + self.size() - 1; + for(int offset = self.size() - 1; offset >= 0; offset--, p--) { + if(*p == '/') return slice(self, 0, offset + 1); + } + return ""; //no path found +} + +// /parent/child.type/() +// /parent/child.type/(name.type) +inline auto file(string_view self) -> string { + const char* p = self.data() + self.size() - 1; + for(int offset = self.size() - 1; offset >= 0; offset--, p--) { + if(*p == '/') return slice(self, offset + 1); + } + return self; //no path found +} + +// (/parent/)child.type/ +// (/parent/child.type/)name.type +inline auto dir(string_view self) -> string { + const char* p = self.data() + self.size() - 1, *last = p; + for(int offset = self.size() - 1; offset >= 0; offset--, p--) { + if(*p == '/' && p == last) continue; + if(*p == '/') return slice(self, 0, offset + 1); + } + return ""; //no path found +} + +// /parent/(child.type/) +// /parent/child.type/(name.type) +inline auto base(string_view self) -> string { + const char* p = self.data() + self.size() - 1, *last = p; + for(int offset = self.size() - 1; offset >= 0; offset--, p--) { + if(*p == '/' && p == last) continue; + if(*p == '/') return slice(self, offset + 1); + } + return self; //no path found +} + +// /parent/(child).type/ +// /parent/child.type/(name).type +inline auto prefix(string_view self) -> string { + const char* p = self.data() + self.size() - 1, *last = p; + for(int offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) { + if(*p == '/' && p == last) continue; + if(*p == '/') return slice(self, offset + 1, (suffix >= 0 ? suffix : self.size()) - offset - 1).trimRight("/"); + if(*p == '.' && suffix == -1) { suffix = offset; continue; } + if(offset == 0) return slice(self, offset, suffix).trimRight("/"); + } + return ""; //no prefix found +} + +// /parent/child(.type)/ +// /parent/child.type/name(.type) +inline auto suffix(string_view self) -> string { + const char* p = self.data() + self.size() - 1, *last = p; + for(int offset = self.size() - 1; offset >= 0; offset--, p--) { + if(*p == '/' && p == last) continue; + if(*p == '/') break; + if(*p == '.') return slice(self, offset).trimRight("/"); + } + return ""; //no suffix found +} + +inline auto notsuffix(string_view self) -> string { + return {path(self), prefix(self)}; +} + +} diff --git a/nall/mac/poly1305.hpp b/nall/mac/poly1305.hpp new file mode 100644 index 0000000..befbf46 --- /dev/null +++ b/nall/mac/poly1305.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include + +namespace nall::MAC { + +struct Poly1305 { + auto authenticate(array_view memory, uint256_t nonce) -> uint128_t { + initialize(nonce); + process(memory.data(), memory.size()); + return finish(); + } + + auto initialize(uint256_t key) -> void { + uint64_t t0 = key >> 0; + uint64_t t1 = key >> 64; + pad[0] = key >> 128; + pad[1] = key >> 192; + + r[0] = (t0 ) & 0xffc0fffffff; + r[1] = (t0 >> 44 | t1 << 20) & 0xfffffc0ffff; + r[2] = ( t1 >> 24) & 0x00ffffffc0f; + + h[0] = 0, h[1] = 0, h[2] = 0; + offset = 0; + } + + auto process(const uint8_t* data, uint64_t size) -> void { + while(size--) { + buffer[offset++] = *data++; + if(offset >= 16) { + block(); + offset = 0; + } + } + } + + auto finish() -> uint128_t { + if(offset) { + buffer[offset++] = 1; + while(offset < 16) buffer[offset++] = 0; + block(true); + } + + uint64_t h0 = h[0], h1 = h[1], h2 = h[2]; + + uint64_t c = h1 >> 44; h1 &= 0xfffffffffff; + h2 += c; c = h2 >> 42; h2 &= 0x3ffffffffff; + h0 += c * 5; c = h0 >> 44; h0 &= 0xfffffffffff; + h1 += c; c = h1 >> 44; h1 &= 0xfffffffffff; + h2 += c; c = h2 >> 42; h2 &= 0x3ffffffffff; + h0 += c * 5; c = h0 >> 44; h0 &= 0xfffffffffff; + h1 += c; + + uint64_t g0 = h0 + 5; c = g0 >> 44; g0 &= 0xfffffffffff; + uint64_t g1 = h1 + c; c = g1 >> 44; g1 &= 0xfffffffffff; + uint64_t g2 = h2 + c - (1ull << 42); + + c = (g2 >> 63) - 1; + g0 &= c, g1 &= c, g2 &= c; + c = ~c; + h0 = (h0 & c) | g0; + h1 = (h1 & c) | g1; + h2 = (h2 & c) | g2; + + uint64_t t0 = pad[0], t1 = pad[1]; + + h0 += ((t0 ) & 0xfffffffffff) ; c = h0 >> 44; h0 &= 0xfffffffffff; + h1 += ((t0 >> 44 | t1 << 20) & 0xfffffffffff) + c; c = h1 >> 44; h1 &= 0xfffffffffff; + h2 += (( t1 >> 24) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff; + + h0 = (h0 >> 0 | h1 << 44); + h1 = (h1 >> 20 | h2 << 24); + + r[0] = 0, r[1] = 0, r[2] = 0; + h[0] = 0, h[1] = 0, h[2] = 0; + pad[0] = 0, pad[1] = 0; + memory::fill(buffer, sizeof(buffer)); + offset = 0; + + return uint128_t(h1) << 64 | h0; + } + +private: + auto block(bool last = false) -> void { + uint64_t r0 = r[0], r1 = r[1], r2 = r[2]; + uint64_t h0 = h[0], h1 = h[1], h2 = h[2]; + + uint64_t s1 = r1 * 20; + uint64_t s2 = r2 * 20; + + uint64_t t0 = memory::readl<8>(buffer + 0); + uint64_t t1 = memory::readl<8>(buffer + 8); + + h0 += ((t0 ) & 0xfffffffffff); + h1 += ((t0 >> 44 | t1 << 20) & 0xfffffffffff); + h2 += (( t1 >> 24) & 0x3ffffffffff) | (last ? 0 : 1ull << 40); + + uint128_t d, d0, d1, d2; + d0 = (uint128_t)h0 * r0; d = (uint128_t)h1 * s2; d0 += d; d = (uint128_t)h2 * s1; d0 += d; + d1 = (uint128_t)h0 * r1; d = (uint128_t)h1 * r0; d1 += d; d = (uint128_t)h2 * s2; d1 += d; + d2 = (uint128_t)h0 * r2; d = (uint128_t)h1 * r1; d2 += d; d = (uint128_t)h2 * r0; d2 += d; + + uint64_t c = (uint64_t)(d0 >> 44); h0 = (uint64_t)d0 & 0xfffffffffff; + d1 += c; c = (uint64_t)(d1 >> 44); h1 = (uint64_t)d1 & 0xfffffffffff; + d2 += c; c = (uint64_t)(d2 >> 42); h2 = (uint64_t)d2 & 0x3ffffffffff; + + h0 += c * 5; c = h0 >> 44; h0 &= 0xfffffffffff; + h1 += c; + + h[0] = h0, h[1] = h1, h[2] = h2; + } + + uint64_t r[3]; + uint64_t h[3]; + uint64_t pad[2]; + + uint8_t buffer[16]; + uint offset; +}; + +} diff --git a/nall/macos/guard.hpp b/nall/macos/guard.hpp new file mode 100644 index 0000000..96cd4d6 --- /dev/null +++ b/nall/macos/guard.hpp @@ -0,0 +1,15 @@ +#ifndef NALL_MACOS_GUARD_HPP +#define NALL_MACOS_GUARD_HPP + +#define Boolean CocoaBoolean +#define decimal CocoaDecimal +#define DEBUG CocoaDebug + +#else +#undef NALL_MACOS_GUARD_HPP + +#undef Boolean +#undef decimal +#undef DEBUG + +#endif diff --git a/nall/main.hpp b/nall/main.hpp new file mode 100755 index 0000000..24642b6 --- /dev/null +++ b/nall/main.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include + +namespace nall { + auto main(Arguments arguments) -> void; + + auto main(int argc, char** argv) -> int { + #if defined(PLATFORM_WINDOWS) + CoInitialize(0); + WSAData wsaData{0}; + WSAStartup(MAKEWORD(2, 2), &wsaData); + _setmode(_fileno(stdin ), O_BINARY); + _setmode(_fileno(stdout), O_BINARY); + _setmode(_fileno(stderr), O_BINARY); + #endif + + main(move(Arguments{argc, argv})); + + //when a program is running, input on the terminal queues in stdin + //when terminating the program, the shell proceeds to try and execute all stdin data + //this is annoying behavior: this code tries to minimize the impact as much as it can + //we can flush all of stdin up to the last line feed, preventing spurious commands from executing + //however, even with setvbuf(_IONBF), we can't stop the last line from echoing to the terminal + #if !defined(PLATFORM_WINDOWS) + auto flags = fcntl(fileno(stdin), F_GETFL, 0); + fcntl(fileno(stdin), F_SETFL, flags | O_NONBLOCK); //don't allow read() to block when empty + char buffer[4096], data = false; + while(read(fileno(stdin), buffer, sizeof(buffer)) > 0) data = true; + fcntl(fileno(stdin), F_SETFL, flags); //restore original flags for the terminal + if(data) putchar('\r'); //ensures PS1 is printed at the start of the line + #endif + + return EXIT_SUCCESS; + } +} + +auto main(int argc, char** argv) -> int { + return nall::main(argc, argv); +} diff --git a/nall/map.hpp b/nall/map.hpp new file mode 100755 index 0000000..58b1e11 --- /dev/null +++ b/nall/map.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include + +namespace nall { + +template struct map { + struct node_t { + T key; + U value; + node_t() = default; + node_t(const T& key) : key(key) {} + node_t(const T& key, const U& value) : key(key), value(value) {} + auto operator< (const node_t& source) const -> bool { return key < source.key; } + auto operator==(const node_t& source) const -> bool { return key == source.key; } + }; + + auto find(const T& key) const -> maybe { + if(auto node = root.find({key})) return node().value; + return nothing; + } + + auto insert(const T& key, const U& value) -> void { root.insert({key, value}); } + auto remove(const T& key) -> void { root.remove({key}); } + auto size() const -> unsigned { return root.size(); } + auto reset() -> void { root.reset(); } + + auto begin() -> typename set::iterator { return root.begin(); } + auto end() -> typename set::iterator { return root.end(); } + + auto begin() const -> const typename set::iterator { return root.begin(); } + auto end() const -> const typename set::iterator { return root.end(); } + +protected: + set root; +}; + +template struct bimap { + auto find(const T& key) const -> maybe { return tmap.find(key); } + auto find(const U& key) const -> maybe { return umap.find(key); } + auto insert(const T& key, const U& value) -> void { tmap.insert(key, value); umap.insert(value, key); } + auto remove(const T& key) -> void { if(auto p = tmap.find(key)) { umap.remove(p().value); tmap.remove(key); } } + auto remove(const U& key) -> void { if(auto p = umap.find(key)) { tmap.remove(p().value); umap.remove(key); } } + auto size() const -> unsigned { return tmap.size(); } + auto reset() -> void { tmap.reset(); umap.reset(); } + + auto begin() -> typename set::node_t>::iterator { return tmap.begin(); } + auto end() -> typename set::node_t>::iterator { return tmap.end(); } + + auto begin() const -> const typename set::node_t>::iterator { return tmap.begin(); } + auto end() const -> const typename set::node_t>::iterator { return tmap.end(); } + +protected: + map tmap; + map umap; +}; + +} diff --git a/nall/matrix-multiply.hpp b/nall/matrix-multiply.hpp new file mode 100755 index 0000000..a82d8ea --- /dev/null +++ b/nall/matrix-multiply.hpp @@ -0,0 +1,36 @@ +#pragma once + +//matrix multiplication primitives +//used in: ruby/opengl/quark + +namespace nall { + +template inline auto MatrixMultiply( +T* output, +const T* xdata, uint xrows, uint xcols, +const T* ydata, uint yrows, uint ycols +) -> void { + if(xcols != yrows) return; + + for(uint y : range(xrows)) { + for(uint x : range(ycols)) { + T sum = 0; + for(uint z : range(xcols)) { + sum += xdata[y * xcols + z] * ydata[z * ycols + x]; + } + *output++ = sum; + } + } +} + +template inline auto MatrixMultiply( +const T* xdata, uint xrows, uint xcols, +const T* ydata, uint yrows, uint ycols +) -> vector { + vector output; + output.resize(xrows * ycols); + MatrixMultiply(output.data(), xdata, xrows, xcols, ydata, yrows, ycols); + return output; +} + +} diff --git a/nall/matrix.hpp b/nall/matrix.hpp new file mode 100644 index 0000000..e266df6 --- /dev/null +++ b/nall/matrix.hpp @@ -0,0 +1,213 @@ +#pragma once + +namespace nall { + +template +struct Matrix { + static_assert(Rows > 0 && Cols > 0); + + Matrix() = default; + Matrix(const Matrix&) = default; + Matrix(const initializer_list& source) { + uint index = 0; + for(auto& value : source) { + if(index >= Rows * Cols) break; + values[index / Cols][index % Cols] = value; + } + } + + operator array_span() { return {values, Rows * Cols}; } + operator array_view() const { return {values, Rows * Cols}; } + + //1D matrices (for polynomials, etc) + auto operator[](uint row) -> T& { return values[row][0]; } + auto operator[](uint row) const -> T { return values[row][0]; } + + //2D matrices + auto operator()(uint row, uint col) -> T& { return values[row][col]; } + auto operator()(uint row, uint col) const -> T { return values[row][col]; } + + //operators + auto operator+() const -> Matrix { + Matrix result; + for(uint row : range(Rows)) { + for(uint col : range(Cols)) { + result(row, col) = +target(row, col); + } + } + return result; + } + + auto operator-() const -> Matrix { + Matrix result; + for(uint row : range(Rows)) { + for(uint col : range(Cols)) { + result(row, col) = -target(row, col); + } + } + return result; + } + + auto operator+(const Matrix& source) const -> Matrix { + Matrix result; + for(uint row : range(Rows)) { + for(uint col : range(Cols)) { + result(row, col) = target(row, col) + source(row, col); + } + } + return result; + } + + auto operator-(const Matrix& source) const -> Matrix { + Matrix result; + for(uint row : range(Rows)) { + for(uint col : range(Cols)) { + result(row, col) = target(row, col) - source(row, col); + } + } + return result; + } + + auto operator*(T source) const -> Matrix { + Matrix result; + for(uint row : range(Rows)) { + for(uint col : range(Cols)) { + result(row, col) = target(row, col) * source; + } + } + return result; + } + + auto operator/(T source) const -> Matrix { + Matrix result; + for(uint row : range(Rows)) { + for(uint col : range(Cols)) { + result(row, col) = target(row, col) / source; + } + } + return result; + } + + //warning: matrix multiplication is not commutative! + template + auto operator*(const Matrix& source) const -> Matrix { + static_assert(Cols == SourceRows); + Matrix result; + for(uint y : range(Rows)) { + for(uint x : range(SourceCols)) { + T sum{}; + for(uint z : range(Cols)) { + sum += target(y, z) * source(z, x); + } + result(y, x) = sum; + } + } + return result; + } + + template + auto operator/(const Matrix& source) const -> maybe> { + static_assert(Cols == SourceRows && SourceRows == SourceCols); + if(auto inverted = source.invert()) return operator*(inverted()); + return {}; + } + + auto& operator+=(const Matrix& source) { return *this = operator+(source); } + auto& operator-=(const Matrix& source) { return *this = operator-(source); } + auto& operator*=(T source) { return *this = operator*(source); } + auto& operator/=(T source) { return *this = operator/(source); } + template + auto& operator*=(const Matrix& source) { return *this = operator*(source); } + //matrix division is not always possible (when matrix cannot be inverted), so operator/= is not provided + + //algorithm: Gauss-Jordan + auto invert() const -> maybe { + static_assert(Rows == Cols); + Matrix source = *this; + Matrix result = identity(); + + const auto add = [&](uint targetRow, uint sourceRow, T factor = 1) { + for(uint col : range(Cols)) { + result(targetRow, col) += result(sourceRow, col) * factor; + source(targetRow, col) += source(sourceRow, col) * factor; + } + }; + + const auto sub = [&](uint targetRow, uint sourceRow, T factor = 1) { + for(uint col : range(Cols)) { + result(targetRow, col) -= result(sourceRow, col) * factor; + source(targetRow, col) -= source(sourceRow, col) * factor; + } + }; + + const auto mul = [&](uint row, T factor) { + for(uint col : range(Cols)) { + result(row, col) *= factor; + source(row, col) *= factor; + } + }; + + for(uint i : range(Cols)) { + if(source(i, i) == 0) { + for(uint row : range(Rows)) { + if(source(row, i) != 0) { + add(i, row); + break; + } + } + //matrix is not invertible: + if(source(i, i) == 0) return {}; + } + + mul(i, T{1} / source(i, i)); + for(uint row : range(Rows)) { + if(row == i) continue; + sub(row, i, source(row, i)); + } + } + + return result; + } + + auto transpose() const -> Matrix { + Matrix result; + for(uint row : range(Rows)) { + for(uint col : range(Cols)) { + result(col, row) = target(row, col); + } + } + return result; + } + + static auto identity() -> Matrix { + static_assert(Rows == Cols); + Matrix result; + for(uint row : range(Rows)) { + for(uint col : range(Cols)) { + result(row, col) = row == col; + } + } + return result; + } + + //debugging function: do not use in production code + template + auto _print() const -> void { + for(uint row : range(Rows)) { + nall::print("[ "); + for(uint col : range(Cols)) { + nall::print(pad(target(row, col), Pad, ' '), " "); + } + nall::print("]\n"); + } + } + +protected: + //same as operator(), but with easier to read syntax inside Matrix class + auto target(uint row, uint col) -> T& { return values[row][col]; } + auto target(uint row, uint col) const -> T { return values[row][col]; } + + T values[Rows][Cols]{}; +}; + +} diff --git a/nall/maybe.hpp b/nall/maybe.hpp new file mode 100755 index 0000000..0c3ae52 --- /dev/null +++ b/nall/maybe.hpp @@ -0,0 +1,91 @@ +#pragma once + +namespace nall { + +struct nothing_t {}; +static nothing_t nothing; +struct else_t {}; + +template +struct maybe { + inline maybe() {} + inline maybe(nothing_t) {} + inline maybe(const T& source) { operator=(source); } + inline maybe(T&& source) { operator=(move(source)); } + inline maybe(const maybe& source) { operator=(source); } + inline maybe(maybe&& source) { operator=(move(source)); } + inline ~maybe() { reset(); } + + inline auto operator=(nothing_t) -> maybe& { reset(); return *this; } + inline auto operator=(const T& source) -> maybe& { reset(); _valid = true; new(&_value.t) T(source); return *this; } + inline auto operator=(T&& source) -> maybe& { reset(); _valid = true; new(&_value.t) T(move(source)); return *this; } + + inline auto operator=(const maybe& source) -> maybe& { + if(this == &source) return *this; + reset(); + if(_valid = source._valid) new(&_value.t) T(source.get()); + return *this; + } + + inline auto operator=(maybe&& source) -> maybe& { + if(this == &source) return *this; + reset(); + if(_valid = source._valid) new(&_value.t) T(move(source.get())); + return *this; + } + + inline explicit operator bool() const { return _valid; } + inline auto reset() -> void { if(_valid) { _value.t.~T(); _valid = false; } } + inline auto data() -> T* { return _valid ? &_value.t : nullptr; } + inline auto get() -> T& { assert(_valid); return _value.t; } + + inline auto data() const -> const T* { return ((maybe*)this)->data(); } + inline auto get() const -> const T& { return ((maybe*)this)->get(); } + inline auto operator->() -> T* { return data(); } + inline auto operator->() const -> const T* { return data(); } + inline auto operator*() -> T& { return get(); } + inline auto operator*() const -> const T& { return get(); } + inline auto operator()() -> T& { return get(); } + inline auto operator()() const -> const T& { return get(); } + inline auto operator()(const T& invalid) const -> const T& { return _valid ? get() : invalid; } + +private: + union U { + T t; + U() {} + ~U() {} + } _value; + bool _valid = false; +}; + +template +struct maybe { + inline maybe() : _value(nullptr) {} + inline maybe(nothing_t) : _value(nullptr) {} + inline maybe(const T& source) : _value((T*)&source) {} + inline maybe(const maybe& source) : _value(source._value) {} + + inline auto operator=(nothing_t) -> maybe& { _value = nullptr; return *this; } + inline auto operator=(const T& source) -> maybe& { _value = (T*)&source; return *this; } + inline auto operator=(const maybe& source) -> maybe& { _value = source._value; return *this; } + + inline explicit operator bool() const { return _value; } + inline auto reset() -> void { _value = nullptr; } + inline auto data() -> T* { return _value; } + inline auto get() -> T& { assert(_value); return *_value; } + + inline auto data() const -> const T* { return ((maybe*)this)->data(); } + inline auto get() const -> const T& { return ((maybe*)this)->get(); } + inline auto operator->() -> T* { return data(); } + inline auto operator->() const -> const T* { return data(); } + inline auto operator*() -> T& { return get(); } + inline auto operator*() const -> const T& { return get(); } + inline auto operator()() -> T& { return get(); } + inline auto operator()() const -> const T& { return get(); } + inline auto operator()(const T& invalid) const -> const T& { return _value ? get() : invalid; } + +private: + T* _value; +}; + +} diff --git a/nall/memory.hpp b/nall/memory.hpp new file mode 100755 index 0000000..9eba671 --- /dev/null +++ b/nall/memory.hpp @@ -0,0 +1,163 @@ +#pragma once + +#include +#include + +namespace nall::memory { + template inline auto allocate(uint size) -> T*; + template inline auto allocate(uint size, const T& value) -> T*; + + template inline auto resize(void* target, uint size) -> T*; + + inline auto free(void* target) -> void; + + template inline auto compare(const void* target, uint capacity, const void* source, uint size) -> int; + template inline auto compare(const void* target, const void* source, uint size) -> int; + + template inline auto icompare(const void* target, uint capacity, const void* source, uint size) -> int; + template inline auto icompare(const void* target, const void* source, uint size) -> int; + + template inline auto copy(void* target, uint capacity, const void* source, uint size) -> T*; + template inline auto copy(void* target, const void* source, uint size) -> T*; + + template inline auto move(void* target, uint capacity, const void* source, uint size) -> T*; + template inline auto move(void* target, const void* source, uint size) -> T*; + + template inline auto fill(void* target, uint capacity, const T& value = {}) -> T*; + + template inline auto assign(T* target) -> void {} + template inline auto assign(T* target, const U& value, P&&... p) -> void; + + template inline auto readl(const void* source) -> T; + template inline auto readm(const void* source) -> T; + + template inline auto writel(void* target, T data) -> void; + template inline auto writem(void* target, T data) -> void; +} + +namespace nall::memory { + +//implementation notes: +//memcmp, memcpy, memmove have terrible performance on small block sizes (FreeBSD 10.0-amd64) +//as this library is used extensively by nall/string, and most strings tend to be small, +//this library hand-codes these functions instead. surprisingly, it's a substantial speedup + +template auto allocate(uint size) -> T* { + return (T*)malloc(size * sizeof(T)); +} + +template auto allocate(uint size, const T& value) -> T* { + auto result = allocate(size); + if(result) fill(result, size, value); + return result; +} + +template auto resize(void* target, uint size) -> T* { + return (T*)realloc(target, size * sizeof(T)); +} + +auto free(void* target) -> void { + ::free(target); +} + +template auto compare(const void* target, uint capacity, const void* source, uint size) -> int { + auto t = (uint8_t*)target; + auto s = (uint8_t*)source; + auto l = min(capacity, size) * sizeof(T); + while(l--) { + auto x = *t++; + auto y = *s++; + if(x != y) return x - y; + } + if(capacity == size) return 0; + return -(capacity < size); +} + +template auto compare(const void* target, const void* source, uint size) -> int { + return compare(target, size, source, size); +} + +template auto icompare(const void* target, uint capacity, const void* source, uint size) -> int { + auto t = (uint8_t*)target; + auto s = (uint8_t*)source; + auto l = min(capacity, size) * sizeof(T); + while(l--) { + auto x = *t++; + auto y = *s++; + if(x - 'A' < 26) x += 32; + if(y - 'A' < 26) y += 32; + if(x != y) return x - y; + } + return -(capacity < size); +} + +template auto icompare(const void* target, const void* source, uint size) -> int { + return icompare(target, size, source, size); +} + +template auto copy(void* target, uint capacity, const void* source, uint size) -> T* { + auto t = (uint8_t*)target; + auto s = (uint8_t*)source; + auto l = min(capacity, size) * sizeof(T); + while(l--) *t++ = *s++; + return (T*)target; +} + +template auto copy(void* target, const void* source, uint size) -> T* { + return copy(target, size, source, size); +} + +template auto move(void* target, uint capacity, const void* source, uint size) -> T* { + auto t = (uint8_t*)target; + auto s = (uint8_t*)source; + auto l = min(capacity, size) * sizeof(T); + if(t < s) { + while(l--) *t++ = *s++; + } else { + t += l; + s += l; + while(l--) *--t = *--s; + } + return (T*)target; +} + +template auto move(void* target, const void* source, uint size) -> T* { + return move(target, size, source, size); +} + +template auto fill(void* target, uint capacity, const T& value) -> T* { + auto t = (T*)target; + while(capacity--) *t++ = value; + return (T*)target; +} + +template auto assign(T* target, const U& value, P&&... p) -> void { + *target++ = value; + assign(target, forward

    (p)...); +} + +template auto readl(const void* source) -> T { + auto p = (const uint8_t*)source; + T data = 0; + for(uint n = 0; n < size; n++) data |= T(*p++) << n * 8; + return data; +} + +template auto readm(const void* source) -> T { + auto p = (const uint8_t*)source; + T data = 0; + for(int n = size - 1; n >= 0; n--) data |= T(*p++) << n * 8; + return data; +} + +template auto writel(void* target, T data) -> void { + auto p = (uint8_t*)target; + for(uint n = 0; n < size; n++) *p++ = data >> n * 8; +} + +template auto writem(void* target, T data) -> void { + auto p = (uint8_t*)target; + for(int n = size - 1; n >= 0; n--) *p++ = data >> n * 8; +} + +} diff --git a/nall/merge-sort.hpp b/nall/merge-sort.hpp new file mode 100755 index 0000000..5c1175b --- /dev/null +++ b/nall/merge-sort.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include +#include + +//class: merge sort +//average: O(n log n) +//worst: O(n log n) +//memory: O(n) +//stack: O(log n) +//stable?: yes + +//note: merge sort was chosen over quick sort, because: +//* it is a stable sort +//* it lacks O(n^2) worst-case overhead +//* it usually runs faster than quick sort anyway + +//note: insertion sort is generally more performant than selection sort +#define NALL_MERGE_SORT_INSERTION +//#define NALL_MERGE_SORT_SELECTION + +namespace nall { + +template auto sort(T list[], uint size, const Comparator& lessthan) -> void { + if(size <= 1) return; //nothing to sort + + //sort smaller blocks using an O(n^2) algorithm (which for small sizes, increases performance) + if(size < 64) { + //insertion sort requires a copy (via move construction) + #if defined(NALL_MERGE_SORT_INSERTION) + for(int i = 1, j; i < size; i++) { + T copy(move(list[i])); + for(j = i - 1; j >= 0; j--) { + if(!lessthan(copy, list[j])) break; + list[j + 1] = move(list[j]); + } + list[j + 1] = move(copy); + } + //selection sort requires a swap + #elif defined(NALL_MERGE_SORT_SELECTION) + for(uint i = 0; i < size; i++) { + uint min = i; + for(uint j = i + 1; j < size; j++) { + if(lessthan(list[j], list[min])) min = j; + } + if(min != i) swap(list[i], list[min]); + } + #endif + return; + } + + //split list in half and recursively sort both + uint middle = size / 2; + sort(list, middle, lessthan); + sort(list + middle, size - middle, lessthan); + + //left and right are sorted here; perform merge sort + //use placement new to avoid needing T to be default-constructable + auto buffer = memory::allocate(size); + uint offset = 0, left = 0, right = middle; + while(left < middle && right < size) { + if(!lessthan(list[right], list[left])) { + new(buffer + offset++) T(move(list[left++])); + } else { + new(buffer + offset++) T(move(list[right++])); + } + } + while(left < middle) new(buffer + offset++) T(move(list[left++])); + while(right < size ) new(buffer + offset++) T(move(list[right++])); + + for(uint i = 0; i < size; i++) { + list[i] = move(buffer[i]); + buffer[i].~T(); + } + memory::free(buffer); +} + +template auto sort(T list[], uint size) -> void { + return sort(list, size, [](const T& l, const T& r) { return l < r; }); +} + +} diff --git a/nall/nall.hpp b/nall/nall.hpp new file mode 100755 index 0000000..ec04866 --- /dev/null +++ b/nall/nall.hpp @@ -0,0 +1,101 @@ +#pragma once + +/* nall + * author: byuu + * license: ISC + * + * nall is a header library that provides both fundamental and useful classes + * its goals are portability, consistency, minimalism and reusability + */ + +//include the most common nall headers with one statement +//does not include the most obscure components with high cost and low usage + +#include + +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //todo: compilation errors when included earlier +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_WINDOWS) + #include + #include +#endif + +#if defined(API_POSIX) + #include +#endif diff --git a/nall/path.hpp b/nall/path.hpp new file mode 100644 index 0000000..5506f7f --- /dev/null +++ b/nall/path.hpp @@ -0,0 +1,155 @@ +#pragma once + +#include + +namespace nall::Path { + +inline auto active() -> string { + char path[PATH_MAX] = ""; + (void)getcwd(path, PATH_MAX); + string result = path; + if(!result) result = "."; + result.transform("\\", "/"); + if(!result.endsWith("/")) result.append("/"); + return result; +} + +inline auto real(string_view name) -> string { + string result; + char path[PATH_MAX] = ""; + if(::realpath(name, path)) result = Location::path(string{path}.transform("\\", "/")); + if(!result) return active(); + result.transform("\\", "/"); + if(!result.endsWith("/")) result.append("/"); + return result; +} + +inline auto program() -> string { + #if defined(PLATFORM_WINDOWS) + wchar_t path[PATH_MAX] = L""; + GetModuleFileName(nullptr, path, PATH_MAX); + string result = (const char*)utf8_t(path); + result.transform("\\", "/"); + return Path::real(result); + #else + Dl_info info; + dladdr((void*)&program, &info); + return Path::real(info.dli_fname); + #endif +} + +// / +// c:/ +inline auto root() -> string { + #if defined(PLATFORM_WINDOWS) + wchar_t path[PATH_MAX] = L""; + SHGetFolderPathW(nullptr, CSIDL_WINDOWS | CSIDL_FLAG_CREATE, nullptr, 0, path); + string result = (const char*)utf8_t(path); + result.transform("\\", "/"); + return slice(result, 0, 3); + #else + return "/"; + #endif +} + +// /home/username/ +// c:/users/username/ +inline auto user() -> string { + #if defined(PLATFORM_WINDOWS) + wchar_t path[PATH_MAX] = L""; + SHGetFolderPathW(nullptr, CSIDL_PROFILE | CSIDL_FLAG_CREATE, nullptr, 0, path); + string result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #else + struct passwd* userinfo = getpwuid(getuid()); + string result = userinfo->pw_dir; + #endif + if(!result) result = "."; + if(!result.endsWith("/")) result.append("/"); + return result; +} + +// /home/username/Desktop/ +// c:/users/username/Desktop/ +inline auto desktop(string_view name = {}) -> string { + return {user(), "Desktop/", name}; +} + +//todo: MacOS uses the same location for userData() and userSettings() +//... is there a better option here? + +// /home/username/.config/ +// ~/Library/Application Support/ +// c:/users/username/appdata/roaming/ +inline auto userSettings() -> string { + #if defined(PLATFORM_WINDOWS) + wchar_t path[PATH_MAX] = L""; + SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); + string result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #elif defined(PLATFORM_MACOS) + string result = {Path::user(), "Library/Application Support/"}; + #else + string result = {Path::user(), ".config/"}; + #endif + if(!result) result = "."; + if(!result.endsWith("/")) result.append("/"); + return result; +} + +// /home/username/.local/share/ +// ~/Library/Application Support/ +// c:/users/username/appdata/local/ +inline auto userData() -> string { + #if defined(PLATFORM_WINDOWS) + wchar_t path[PATH_MAX] = L""; + SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); + string result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #elif defined(PLATFORM_MACOS) + string result = {Path::user(), "Library/Application Support/"}; + #else + string result = {Path::user(), ".local/share/"}; + #endif + if(!result) result = "."; + if(!result.endsWith("/")) result.append("/"); + return result; +} + +// /usr/share +// /Library/Application Support/ +// c:/ProgramData/ +inline auto sharedData() -> string { + #if defined(PLATFORM_WINDOWS) + wchar_t path[PATH_MAX] = L""; + SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); + string result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #elif defined(PLATFORM_MACOS) + string result = "/Library/Application Support/"; + #else + string result = "/usr/share/"; + #endif + if(!result) result = "."; + if(!result.endsWith("/")) result.append("/"); + return result; +} + +// /tmp +// c:/users/username/AppData/Local/Temp/ +inline auto temporary() -> string { + #if defined(PLATFORM_WINDOWS) + wchar_t path[PATH_MAX] = L""; + GetTempPathW(PATH_MAX, path); + string result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #elif defined(P_tmpdir) + string result = P_tmpdir; + #else + string result = "/tmp/"; + #endif + if(!result.endsWith("/")) result.append("/"); + return result; +} + +} diff --git a/nall/platform.hpp b/nall/platform.hpp new file mode 100755 index 0000000..bf8711c --- /dev/null +++ b/nall/platform.hpp @@ -0,0 +1,124 @@ +#pragma once + +#include + +namespace Math { + static const long double e = 2.71828182845904523536; + static const long double Pi = 3.14159265358979323846; +} + +#if defined(PLATFORM_WINDOWS) + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if !defined(PLATFORM_WINDOWS) + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +#if defined(COMPILER_MICROSOFT) + #define va_copy(dest, src) ((dest) = (src)) +#endif + +#if defined(PLATFORM_WINDOWS) + #undef IN + #undef OUT + #undef interface + #define dllexport __declspec(dllexport) + #define MSG_NOSIGNAL 0 + + extern "C" { + using pollfd = WSAPOLLFD; + } + + inline auto access(const char* path, int amode) -> int { return _waccess(nall::utf16_t(path), amode); } + inline auto getcwd(char* buf, size_t size) -> char* { wchar_t wpath[PATH_MAX] = L""; if(!_wgetcwd(wpath, size)) return nullptr; strcpy(buf, nall::utf8_t(wpath)); return buf; } + inline auto mkdir(const char* path, int mode) -> int { return _wmkdir(nall::utf16_t(path)); } + inline auto poll(struct pollfd fds[], unsigned long nfds, int timeout) -> int { return WSAPoll(fds, nfds, timeout); } + inline auto putenv(const char* value) -> int { return _wputenv(nall::utf16_t(value)); } + inline auto realpath(const char* file_name, char* resolved_name) -> char* { wchar_t wfile_name[PATH_MAX] = L""; if(!_wfullpath(wfile_name, nall::utf16_t(file_name), PATH_MAX)) return nullptr; strcpy(resolved_name, nall::utf8_t(wfile_name)); return resolved_name; } + inline auto rename(const char* oldname, const char* newname) -> int { return _wrename(nall::utf16_t(oldname), nall::utf16_t(newname)); } + + namespace nall { + //network functions take void*, not char*. this allows them to be used without casting + + inline auto recv(int socket, void* buffer, size_t length, int flags) -> ssize_t { + return ::recv(socket, (char*)buffer, length, flags); + } + + inline auto send(int socket, const void* buffer, size_t length, int flags) -> ssize_t { + return ::send(socket, (const char*)buffer, length, flags); + } + + inline auto setsockopt(int socket, int level, int option_name, const void* option_value, socklen_t option_len) -> int { + return ::setsockopt(socket, level, option_name, (const char*)option_value, option_len); + } + } +#else + #define dllexport +#endif + +#if defined(PLATFORM_MACOS) + #define MSG_NOSIGNAL 0 +#endif + +#if defined(COMPILER_CLANG) || defined(COMPILER_GCC) + #define noinline __attribute__((noinline)) + #define alwaysinline inline __attribute__((always_inline)) +#elif defined(COMPILER_MICROSOFT) + #define noinline __declspec(noinline) + #define alwaysinline inline __forceinline +#else + #define noinline + #define alwaysinline inline +#endif + +//P0627: [[unreachable]] -- impossible to simulate with identical syntax, must omit brackets ... +#if defined(COMPILER_CLANG) || defined(COMPILER_GCC) + #define unreachable __builtin_unreachable() +#else + #define unreachable throw +#endif + +#define export $export +#define register $register diff --git a/nall/pointer.hpp b/nall/pointer.hpp new file mode 100644 index 0000000..0e96ddb --- /dev/null +++ b/nall/pointer.hpp @@ -0,0 +1,34 @@ +#pragma once + +namespace nall { + +template +struct pointer { + explicit operator bool() const { return value; } + + pointer() = default; + pointer(T* source) { value = source; } + pointer(const pointer& source) { value = source.value; } + + auto& operator=(T* source) { value = source; return *this; } + auto& operator=(const pointer& source) { value = source.value; return *this; } + + auto operator()() -> T* { return value; } + auto operator()() const -> const T* { return value; } + + auto operator->() -> T* { return value; } + auto operator->() const -> const T* { return value; } + + auto operator*() -> T& { return *value; } + auto operator*() const -> const T& { return *value; } + + auto reset() -> void { value = nullptr; } + + auto data() -> T* { return value; } + auto data() const -> const T* { return value; } + +private: + T* value = nullptr; +}; + +} diff --git a/nall/posix/service.hpp b/nall/posix/service.hpp new file mode 100644 index 0000000..623682c --- /dev/null +++ b/nall/posix/service.hpp @@ -0,0 +1,114 @@ +#pragma once + +#include + +namespace nall { + +struct service { + inline explicit operator bool() const; + inline auto command(const string& name, const string& command) -> bool; + inline auto receive() -> string; + inline auto name() const -> string; + inline auto stop() const -> bool; + +private: + shared_memory shared; + string _name; + bool _stop = false; +}; + +service::operator bool() const { + return (bool)shared; +} + +//returns true on new service process creation (false is not necessarily an error) +auto service::command(const string& name, const string& command) -> bool { + if(!name) return false; + if(!command) return print("[{0}] usage: {service} command\n" + "commands:\n" + " status : query whether service is running\n" + " start : start service if it is not running\n" + " stop : stop service if it is running\n" + " remove : remove semaphore lock if service crashed\n" + " {value} : send custom command to service\n" + "", string_format{name}), false; + + if(shared.open(name, 4096)) { + if(command == "start") { + print("[{0}] already started\n", string_format{name}); + } else if(command == "status") { + print("[{0}] running\n", string_format{name}); + } + if(auto data = shared.acquire()) { + if(command == "stop") print("[{0}] stopped\n", string_format{name}); + memory::copy(data, 4096, command.data(), command.size()); + shared.release(); + } + if(command == "remove") { + shared.remove(); + print("[{0}] removed\n", string_format{name}); + } + return false; + } + + if(command == "start") { + if(shared.create(name, 4096)) { + print("[{0}] started\n", string_format{name}); + auto pid = fork(); + if(pid == 0) { + signal(SIGHUP, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + _name = name; + return true; + } + shared.close(); + } else { + print("[{0}] start failed ({1})\n", string_format{name, strerror(errno)}); + } + return false; + } + + if(command == "status") { + print("[{0}] stopped\n", string_format{name}); + return false; + } + + return false; +} + +auto service::receive() -> string { + string command; + if(shared) { + if(auto data = shared.acquire()) { + if(*data) { + command.resize(4095); + memory::copy(command.get(), data, 4095); + memory::fill(data, 4096); + } + shared.release(); + if(command == "remove") { + _stop = true; + return ""; + } else if(command == "start") { + return ""; + } else if(command == "status") { + return ""; + } else if(command == "stop") { + _stop = true; + shared.remove(); + return ""; + } + } + } + return command; +} + +auto service::name() const -> string { + return _name; +} + +auto service::stop() const -> bool { + return _stop; +} + +} diff --git a/nall/posix/shared-memory.hpp b/nall/posix/shared-memory.hpp new file mode 100644 index 0000000..af66563 --- /dev/null +++ b/nall/posix/shared-memory.hpp @@ -0,0 +1,147 @@ +#pragma once + +#include +#include + +namespace nall { + +struct shared_memory { + shared_memory() = default; + shared_memory(const shared_memory&) = delete; + auto operator=(const shared_memory&) -> shared_memory& = delete; + + ~shared_memory() { + reset(); + } + + explicit operator bool() const { + return _mode != mode::inactive; + } + + auto size() const -> unsigned { + return _size; + } + + auto acquired() const -> bool { + return _acquired; + } + + auto acquire() -> uint8_t* { + if(!acquired()) { + sem_wait(_semaphore); + _acquired = true; + } + return _data; + } + + auto release() -> void { + if(acquired()) { + sem_post(_semaphore); + _acquired = false; + } + } + + auto reset() -> void { + release(); + if(_mode == mode::server) return remove(); + if(_mode == mode::client) return close(); + } + + auto create(const string& name, unsigned size) -> bool { + reset(); + + _name = {"/nall-", string{name}.transform("/:", "--")}; + _size = size; + + //O_CREAT | O_EXCL seems to throw ENOENT even when semaphore does not exist ... + _semaphore = sem_open(_name, O_CREAT, 0644, 1); + if(_semaphore == SEM_FAILED) return remove(), false; + + _descriptor = shm_open(_name, O_CREAT | O_TRUNC | O_RDWR, 0644); + if(_descriptor < 0) return remove(), false; + + if(ftruncate(_descriptor, _size) != 0) return remove(), false; + + _data = (uint8_t*)mmap(nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _descriptor, 0); + if(_data == MAP_FAILED) return remove(), false; + + memory::fill(_data, _size); + + _mode = mode::server; + return true; + } + + auto remove() -> void { + if(_data) { + munmap(_data, _size); + _data = nullptr; + } + + if(_descriptor) { + ::close(_descriptor); + shm_unlink(_name); + _descriptor = -1; + } + + if(_semaphore) { + sem_close(_semaphore); + sem_unlink(_name); + _semaphore = nullptr; + } + + _mode = mode::inactive; + _name = ""; + _size = 0; + } + + auto open(const string& name, unsigned size) -> bool { + reset(); + + _name = {"/nall-", string{name}.transform("/:", "--")}; + _size = size; + + _semaphore = sem_open(_name, 0, 0644); + if(_semaphore == SEM_FAILED) return close(), false; + + _descriptor = shm_open(_name, O_RDWR, 0644); + if(_descriptor < 0) return close(), false; + + _data = (uint8_t*)mmap(nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _descriptor, 0); + if(_data == MAP_FAILED) return close(), false; + + _mode = mode::client; + return true; + } + + auto close() -> void { + if(_data) { + munmap(_data, _size); + _data = nullptr; + } + + if(_descriptor) { + ::close(_descriptor); + _descriptor = -1; + } + + if(_semaphore) { + sem_close(_semaphore); + _semaphore = nullptr; + } + + _mode = mode::inactive; + _name = ""; + _size = 0; + } + +private: + enum class mode : unsigned { server, client, inactive } _mode = mode::inactive; + string _name; + sem_t* _semaphore = nullptr; + signed _descriptor = -1; + uint8_t* _data = nullptr; + unsigned _size = 0; + bool _acquired = false; +}; + +} diff --git a/nall/primitives.hpp b/nall/primitives.hpp new file mode 100644 index 0000000..fd81129 --- /dev/null +++ b/nall/primitives.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +namespace nall { + struct Boolean; + template struct Natural; + template struct Integer; + template struct Real; +} + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nall { + template auto Natural::integer() const -> Integer { return Integer(*this); } + template auto Integer::natural() const -> Natural { return Natural(*this); } +} diff --git a/nall/primitives/bit-field.hpp b/nall/primitives/bit-field.hpp new file mode 100644 index 0000000..0ee52ff --- /dev/null +++ b/nall/primitives/bit-field.hpp @@ -0,0 +1,124 @@ +#pragma once + +namespace nall { + +template struct BitField; + +/* static BitField */ + +template struct BitField { + static_assert(Precision >= 1 && Precision <= 64); + enum : uint { bits = Precision }; + using type = + conditional_t>>>; + enum : uint { shift = Index < 0 ? Precision + Index : Index }; + enum : type { mask = 1ull << shift }; + + BitField(const BitField&) = delete; + + inline auto& operator=(const BitField& source) { + target = target & ~mask | (bool)source << shift; + return *this; + } + + template inline BitField(T* source) : target((type&)*source) { + static_assert(sizeof(T) == sizeof(type)); + } + + inline auto bit() const { + return shift; + } + + inline operator bool() const { + return target & mask; + } + + inline auto& operator=(bool source) { + target = target & ~mask | source << shift; + return *this; + } + + inline auto& operator&=(bool source) { + target = target & (~mask | source << shift); + return *this; + } + + inline auto& operator^=(bool source) { + target = target ^ source << shift; + return *this; + } + + inline auto& operator|=(bool source) { + target = target | source << shift; + return *this; + } + +private: + type& target; +}; + +/* dynamic BitField */ + +template struct BitField { + static_assert(Precision >= 1 && Precision <= 64); + enum : uint { bits = Precision }; + using type = + conditional_t>>>; + + BitField(const BitField&) = delete; + + inline auto& operator=(const BitField& source) { + target = target & ~mask | (bool)source << shift; + return *this; + } + + template inline BitField(T* source, int index) : target((type&)*source) { + static_assert(sizeof(T) == sizeof(type)); + if(index < 0) index = Precision + index; + mask = 1ull << index; + shift = index; + } + + inline auto bit() const { + return shift; + } + + inline operator bool() const { + return target & mask; + } + + inline auto& operator=(bool source) { + target = target & ~mask | source << shift; + return *this; + } + + inline auto& operator&=(bool source) { + target = target & (~mask | source << shift); + return *this; + } + + inline auto& operator^=(bool source) { + target = target ^ source << shift; + return *this; + } + + inline auto& operator|=(bool source) { + target = target | source << shift; + return *this; + } + +private: + type& target; + type mask; + uint shift; +}; + +} diff --git a/nall/primitives/bit-range.hpp b/nall/primitives/bit-range.hpp new file mode 100644 index 0000000..1efc21c --- /dev/null +++ b/nall/primitives/bit-range.hpp @@ -0,0 +1,255 @@ +#pragma once + +namespace nall { + +template struct BitRange; + +/* static BitRange */ + +template struct BitRange { + static_assert(Precision >= 1 && Precision <= 64); + enum : uint { bits = Precision }; + using type = + conditional_t>>>; + enum : uint { lo = Lo < 0 ? Precision + Lo : Lo }; + enum : uint { hi = Hi < 0 ? Precision + Hi : Hi }; + enum : type { mask = ~0ull >> 64 - (hi - lo + 1) << lo }; + enum : uint { shift = lo }; + + BitRange(const BitRange& source) = delete; + + inline auto& operator=(const BitRange& source) { + target = target & ~mask | ((source.target & source.mask) >> source.shift) << shift & mask; + return *this; + } + + template inline BitRange(T* source) : target((type&)*source) { + static_assert(sizeof(T) == sizeof(type)); + } + + inline operator type() const { + return (target & mask) >> shift; + } + + inline auto operator++(int) { + auto value = (target & mask) >> shift; + target = target & ~mask | target + (1 << shift) & mask; + return value; + } + + inline auto operator--(int) { + auto value = (target & mask) >> shift; + target = target & ~mask | target - (1 << shift) & mask; + return value; + } + + inline auto& operator++() { + target = target & ~mask | target + (1 << shift) & mask; + return *this; + } + + inline auto& operator--() { + target = target & ~mask | target - (1 << shift) & mask; + return *this; + } + + template inline auto& operator=(const T& source) { + target = target & ~mask | source << shift & mask; + return *this; + } + + template inline auto& operator*=(const T& source) { + auto value = ((target & mask) >> shift) * source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator/=(const T& source) { + auto value = ((target & mask) >> shift) / source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator%=(const T& source) { + auto value = ((target & mask) >> shift) % source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator+=(const T& source) { + auto value = ((target & mask) >> shift) + source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator-=(const T& source) { + auto value = ((target & mask) >> shift) - source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator<<=(const T& source) { + auto value = ((target & mask) >> shift) << source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator>>=(const T& source) { + auto value = ((target & mask) >> shift) >> source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator&=(const T& source) { + target = target & (~mask | source << shift & mask); + return *this; + } + + template inline auto& operator^=(const T& source) { + target = target ^ source << shift & mask; + return *this; + } + + template inline auto& operator|=(const T& source) { + target = target | source << shift & mask; + return *this; + } + +private: + type& target; +}; + +/* dynamic BitRange */ + +template struct BitRange { + static_assert(Precision >= 1 && Precision <= 64); + enum : uint { bits = Precision }; + using type = + conditional_t>>>; + + BitRange(const BitRange& source) = delete; + + inline auto& operator=(const BitRange& source) { + target = target & ~mask | ((source.target & source.mask) >> source.shift) << shift & mask; + return *this; + } + + template inline BitRange(T* source, int index) : target((type&)*source) { + static_assert(sizeof(T) == sizeof(type)); + if(index < 0) index = Precision + index; + mask = 1ull << index; + shift = index; + } + + template inline BitRange(T* source, int lo, int hi) : target((type&)*source) { + static_assert(sizeof(T) == sizeof(type)); + if(lo < 0) lo = Precision + lo; + if(hi < 0) hi = Precision + hi; + if(lo > hi) swap(lo, hi); + mask = ~0ull >> 64 - (hi - lo + 1) << lo; + shift = lo; + } + + inline operator type() const { + return (target & mask) >> shift; + } + + inline auto operator++(int) { + auto value = (target & mask) >> shift; + target = target & ~mask | target + (1 << shift) & mask; + return value; + } + + inline auto operator--(int) { + auto value = (target & mask) >> shift; + target = target & ~mask | target - (1 << shift) & mask; + return value; + } + + inline auto& operator++() { + target = target & ~mask | target + (1 << shift) & mask; + return *this; + } + + inline auto& operator--() { + target = target & ~mask | target - (1 << shift) & mask; + return *this; + } + + template inline auto& operator=(const T& source) { + target = target & ~mask | source << shift & mask; + return *this; + } + + template inline auto& operator*=(const T& source) { + auto value = ((target & mask) >> shift) * source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator/=(const T& source) { + auto value = ((target & mask) >> shift) / source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator%=(const T& source) { + auto value = ((target & mask) >> shift) % source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator+=(const T& source) { + auto value = ((target & mask) >> shift) + source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator-=(const T& source) { + auto value = ((target & mask) >> shift) - source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator<<=(const T& source) { + auto value = ((target & mask) >> shift) << source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator>>=(const T& source) { + auto value = ((target & mask) >> shift) >> source; + target = target & ~mask | value << shift & mask; + return *this; + } + + template inline auto& operator&=(const T& source) { + target = target & (~mask | source << shift & mask); + return *this; + } + + template inline auto& operator^=(const T& source) { + target = target ^ source << shift & mask; + return *this; + } + + template inline auto& operator|=(const T& source) { + target = target | source << shift & mask; + return *this; + } + +private: + type& target; + type mask; + uint shift; +}; + +} diff --git a/nall/primitives/boolean.hpp b/nall/primitives/boolean.hpp new file mode 100644 index 0000000..0426a37 --- /dev/null +++ b/nall/primitives/boolean.hpp @@ -0,0 +1,30 @@ +#pragma once + +namespace nall { + +struct Boolean { + static inline constexpr auto bits() -> uint { return 1; } + using btype = bool; + + inline Boolean() : data(false) {} + template inline Boolean(const T& value) : data(value) {} + explicit inline Boolean(const char* value) { data = !strcmp(value, "true"); } + + inline operator bool() const { return data; } + template inline auto& operator=(const T& value) { data = value; return *this; } + + inline auto flip() { return data ^= 1; } + inline auto raise() { return data == 0 ? data = 1, true : false; } + inline auto lower() { return data == 1 ? data = 0, true : false; } + + inline auto flip(bool value) { return data != value ? (data = value, true) : false; } + inline auto raise(bool value) { return !data && value ? (data = value, true) : (data = value, false); } + inline auto lower(bool value) { return data && !value ? (data = value, true) : (data = value, false); } + + inline auto serialize(serializer& s) { s(data); } + +private: + btype data; +}; + +} diff --git a/nall/primitives/integer.hpp b/nall/primitives/integer.hpp new file mode 100644 index 0000000..92e6e89 --- /dev/null +++ b/nall/primitives/integer.hpp @@ -0,0 +1,86 @@ +#pragma once + +namespace nall { + +template struct Integer { + static_assert(Precision >= 1 && Precision <= 64); + static inline constexpr auto bits() -> uint { return Precision; } + using stype = + conditional_t>>>; + using utype = typename Natural::utype; + static inline constexpr auto mask() -> utype { return ~0ull >> 64 - Precision; } + static inline constexpr auto sign() -> utype { return 1ull << Precision - 1; } + + inline Integer() : data(0) {} + template inline Integer(Integer value) { data = cast(value); } + template inline Integer(const T& value) { data = cast(value); } + explicit inline Integer(const char* value) { data = cast(toInteger(value)); } + + inline operator stype() const { return data; } + + inline auto operator++(int) { auto value = *this; data = cast(data + 1); return value; } + inline auto operator--(int) { auto value = *this; data = cast(data - 1); return value; } + + inline auto& operator++() { data = cast(data + 1); return *this; } + inline auto& operator--() { data = cast(data - 1); return *this; } + + template inline auto& operator =(const T& value) { data = cast( value); return *this; } + template inline auto& operator *=(const T& value) { data = cast(data * value); return *this; } + template inline auto& operator /=(const T& value) { data = cast(data / value); return *this; } + template inline auto& operator %=(const T& value) { data = cast(data % value); return *this; } + template inline auto& operator +=(const T& value) { data = cast(data + value); return *this; } + template inline auto& operator -=(const T& value) { data = cast(data - value); return *this; } + template inline auto& operator<<=(const T& value) { data = cast(data << value); return *this; } + template inline auto& operator>>=(const T& value) { data = cast(data >> value); return *this; } + template inline auto& operator &=(const T& value) { data = cast(data & value); return *this; } + template inline auto& operator ^=(const T& value) { data = cast(data ^ value); return *this; } + template inline auto& operator |=(const T& value) { data = cast(data | value); return *this; } + + inline auto bit(int index) -> BitRange { return {&data, index}; } + inline auto bit(int index) const -> const BitRange { return {&data, index}; } + + inline auto bit(int lo, int hi) -> BitRange { return {&data, lo, hi}; } + inline auto bit(int lo, int hi) const -> const BitRange { return {&data, lo, hi}; } + + inline auto byte(int index) -> BitRange { return {&data, index * 8 + 0, index * 8 + 7}; } + inline auto byte(int index) const -> const BitRange { return {&data, index * 8 + 0, index * 8 + 7}; } + + inline auto mask(int index) const -> utype { + return data & 1 << index; + } + + inline auto mask(int lo, int hi) const -> utype { + return data & (~0ull >> 64 - (hi - lo + 1) << lo); + } + + inline auto slice(int index) const { return Natural<>{bit(index)}; } + inline auto slice(int lo, int hi) const { return Natural<>{bit(lo, hi)}; } + + inline auto clamp(uint bits) -> stype { + const int64_t b = 1ull << bits - 1; + const int64_t m = b - 1; + return data > m ? m : data < -b ? -b : data; + } + + inline auto clip(uint bits) -> stype { + const uint64_t b = 1ull << bits - 1; + const uint64_t m = b * 2 - 1; + return (data & m ^ b) - b; + } + + inline auto serialize(serializer& s) { s(data); } + inline auto natural() const -> Natural; + +private: + inline auto cast(stype value) const -> stype { + return (value & mask() ^ sign()) - sign(); + } + + stype data; +}; + +} diff --git a/nall/primitives/literals.hpp b/nall/primitives/literals.hpp new file mode 100644 index 0000000..0e85233 --- /dev/null +++ b/nall/primitives/literals.hpp @@ -0,0 +1,143 @@ +#pragma once + +namespace nall { + +inline auto operator"" _b(unsigned long long value) { return boolean{value}; } +inline auto operator"" _n(unsigned long long value) { return natural{value}; } +inline auto operator"" _i(unsigned long long value) { return integer{value}; } +inline auto operator"" _r(long double value) { return real{value}; } + +inline auto operator"" _n1(unsigned long long value) { return natural1{value}; } +inline auto operator"" _n2(unsigned long long value) { return natural2{value}; } +inline auto operator"" _n3(unsigned long long value) { return natural3{value}; } +inline auto operator"" _n4(unsigned long long value) { return natural4{value}; } +inline auto operator"" _n5(unsigned long long value) { return natural5{value}; } +inline auto operator"" _n6(unsigned long long value) { return natural6{value}; } +inline auto operator"" _n7(unsigned long long value) { return natural7{value}; } +inline auto operator"" _n8(unsigned long long value) { return natural8{value}; } +inline auto operator"" _n9(unsigned long long value) { return natural9{value}; } +inline auto operator"" _n10(unsigned long long value) { return natural10{value}; } +inline auto operator"" _n11(unsigned long long value) { return natural11{value}; } +inline auto operator"" _n12(unsigned long long value) { return natural12{value}; } +inline auto operator"" _n13(unsigned long long value) { return natural13{value}; } +inline auto operator"" _n14(unsigned long long value) { return natural14{value}; } +inline auto operator"" _n15(unsigned long long value) { return natural15{value}; } +inline auto operator"" _n16(unsigned long long value) { return natural16{value}; } +inline auto operator"" _n17(unsigned long long value) { return natural17{value}; } +inline auto operator"" _n18(unsigned long long value) { return natural18{value}; } +inline auto operator"" _n19(unsigned long long value) { return natural19{value}; } +inline auto operator"" _n20(unsigned long long value) { return natural20{value}; } +inline auto operator"" _n21(unsigned long long value) { return natural21{value}; } +inline auto operator"" _n22(unsigned long long value) { return natural22{value}; } +inline auto operator"" _n23(unsigned long long value) { return natural23{value}; } +inline auto operator"" _n24(unsigned long long value) { return natural24{value}; } +inline auto operator"" _n25(unsigned long long value) { return natural25{value}; } +inline auto operator"" _n26(unsigned long long value) { return natural26{value}; } +inline auto operator"" _n27(unsigned long long value) { return natural27{value}; } +inline auto operator"" _n28(unsigned long long value) { return natural28{value}; } +inline auto operator"" _n29(unsigned long long value) { return natural29{value}; } +inline auto operator"" _n30(unsigned long long value) { return natural30{value}; } +inline auto operator"" _n31(unsigned long long value) { return natural31{value}; } +inline auto operator"" _n32(unsigned long long value) { return natural32{value}; } +inline auto operator"" _n33(unsigned long long value) { return natural33{value}; } +inline auto operator"" _n34(unsigned long long value) { return natural34{value}; } +inline auto operator"" _n35(unsigned long long value) { return natural35{value}; } +inline auto operator"" _n36(unsigned long long value) { return natural36{value}; } +inline auto operator"" _n37(unsigned long long value) { return natural37{value}; } +inline auto operator"" _n38(unsigned long long value) { return natural38{value}; } +inline auto operator"" _n39(unsigned long long value) { return natural39{value}; } +inline auto operator"" _n40(unsigned long long value) { return natural40{value}; } +inline auto operator"" _n41(unsigned long long value) { return natural41{value}; } +inline auto operator"" _n42(unsigned long long value) { return natural42{value}; } +inline auto operator"" _n43(unsigned long long value) { return natural43{value}; } +inline auto operator"" _n44(unsigned long long value) { return natural44{value}; } +inline auto operator"" _n45(unsigned long long value) { return natural45{value}; } +inline auto operator"" _n46(unsigned long long value) { return natural46{value}; } +inline auto operator"" _n47(unsigned long long value) { return natural47{value}; } +inline auto operator"" _n48(unsigned long long value) { return natural48{value}; } +inline auto operator"" _n49(unsigned long long value) { return natural49{value}; } +inline auto operator"" _n50(unsigned long long value) { return natural50{value}; } +inline auto operator"" _n51(unsigned long long value) { return natural51{value}; } +inline auto operator"" _n52(unsigned long long value) { return natural52{value}; } +inline auto operator"" _n53(unsigned long long value) { return natural53{value}; } +inline auto operator"" _n54(unsigned long long value) { return natural54{value}; } +inline auto operator"" _n55(unsigned long long value) { return natural55{value}; } +inline auto operator"" _n56(unsigned long long value) { return natural56{value}; } +inline auto operator"" _n57(unsigned long long value) { return natural57{value}; } +inline auto operator"" _n58(unsigned long long value) { return natural58{value}; } +inline auto operator"" _n59(unsigned long long value) { return natural59{value}; } +inline auto operator"" _n60(unsigned long long value) { return natural60{value}; } +inline auto operator"" _n61(unsigned long long value) { return natural61{value}; } +inline auto operator"" _n62(unsigned long long value) { return natural62{value}; } +inline auto operator"" _n63(unsigned long long value) { return natural63{value}; } +inline auto operator"" _n64(unsigned long long value) { return natural64{value}; } + +inline auto operator"" _i1(unsigned long long value) { return integer1{value}; } +inline auto operator"" _i2(unsigned long long value) { return integer2{value}; } +inline auto operator"" _i3(unsigned long long value) { return integer3{value}; } +inline auto operator"" _i4(unsigned long long value) { return integer4{value}; } +inline auto operator"" _i5(unsigned long long value) { return integer5{value}; } +inline auto operator"" _i6(unsigned long long value) { return integer6{value}; } +inline auto operator"" _i7(unsigned long long value) { return integer7{value}; } +inline auto operator"" _i8(unsigned long long value) { return integer8{value}; } +inline auto operator"" _i9(unsigned long long value) { return integer9{value}; } +inline auto operator"" _i10(unsigned long long value) { return integer10{value}; } +inline auto operator"" _i11(unsigned long long value) { return integer11{value}; } +inline auto operator"" _i12(unsigned long long value) { return integer12{value}; } +inline auto operator"" _i13(unsigned long long value) { return integer13{value}; } +inline auto operator"" _i14(unsigned long long value) { return integer14{value}; } +inline auto operator"" _i15(unsigned long long value) { return integer15{value}; } +inline auto operator"" _i16(unsigned long long value) { return integer16{value}; } +inline auto operator"" _i17(unsigned long long value) { return integer17{value}; } +inline auto operator"" _i18(unsigned long long value) { return integer18{value}; } +inline auto operator"" _i19(unsigned long long value) { return integer19{value}; } +inline auto operator"" _i20(unsigned long long value) { return integer20{value}; } +inline auto operator"" _i21(unsigned long long value) { return integer21{value}; } +inline auto operator"" _i22(unsigned long long value) { return integer22{value}; } +inline auto operator"" _i23(unsigned long long value) { return integer23{value}; } +inline auto operator"" _i24(unsigned long long value) { return integer24{value}; } +inline auto operator"" _i25(unsigned long long value) { return integer25{value}; } +inline auto operator"" _i26(unsigned long long value) { return integer26{value}; } +inline auto operator"" _i27(unsigned long long value) { return integer27{value}; } +inline auto operator"" _i28(unsigned long long value) { return integer28{value}; } +inline auto operator"" _i29(unsigned long long value) { return integer29{value}; } +inline auto operator"" _i30(unsigned long long value) { return integer30{value}; } +inline auto operator"" _i31(unsigned long long value) { return integer31{value}; } +inline auto operator"" _i32(unsigned long long value) { return integer32{value}; } +inline auto operator"" _i33(unsigned long long value) { return integer33{value}; } +inline auto operator"" _i34(unsigned long long value) { return integer34{value}; } +inline auto operator"" _i35(unsigned long long value) { return integer35{value}; } +inline auto operator"" _i36(unsigned long long value) { return integer36{value}; } +inline auto operator"" _i37(unsigned long long value) { return integer37{value}; } +inline auto operator"" _i38(unsigned long long value) { return integer38{value}; } +inline auto operator"" _i39(unsigned long long value) { return integer39{value}; } +inline auto operator"" _i40(unsigned long long value) { return integer40{value}; } +inline auto operator"" _i41(unsigned long long value) { return integer41{value}; } +inline auto operator"" _i42(unsigned long long value) { return integer42{value}; } +inline auto operator"" _i43(unsigned long long value) { return integer43{value}; } +inline auto operator"" _i44(unsigned long long value) { return integer44{value}; } +inline auto operator"" _i45(unsigned long long value) { return integer45{value}; } +inline auto operator"" _i46(unsigned long long value) { return integer46{value}; } +inline auto operator"" _i47(unsigned long long value) { return integer47{value}; } +inline auto operator"" _i48(unsigned long long value) { return integer48{value}; } +inline auto operator"" _i49(unsigned long long value) { return integer49{value}; } +inline auto operator"" _i50(unsigned long long value) { return integer50{value}; } +inline auto operator"" _i51(unsigned long long value) { return integer51{value}; } +inline auto operator"" _i52(unsigned long long value) { return integer52{value}; } +inline auto operator"" _i53(unsigned long long value) { return integer53{value}; } +inline auto operator"" _i54(unsigned long long value) { return integer54{value}; } +inline auto operator"" _i55(unsigned long long value) { return integer55{value}; } +inline auto operator"" _i56(unsigned long long value) { return integer56{value}; } +inline auto operator"" _i57(unsigned long long value) { return integer57{value}; } +inline auto operator"" _i58(unsigned long long value) { return integer58{value}; } +inline auto operator"" _i59(unsigned long long value) { return integer59{value}; } +inline auto operator"" _i60(unsigned long long value) { return integer60{value}; } +inline auto operator"" _i61(unsigned long long value) { return integer61{value}; } +inline auto operator"" _i62(unsigned long long value) { return integer62{value}; } +inline auto operator"" _i63(unsigned long long value) { return integer63{value}; } +inline auto operator"" _i64(unsigned long long value) { return integer64{value}; } + +inline auto operator"" _r32(long double value) { return real32{value}; } +inline auto operator"" _r64(long double value) { return real32{value}; } + +} diff --git a/nall/primitives/natural.hpp b/nall/primitives/natural.hpp new file mode 100644 index 0000000..7bf3237 --- /dev/null +++ b/nall/primitives/natural.hpp @@ -0,0 +1,84 @@ +#pragma once + +namespace nall { + +template struct Natural { + static_assert(Precision >= 1 && Precision <= 64); + static inline constexpr auto bits() -> uint { return Precision; } + using utype = + conditional_t>>>; + static inline constexpr auto mask() -> utype { return ~0ull >> 64 - Precision; } + + inline Natural() : data(0) {} + template inline Natural(Natural value) { data = cast(value); } + template inline Natural(const T& value) { data = cast(value); } + explicit inline Natural(const char* value) { data = cast(toNatural(value)); } + + inline operator utype() const { return data; } + + inline auto operator++(int) { auto value = *this; data = cast(data + 1); return value; } + inline auto operator--(int) { auto value = *this; data = cast(data - 1); return value; } + + inline auto& operator++() { data = cast(data + 1); return *this; } + inline auto& operator--() { data = cast(data - 1); return *this; } + + template inline auto& operator =(const T& value) { data = cast( value); return *this; } + template inline auto& operator *=(const T& value) { data = cast(data * value); return *this; } + template inline auto& operator /=(const T& value) { data = cast(data / value); return *this; } + template inline auto& operator %=(const T& value) { data = cast(data % value); return *this; } + template inline auto& operator +=(const T& value) { data = cast(data + value); return *this; } + template inline auto& operator -=(const T& value) { data = cast(data - value); return *this; } + template inline auto& operator<<=(const T& value) { data = cast(data << value); return *this; } + template inline auto& operator>>=(const T& value) { data = cast(data >> value); return *this; } + template inline auto& operator &=(const T& value) { data = cast(data & value); return *this; } + template inline auto& operator ^=(const T& value) { data = cast(data ^ value); return *this; } + template inline auto& operator |=(const T& value) { data = cast(data | value); return *this; } + + inline auto bit(int index) -> BitRange { return {&data, index}; } + inline auto bit(int index) const -> const BitRange { return {&data, index}; } + + inline auto bit(int lo, int hi) -> BitRange { return {&data, lo, hi}; } + inline auto bit(int lo, int hi) const -> const BitRange { return {&data, lo, hi}; } + + inline auto byte(int index) -> BitRange { return {&data, index * 8 + 0, index * 8 + 7}; } + inline auto byte(int index) const -> const BitRange { return {&data, index * 8 + 0, index * 8 + 7}; } + + inline auto mask(int index) const -> utype { + return data & 1 << index; + } + + inline auto mask(int lo, int hi) const -> utype { + return data & (~0ull >> 64 - (hi - lo + 1) << lo); + } + + inline auto slice(int index) const { return Natural<>{bit(index)}; } + inline auto slice(int lo, int hi) const { return Natural<>{bit(lo, hi)}; } + + inline auto clamp(uint bits) -> utype { + const uint64_t b = 1ull << bits - 1; + const uint64_t m = b * 2 - 1; + return data < m ? data : m; + } + + inline auto clip(uint bits) -> utype { + const uint64_t b = 1ull << bits - 1; + const uint64_t m = b * 2 - 1; + return data & m; + } + + inline auto serialize(serializer& s) { s(data); } + inline auto integer() const -> Integer; + +private: + inline auto cast(utype value) const -> utype { + return value & mask(); + } + + utype data; +}; + +} diff --git a/nall/primitives/real.hpp b/nall/primitives/real.hpp new file mode 100644 index 0000000..0145363 --- /dev/null +++ b/nall/primitives/real.hpp @@ -0,0 +1,39 @@ +#pragma once + +namespace nall { + +template struct Real { + static_assert(Precision == 32 || Precision == 64); + static inline constexpr auto bits() -> uint { return Precision; } + using ftype = + conditional_t>; + + inline Real() : data(0.0) {} + template inline Real(Real value) : data((ftype)value) {} + template inline Real(const T& value) : data((ftype)value) {} + explicit inline Real(const char* value) : data((ftype)toReal(value)) {} + + inline operator ftype() const { return data; } + + inline auto operator++(int) { auto value = *this; ++data; return value; } + inline auto operator--(int) { auto value = *this; --data; return value; } + + inline auto& operator++() { data++; return *this; } + inline auto& operator--() { data--; return *this; } + + template inline auto& operator =(const T& value) { data = value; return *this; } + template inline auto& operator*=(const T& value) { data = data * value; return *this; } + template inline auto& operator/=(const T& value) { data = data / value; return *this; } + template inline auto& operator%=(const T& value) { data = data % value; return *this; } + template inline auto& operator+=(const T& value) { data = data + value; return *this; } + template inline auto& operator-=(const T& value) { data = data - value; return *this; } + + inline auto serialize(serializer& s) { s(data); } + +private: + ftype data; +}; + +} diff --git a/nall/primitives/types.hpp b/nall/primitives/types.hpp new file mode 100644 index 0000000..74ca6a6 --- /dev/null +++ b/nall/primitives/types.hpp @@ -0,0 +1,45 @@ +#pragma once + +namespace nall { + using boolean = Boolean; + using natural = Natural<>; + using integer = Integer<>; + using real = Real<>; + + using natural1 = Natural< 1>; using natural2 = Natural< 2>; using natural3 = Natural< 3>; using natural4 = Natural< 4>; + using natural5 = Natural< 5>; using natural6 = Natural< 6>; using natural7 = Natural< 7>; using natural8 = Natural< 8>; + using natural9 = Natural< 9>; using natural10 = Natural<10>; using natural11 = Natural<11>; using natural12 = Natural<12>; + using natural13 = Natural<13>; using natural14 = Natural<14>; using natural15 = Natural<15>; using natural16 = Natural<16>; + using natural17 = Natural<17>; using natural18 = Natural<18>; using natural19 = Natural<19>; using natural20 = Natural<20>; + using natural21 = Natural<21>; using natural22 = Natural<22>; using natural23 = Natural<23>; using natural24 = Natural<24>; + using natural25 = Natural<25>; using natural26 = Natural<26>; using natural27 = Natural<27>; using natural28 = Natural<28>; + using natural29 = Natural<29>; using natural30 = Natural<30>; using natural31 = Natural<31>; using natural32 = Natural<32>; + using natural33 = Natural<33>; using natural34 = Natural<34>; using natural35 = Natural<35>; using natural36 = Natural<36>; + using natural37 = Natural<37>; using natural38 = Natural<38>; using natural39 = Natural<39>; using natural40 = Natural<40>; + using natural41 = Natural<41>; using natural42 = Natural<42>; using natural43 = Natural<43>; using natural44 = Natural<44>; + using natural45 = Natural<45>; using natural46 = Natural<46>; using natural47 = Natural<47>; using natural48 = Natural<48>; + using natural49 = Natural<49>; using natural50 = Natural<50>; using natural51 = Natural<51>; using natural52 = Natural<52>; + using natural53 = Natural<53>; using natural54 = Natural<54>; using natural55 = Natural<55>; using natural56 = Natural<56>; + using natural57 = Natural<57>; using natural58 = Natural<58>; using natural59 = Natural<59>; using natural60 = Natural<60>; + using natural61 = Natural<61>; using natural62 = Natural<62>; using natural63 = Natural<63>; using natural64 = Natural<64>; + + using integer1 = Integer< 1>; using integer2 = Integer< 2>; using integer3 = Integer< 3>; using integer4 = Integer< 4>; + using integer5 = Integer< 5>; using integer6 = Integer< 6>; using integer7 = Integer< 7>; using integer8 = Integer< 8>; + using integer9 = Integer< 9>; using integer10 = Integer<10>; using integer11 = Integer<11>; using integer12 = Integer<12>; + using integer13 = Integer<13>; using integer14 = Integer<14>; using integer15 = Integer<15>; using integer16 = Integer<16>; + using integer17 = Integer<17>; using integer18 = Integer<18>; using integer19 = Integer<19>; using integer20 = Integer<20>; + using integer21 = Integer<21>; using integer22 = Integer<22>; using integer23 = Integer<23>; using integer24 = Integer<24>; + using integer25 = Integer<25>; using integer26 = Integer<26>; using integer27 = Integer<27>; using integer28 = Integer<28>; + using integer29 = Integer<29>; using integer30 = Integer<30>; using integer31 = Integer<31>; using integer32 = Integer<32>; + using integer33 = Integer<33>; using integer34 = Integer<34>; using integer35 = Integer<35>; using integer36 = Integer<36>; + using integer37 = Integer<37>; using integer38 = Integer<38>; using integer39 = Integer<39>; using integer40 = Integer<40>; + using integer41 = Integer<41>; using integer42 = Integer<42>; using integer43 = Integer<43>; using integer44 = Integer<44>; + using integer45 = Integer<45>; using integer46 = Integer<46>; using integer47 = Integer<47>; using integer48 = Integer<48>; + using integer49 = Integer<49>; using integer50 = Integer<50>; using integer51 = Integer<51>; using integer52 = Integer<52>; + using integer53 = Integer<53>; using integer54 = Integer<54>; using integer55 = Integer<55>; using integer56 = Integer<56>; + using integer57 = Integer<57>; using integer58 = Integer<58>; using integer59 = Integer<59>; using integer60 = Integer<60>; + using integer61 = Integer<61>; using integer62 = Integer<62>; using integer63 = Integer<63>; using integer64 = Integer<64>; + + using real32 = Real<32>; + using real64 = Real<64>; +} diff --git a/nall/property.hpp b/nall/property.hpp new file mode 100644 index 0000000..00dd7c7 --- /dev/null +++ b/nall/property.hpp @@ -0,0 +1,13 @@ +#if !defined(property) + #define property1(declaration) public: declaration + #define property2(declaration, getter) public: __declspec(property(get=getter)) declaration; protected: declaration##_ + #define property3(declaration, getter, setter) public: __declspec(property(get=getter, put=setter)) declaration; protected: declaration##_ + #define property_(_1, _2, _3, name, ...) name + #define property(...) property_(__VA_ARGS__, property3, property2, property1)(__VA_ARGS__) +#else + #undef property1 + #undef property2 + #undef property3 + #undef property_ + #undef property +#endif diff --git a/nall/queue.hpp b/nall/queue.hpp new file mode 100644 index 0000000..062eda7 --- /dev/null +++ b/nall/queue.hpp @@ -0,0 +1,113 @@ +#pragma once + +//simple circular ring buffer + +#include +#include + +namespace nall { + +template +struct queue { + queue() = default; + queue(const queue& source) { operator=(source); } + queue(queue&& source) { operator=(move(source)); } + ~queue() { reset(); } + + auto operator=(const queue& source) -> queue& { + if(this == &source) return *this; + delete[] _data; + _data = new T[source._capacity]; + _capacity = source._capacity; + _size = source._size; + _read = source._read; + _write = source._write; + for(uint n : range(_capacity)) _data[n] = source._data[n]; + return *this; + } + + auto operator=(queue&& source) -> queue& { + if(this == &source) return *this; + _data = source._data; + _capacity = source._capacity; + _size = source._size; + _read = source._read; + _write = source._write; + source._data = nullptr; + source.reset(); + return *this; + } + + template auto capacity() const -> uint { return _capacity * sizeof(T) / sizeof(U); } + template auto size() const -> uint { return _size * sizeof(T) / sizeof(U); } + auto empty() const -> bool { return _size == 0; } + auto pending() const -> bool { return _size > 0; } + auto full() const -> bool { return _size >= (int)_capacity; } + auto underflow() const -> bool { return _size < 0; } + auto overflow() const -> bool { return _size > (int)_capacity; } + + auto data() -> T* { return _data; } + auto data() const -> const T* { return _data; } + + auto reset() { + delete[] _data; + _data = nullptr; + _capacity = 0; + _size = 0; + _read = 0; + _write = 0; + } + + auto resize(uint capacity, const T& value = {}) -> void { + delete[] _data; + _data = new T[capacity]; + _capacity = capacity; + _size = 0; + _read = 0; + _write = 0; + for(uint n : range(_capacity)) _data[n] = value; + } + + auto flush() -> void { + _size = 0; + _read = 0; + _write = 0; + } + + auto fill(const T& value = {}) -> void { + _size = 0; + _read = 0; + _write = 0; + for(uint n : range(_capacity)) _data[n] = value; + } + + auto read() -> T { + T value = _data[_read++]; + if(_read >= _capacity) _read = 0; + _size--; + return value; + } + + auto write(const T& value) -> void { + _data[_write++] = value; + if(_write >= _capacity) _write = 0; + _size++; + } + + auto serialize(serializer& s) -> void { + s.array(_data, _capacity); + s.integer(_capacity); + s.integer(_size); + s.integer(_read); + s.integer(_write); + } + +private: + T* _data = nullptr; + uint _capacity = 0; + int _size = 0; + uint _read = 0; + uint _write = 0; +}; + +} diff --git a/nall/random.hpp b/nall/random.hpp new file mode 100755 index 0000000..5b7b3c2 --- /dev/null +++ b/nall/random.hpp @@ -0,0 +1,168 @@ +#pragma once + +#include +#include +#include +#include +#include +#if !defined(PLATFORM_ANDROID) +#include +#endif + +#if defined(PLATFORM_LINUX) && __has_include() + #include +#elif defined(PLATFORM_ANDROID) && __has_include() + #include +#elif defined(PLATFORM_WINDOWS) && __has_include() + #include +#else + #include +#endif + +namespace nall { + +template struct RNG { + template auto random() -> T { + T value = 0; + for(uint n : range((sizeof(T) + 3) / 4)) { + value = value << 32 | (uint32_t)static_cast(this)->read(); + } + return value; + } + + template auto bound(T range) -> T { + T threshold = -range % range; + while(true) { + T value = random(); + if(value >= threshold) return value % range; + } + } + +protected: + auto randomSeed() -> uint256_t { + uint256_t seed = 0; + #if defined(PLATFORM_BSD) || defined(PLATFORM_MACOS) + for(uint n : range(8)) seed = seed << 32 | (uint32_t)arc4random(); + #elif defined(PLATFORM_LINUX) && __has_include() + getrandom(&seed, 32, GRND_NONBLOCK); + #elif defined(PLATFORM_ANDROID) && __has_include() + syscall(__NR_getrandom, &seed, 32, 0x0001); //GRND_NONBLOCK + #elif defined(PLATFORM_WINDOWS) && __has_include() + HCRYPTPROV provider; + if(CryptAcquireContext(&provider, nullptr, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + CryptGenRandom(provider, 32, (BYTE*)&seed); + CryptReleaseContext(provider, 0); + } + #else + srand(time(nullptr)); + for(uint n : range(32)) seed = seed << 8 | (uint8_t)rand(); + if(auto fp = fopen("/dev/urandom", "rb")) { + fread(&seed, 32, 1, fp); + fclose(fp); + } + #endif + return seed; + } +}; + +namespace PRNG { + +//Galois linear feedback shift register using CRC64 polynomials +struct LFSR : RNG { + LFSR() { seed(); } + + auto seed(maybe seed = {}) -> void { + lfsr = seed ? seed() : (uint64_t)randomSeed(); + for(uint n : range(8)) read(); //hide the CRC64 polynomial from initial output + } + + auto serialize(serializer& s) -> void { + s.integer(lfsr); + } + +private: + auto read() -> uint64_t { + return lfsr = (lfsr >> 1) ^ (-(lfsr & 1) & crc64); + } + + static const uint64_t crc64 = 0xc96c'5795'd787'0f42; + uint64_t lfsr = crc64; + + friend class RNG; +}; + +struct PCG : RNG { + PCG() { seed(); } + + auto seed(maybe seed = {}, maybe sequence = {}) -> void { + if(!seed) seed = (uint32_t)randomSeed(); + if(!sequence) sequence = 0; + + state = 0; + increment = sequence() << 1 | 1; + read(); + state += seed(); + read(); + } + + auto serialize(serializer& s) -> void { + s.integer(state); + s.integer(increment); + } + +private: + auto read() -> uint32_t { + uint64_t state = this->state; + this->state = state * 6'364'136'223'846'793'005ull + increment; + uint32_t xorshift = (state >> 18 ^ state) >> 27; + uint32_t rotate = state >> 59; + return xorshift >> rotate | xorshift << (-rotate & 31); + } + + uint64_t state = 0; + uint64_t increment = 0; + + friend class RNG; +}; + +} + +#if !defined(PLATFORM_ANDROID) +namespace CSPRNG { + +//XChaCha20 cryptographically secure pseudo-random number generator +struct XChaCha20 : RNG { + XChaCha20() { seed(); } + + auto seed(maybe key = {}, maybe nonce = {}) -> void { + //the randomness comes from the key; the nonce just adds a bit of added entropy + if(!key) key = randomSeed(); + if(!nonce) nonce = (uint192_t)clock() << 64 | chrono::nanosecond(); + context = {key(), nonce()}; + } + +private: + auto read() -> uint32_t { + if(!counter) { context.cipher(); context.increment(); } + uint32_t value = context.block[counter++]; + if(counter == 16) counter = 0; //64-bytes per block; 4 bytes per read + return value; + } + + Cipher::XChaCha20 context{0, 0}; + uint counter = 0; + + friend class RNG; +}; + +} +#endif + +// + +template inline auto random() -> T { + static PRNG::PCG pcg; //note: unseeded + return pcg.random(); +} + +} diff --git a/nall/range.hpp b/nall/range.hpp new file mode 100755 index 0000000..891f5ec --- /dev/null +++ b/nall/range.hpp @@ -0,0 +1,51 @@ +#pragma once + +namespace nall { + +struct range_t { + struct iterator { + iterator(int64_t position, int64_t step = 0) : position(position), step(step) {} + auto operator*() const -> int64_t { return position; } + auto operator!=(const iterator& source) const -> bool { return step > 0 ? position < source.position : position > source.position; } + auto operator++() -> iterator& { position += step; return *this; } + + private: + int64_t position; + const int64_t step; + }; + + struct reverse_iterator { + reverse_iterator(int64_t position, int64_t step = 0) : position(position), step(step) {} + auto operator*() const -> int64_t { return position; } + auto operator!=(const reverse_iterator& source) const -> bool { return step > 0 ? position > source.position : position < source.position; } + auto operator++() -> reverse_iterator& { position -= step; return *this; } + + private: + int64_t position; + const int64_t step; + }; + + auto begin() const -> iterator { return {origin, stride}; } + auto end() const -> iterator { return {target}; } + + auto rbegin() const -> reverse_iterator { return {target - stride, stride}; } + auto rend() const -> reverse_iterator { return {origin - stride}; } + + int64_t origin; + int64_t target; + int64_t stride; +}; + +inline auto range(int64_t size) { + return range_t{0, size, 1}; +} + +inline auto range(int64_t offset, int64_t size) { + return range_t{offset, size, 1}; +} + +inline auto range(int64_t offset, int64_t size, int64_t step) { + return range_t{offset, size, step}; +} + +} diff --git a/nall/reed-solomon.hpp b/nall/reed-solomon.hpp new file mode 100644 index 0000000..d04bb66 --- /dev/null +++ b/nall/reed-solomon.hpp @@ -0,0 +1,218 @@ +#pragma once + +namespace nall { + +//RS(n,k) = ReedSolomon +template +struct ReedSolomon { + enum : uint { Parity = Length - Inputs }; + static_assert(Length <= 255 && Length > 0); + static_assert(Parity <= 32 && Parity > 0); + + using Field = GaloisField; + template using Polynomial = Matrix; + + template + static auto shift(Polynomial polynomial) -> Polynomial { + for(int n = Size - 1; n > 0; n--) polynomial[n] = polynomial[n - 1]; + polynomial[0] = 0; + return polynomial; + } + + template + static auto degree(const Polynomial& polynomial) -> uint { + for(int n = Size; n > 0; n--) { + if(polynomial[n - 1] != 0) return n - 1; + } + return 0; + } + + template + static auto evaluate(const Polynomial& polynomial, Field field) -> Field { + Field sum = 0; + for(uint n : range(Size)) sum += polynomial[n] * field.pow(n); + return sum; + } + + Polynomial message; + Polynomial syndromes; + Polynomial locators; + + ReedSolomon() = default; + ReedSolomon(const ReedSolomon&) = default; + + ReedSolomon(const initializer_list& source) { + uint index = 0; + for(auto& value : source) { + if(index >= Length) break; + message[index++] = value; + } + } + + auto operator[](uint index) -> Field& { return message[index]; } + auto operator[](uint index) const -> Field { return message[index]; } + + auto calculateSyndromes() -> void { + static const Polynomial bases = [] { + Polynomial bases; + for(uint n : range(Parity)) { + bases[n] = Field::exp(n); + } + return bases; + }(); + + syndromes = {}; + for(uint m : range(Length)) { + for(uint p : range(Parity)) { + syndromes[p] *= bases[p]; + syndromes[p] += message[m]; + } + } + } + + auto generateParity() -> void { + static const Polynomial matrix = [] { + Polynomial matrix{}; + for(uint row : range(Parity)) { + for(uint col : range(Parity)) { + matrix(row, col) = Field::exp(row * col); + } + } + if(auto result = matrix.invert()) return *result; + throw; //should never occur + }(); + + for(uint p : range(Parity)) message[Inputs + p] = 0; + calculateSyndromes(); + auto parity = matrix * syndromes; + for(uint p : range(Parity)) message[Inputs + p] = parity[Parity - (p + 1)]; + } + + auto syndromesAreZero() -> bool { + for(uint p : range(Parity)) { + if(syndromes[p]) return false; + } + return true; + } + + //algorithm: Berlekamp-Massey + auto calculateLocators() -> void { + Polynomial history{1}; + locators = history; + uint errors = 0; + + for(uint n : range(Parity)) { + Field discrepancy = 0; + for(uint l : range(errors + 1)) { + discrepancy += locators[l] * syndromes[n - l]; + } + + history = shift(history); + if(discrepancy) { + auto located = locators - history * discrepancy; + if(errors * 2 <= n) { + errors = (n + 1) - errors; + history = locators * discrepancy.inv(); + } + locators = located; + } + } + } + + //algorithm: brute force + //todo: implement Chien search here + auto calculateErrors() -> vector { + calculateSyndromes(); + if(syndromesAreZero()) return {}; //no errors detected + calculateLocators(); + vector errors; + for(uint n : range(Length)) { + if(evaluate(locators, Field{2}.pow(255 - n))) continue; + errors.append(Length - (n + 1)); + } + return errors; + } + + template + static auto calculateErasures(array_view errors) -> maybe> { + Polynomial matrix{}; + for(uint row : range(Size)) { + for(uint col : range(Size)) { + uint index = Length - (errors[col] + 1); + matrix(row, col) = Field::exp(row * index); + } + } + return matrix.invert(); + } + + template + auto correctErasures(array_view errors) -> int { + calculateSyndromes(); + if(syndromesAreZero()) return 0; //no errors detected + if(auto matrix = calculateErasures(errors)) { + Polynomial factors; + for(uint n : range(Size)) factors[n] = syndromes[n]; + auto errata = matrix() * factors; + for(uint m : range(Size)) { + message[errors[m]] += errata[m]; + } + calculateSyndromes(); + if(syndromesAreZero()) return Size; //corrected Size errors + return -Size; //failed to correct Size errors + } + return -Size; //should never occur, but might ... + } + + //note: the erasure matrix is generated as a Polynomial, where N is the number of errors to correct. + //because this is a template parameter, and the actual number of errors may very, this function is needed. + //the alternative would be to convert Matrix to a dynamically sized Matrix(Rows, Cols) type, + //but this would require heap memory allocations and would be a massive performance penalty. + auto correctErrata(array_view errors) -> int { + if(errors.size() >= Parity) return -errors.size(); //too many errors to be correctable + + switch(errors.size()) { + case 0: return 0; + case 1: return correctErasures< 1>(errors); + case 2: return correctErasures< 2>(errors); + case 3: return correctErasures< 3>(errors); + case 4: return correctErasures< 4>(errors); + case 5: return correctErasures< 5>(errors); + case 6: return correctErasures< 6>(errors); + case 7: return correctErasures< 7>(errors); + case 8: return correctErasures< 8>(errors); + case 9: return correctErasures< 9>(errors); + case 10: return correctErasures<10>(errors); + case 11: return correctErasures<11>(errors); + case 12: return correctErasures<12>(errors); + case 13: return correctErasures<13>(errors); + case 14: return correctErasures<14>(errors); + case 15: return correctErasures<15>(errors); + case 16: return correctErasures<16>(errors); + case 17: return correctErasures<17>(errors); + case 18: return correctErasures<18>(errors); + case 19: return correctErasures<19>(errors); + case 20: return correctErasures<20>(errors); + case 21: return correctErasures<21>(errors); + case 22: return correctErasures<22>(errors); + case 23: return correctErasures<23>(errors); + case 24: return correctErasures<24>(errors); + case 25: return correctErasures<25>(errors); + case 26: return correctErasures<26>(errors); + case 27: return correctErasures<27>(errors); + case 28: return correctErasures<28>(errors); + case 29: return correctErasures<29>(errors); + case 30: return correctErasures<30>(errors); + case 31: return correctErasures<31>(errors); + case 32: return correctErasures<32>(errors); + } + return -errors.size(); //it's possible to correct more errors if the above switch were extended ... + } + + //convenience function for when erasures aren't needed + auto correctErrors() -> int { + auto errors = calculateErrors(); + return correctErrata(errors); + } +}; + +} diff --git a/nall/run.hpp b/nall/run.hpp new file mode 100755 index 0000000..14f92ec --- /dev/null +++ b/nall/run.hpp @@ -0,0 +1,214 @@ +#pragma once + +//auto execute(const string& name, const string& args...) -> string; +//[[synchronous]] +//executes program, waits for completion, and returns data written to stdout + +//auto invoke(const string& name, const string& args...) -> void; +//[[asynchronous]] +//if a program is specified, it is executed with the arguments provided +//if a file is specified, the file is opened using the program associated with said file type +//if a folder is specified, the folder is opened using the associated file explorer +//if a URL is specified, the default web browser is opened and pointed at the URL requested + +#include +#include + +namespace nall { + +struct execute_result_t { + explicit operator bool() const { return code == EXIT_SUCCESS; } + + int code = EXIT_FAILURE; + string output; + string error; +}; + +#if defined(PLATFORM_MACOS) || defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) + +template inline auto execute(const string& name, P&&... p) -> execute_result_t { + int fdout[2]; + int fderr[2]; + if(pipe(fdout) == -1) return {}; + if(pipe(fderr) == -1) return {}; + + pid_t pid = fork(); + if(pid == 0) { + const char* argv[1 + sizeof...(p) + 1]; + const char** argp = argv; + vector argl(forward

    (p)...); + *argp++ = (const char*)name; + for(auto& arg : argl) *argp++ = (const char*)arg; + *argp++ = nullptr; + + dup2(fdout[1], STDOUT_FILENO); + dup2(fderr[1], STDERR_FILENO); + close(fdout[0]); + close(fderr[0]); + close(fdout[1]); + close(fderr[1]); + execvp(name, (char* const*)argv); + //this is called only if execvp fails: + //use _exit instead of exit, to avoid destroying key shared file descriptors + _exit(EXIT_FAILURE); + } else { + close(fdout[1]); + close(fderr[1]); + + char buffer[256]; + execute_result_t result; + + while(true) { + auto size = read(fdout[0], buffer, sizeof(buffer)); + if(size <= 0) break; + + auto offset = result.output.size(); + result.output.resize(offset + size); + memory::copy(result.output.get() + offset, buffer, size); + } + + while(true) { + auto size = read(fderr[0], buffer, sizeof(buffer)); + if(size <= 0) break; + + auto offset = result.error.size(); + result.error.resize(offset + size); + memory::copy(result.error.get() + offset, buffer, size); + } + + close(fdout[0]); + close(fderr[0]); + + int status = 0; + waitpid(pid, &status, 0); + if(!WIFEXITED(status)) return {}; + result.code = WEXITSTATUS(status); + return result; + } +} + +template inline auto invoke(const string& name, P&&... p) -> void { + pid_t pid = fork(); + if(pid == 0) { + const char* argv[1 + sizeof...(p) + 1]; + const char** argp = argv; + vector argl(forward

    (p)...); + *argp++ = (const char*)name; + for(auto& arg : argl) *argp++ = (const char*)arg; + *argp++ = nullptr; + + if(execvp(name, (char* const*)argv) < 0) { + #if defined(PLATFORM_MACOS) + execlp("open", "open", (const char*)name, nullptr); + #else + execlp("xdg-open", "xdg-open", (const char*)name, nullptr); + #endif + } + exit(0); + } +} + +#elif defined(PLATFORM_WINDOWS) + +template inline auto execute(const string& name, P&&... p) -> execute_result_t { + vector argl(name, forward

    (p)...); + for(auto& arg : argl) if(arg.find(" ")) arg = {"\"", arg, "\""}; + string arguments = argl.merge(" "); + + SECURITY_ATTRIBUTES sa; + ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = true; + sa.lpSecurityDescriptor = nullptr; + + HANDLE stdoutRead; + HANDLE stdoutWrite; + if(!CreatePipe(&stdoutRead, &stdoutWrite, &sa, 0)) return {}; + if(!SetHandleInformation(stdoutRead, HANDLE_FLAG_INHERIT, 0)) return {}; + + HANDLE stderrRead; + HANDLE stderrWrite; + if(!CreatePipe(&stderrRead, &stderrWrite, &sa, 0)) return {}; + if(!SetHandleInformation(stderrRead, HANDLE_FLAG_INHERIT, 0)) return {}; + + HANDLE stdinRead; + HANDLE stdinWrite; + if(!CreatePipe(&stdinRead, &stdinWrite, &sa, 0)) return {}; + if(!SetHandleInformation(stdinWrite, HANDLE_FLAG_INHERIT, 0)) return {}; + + STARTUPINFO si; + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.hStdOutput = stdoutWrite; + si.hStdError = stderrWrite; + si.hStdInput = stdinRead; + si.dwFlags = STARTF_USESTDHANDLES; + + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + + if(!CreateProcess( + nullptr, utf16_t(arguments), + nullptr, nullptr, true, CREATE_NO_WINDOW, + nullptr, nullptr, &si, &pi + )) return {}; + + DWORD exitCode = EXIT_FAILURE; + if(WaitForSingleObject(pi.hProcess, INFINITE)) return {}; + if(!GetExitCodeProcess(pi.hProcess, &exitCode)) return {}; + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + char buffer[256]; + execute_result_t result; + result.code = exitCode; + + while(true) { + DWORD read, available, remaining; + if(!PeekNamedPipe(stdoutRead, nullptr, sizeof(buffer), &read, &available, &remaining)) break; + if(read == 0) break; + + if(!ReadFile(stdoutRead, buffer, sizeof(buffer), &read, nullptr)) break; + if(read == 0) break; + + auto offset = result.output.size(); + result.output.resize(offset + read); + memory::copy(result.output.get() + offset, buffer, read); + } + + while(true) { + DWORD read, available, remaining; + if(!PeekNamedPipe(stderrRead, nullptr, sizeof(buffer), &read, &available, &remaining)) break; + if(read == 0) break; + + if(!ReadFile(stderrRead, buffer, sizeof(buffer), &read, nullptr)) break; + if(read == 0) break; + + auto offset = result.error.size(); + result.error.resize(offset + read); + memory::copy(result.error.get() + offset, buffer, read); + } + + return result; +} + +template inline auto invoke(const string& name, P&&... p) -> void { + vector argl(forward

    (p)...); + for(auto& arg : argl) if(arg.find(" ")) arg = {"\"", arg, "\""}; + string arguments = argl.merge(" "); + string directory = Path::program().replace("/", "\\"); + ShellExecute(nullptr, nullptr, utf16_t(name), utf16_t(arguments), utf16_t(directory), SW_SHOWNORMAL); +} + +#else + +template inline auto execute(const string& name, P&&... p) -> string { + return ""; +} + +template inline auto invoke(const string& name, P&&... p) -> void { +} + +#endif + +} diff --git a/nall/serial.hpp b/nall/serial.hpp new file mode 100755 index 0000000..671e8ff --- /dev/null +++ b/nall/serial.hpp @@ -0,0 +1,113 @@ +#pragma once + +#include +#include +#include + +#if !defined(API_POSIX) + #error "nall/serial: unsupported system" +#endif + +#include +#include +#include +#include + +namespace nall { + +struct serial { + ~serial() { + close(); + } + + auto readable() -> bool { + if(!opened) return false; + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(port, &fdset); + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + int result = select(FD_SETSIZE, &fdset, nullptr, nullptr, &timeout); + if(result < 1) return false; + return FD_ISSET(port, &fdset); + } + + //-1 on error, otherwise return bytes read + auto read(uint8_t* data, uint length) -> int { + if(!opened) return -1; + return ::read(port, (void*)data, length); + } + + auto writable() -> bool { + if(!opened) return false; + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(port, &fdset); + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + int result = select(FD_SETSIZE, nullptr, &fdset, nullptr, &timeout); + if(result < 1) return false; + return FD_ISSET(port, &fdset); + } + + //-1 on error, otherwise return bytes written + auto write(const uint8_t* data, uint length) -> int { + if(!opened) return -1; + return ::write(port, (void*)data, length); + } + + //rate==0: use flow control (synchronous mode) + //rate!=0: baud-rate (asynchronous mode) + auto open(string device, uint rate = 0) -> bool { + close(); + + if(!device) device = "/dev/ttyU0"; //note: default device name is for FreeBSD 10+ + port = ::open(device, 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 ? rate : 57600); //rate value has no effect in synchronous mode + + 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(rate) { + 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 opened = true; + } + + auto close() -> void { + if(port != -1) { + tcdrain(port); + if(opened) { + tcsetattr(port, TCSANOW, &original_attr); + opened = false; + } + ::close(port); + port = -1; + } + } + +private: + int port = -1; + bool opened = false; + termios original_attr; +}; + +} diff --git a/nall/serializer.hpp b/nall/serializer.hpp new file mode 100755 index 0000000..0910529 --- /dev/null +++ b/nall/serializer.hpp @@ -0,0 +1,201 @@ +#pragma once + +//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 different implementations + +#include +#include +#include +#include +#include + +namespace nall { + +struct serializer; + +template +struct has_serialize { + template static auto test(decltype(std::declval().serialize(std::declval()))*) -> char; + template static auto test(...) -> long; + static const bool value = sizeof(test(0)) == sizeof(char); +}; + +struct serializer { + enum Mode : uint { Load, Save, Size }; + + explicit operator bool() const { + return _size; + } + + auto setMode(Mode mode) -> void { + _mode = mode; + _size = 0; + } + + auto mode() const -> Mode { + return _mode; + } + + auto data() const -> const uint8_t* { + return _data; + } + + auto size() const -> uint { + return _size; + } + + auto capacity() const -> uint { + return _capacity; + } + + template auto real(T& value) -> serializer& { + enum : uint { size = sizeof(T) }; + //this is rather dangerous, and not cross-platform safe; + //but there is no standardized way to export FP-values + auto p = (uint8_t*)&value; + if(_mode == Save) { + for(uint n : range(size)) _data[_size++] = p[n]; + } else if(_mode == Load) { + for(uint n : range(size)) p[n] = _data[_size++]; + } else { + _size += size; + } + return *this; + } + + template auto boolean(T& value) -> serializer& { + if(_mode == Save) { + _data[_size++] = (bool)value; + } else if(_mode == Load) { + value = (bool)_data[_size++]; + } else if(_mode == Size) { + _size += 1; + } + return *this; + } + + template auto integer(T& value) -> serializer& { + enum : uint { size = std::is_same::value ? 1 : sizeof(T) }; + if(_mode == Save) { + T copy = value; + for(uint n : range(size)) _data[_size++] = copy, copy >>= 8; + } else if(_mode == Load) { + value = 0; + for(uint n : range(size)) value |= (T)_data[_size++] << (n << 3); + } else if(_mode == Size) { + _size += size; + } + return *this; + } + + template auto array(T (&array)[N]) -> serializer& { + for(uint n : range(N)) operator()(array[n]); + return *this; + } + + template auto array(T array, uint size) -> serializer& { + for(uint n : range(size)) operator()(array[n]); + return *this; + } + + template auto array(nall::array& array) -> serializer& { + for(auto& value : array) operator()(value); + return *this; + } + + //optimized specializations + + auto array(uint8_t* data, uint size) -> serializer& { + if(_mode == Save) { + memory::copy(_data + _size, data, size); + } else if(_mode == Load) { + memory::copy(data, _data + _size, size); + } else { + } + _size += size; + return *this; + } + + template auto array(uint8_t (&data)[N]) -> serializer& { + return array(data, N); + } + + //nall/serializer saves data in little-endian ordering + #if defined(ENDIAN_LSB) + auto array(uint16_t* data, uint size) -> serializer& { return array((uint8_t*)data, size * sizeof(uint16_t)); } + auto array(uint32_t* data, uint size) -> serializer& { return array((uint8_t*)data, size * sizeof(uint32_t)); } + auto array(uint64_t* data, uint size) -> serializer& { return array((uint8_t*)data, size * sizeof(uint64_t)); } + template auto array(uint16_t (&data)[N]) -> serializer& { return array(data, N); } + template auto array(uint32_t (&data)[N]) -> serializer& { return array(data, N); } + template auto array(uint64_t (&data)[N]) -> serializer& { return array(data, N); } + #endif + + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { value.serialize(*this); return *this; } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return integer(value); } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return real(value); } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return array(value); } + template auto operator()(T& value, uint size, typename std::enable_if::value>::type* = 0) -> serializer& { return array(value, size); } + + auto operator=(const serializer& s) -> serializer& { + if(_data) delete[] _data; + + _mode = s._mode; + _data = new uint8_t[s._capacity]; + _size = s._size; + _capacity = s._capacity; + + memcpy(_data, s._data, s._capacity); + return *this; + } + + auto operator=(serializer&& s) -> serializer& { + if(_data) delete[] _data; + + _mode = s._mode; + _data = s._data; + _size = s._size; + _capacity = s._capacity; + + s._data = nullptr; + return *this; + } + + serializer() = default; + serializer(const serializer& s) { operator=(s); } + serializer(serializer&& s) { operator=(move(s)); } + + serializer(uint capacity) { + _mode = Save; + _data = new uint8_t[capacity](); + _size = 0; + _capacity = capacity; + } + + serializer(const uint8_t* data, uint capacity) { + _mode = Load; + _data = new uint8_t[capacity]; + _size = 0; + _capacity = capacity; + memcpy(_data, data, capacity); + } + + ~serializer() { + if(_data) delete[] _data; + } + +private: + Mode _mode = Size; + uint8_t* _data = nullptr; + uint _size = 0; + uint _capacity = 0; +}; + +} diff --git a/nall/service.hpp b/nall/service.hpp new file mode 100755 index 0000000..3d3c902 --- /dev/null +++ b/nall/service.hpp @@ -0,0 +1,13 @@ +#pragma once + +//service model template built on top of shared-memory + +#include + +#if defined(API_POSIX) + #include +#endif + +#if defined(API_WINDOWS) + #include +#endif diff --git a/nall/set.hpp b/nall/set.hpp new file mode 100755 index 0000000..733bf84 --- /dev/null +++ b/nall/set.hpp @@ -0,0 +1,266 @@ +#pragma once + +//set +//implementation: red-black tree +// +//search: O(log n) average; O(log n) worst +//insert: O(log n) average; O(log n) worst +//remove: O(log n) average; O(log n) worst +// +//requirements: +// bool T::operator==(const T&) const; +// bool T::operator< (const T&) const; + +#include +#include + +namespace nall { + +template struct set { + struct node_t { + T value; + bool red = 1; + node_t* link[2] = {nullptr, nullptr}; + node_t() = default; + node_t(const T& value) : value(value) {} + }; + + node_t* root = nullptr; + uint nodes = 0; + + set() = default; + set(const set& source) { operator=(source); } + set(set&& source) { operator=(move(source)); } + set(std::initializer_list list) { for(auto& value : list) insert(value); } + ~set() { reset(); } + + auto operator=(const set& source) -> set& { + if(this == &source) return *this; + reset(); + copy(root, source.root); + nodes = source.nodes; + return *this; + } + + auto operator=(set&& source) -> set& { + if(this == &source) return *this; + root = source.root; + nodes = source.nodes; + source.root = nullptr; + source.nodes = 0; + return *this; + } + + explicit operator bool() const { return nodes; } + auto size() const -> uint { return nodes; } + + auto reset() -> void { + reset(root); + nodes = 0; + } + + auto find(const T& value) -> maybe { + if(node_t* node = find(root, value)) return node->value; + return nothing; + } + + auto find(const T& value) const -> maybe { + if(node_t* node = find(root, value)) return node->value; + return nothing; + } + + auto insert(const T& value) -> maybe { + uint count = size(); + node_t* v = insert(root, value); + root->red = 0; + if(size() == count) return nothing; + return v->value; + } + + template auto insert(const T& value, P&&... p) -> bool { + bool result = insert(value); + insert(forward

    (p)...) | result; + return result; + } + + auto remove(const T& value) -> bool { + uint count = size(); + bool done = 0; + remove(root, &value, done); + if(root) root->red = 0; + return size() < count; + } + + template auto remove(const T& value, P&&... p) -> bool { + bool result = remove(value); + return remove(forward

    (p)...) | result; + } + + struct base_iterator { + auto operator!=(const base_iterator& source) const -> bool { return position != source.position; } + + auto operator++() -> base_iterator& { + if(++position >= source.size()) { position = source.size(); return *this; } + + if(stack.right()->link[1]) { + stack.append(stack.right()->link[1]); + while(stack.right()->link[0]) stack.append(stack.right()->link[0]); + } else { + node_t* child; + do child = stack.takeRight(); + while(child == stack.right()->link[1]); + } + + return *this; + } + + base_iterator(const set& source, uint position) : source(source), position(position) { + node_t* node = source.root; + while(node) { + stack.append(node); + node = node->link[0]; + } + } + + protected: + const set& source; + uint position; + vector stack; + }; + + struct iterator : base_iterator { + iterator(const set& source, uint position) : base_iterator(source, position) {} + auto operator*() const -> T& { return base_iterator::stack.right()->value; } + }; + + auto begin() -> iterator { return iterator(*this, 0); } + auto end() -> iterator { return iterator(*this, size()); } + + struct const_iterator : base_iterator { + const_iterator(const set& source, uint position) : base_iterator(source, position) {} + auto operator*() const -> const T& { return base_iterator::stack.right()->value; } + }; + + auto begin() const -> const const_iterator { return const_iterator(*this, 0); } + auto end() const -> const const_iterator { return const_iterator(*this, size()); } + +private: + auto reset(node_t*& node) -> void { + if(!node) return; + if(node->link[0]) reset(node->link[0]); + if(node->link[1]) reset(node->link[1]); + delete node; + node = nullptr; + } + + auto copy(node_t*& target, const node_t* source) -> void { + if(!source) return; + target = new node_t(source->value); + target->red = source->red; + copy(target->link[0], source->link[0]); + copy(target->link[1], source->link[1]); + } + + auto find(node_t* node, const T& value) const -> node_t* { + if(node == nullptr) return nullptr; + if(node->value == value) return node; + return find(node->link[node->value < value], value); + } + + auto red(node_t* node) const -> bool { return node && node->red; } + auto black(node_t* node) const -> bool { return !red(node); } + + auto rotate(node_t*& a, bool dir) -> void { + node_t*& b = a->link[!dir]; + node_t*& c = b->link[dir]; + a->red = 1, b->red = 0; + std::swap(a, b); + std::swap(b, c); + } + + auto rotateTwice(node_t*& node, bool dir) -> void { + rotate(node->link[!dir], !dir); + rotate(node, dir); + } + + auto insert(node_t*& node, const T& value) -> node_t* { + if(!node) { nodes++; node = new node_t(value); return node; } + if(node->value == value) { node->value = value; return node; } //prevent duplicate entries + + bool dir = node->value < value; + node_t* v = insert(node->link[dir], value); + if(black(node->link[dir])) return v; + + if(red(node->link[!dir])) { + node->red = 1; + node->link[0]->red = 0; + node->link[1]->red = 0; + } else if(red(node->link[dir]->link[dir])) { + rotate(node, !dir); + } else if(red(node->link[dir]->link[!dir])) { + rotateTwice(node, !dir); + } + + return v; + } + + auto balance(node_t*& node, bool dir, bool& done) -> void { + node_t* p = node; + node_t* s = node->link[!dir]; + if(!s) return; + + if(red(s)) { + rotate(node, dir); + s = p->link[!dir]; + } + + if(black(s->link[0]) && black(s->link[1])) { + if(red(p)) done = 1; + p->red = 0, s->red = 1; + } else { + bool save = p->red; + bool head = node == p; + + if(red(s->link[!dir])) rotate(p, dir); + else rotateTwice(p, dir); + + p->red = save; + p->link[0]->red = 0; + p->link[1]->red = 0; + + if(head) node = p; + else node->link[dir] = p; + + done = 1; + } + } + + auto remove(node_t*& node, const T* value, bool& done) -> void { + if(!node) { done = 1; return; } + + if(node->value == *value) { + if(!node->link[0] || !node->link[1]) { + node_t* save = node->link[!node->link[0]]; + + if(red(node)) done = 1; + else if(red(save)) save->red = 0, done = 1; + + nodes--; + delete node; + node = save; + return; + } else { + node_t* heir = node->link[0]; + while(heir->link[1]) heir = heir->link[1]; + node->value = heir->value; + value = &heir->value; + } + } + + bool dir = node->value < *value; + remove(node->link[dir], value, done); + if(!done) balance(node, dir, done); + } +}; + +} diff --git a/nall/shared-memory.hpp b/nall/shared-memory.hpp new file mode 100755 index 0000000..9d40bca --- /dev/null +++ b/nall/shared-memory.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +#if defined(API_POSIX) + #include +#endif + +#if defined(API_WINDOWS) + #include +#endif diff --git a/nall/shared-pointer.hpp b/nall/shared-pointer.hpp new file mode 100755 index 0000000..e5755c1 --- /dev/null +++ b/nall/shared-pointer.hpp @@ -0,0 +1,291 @@ +#pragma once + +#include +#include +#include +#include + +namespace nall { + +template struct shared_pointer; + +struct shared_pointer_manager { + void* pointer = nullptr; + function deleter; + uint strong = 0; + uint weak = 0; + + shared_pointer_manager(void* pointer) : pointer(pointer) { + } +}; + +template struct shared_pointer; +template struct shared_pointer_weak; +template struct shared_pointer_this; +struct shared_pointer_this_base{}; + +template +struct shared_pointer { + template static auto create(P&&... p) { + return shared_pointer{new T{forward

    (p)...}}; + } + + using type = T; + shared_pointer_manager* manager = nullptr; + + template + struct is_compatible { + static constexpr bool value = is_base_of::value || is_base_of::value; + }; + + shared_pointer() { + } + + shared_pointer(T* source) { + operator=(source); + } + + shared_pointer(T* source, const function& deleter) { + operator=(source); + manager->deleter = function([=](void* p) { + deleter((T*)p); + }); + } + + shared_pointer(const shared_pointer& source) { + operator=(source); + } + + shared_pointer(shared_pointer&& source) { + operator=(move(source)); + } + + template::value>> + shared_pointer(const shared_pointer& source) { + operator=(source); + } + + template::value>> + shared_pointer(shared_pointer&& source) { + operator=(move(source)); + } + + template::value>> + shared_pointer(const shared_pointer_weak& source) { + operator=(source); + } + + template::value>> + shared_pointer(const shared_pointer& source, T* pointer) { + if((bool)source && (T*)source.manager->pointer == pointer) { + manager = source.manager; + manager->strong++; + } + } + + ~shared_pointer() { + reset(); + } + + auto operator=(T* source) -> shared_pointer& { + reset(); + if(source) { + manager = new shared_pointer_manager((void*)source); + manager->strong++; + if constexpr(is_base_of_v) { + source->weak = *this; + } + } + return *this; + } + + auto operator=(const shared_pointer& source) -> shared_pointer& { + if(this != &source) { + reset(); + if((bool)source) { + manager = source.manager; + manager->strong++; + } + } + return *this; + } + + auto operator=(shared_pointer&& source) -> shared_pointer& { + if(this != &source) { + reset(); + manager = source.manager; + source.manager = nullptr; + } + return *this; + } + + template::value>> + auto operator=(const shared_pointer& source) -> shared_pointer& { + if((uintptr)this != (uintptr)&source) { + reset(); + if((bool)source) { + manager = source.manager; + manager->strong++; + } + } + return *this; + } + + template::value>> + auto operator=(shared_pointer&& source) -> shared_pointer& { + if((uintptr)this != (uintptr)&source) { + reset(); + manager = source.manager; + source.manager = nullptr; + } + return *this; + } + + template::value>> + auto operator=(const shared_pointer_weak& source) -> shared_pointer& { + reset(); + if((bool)source) { + manager = source.manager; + manager->strong++; + } + return *this; + } + + auto data() -> T* { + if(manager) return (T*)manager->pointer; + return nullptr; + } + + auto data() const -> const T* { + if(manager) return (T*)manager->pointer; + return nullptr; + } + + auto operator->() -> T* { return data(); } + auto operator->() const -> const T* { return data(); } + + auto operator*() -> T& { return *data(); } + auto operator*() const -> const T& { return *data(); } + + auto operator()() -> T& { return *data(); } + auto operator()() const -> const T& { return *data(); } + + template + auto operator==(const shared_pointer& source) const -> bool { + return manager == source.manager; + } + + template + auto operator!=(const shared_pointer& source) const -> bool { + return manager != source.manager; + } + + explicit operator bool() const { + return manager && manager->strong; + } + + auto unique() const -> bool { + return manager && manager->strong == 1; + } + + auto references() const -> uint { + return manager ? manager->strong : 0; + } + + auto reset() -> void { + if(manager && manager->strong) { + //pointer may contain weak references; if strong==0 it may destroy manager + //as such, we must destroy strong before decrementing it to zero + if(manager->strong == 1) { + if(manager->deleter) { + manager->deleter(manager->pointer); + } else { + delete (T*)manager->pointer; + } + manager->pointer = nullptr; + } + if(--manager->strong == 0) { + if(manager->weak == 0) { + delete manager; + } + } + } + manager = nullptr; + } + + template + auto cast() -> shared_pointer { + if(auto pointer = dynamic_cast(data())) { + return {*this, pointer}; + } + return {}; + } +}; + +template +struct shared_pointer_weak { + using type = T; + shared_pointer_manager* manager = nullptr; + + shared_pointer_weak() { + } + + shared_pointer_weak(const shared_pointer& source) { + operator=(source); + } + + auto operator=(const shared_pointer& source) -> shared_pointer_weak& { + reset(); + if(manager = source.manager) manager->weak++; + return *this; + } + + ~shared_pointer_weak() { + reset(); + } + + auto operator==(const shared_pointer_weak& source) const -> bool { + return manager == source.manager; + } + + auto operator!=(const shared_pointer_weak& source) const -> bool { + return manager != source.manager; + } + + explicit operator bool() const { + return manager && manager->strong; + } + + auto acquire() const -> shared_pointer { + return shared_pointer(*this); + } + + auto reset() -> void { + if(manager && --manager->weak == 0) { + if(manager->strong == 0) { + delete manager; + } + } + manager = nullptr; + } +}; + +template +struct shared_pointer_this : shared_pointer_this_base { + shared_pointer_weak weak; + auto shared() -> shared_pointer { return weak; } + auto shared() const -> shared_pointer { return weak; } +}; + +template +auto shared_pointer_make(P&&... p) -> shared_pointer { + return shared_pointer{new T{forward

    (p)...}}; +} + +template +struct shared_pointer_new : shared_pointer { + shared_pointer_new(const shared_pointer& source) : shared_pointer(source) {} + template shared_pointer_new(P&&... p) : shared_pointer(new T(forward

    (p)...)) {} +}; + +} diff --git a/nall/simd.hpp b/nall/simd.hpp new file mode 100644 index 0000000..b413ee8 --- /dev/null +++ b/nall/simd.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace nall { + +#if defined(__AVX2__) + #define SIMD 256 + #define SIMD_AVX2 + #include +#endif + +} diff --git a/nall/smtp.hpp b/nall/smtp.hpp new file mode 100755 index 0000000..6bad413 --- /dev/null +++ b/nall/smtp.hpp @@ -0,0 +1,314 @@ +#pragma once + +#include +#include +#include + +#if !defined(PLATFORM_WINDOWS) + #include + #include + #include + #include +#else + #include + #include +#endif + +namespace nall { + +struct SMTP { + enum class Format : uint { Plain, HTML }; + + inline auto server(string server, uint16_t port = 25) -> void; + inline auto from(string mail, string name = "") -> void; + inline auto to(string mail, string name = "") -> void; + inline auto cc(string mail, string name = "") -> void; + inline auto bcc(string mail, string name = "") -> void; + inline auto attachment(const uint8_t* data, uint size, string name) -> void; + inline auto attachment(string filename, string name = "") -> bool; + inline auto subject(string subject) -> void; + inline auto body(string body, Format format = Format::Plain) -> void; + + inline auto send() -> bool; + inline auto message() -> string; + inline auto response() -> string; + + #if defined(API_WINDOWS) + inline auto close(int) -> int; + inline SMTP(); + #endif + +private: + struct Information { + string server; + uint16_t port; + struct Contact { + string mail; + string name; + }; + Contact from; + vector to; + vector cc; + vector bcc; + struct Attachment { + vector buffer; + string name; + }; + string subject; + string body; + Format format = Format::Plain; + vector attachments; + + string message; + string response; + } info; + + inline auto send(int sock, const string& text) -> bool; + inline auto recv(int sock) -> string; + inline auto boundary() -> string; + inline auto filename(const string& filename) -> string; + inline auto contact(const Information::Contact& contact) -> string; + inline auto contacts(const vector& contacts) -> string; + inline auto split(const string& text) -> string; +}; + +auto SMTP::server(string server, uint16_t port) -> void { + info.server = server; + info.port = port; +} + +auto SMTP::from(string mail, string name) -> void { + info.from = {mail, name}; +} + +auto SMTP::to(string mail, string name) -> void { + info.to.append({mail, name}); +} + +auto SMTP::cc(string mail, string name) -> void { + info.cc.append({mail, name}); +} + +auto SMTP::bcc(string mail, string name) -> void { + info.bcc.append({mail, name}); +} + +auto SMTP::attachment(const uint8_t* data, uint size, string name) -> void { + vector buffer; + buffer.resize(size); + memcpy(buffer.data(), data, size); + info.attachments.append({std::move(buffer), name}); +} + +auto SMTP::attachment(string filename, string name) -> bool { + if(!file::exists(filename)) return false; + if(name == "") name = notdir(filename); + auto buffer = file::read(filename); + info.attachments.append({std::move(buffer), name}); + return true; +} + +auto SMTP::subject(string subject) -> void { + info.subject = subject; +} + +auto SMTP::body(string body, Format format) -> void { + info.body = body; + info.format = format; +} + +auto SMTP::send() -> bool { + info.message.append("From: =?UTF-8?B?", Base64::encode(contact(info.from)), "?=\r\n"); + info.message.append("To: =?UTF-8?B?", Base64::encode(contacts(info.to)), "?=\r\n"); + info.message.append("Cc: =?UTF-8?B?", Base64::encode(contacts(info.cc)), "?=\r\n"); + info.message.append("Subject: =?UTF-8?B?", Base64::encode(info.subject), "?=\r\n"); + + string uniqueID = boundary(); + + info.message.append("MIME-Version: 1.0\r\n"); + info.message.append("Content-Type: multipart/mixed; boundary=", uniqueID, "\r\n"); + info.message.append("\r\n"); + + string format = (info.format == Format::Plain ? "text/plain" : "text/html"); + + info.message.append("--", uniqueID, "\r\n"); + info.message.append("Content-Type: ", format, "; charset=UTF-8\r\n"); + info.message.append("Content-Transfer-Encoding: base64\r\n"); + info.message.append("\r\n"); + info.message.append(split(Base64::encode(info.body)), "\r\n"); + info.message.append("\r\n"); + + for(auto& attachment : info.attachments) { + info.message.append("--", uniqueID, "\r\n"); + info.message.append("Content-Type: application/octet-stream\r\n"); + info.message.append("Content-Transfer-Encoding: base64\r\n"); + info.message.append("Content-Disposition: attachment; size=", attachment.buffer.size(), "; filename*=UTF-8''", filename(attachment.name), "\r\n"); + info.message.append("\r\n"); + info.message.append(split(Base64::encode(attachment.buffer)), "\r\n"); + info.message.append("\r\n"); + } + + info.message.append("--", uniqueID, "--\r\n"); + + addrinfo hints; + memset(&hints, 0, sizeof(addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + addrinfo* serverinfo; + int status = getaddrinfo(info.server, string(info.port), &hints, &serverinfo); + if(status != 0) return false; + + int sock = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol); + if(sock == -1) return false; + + int result = connect(sock, serverinfo->ai_addr, serverinfo->ai_addrlen); + if(result == -1) return false; + + string response; + info.response.append(response = recv(sock)); + if(!response.beginswith("220 ")) { close(sock); return false; } + + send(sock, {"HELO ", info.server, "\r\n"}); + info.response.append(response = recv(sock)); + if(!response.beginswith("250 ")) { close(sock); return false; } + + send(sock, {"MAIL FROM: <", info.from.mail, ">\r\n"}); + info.response.append(response = recv(sock)); + if(!response.beginswith("250 ")) { close(sock); return false; } + + for(auto& contact : info.to) { + send(sock, {"RCPT TO: <", contact.mail, ">\r\n"}); + info.response.append(response = recv(sock)); + if(!response.beginswith("250 ")) { close(sock); return false; } + } + + for(auto& contact : info.cc) { + send(sock, {"RCPT TO: <", contact.mail, ">\r\n"}); + info.response.append(response = recv(sock)); + if(!response.beginswith("250 ")) { close(sock); return false; } + } + + for(auto& contact : info.bcc) { + send(sock, {"RCPT TO: <", contact.mail, ">\r\n"}); + info.response.append(response = recv(sock)); + if(!response.beginswith("250 ")) { close(sock); return false; } + } + + send(sock, {"DATA\r\n"}); + info.response.append(response = recv(sock)); + if(!response.beginswith("354 ")) { close(sock); return false; } + + send(sock, {info.message, "\r\n", ".\r\n"}); + info.response.append(response = recv(sock)); + if(!response.beginswith("250 ")) { close(sock); return false; } + + send(sock, {"QUIT\r\n"}); + info.response.append(response = recv(sock)); +//if(!response.beginswith("221 ")) { close(sock); return false; } + + close(sock); + return true; +} + +auto SMTP::message() -> string { + return info.message; +} + +auto SMTP::response() -> string { + return info.response; +} + +auto SMTP::send(int sock, const string& text) -> bool { + const char* data = text.data(); + uint size = text.size(); + while(size) { + int length = ::send(sock, (const char*)data, size, 0); + if(length == -1) return false; + data += length; + size -= length; + } + return true; +} + +auto SMTP::recv(int sock) -> string { + vector buffer; + while(true) { + char c; + if(::recv(sock, &c, sizeof(char), 0) < 1) break; + buffer.append(c); + if(c == '\n') break; + } + buffer.append(0); + return buffer; +} + +auto SMTP::boundary() -> string { + random_lfsr random; + random.seed(time(0)); + string boundary; + for(uint n = 0; n < 16; n++) boundary.append(hex<2>(random())); + return boundary; +} + +auto SMTP::filename(const string& filename) -> string { + string result; + for(auto& n : filename) { + if(n <= 32 || n >= 127) result.append("%", hex<2>(n)); + else result.append(n); + } + return result; +} + +auto SMTP::contact(const Information::Contact& contact) -> string { + if(!contact.name) return contact.mail; + return {"\"", contact.name, "\" <", contact.mail, ">"}; +} + +auto SMTP::contacts(const vector& contacts) -> string { + string result; + for(auto& contact : contacts) { + result.append(this->contact(contact), "; "); + } + result.trimRight("; ", 1L); + return result; +} + +auto SMTP::split(const string& text) -> string { + string result; + + uint offset = 0; + while(offset < text.size()) { + uint length = min(76, text.size() - offset); + if(length < 76) { + result.append(text.slice(offset)); + } else { + result.append(text.slice(offset, 76), "\r\n"); + } + offset += length; + } + + return result; +} + +#if defined(API_WINDOWS) +auto SMTP::close(int sock) -> int { + return closesocket(sock); +} + +SMTP::SMTP() { + 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 + +} diff --git a/nall/stdint.hpp b/nall/stdint.hpp new file mode 100755 index 0000000..9b36a6c --- /dev/null +++ b/nall/stdint.hpp @@ -0,0 +1,65 @@ +#pragma once + +#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 + +//note: (u)intmax actually mean it: use as many bits as is possible +#if defined(__SIZEOF_INT128__) + using int128_t = signed __int128; + using uint128_t = unsigned __int128; + + #define INTMAX_BITS 128 + using intmax = int128_t; + using uintmax = uint128_t; +#else + #define INTMAX_BITS 64 + using intmax = intmax_t; + using uintmax = uintmax_t; +#endif + +using intptr = intptr_t; +using uintptr = uintptr_t; + +using float32_t = float; +using float64_t = double; +//note: long double size is not reliable across platforms +//using float80_t = long double; + +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"); + +static_assert(sizeof(float) >= 4, "float32_t is not of the correct size"); +static_assert(sizeof(double) >= 8, "float64_t is not of the correct size"); +//static_assert(sizeof(long double) >= 10, "float80_t is not of the correct size"); + +using uint = unsigned int; diff --git a/nall/string.hpp b/nall/string.hpp new file mode 100755 index 0000000..8a83798 --- /dev/null +++ b/nall/string.hpp @@ -0,0 +1,366 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nall { + +struct string; +struct string_format; + +struct string_view { + using type = string_view; + + //view.hpp + inline string_view(); + inline string_view(const string_view& source); + inline string_view(string_view&& source); + inline string_view(const char* data); + inline string_view(const char* data, uint size); + inline string_view(const string& source); + template inline string_view(P&&... p); + inline ~string_view(); + + inline auto operator=(const string_view& source) -> type&; + inline auto operator=(string_view&& source) -> type&; + + inline explicit operator bool() const; + inline operator const char*() const; + inline auto data() const -> const char*; + inline auto size() const -> uint; + + inline auto begin() const { return &_data[0]; } + inline auto end() const { return &_data[size()]; } + +protected: + string* _string; + const char* _data; + mutable int _size; +}; + +//adaptive (SSO + COW) is by far the best choice, the others exist solely to: +//1) demonstrate the performance benefit of combining SSO + COW +//2) rule out allocator bugs by trying different allocators when needed +#define NALL_STRING_ALLOCATOR_ADAPTIVE +//#define NALL_STRING_ALLOCATOR_COPY_ON_WRITE +//#define NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION +//#define NALL_STRING_ALLOCATOR_VECTOR + +//cast.hpp +template struct stringify; + +//format.hpp +template inline auto print(P&&...) -> void; +template inline auto print(FILE*, P&&...) -> void; +template inline auto pad(const T& value, long precision = 0, char padchar = ' ') -> string; +inline auto hex(uintmax value, long precision = 0, char padchar = '0') -> string; +inline auto octal(uintmax value, long precision = 0, char padchar = '0') -> string; +inline auto binary(uintmax value, long precision = 0, char padchar = '0') -> string; + +//match.hpp +inline auto tokenize(const char* s, const char* p) -> bool; +inline auto tokenize(vector& list, const char* s, const char* p) -> bool; + +//utf8.hpp +inline auto characters(string_view self, int offset = 0, int length = -1) -> uint; + +//utility.hpp +inline auto slice(string_view self, int offset = 0, int length = -1) -> string; +template inline auto fromInteger(char* result, T value) -> char*; +template inline auto fromNatural(char* result, T value) -> char*; +template inline auto fromReal(char* str, T value) -> uint; + +struct string { + using type = string; + +protected: + #if defined(NALL_STRING_ALLOCATOR_ADAPTIVE) + enum : uint { SSO = 24 }; + union { + struct { //copy-on-write + char* _data; + uint* _refs; + }; + struct { //small-string-optimization + char _text[SSO]; + }; + }; + inline auto _allocate() -> void; + inline auto _copy() -> void; + inline auto _resize() -> void; + #endif + + #if defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE) + char* _data; + mutable uint* _refs; + inline auto _allocate() -> char*; + inline auto _copy() -> char*; + #endif + + #if defined(NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION) + enum : uint { SSO = 24 }; + union { + char* _data; + char _text[SSO]; + }; + #endif + + #if defined(NALL_STRING_ALLOCATOR_VECTOR) + char* _data; + #endif + + uint _capacity; + uint _size; + +public: + inline string(); + inline string(string& source) : string() { operator=(source); } + inline string(const string& source) : string() { operator=(source); } + inline string(string&& source) : string() { operator=(move(source)); } + template inline auto get() -> T*; + template inline auto data() const -> const T*; + template auto size() const -> uint { return _size / sizeof(T); } + template auto capacity() const -> uint { return _capacity / sizeof(T); } + inline auto reset() -> type&; + inline auto reserve(uint) -> type&; + inline auto resize(uint) -> type&; + inline auto operator=(const string&) -> type&; + inline auto operator=(string&&) -> type&; + + template string(T&& s, P&&... p) : string() { + append(forward(s), forward

    (p)...); + } + ~string() { reset(); } + + explicit operator bool() const { return _size; } + operator const char*() const { return (const char*)data(); } + operator array_span() { return {(char*)get(), size()}; } + operator array_view() const { return {(const char*)data(), size()}; } + operator array_span() { return {(uint8_t*)get(), size()}; } + operator array_view() const { return {(const uint8_t*)data(), size()}; } + + auto operator==(const string& source) const -> bool { + return size() == source.size() && memory::compare(data(), source.data(), size()) == 0; + } + auto operator!=(const string& source) const -> bool { + return size() != source.size() || memory::compare(data(), source.data(), size()) != 0; + } + + auto operator==(const char* source) const -> bool { return strcmp(data(), source) == 0; } + auto operator!=(const char* source) const -> bool { return strcmp(data(), source) != 0; } + + auto operator==(string_view source) const -> bool { return compare(source) == 0; } + auto operator!=(string_view source) const -> bool { return compare(source) != 0; } + auto operator< (string_view source) const -> bool { return compare(source) < 0; } + auto operator<=(string_view source) const -> bool { return compare(source) <= 0; } + auto operator> (string_view source) const -> bool { return compare(source) > 0; } + auto operator>=(string_view source) const -> bool { return compare(source) >= 0; } + + auto begin() -> char* { return &get()[0]; } + auto end() -> char* { return &get()[size()]; } + auto begin() const -> const char* { return &data()[0]; } + auto end() const -> const char* { return &data()[size()]; } + + //atoi.hpp + inline auto boolean() const -> bool; + inline auto integer() const -> intmax; + inline auto natural() const -> uintmax; + inline auto hex() const -> uintmax; + inline auto real() const -> double; + + //core.hpp + inline auto operator[](uint) const -> const char&; + inline auto operator()(uint, char = 0) const -> char; + template inline auto assign(P&&...) -> type&; + template inline auto prepend(const T&, P&&...) -> type&; + template inline auto prepend(const nall::string_format&, P&&...) -> type&; + template inline auto _prepend(const stringify&) -> type&; + template inline auto append(const T&, P&&...) -> type&; + template inline auto append(const nall::string_format&, P&&...) -> type&; + template inline auto _append(const stringify&) -> type&; + inline auto length() const -> uint; + + //find.hpp + inline auto contains(string_view characters) const -> maybe; + + template inline auto _find(int, string_view) const -> maybe; + + inline auto find(string_view source) const -> maybe; + inline auto ifind(string_view source) const -> maybe; + inline auto qfind(string_view source) const -> maybe; + inline auto iqfind(string_view source) const -> maybe; + + inline auto findFrom(int offset, string_view source) const -> maybe; + inline auto ifindFrom(int offset, string_view source) const -> maybe; + + inline auto findNext(int offset, string_view source) const -> maybe; + inline auto ifindNext(int offset, string_view source) const -> maybe; + + inline auto findPrevious(int offset, string_view source) const -> maybe; + inline auto ifindPrevious(int offset, string_view source) const -> maybe; + + //format.hpp + inline auto format(const nall::string_format& params) -> type&; + + //compare.hpp + template inline static auto _compare(const char*, uint, const char*, uint) -> int; + + inline static auto compare(string_view, string_view) -> int; + inline static auto icompare(string_view, string_view) -> int; + + inline auto compare(string_view source) const -> int; + inline auto icompare(string_view source) const -> int; + + inline auto equals(string_view source) const -> bool; + inline auto iequals(string_view source) const -> bool; + + inline auto beginsWith(string_view source) const -> bool; + inline auto ibeginsWith(string_view source) const -> bool; + + inline auto endsWith(string_view source) const -> bool; + inline auto iendsWith(string_view source) const -> bool; + + //convert.hpp + inline auto downcase() -> type&; + inline auto upcase() -> type&; + + inline auto qdowncase() -> type&; + inline auto qupcase() -> type&; + + inline auto transform(string_view from, string_view to) -> type&; + + //match.hpp + inline auto match(string_view source) const -> bool; + inline auto imatch(string_view source) const -> bool; + + //replace.hpp + template inline auto _replace(string_view, string_view, long) -> type&; + inline auto replace(string_view from, string_view to, long limit = LONG_MAX) -> type&; + inline auto ireplace(string_view from, string_view to, long limit = LONG_MAX) -> type&; + inline auto qreplace(string_view from, string_view to, long limit = LONG_MAX) -> type&; + inline auto iqreplace(string_view from, string_view to, long limit = LONG_MAX) -> type&; + + //split.hpp + inline auto split(string_view key, long limit = LONG_MAX) const -> vector; + inline auto isplit(string_view key, long limit = LONG_MAX) const -> vector; + inline auto qsplit(string_view key, long limit = LONG_MAX) const -> vector; + inline auto iqsplit(string_view key, long limit = LONG_MAX) const -> vector; + + //trim.hpp + inline auto trim(string_view lhs, string_view rhs, long limit = LONG_MAX) -> type&; + inline auto trimLeft(string_view lhs, long limit = LONG_MAX) -> type&; + inline auto trimRight(string_view rhs, long limit = LONG_MAX) -> type&; + + inline auto itrim(string_view lhs, string_view rhs, long limit = LONG_MAX) -> type&; + inline auto itrimLeft(string_view lhs, long limit = LONG_MAX) -> type&; + inline auto itrimRight(string_view rhs, long limit = LONG_MAX) -> type&; + + inline auto strip() -> type&; + inline auto stripLeft() -> type&; + inline auto stripRight() -> type&; + + //utf8.hpp + inline auto characters(int offset = 0, int length = -1) const -> uint; + + //utility.hpp + inline static auto read(string_view filename) -> string; + inline static auto repeat(string_view pattern, uint times) -> string; + inline auto fill(char fill = ' ') -> type&; + inline auto hash() const -> uint; + inline auto remove(uint offset, uint length) -> type&; + inline auto reverse() -> type&; + inline auto size(int length, char fill = ' ') -> type&; + inline auto slice(int offset = 0, int length = -1) const -> string; +}; + +template<> struct vector : vector_base { + using type = vector; + using vector_base::vector_base; + + vector(const vector& source) { vector_base::operator=(source); } + vector(vector& source) { vector_base::operator=(source); } + vector(vector&& source) { vector_base::operator=(move(source)); } + template vector(P&&... p) { append(forward

    (p)...); } + + inline auto operator=(const vector& source) -> type& { return vector_base::operator=(source), *this; } + inline auto operator=(vector& source) -> type& { return vector_base::operator=(source), *this; } + inline auto operator=(vector&& source) -> type& { return vector_base::operator=(move(source)), *this; } + + //vector.hpp + template inline auto append(const string&, P&&...) -> type&; + inline auto append() -> type&; + + inline auto isort() -> type&; + inline auto find(string_view source) const -> maybe; + inline auto ifind(string_view source) const -> maybe; + inline auto match(string_view pattern) const -> vector; + inline auto merge(string_view separator) const -> string; + inline auto strip() -> type&; + + //split.hpp + template inline auto _split(string_view, string_view, long) -> type&; +}; + +struct string_format : vector { + using type = string_format; + + template string_format(P&&... p) { reserve(sizeof...(p)); append(forward

    (p)...); } + template inline auto append(const T&, P&&... p) -> type&; + inline auto append() -> type&; +}; + +inline auto operator"" _s(const char* value, std::size_t) -> string { return {value}; } + +} + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include diff --git a/nall/string/allocator/adaptive.hpp b/nall/string/allocator/adaptive.hpp new file mode 100755 index 0000000..174a72d --- /dev/null +++ b/nall/string/allocator/adaptive.hpp @@ -0,0 +1,123 @@ +#pragma once + +/***** + adaptive allocator + sizeof(string) == SSO + 8 + + aggressively tries to avoid heap allocations + small strings are stored on the stack + large strings are shared via copy-on-write + + SSO alone is very slow on large strings due to copying + SSO alone is very slightly faster than this allocator on small strings + + COW alone is very slow on small strings due to heap allocations + COW alone is very slightly faster than this allocator on large strings + + adaptive is thus very fast for all string sizes +*****/ + +namespace nall { + +string::string() : _data(nullptr), _capacity(SSO - 1), _size(0) { +} + +template +auto string::get() -> T* { + if(_capacity < SSO) return (T*)_text; + if(*_refs > 1) _copy(); + return (T*)_data; +} + +template +auto string::data() const -> const T* { + if(_capacity < SSO) return (const T*)_text; + return (const T*)_data; +} + +auto string::reset() -> type& { + if(_capacity >= SSO && !--*_refs) memory::free(_data); + _data = nullptr; + _capacity = SSO - 1; + _size = 0; + return *this; +} + +auto string::reserve(uint capacity) -> type& { + if(capacity <= _capacity) return *this; + capacity = bit::round(capacity + 1) - 1; + if(_capacity < SSO) { + _capacity = capacity; + _allocate(); + } else if(*_refs > 1) { + _capacity = capacity; + _copy(); + } else { + _capacity = capacity; + _resize(); + } + return *this; +} + +auto string::resize(uint size) -> type& { + reserve(size); + get()[_size = size] = 0; + return *this; +} + +auto string::operator=(const string& source) -> type& { + if(&source == this) return *this; + reset(); + if(source._capacity >= SSO) { + _data = source._data; + _refs = source._refs; + _capacity = source._capacity; + _size = source._size; + ++*_refs; + } else { + memory::copy(_text, source._text, SSO); + _capacity = source._capacity; + _size = source._size; + } + return *this; +} + +auto string::operator=(string&& source) -> type& { + if(&source == this) return *this; + reset(); + memory::copy(this, &source, sizeof(string)); + source._data = nullptr; + source._capacity = SSO - 1; + source._size = 0; + return *this; +} + +//SSO -> COW +auto string::_allocate() -> void { + char _temp[SSO]; + memory::copy(_temp, _text, SSO); + _data = memory::allocate(_capacity + 1 + sizeof(uint)); + memory::copy(_data, _temp, SSO); + _refs = (uint*)(_data + _capacity + 1); //always aligned by 32 via reserve() + *_refs = 1; +} + +//COW -> Unique +auto string::_copy() -> void { + auto _temp = memory::allocate(_capacity + 1 + sizeof(uint)); + memory::copy(_temp, _data, _size = min(_capacity, _size)); + _temp[_size] = 0; + --*_refs; + _data = _temp; + _refs = (uint*)(_data + _capacity + 1); + *_refs = 1; +} + +//COW -> Resize +auto string::_resize() -> void { + _data = memory::resize(_data, _capacity + 1 + sizeof(uint)); + _refs = (uint*)(_data + _capacity + 1); + *_refs = 1; +} + +} diff --git a/nall/string/allocator/copy-on-write.hpp b/nall/string/allocator/copy-on-write.hpp new file mode 100755 index 0000000..c1a19ae --- /dev/null +++ b/nall/string/allocator/copy-on-write.hpp @@ -0,0 +1,92 @@ +#pragma once + +namespace nall { + +string::string() : _data(nullptr), _refs(nullptr), _capacity(0), _size(0) { +} + +template +auto string::get() -> T* { + static char _null[] = ""; + if(!_data) return (T*)_null; + if(*_refs > 1) _data = _copy(); //make unique for write operations + return (T*)_data; +} + +template +auto string::data() const -> const T* { + static const char _null[] = ""; + if(!_data) return (const T*)_null; + return (const T*)_data; +} + +auto string::reset() -> type& { + if(_data && !--*_refs) { + memory::free(_data); + _data = nullptr; //_refs = nullptr; is unnecessary + } + _capacity = 0; + _size = 0; + return *this; +} + +auto string::reserve(uint capacity) -> type& { + if(capacity > _capacity) { + _capacity = bit::round(max(31u, capacity) + 1) - 1; + _data = _data ? _copy() : _allocate(); + } + return *this; +} + +auto string::resize(uint size) -> type& { + reserve(size); + get()[_size = size] = 0; + return *this; +} + +auto string::operator=(const string& source) -> string& { + if(&source == this) return *this; + reset(); + if(source._data) { + _data = source._data; + _refs = source._refs; + _capacity = source._capacity; + _size = source._size; + ++*_refs; + } + return *this; +} + +auto string::operator=(string&& source) -> string& { + if(&source == this) return *this; + reset(); + _data = source._data; + _refs = source._refs; + _capacity = source._capacity; + _size = source._size; + source._data = nullptr; + source._refs = nullptr; + source._capacity = 0; + source._size = 0; + return *this; +} + +auto string::_allocate() -> char* { + auto _temp = memory::allocate(_capacity + 1 + sizeof(uint)); + *_temp = 0; + _refs = (uint*)(_temp + _capacity + 1); //this will always be aligned by 32 via reserve() + *_refs = 1; + return _temp; +} + +auto string::_copy() -> char* { + auto _temp = memory::allocate(_capacity + 1 + sizeof(uint)); + memory::copy(_temp, _data, _size = min(_capacity, _size)); + _temp[_size] = 0; + --*_refs; + _refs = (uint*)(_temp + _capacity + 1); + *_refs = 1; + return _temp; +} + +} diff --git a/nall/string/allocator/small-string-optimization.hpp b/nall/string/allocator/small-string-optimization.hpp new file mode 100755 index 0000000..39aad4e --- /dev/null +++ b/nall/string/allocator/small-string-optimization.hpp @@ -0,0 +1,95 @@ +#pragma once + +/* +small string optimization (SSO) allocator +sizeof(string) == 8 + string::SSO + +utilizes a union to store small strings directly into text pointer +bypasses the need to allocate heap memory for small strings +requires extra computations, which can be slower for large strings + +pros: +* potential for in-place resize +* no heap allocation when (capacity < SSO) + +cons: +* added overhead to fetch data() +* pass-by-value requires heap allocation when (capacity >= SSO) + +*/ + +namespace nall { + +string::string() { + _data = nullptr; + _capacity = SSO - 1; + _size = 0; +} + +template +auto string::get() -> T* { + if(_capacity < SSO) return (T*)_text; + return (T*)_data; +} + +template +auto string::data() const -> const T* { + if(_capacity < SSO) return (const T*)_text; + return (const T*)_data; +} + +auto string::reset() -> type& { + if(_capacity >= SSO) memory::free(_data); + _data = nullptr; + _capacity = SSO - 1; + _size = 0; + return *this; +} + +auto string::reserve(uint capacity) -> type& { + if(capacity <= _capacity) return *this; + capacity = bit::round(capacity + 1) - 1; + if(_capacity < SSO) { + char _temp[SSO]; + memory::copy(_temp, _text, SSO); + _data = memory::allocate(_capacity = capacity + 1); + memory::copy(_data, _temp, SSO); + } else { + _data = memory::resize(_data, _capacity = capacity + 1); + } + return *this; +} + +auto string::resize(uint size) -> type& { + reserve(size); + get()[_size = size] = 0; + return *this; +} + +auto string::operator=(const string& source) -> type& { + if(&source == this) return *this; + reset(); + if(source._capacity >= SSO) { + _data = memory::allocate(source._capacity + 1); + _capacity = source._capacity; + _size = source._size; + memory::copy(_data, source._data, source._size + 1); + } else { + memory::copy(_text, source._text, SSO); + _capacity = SSO - 1; + _size = source._size; + } + return *this; +} + +auto string::operator=(string&& source) -> type& { + if(&source == this) return *this; + reset(); + memory::copy(this, &source, sizeof(string)); + source._data = nullptr; + source._capacity = SSO - 1; + source._size = 0; + return *this; +} + +} diff --git a/nall/string/allocator/vector.hpp b/nall/string/allocator/vector.hpp new file mode 100755 index 0000000..ad11316 --- /dev/null +++ b/nall/string/allocator/vector.hpp @@ -0,0 +1,84 @@ +#pragma once + +/* +vector allocator +sizeof(string) == 16 (amd64) + +utilizes a raw string pointer +always allocates memory onto the heap when string is not empty + +pros: +* potential for in-place resize +* simplicity + +cons: +* always allocates heap memory on (capacity > 0) +* pass-by-value requires heap allocation + +*/ + +namespace nall { + +template +auto string::get() -> T* { + if(_capacity == 0) reserve(1); + return (T*)_data; +} + +template +auto string::data() const -> const T* { + if(_capacity == 0) return (const T*)""; + return (const T*)_data; +} + +auto string::reset() -> type& { + if(_data) { memory::free(_data); _data = nullptr; } + _capacity = 0; + _size = 0; + return *this; +} + +auto string::reserve(uint capacity) -> type& { + if(capacity > _capacity) { + _capacity = bit::round(capacity + 1) - 1; + _data = memory::resize(_data, _capacity + 1); + _data[_capacity] = 0; + } + return *this; +} + +auto string::resize(uint size) -> type& { + reserve(size); + get()[_size = size] = 0; + return *this; +} + +auto string::operator=(const string& source) -> type& { + if(&source == this) return *this; + reset(); + _data = memory::allocate(source._size + 1); + _capacity = source._size; + _size = source._size; + memory::copy(_data, source.data(), source.size() + 1); + return *this; +} + +auto string::operator=(string&& source) -> type& { + if(&source == this) return *this; + reset(); + _data = source._data; + _capacity = source._capacity; + _size = source._size; + source._data = nullptr; + source._capacity = 0; + source._size = 0; + return *this; +} + +string::string() { + _data = nullptr; + _capacity = 0; + _size = 0; +} + +} diff --git a/nall/string/atoi.hpp b/nall/string/atoi.hpp new file mode 100644 index 0000000..11dafbc --- /dev/null +++ b/nall/string/atoi.hpp @@ -0,0 +1,25 @@ +#pragma once + +namespace nall { + +auto string::boolean() const -> bool { + return equals("true"); +} + +auto string::integer() const -> intmax { + return toInteger(data()); +} + +auto string::natural() const -> uintmax { + return toNatural(data()); +} + +auto string::hex() const -> uintmax { + return toHex(data()); +} + +auto string::real() const -> double { + return toReal(data()); +} + +} diff --git a/nall/string/cast.hpp b/nall/string/cast.hpp new file mode 100755 index 0000000..da915ee --- /dev/null +++ b/nall/string/cast.hpp @@ -0,0 +1,288 @@ +#pragma once + +//convert any (supported) type to a const char* without constructing a new nall::string +//this is used inside string{...} to build nall::string values + +namespace nall { + +//booleans + +template<> struct stringify { + stringify(bool value) : _value(value) {} + auto data() const -> const char* { return _value ? "true" : "false"; } + auto size() const -> uint { return _value ? 4 : 5; } + bool _value; +}; + +template<> struct stringify { + stringify(bool value) : _value(value) {} + auto data() const -> const char* { return _value ? "true" : "false"; } + auto size() const -> uint { return _value ? 4 : 5; } + bool _value; +}; + +//characters + +template<> struct stringify { + stringify(char source) { _data[0] = source; _data[1] = 0; } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return 1; } + char _data[2]; +}; + +//signed integers + +template<> struct stringify { + stringify(signed char source) { fromInteger(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[2 + sizeof(signed char) * 3]; +}; + +template<> struct stringify { + stringify(signed short source) { fromInteger(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[2 + sizeof(signed short) * 3]; +}; + +template<> struct stringify { + stringify(signed int source) { fromInteger(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[2 + sizeof(signed int) * 3]; +}; + +template<> struct stringify { + stringify(signed long source) { fromInteger(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[2 + sizeof(signed long) * 3]; +}; + +template<> struct stringify { + stringify(signed long long source) { fromInteger(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[2 + sizeof(signed long long) * 3]; +}; + +#if defined(__SIZEOF_INT128__) +template<> struct stringify { + stringify(int128_t source) { fromInteger(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[2 + sizeof(int128_t) * 3]; +}; +#endif + +template struct stringify> { + stringify(Integer source) { fromInteger(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[2 + sizeof(int64_t) * 3]; +}; + +//unsigned integers + +template<> struct stringify { + stringify(unsigned char source) { fromNatural(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[1 + sizeof(unsigned char) * 3]; +}; + +template<> struct stringify { + stringify(unsigned short source) { fromNatural(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[1 + sizeof(unsigned short) * 3]; +}; + +template<> struct stringify { + stringify(unsigned int source) { fromNatural(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[1 + sizeof(unsigned int) * 3]; +}; + +template<> struct stringify { + stringify(unsigned long source) { fromNatural(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[1 + sizeof(unsigned long) * 3]; +}; + +template<> struct stringify { + stringify(unsigned long long source) { fromNatural(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[1 + sizeof(unsigned long long) * 3]; +}; + +#if defined(__SIZEOF_INT128__) +template<> struct stringify { + stringify(uint128_t source) { fromNatural(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[1 + sizeof(uint128_t) * 3]; +}; +#endif + +template struct stringify> { + stringify(Natural source) { fromNatural(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[1 + sizeof(uint64_t) * 3]; +}; + +//floating-point + +template<> struct stringify { + stringify(float source) { fromReal(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[256]; +}; + +template<> struct stringify { + stringify(double source) { fromReal(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[256]; +}; + +template<> struct stringify { + stringify(long double source) { fromReal(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[256]; +}; + +template struct stringify> { + stringify(Real source) { fromReal(_data, source); } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[256]; +}; + +//arrays + +template<> struct stringify> { + stringify(vector source) { + _text.resize(source.size()); + memory::copy(_text.data(), source.data(), source.size()); + } + auto data() const -> const char* { return _text.data(); } + auto size() const -> uint { return _text.size(); } + vector _text; +}; + +template<> struct stringify&> { + stringify(const vector& source) { + _text.resize(source.size()); + memory::copy(_text.data(), source.data(), source.size()); + } + auto data() const -> const char* { return _text.data(); } + auto size() const -> uint { return _text.size(); } + vector _text; +}; + +//char arrays + +template<> struct stringify { + stringify(char* source) : _data(source ? source : "") {} + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + const char* _data; +}; + +template<> struct stringify { + stringify(const char* source) : _data(source ? source : "") {} + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + const char* _data; +}; + +//strings + +template<> struct stringify { + stringify(const string& source) : _text(source) {} + auto data() const -> const char* { return _text.data(); } + auto size() const -> uint { return _text.size(); } + const string& _text; +}; + +template<> struct stringify { + stringify(const string& source) : _text(source) {} + auto data() const -> const char* { return _text.data(); } + auto size() const -> uint { return _text.size(); } + const string& _text; +}; + +template<> struct stringify { + stringify(const string_view& source) : _view(source) {} + auto data() const -> const char* { return _view.data(); } + auto size() const -> uint { return _view.size(); } + const string_view& _view; +}; + +template<> struct stringify { + stringify(const string_view& source) : _view(source) {} + auto data() const -> const char* { return _view.data(); } + auto size() const -> uint { return _view.size(); } + const string_view& _view; +}; + +template<> struct stringify> { + stringify(const array_view& source) : _view(source) {} + auto data() const -> const char* { return _view.data(); } + auto size() const -> uint { return _view.size(); } + const array_view& _view; +}; + +template<> struct stringify&> { + stringify(const array_view& source) : _view(source) {} + auto data() const -> const char* { return _view.data(); } + auto size() const -> uint { return _view.size(); } + const array_view& _view; +}; + +template<> struct stringify { + stringify(const string_pascal& source) : _text(source) {} + auto data() const -> const char* { return _text.data(); } + auto size() const -> uint { return _text.size(); } + const string_pascal& _text; +}; + +template<> struct stringify { + stringify(const string_pascal& source) : _text(source) {} + auto data() const -> const char* { return _text.data(); } + auto size() const -> uint { return _text.size(); } + const string_pascal& _text; +}; + +//pointers + +//note: T = char* is matched by stringify +template struct stringify { + stringify(const T* source) { + if(!source) { + memory::copy(_data, "(nullptr)", 10); + } else { + memory::copy(_data, "0x", 2); + fromNatural(_data + 2, (uintptr)source); + } + } + auto data() const -> const char* { return _data; } + auto size() const -> uint { return strlen(_data); } + char _data[256]; +}; + +// + +template auto make_string(T value) -> stringify { + return stringify(forward(value)); +} + +} diff --git a/nall/string/compare.hpp b/nall/string/compare.hpp new file mode 100755 index 0000000..08479ba --- /dev/null +++ b/nall/string/compare.hpp @@ -0,0 +1,58 @@ +#pragma once + +namespace nall { + +template +auto string::_compare(const char* target, uint capacity, const char* source, uint size) -> int { + if(Insensitive) return memory::icompare(target, capacity, source, size); + return memory::compare(target, capacity, source, size); +} + +//size() + 1 includes null-terminator; required to properly compare strings of differing lengths +auto string::compare(string_view x, string_view y) -> int { + return memory::compare(x.data(), x.size() + 1, y.data(), y.size() + 1); +} + +auto string::icompare(string_view x, string_view y) -> int { + return memory::icompare(x.data(), x.size() + 1, y.data(), y.size() + 1); +} + +auto string::compare(string_view source) const -> int { + return memory::compare(data(), size() + 1, source.data(), source.size() + 1); +} + +auto string::icompare(string_view source) const -> int { + return memory::icompare(data(), size() + 1, source.data(), source.size() + 1); +} + +auto string::equals(string_view source) const -> bool { + if(size() != source.size()) return false; + return memory::compare(data(), source.data(), source.size()) == 0; +} + +auto string::iequals(string_view source) const -> bool { + if(size() != source.size()) return false; + return memory::icompare(data(), source.data(), source.size()) == 0; +} + +auto string::beginsWith(string_view source) const -> bool { + if(source.size() > size()) return false; + return memory::compare(data(), source.data(), source.size()) == 0; +} + +auto string::ibeginsWith(string_view source) const -> bool { + if(source.size() > size()) return false; + return memory::icompare(data(), source.data(), source.size()) == 0; +} + +auto string::endsWith(string_view source) const -> bool { + if(source.size() > size()) return false; + return memory::compare(data() + size() - source.size(), source.data(), source.size()) == 0; +} + +auto string::iendsWith(string_view source) const -> bool { + if(source.size() > size()) return false; + return memory::icompare(data() + size() - source.size(), source.data(), source.size()) == 0; +} + +} diff --git a/nall/string/convert.hpp b/nall/string/convert.hpp new file mode 100755 index 0000000..4c7d4ab --- /dev/null +++ b/nall/string/convert.hpp @@ -0,0 +1,53 @@ +#pragma once + +namespace nall { + +auto string::downcase() -> string& { + char* p = get(); + for(uint n = 0; n < size(); n++) { + if(p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20; + } + return *this; +} + +auto string::qdowncase() -> string& { + char* p = get(); + for(uint n = 0, quoted = 0; n < size(); n++) { + if(p[n] == '\"') quoted ^= 1; + if(!quoted && p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20; + } + return *this; +} + +auto string::upcase() -> string& { + char* p = get(); + for(uint n = 0; n < size(); n++) { + if(p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20; + } + return *this; +} + +auto string::qupcase() -> string& { + char* p = get(); + for(uint n = 0, quoted = 0; n < size(); n++) { + if(p[n] == '\"') quoted ^= 1; + if(!quoted && p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20; + } + return *this; +} + +auto string::transform(string_view from, string_view to) -> string& { + if(from.size() != to.size() || from.size() == 0) return *this; //patterns must be the same length + char* p = get(); + for(uint n = 0; n < size(); n++) { + for(uint s = 0; s < from.size(); s++) { + if(p[n] == from[s]) { + p[n] = to[s]; + break; + } + } + } + return *this; +} + +} diff --git a/nall/string/core.hpp b/nall/string/core.hpp new file mode 100755 index 0000000..9c5074d --- /dev/null +++ b/nall/string/core.hpp @@ -0,0 +1,75 @@ +#pragma once + +//only allocators may access _data or modify _size and _capacity +//all other functions must use data(), size(), capacity() + +#if defined(NALL_STRING_ALLOCATOR_ADAPTIVE) + #include +#elif defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE) + #include +#elif defined(NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION) + #include +#elif defined(NALL_STRING_ALLOCATOR_VECTOR) + #include +#endif + +namespace nall { + +auto string::operator[](uint position) const -> const char& { + #ifdef DEBUG + struct out_of_bounds {}; + if(position >= size() + 1) throw out_of_bounds{}; + #endif + return data()[position]; +} + +auto string::operator()(uint position, char fallback) const -> char { + if(position >= size() + 1) return fallback; + return data()[position]; +} + +template auto string::assign(P&&... p) -> string& { + resize(0); + return append(forward

    (p)...); +} + +template auto string::prepend(const T& value, P&&... p) -> string& { + if constexpr(sizeof...(p)) prepend(forward

    (p)...); + return _prepend(make_string(value)); +} + +template auto string::prepend(const nall::string_format& value, P&&... p) -> string& { + if constexpr(sizeof...(p)) prepend(forward

    (p)...); + return format(value); +} + +template auto string::_prepend(const stringify& source) -> string& { + resize(source.size() + size()); + memory::move(get() + source.size(), get(), size() - source.size()); + memory::copy(get(), source.data(), source.size()); + return *this; +} + +template auto string::append(const T& value, P&&... p) -> string& { + _append(make_string(value)); + if constexpr(sizeof...(p) > 0) append(forward

    (p)...); + return *this; +} + +template auto string::append(const nall::string_format& value, P&&... p) -> string& { + format(value); + if constexpr(sizeof...(p)) append(forward

    (p)...); + return *this; +} + +template auto string::_append(const stringify& source) -> string& { + resize(size() + source.size()); + memory::copy(get() + size() - source.size(), source.data(), source.size()); + return *this; +} + +auto string::length() const -> uint { + return strlen(data()); +} + +} diff --git a/nall/string/eval/evaluator.hpp b/nall/string/eval/evaluator.hpp new file mode 100755 index 0000000..cecffd4 --- /dev/null +++ b/nall/string/eval/evaluator.hpp @@ -0,0 +1,146 @@ +#pragma once + +namespace nall::Eval { + +inline auto evaluateExpression(Node* node) -> string { + #define p(n) evaluateExpression(node->link[n]) + switch(node->type) { + case Node::Type::Null: return "Null"; + case Node::Type::Literal: return {"Literal:", node->literal}; + case Node::Type::Function: return {"Function(0:", p(0), ", 1:", p(1), ")"}; + case Node::Type::Subscript: return {"Subscript(0:", p(0), ", 1:", p(1), ")"}; + case Node::Type::Member: return {"Member(0:", p(0), ", 1:", p(1), ")"}; + case Node::Type::SuffixIncrement: return {"SuffixIncrement(0:", p(0), ")"}; + case Node::Type::SuffixDecrement: return {"SuffixDecrement(0:", p(0), ")"}; + case Node::Type::Reference: return {"Reference(0:", p(0), ")"}; + case Node::Type::Dereference: return {"Dereference(0:", p(0), ")"}; + case Node::Type::BitwiseNot: return {"Complement(0:", p(0), ")"}; + case Node::Type::PrefixIncrement: return {"PrefixIncrement(0:", p(0), ")"}; + case Node::Type::PrefixDecrement: return {"PrefixDecrement(0:", p(0), ")"}; + case Node::Type::Add: return {"Add(0:", p(0), ", 1:", p(1), ")"}; + case Node::Type::Multiply: return {"Multiply(0:", p(0), ", 1:", p(1), ")"}; + case Node::Type::Concatenate: return {"Concatenate(0:", p(0), ", ", p(1), ")"}; + case Node::Type::Coalesce: return {"Coalesce(0:", p(0), ", ", p(1), ")"}; + case Node::Type::Condition: return {"Condition(0:", p(0), ", ", p(1), ", ", p(2), ")"}; + case Node::Type::Assign: return {"Assign(0:", p(0), ", ", p(1), ")"}; + case Node::Type::Separator: { + string result = "Separator("; + for(auto& link : node->link) { + result.append(evaluateExpression(link), ", "); + } + return result.trimRight(", ", 1L).append(")"); + } + } + #undef p + + throw "invalid operator"; +} + +inline auto evaluateInteger(Node* node) -> int64_t { + if(node->type == Node::Type::Literal) return toInteger(node->literal); + + #define p(n) evaluateInteger(node->link[n]) + switch(node->type) { + case Node::Type::SuffixIncrement: return p(0); + case Node::Type::SuffixDecrement: return p(0); + case Node::Type::LogicalNot: return !p(0); + case Node::Type::BitwiseNot: return ~p(0); + case Node::Type::Positive: return +p(0); + case Node::Type::Negative: return -p(0); + case Node::Type::PrefixIncrement: return p(0) + 1; + case Node::Type::PrefixDecrement: return p(0) - 1; + case Node::Type::Multiply: return p(0) * p(1); + case Node::Type::Divide: return p(0) / p(1); + case Node::Type::Modulo: return p(0) % p(1); + case Node::Type::Add: return p(0) + p(1); + case Node::Type::Subtract: return p(0) - p(1); + case Node::Type::ShiftLeft: return p(0) << p(1); + case Node::Type::ShiftRight: return p(0) >> p(1); + case Node::Type::BitwiseAnd: return p(0) & p(1); + case Node::Type::BitwiseOr: return p(0) | p(1); + case Node::Type::BitwiseXor: return p(0) ^ p(1); + case Node::Type::Equal: return p(0) == p(1); + case Node::Type::NotEqual: return p(0) != p(1); + case Node::Type::LessThanEqual: return p(0) <= p(1); + case Node::Type::GreaterThanEqual: return p(0) >= p(1); + case Node::Type::LessThan: return p(0) < p(1); + case Node::Type::GreaterThan: return p(0) > p(1); + case Node::Type::LogicalAnd: return p(0) && p(1); + case Node::Type::LogicalOr: return p(0) || p(1); + case Node::Type::Condition: return p(0) ? p(1) : p(2); + case Node::Type::Assign: return p(1); + case Node::Type::AssignMultiply: return p(0) * p(1); + case Node::Type::AssignDivide: return p(0) / p(1); + case Node::Type::AssignModulo: return p(0) % p(1); + case Node::Type::AssignAdd: return p(0) + p(1); + case Node::Type::AssignSubtract: return p(0) - p(1); + case Node::Type::AssignShiftLeft: return p(0) << p(1); + case Node::Type::AssignShiftRight: return p(0) >> p(1); + case Node::Type::AssignBitwiseAnd: return p(0) & p(1); + case Node::Type::AssignBitwiseOr: return p(0) | p(1); + case Node::Type::AssignBitwiseXor: return p(0) ^ p(1); + } + #undef p + + throw "invalid operator"; +} + +inline auto integer(const string& expression) -> maybe { + try { + auto tree = new Node; + const char* p = expression; + parse(tree, p, 0); + auto result = evaluateInteger(tree); + delete tree; + return result; + } catch(const char*) { + return nothing; + } +} + +inline auto evaluateReal(Node* node) -> long double { + if(node->type == Node::Type::Literal) return toReal(node->literal); + + #define p(n) evaluateReal(node->link[n]) + switch(node->type) { + case Node::Type::LogicalNot: return !p(0); + case Node::Type::Positive: return +p(0); + case Node::Type::Negative: return -p(0); + case Node::Type::Multiply: return p(0) * p(1); + case Node::Type::Divide: return p(0) / p(1); + case Node::Type::Add: return p(0) + p(1); + case Node::Type::Subtract: return p(0) - p(1); + case Node::Type::Equal: return p(0) == p(1); + case Node::Type::NotEqual: return p(0) != p(1); + case Node::Type::LessThanEqual: return p(0) <= p(1); + case Node::Type::GreaterThanEqual: return p(0) >= p(1); + case Node::Type::LessThan: return p(0) < p(1); + case Node::Type::GreaterThan: return p(0) > p(1); + case Node::Type::LogicalAnd: return p(0) && p(1); + case Node::Type::LogicalOr: return p(0) || p(1); + case Node::Type::Condition: return p(0) ? p(1) : p(2); + case Node::Type::Assign: return p(1); + case Node::Type::AssignMultiply: return p(0) * p(1); + case Node::Type::AssignDivide: return p(0) / p(1); + case Node::Type::AssignAdd: return p(0) + p(1); + case Node::Type::AssignSubtract: return p(0) - p(1); + } + #undef p + + throw "invalid operator"; +} + +inline auto real(const string& expression) -> maybe { + try { + auto tree = new Node; + const char* p = expression; + parse(tree, p, 0); + auto result = evaluateReal(tree); + delete tree; + return result; + } catch(const char*) { + return nothing; + } +} + +} diff --git a/nall/string/eval/literal.hpp b/nall/string/eval/literal.hpp new file mode 100755 index 0000000..4c106fc --- /dev/null +++ b/nall/string/eval/literal.hpp @@ -0,0 +1,99 @@ +#pragma once + +namespace nall::Eval { + +inline auto isLiteral(const char*& s) -> bool { + char n = s[0]; + return (n >= 'A' && n <= 'Z') + || (n >= 'a' && n <= 'z') + || (n >= '0' && n <= '9') + || (n == '%' || n == '$' || n == '_' || n == '.') + || (n == '\'' || n == '\"'); +} + +inline auto literalNumber(const char*& s) -> string { + const char* p = s; + + //binary + if(p[0] == '%' || (p[0] == '0' && p[1] == 'b')) { + uint prefix = 1 + (p[0] == '0'); + p += prefix; + while(p[0] == '\'' || p[0] == '0' || p[0] == '1') p++; + if(p - s <= prefix) throw "invalid binary literal"; + string result = slice(s, 0, p - s); + s = p; + return result; + } + + //octal + if(p[0] == '0' && p[1] == 'o') { + uint prefix = 1 + (p[0] == '0'); + p += prefix; + while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '7')) p++; + if(p - s <= prefix) throw "invalid octal literal"; + string result = slice(s, 0, p - s); + s = p; + return result; + } + + //hex + if(p[0] == '$' || (p[0] == '0' && p[1] == 'x')) { + uint prefix = 1 + (p[0] == '0'); + p += prefix; + while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9') || (p[0] >= 'A' && p[0] <= 'F') || (p[0] >= 'a' && p[0] <= 'f')) p++; + if(p - s <= prefix) throw "invalid hex literal"; + string result = slice(s, 0, p - s); + s = p; + return result; + } + + //decimal + while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9')) p++; + if(p[0] != '.') { + string result = slice(s, 0, p - s); + s = p; + return result; + } + + //floating-point + p++; + while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9')) p++; + string result = slice(s, 0, p - s); + s = p; + return result; +} + +inline auto literalString(const char*& s) -> string { + const char* p = s; + char escape = *p++; + + while(p[0] && p[0] != escape) p++; + if(*p++ != escape) throw "unclosed string literal"; + + string result = slice(s, 0, p - s); + s = p; + return result; +} + +inline auto literalVariable(const char*& s) -> string { + const char* p = s; + + while(p[0] == '_' || p[0] == '.' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || (p[0] >= '0' && p[0] <= '9')) p++; + + string result = slice(s, 0, p - s); + s = p; + return result; +} + +inline auto literal(const char*& s) -> string { + const char* p = s; + + if(p[0] >= '0' && p[0] <= '9') return literalNumber(s); + if(p[0] == '%' || p[0] == '$') return literalNumber(s); + if(p[0] == '\'' || p[0] == '\"') return literalString(s); + if(p[0] == '_' || p[0] == '.' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')) return literalVariable(s); + + throw "invalid literal"; +} + +} diff --git a/nall/string/eval/node.hpp b/nall/string/eval/node.hpp new file mode 100755 index 0000000..d02a928 --- /dev/null +++ b/nall/string/eval/node.hpp @@ -0,0 +1,37 @@ +#pragma once + +namespace nall::Eval { + +struct Node { + enum class Type : uint { + Null, + Literal, + Function, Subscript, Member, SuffixIncrement, SuffixDecrement, + Reference, Dereference, LogicalNot, BitwiseNot, Positive, Negative, PrefixIncrement, PrefixDecrement, + Multiply, Divide, Modulo, + Add, Subtract, + RotateLeft, RotateRight, ShiftLeft, ShiftRight, + BitwiseAnd, BitwiseOr, BitwiseXor, + Concatenate, + Equal, NotEqual, LessThanEqual, GreaterThanEqual, LessThan, GreaterThan, + LogicalAnd, LogicalOr, + Coalesce, Condition, + Assign, Create, //all assignment operators have the same precedence + AssignMultiply, AssignDivide, AssignModulo, + AssignAdd, AssignSubtract, + AssignRotateLeft, AssignRotateRight, AssignShiftLeft, AssignShiftRight, + AssignBitwiseAnd, AssignBitwiseOr, AssignBitwiseXor, + AssignConcatenate, + Separator, + }; + + Type type; + string literal; + vector link; + + Node() : type(Type::Null) {} + Node(Type type) : type(type) {} + ~Node() { for(auto& node : link) delete node; } +}; + +} diff --git a/nall/string/eval/parser.hpp b/nall/string/eval/parser.hpp new file mode 100755 index 0000000..f736d22 --- /dev/null +++ b/nall/string/eval/parser.hpp @@ -0,0 +1,164 @@ +#pragma once + +namespace nall::Eval { + +inline auto whitespace(char n) -> bool { + return n == ' ' || n == '\t' || n == '\r' || n == '\n'; +} + +inline auto parse(Node*& node, const char*& s, uint depth) -> void { + auto unaryPrefix = [&](Node::Type type, uint seek, uint depth) { + auto parent = new Node(type); + parse(parent->link(0) = new Node, s += seek, depth); + node = parent; + }; + + auto unarySuffix = [&](Node::Type type, uint seek, uint depth) { + auto parent = new Node(type); + parent->link(0) = node; + parse(parent, s += seek, depth); + node = parent; + }; + + auto binary = [&](Node::Type type, uint seek, uint depth) { + auto parent = new Node(type); + parent->link(0) = node; + parse(parent->link(1) = new Node, s += seek, depth); + node = parent; + }; + + auto ternary = [&](Node::Type type, uint seek, uint depth) { + auto parent = new Node(type); + parent->link(0) = node; + parse(parent->link(1) = new Node, s += seek, depth); + if(s[0] != ':') throw "mismatched ternary"; + parse(parent->link(2) = new Node, s += seek, depth); + node = parent; + }; + + auto separator = [&](Node::Type type, uint seek, uint depth) { + if(node->type != Node::Type::Separator) return binary(type, seek, depth); + uint n = node->link.size(); + parse(node->link(n) = new Node, s += seek, depth); + }; + + while(whitespace(s[0])) s++; + if(!s[0]) return; + + if(s[0] == '(' && !node->link) { + parse(node, s += 1, 1); + if(*s++ != ')') throw "mismatched group"; + } + + if(isLiteral(s)) { + node->type = Node::Type::Literal; + node->literal = literal(s); + } + + #define p() (!node->literal && !node->link) + while(true) { + while(whitespace(s[0])) s++; + if(!s[0]) return; + + if(depth >= 13) break; + if(s[0] == '(' && !p()) { + binary(Node::Type::Function, 1, 1); + if(*s++ != ')') throw "mismatched function"; + continue; + } + if(s[0] == '[') { + binary(Node::Type::Subscript, 1, 1); + if(*s++ != ']') throw "mismatched subscript"; + continue; + } + if(s[0] == '.') { binary(Node::Type::Member, 1, 13); continue; } + if(s[0] == '+' && s[1] == '+' && !p()) { unarySuffix(Node::Type::SuffixIncrement, 2, 13); continue; } + if(s[0] == '-' && s[1] == '-' && !p()) { unarySuffix(Node::Type::SuffixDecrement, 2, 13); continue; } + + if(s[0] == '&' && p()) { unaryPrefix(Node::Type::Reference, 1, 12); continue; } + if(s[0] == '*' && p()) { unaryPrefix(Node::Type::Dereference, 1, 12); continue; } + if(s[0] == '!' && p()) { unaryPrefix(Node::Type::LogicalNot, 1, 12); continue; } + if(s[0] == '~' && p()) { unaryPrefix(Node::Type::BitwiseNot, 1, 12); continue; } + if(s[0] == '+' && s[1] != '+' && p()) { unaryPrefix(Node::Type::Positive, 1, 12); continue; } + if(s[0] == '-' && s[1] != '-' && p()) { unaryPrefix(Node::Type::Negative, 1, 12); continue; } + if(s[0] == '+' && s[1] == '+' && p()) { unaryPrefix(Node::Type::PrefixIncrement, 2, 12); continue; } + if(s[0] == '-' && s[1] == '-' && p()) { unaryPrefix(Node::Type::PrefixDecrement, 2, 12); continue; } + if(depth >= 12) break; + + if(depth >= 11) break; + if(s[0] == '*' && s[1] != '=') { binary(Node::Type::Multiply, 1, 11); continue; } + if(s[0] == '/' && s[1] != '=') { binary(Node::Type::Divide, 1, 11); continue; } + if(s[0] == '%' && s[1] != '=') { binary(Node::Type::Modulo, 1, 11); continue; } + + if(depth >= 10) break; + if(s[0] == '+' && s[1] != '=') { binary(Node::Type::Add, 1, 10); continue; } + if(s[0] == '-' && s[1] != '=') { binary(Node::Type::Subtract, 1, 10); continue; } + + if(depth >= 9) break; + if(s[0] == '<' && s[1] == '<' && s[2] == '<' && s[3] != '=') { binary(Node::Type::RotateLeft, 3, 9); continue; } + if(s[0] == '>' && s[1] == '>' && s[2] == '>' && s[3] != '=') { binary(Node::Type::RotateRight, 3, 9); continue; } + if(s[0] == '<' && s[1] == '<' && s[2] != '=') { binary(Node::Type::ShiftLeft, 2, 9); continue; } + if(s[0] == '>' && s[1] == '>' && s[2] != '=') { binary(Node::Type::ShiftRight, 2, 9); continue; } + + if(depth >= 8) break; + if(s[0] == '&' && s[1] != '&' && s[1] != '=') { binary(Node::Type::BitwiseAnd, 1, 8); continue; } + if(s[0] == '|' && s[1] != '|' && s[1] != '=') { binary(Node::Type::BitwiseOr, 1, 8); continue; } + if(s[0] == '^' && s[1] != '^' && s[1] != '=') { binary(Node::Type::BitwiseXor, 1, 8); continue; } + + if(depth >= 7) break; + if(s[0] == '~' && s[1] != '=') { binary(Node::Type::Concatenate, 1, 7); continue; } + + if(depth >= 6) break; + if(s[0] == '=' && s[1] == '=') { binary(Node::Type::Equal, 2, 6); continue; } + if(s[0] == '!' && s[1] == '=') { binary(Node::Type::NotEqual, 2, 6); continue; } + if(s[0] == '<' && s[1] == '=') { binary(Node::Type::LessThanEqual, 2, 6); continue; } + if(s[0] == '>' && s[1] == '=') { binary(Node::Type::GreaterThanEqual, 2, 6); continue; } + if(s[0] == '<') { binary(Node::Type::LessThan, 1, 6); continue; } + if(s[0] == '>') { binary(Node::Type::GreaterThan, 1, 6); continue; } + + if(depth >= 5) break; + if(s[0] == '&' && s[1] == '&') { binary(Node::Type::LogicalAnd, 2, 5); continue; } + if(s[0] == '|' && s[1] == '|') { binary(Node::Type::LogicalOr, 2, 5); continue; } + + if(s[0] == '?' && s[1] == '?') { binary(Node::Type::Coalesce, 2, 4); continue; } + if(s[0] == '?' && s[1] != '?') { ternary(Node::Type::Condition, 1, 4); continue; } + if(depth >= 4) break; + + if(s[0] == '=') { binary(Node::Type::Assign, 1, 3); continue; } + if(s[0] == ':' && s[1] == '=') { binary(Node::Type::Create, 2, 3); continue; } + if(s[0] == '*' && s[1] == '=') { binary(Node::Type::AssignMultiply, 2, 3); continue; } + if(s[0] == '/' && s[1] == '=') { binary(Node::Type::AssignDivide, 2, 3); continue; } + if(s[0] == '%' && s[1] == '=') { binary(Node::Type::AssignModulo, 2, 3); continue; } + if(s[0] == '+' && s[1] == '=') { binary(Node::Type::AssignAdd, 2, 3); continue; } + if(s[0] == '-' && s[1] == '=') { binary(Node::Type::AssignSubtract, 2, 3); continue; } + if(s[0] == '<' && s[1] == '<' && s[2] == '<' && s[3] == '=') { binary(Node::Type::AssignRotateLeft, 4, 3); continue; } + if(s[0] == '>' && s[1] == '>' && s[2] == '>' && s[3] == '=') { binary(Node::Type::AssignRotateRight, 4, 3); continue; } + if(s[0] == '<' && s[1] == '<' && s[2] == '=') { binary(Node::Type::AssignShiftLeft, 3, 3); continue; } + if(s[0] == '>' && s[1] == '>' && s[2] == '=') { binary(Node::Type::AssignShiftRight, 3, 3); continue; } + if(s[0] == '&' && s[1] == '=') { binary(Node::Type::AssignBitwiseAnd, 2, 3); continue; } + if(s[0] == '|' && s[1] == '=') { binary(Node::Type::AssignBitwiseOr, 2, 3); continue; } + if(s[0] == '^' && s[1] == '=') { binary(Node::Type::AssignBitwiseXor, 2, 3); continue; } + if(s[0] == '~' && s[1] == '=') { binary(Node::Type::AssignConcatenate, 2, 3); continue; } + if(depth >= 3) break; + + if(depth >= 2) break; + if(s[0] == ',') { separator(Node::Type::Separator, 1, 2); continue; } + + if(depth >= 1 && (s[0] == ')' || s[0] == ']')) break; + + while(whitespace(s[0])) s++; + if(!s[0]) break; + + throw "unrecognized terminal"; + } + #undef p +} + +inline auto parse(const string& expression) -> Node* { + auto result = new Node; + const char* p = expression; + parse(result, p, 0); + return result; +} + +} diff --git a/nall/string/find.hpp b/nall/string/find.hpp new file mode 100755 index 0000000..c9c4442 --- /dev/null +++ b/nall/string/find.hpp @@ -0,0 +1,65 @@ +#pragma once + +namespace nall { + +auto string::contains(string_view characters) const -> maybe { + for(uint x : range(size())) { + for(char y : characters) { + if(operator[](x) == y) return x; + } + } + return nothing; +} + +template auto string::_find(int offset, string_view source) const -> maybe { + if(source.size() == 0) return nothing; + auto p = data(); + for(uint n = offset, quoted = 0; n < size();) { + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } + if(_compare(p + n, size() - n, source.data(), source.size())) { n++; continue; } + return n - offset; + } + return nothing; +} + +auto string::find(string_view source) const -> maybe { return _find<0, 0>(0, source); } +auto string::ifind(string_view source) const -> maybe { return _find<1, 0>(0, source); } +auto string::qfind(string_view source) const -> maybe { return _find<0, 1>(0, source); } +auto string::iqfind(string_view source) const -> maybe { return _find<1, 1>(0, source); } + +auto string::findFrom(int offset, string_view source) const -> maybe { return _find<0, 0>(offset, source); } +auto string::ifindFrom(int offset, string_view source) const -> maybe { return _find<1, 0>(offset, source); } + +auto string::findNext(int offset, string_view source) const -> maybe { + if(source.size() == 0) return nothing; + for(int n = offset + 1; n < size(); n++) { + if(memory::compare(data() + n, size() - n, source.data(), source.size()) == 0) return n; + } + return nothing; +} + +auto string::ifindNext(int offset, string_view source) const -> maybe { + if(source.size() == 0) return nothing; + for(int n = offset + 1; n < size(); n++) { + if(memory::icompare(data() + n, size() - n, source.data(), source.size()) == 0) return n; + } + return nothing; +} + +auto string::findPrevious(int offset, string_view source) const -> maybe { + if(source.size() == 0) return nothing; + for(int n = offset - 1; n >= 0; n--) { + if(memory::compare(data() + n, size() - n, source.data(), source.size()) == 0) return n; + } + return nothing; +} + +auto string::ifindPrevious(int offset, string_view source) const -> maybe { + if(source.size() == 0) return nothing; + for(int n = offset - 1; n >= 0; n--) { + if(memory::icompare(data() + n, size() - n, source.data(), source.size()) == 0) return n; + } + return nothing; +} + +} diff --git a/nall/string/format.hpp b/nall/string/format.hpp new file mode 100755 index 0000000..9f8a697 --- /dev/null +++ b/nall/string/format.hpp @@ -0,0 +1,138 @@ +#pragma once + +namespace nall { + +//nall::format is a vector of parameters that can be applied to a string +//each {#} token will be replaced with its appropriate format parameter + +auto string::format(const nall::string_format& params) -> type& { + auto size = (int)this->size(); + auto data = memory::allocate(size); + memory::copy(data, this->data(), size); + + int x = 0; + while(x < size - 2) { //2 = minimum tag length + if(data[x] != '{') { x++; continue; } + + int y = x + 1; + while(y < size - 1) { //-1 avoids going out of bounds on test after this loop + if(data[y] != '}') { y++; continue; } + break; + } + + if(data[y++] != '}') { x++; continue; } + + static auto isNumeric = [](char* s, char* e) -> bool { + if(s == e) return false; //ignore empty tags: {} + while(s < e) { + if(*s >= '0' && *s <= '9') { s++; continue; } + return false; + } + return true; + }; + if(!isNumeric(&data[x + 1], &data[y - 1])) { x++; continue; } + + uint index = toNatural(&data[x + 1]); + if(index >= params.size()) { x++; continue; } + + uint sourceSize = y - x; + uint targetSize = params[index].size(); + uint remaining = size - x; + + if(sourceSize > targetSize) { + uint difference = sourceSize - targetSize; + memory::move(&data[x], &data[x + difference], remaining); + size -= difference; + } else if(targetSize > sourceSize) { + uint difference = targetSize - sourceSize; + data = (char*)realloc(data, size + difference); + size += difference; + memory::move(&data[x + difference], &data[x], remaining); + } + memory::copy(&data[x], params[index].data(), targetSize); + x += targetSize; + } + + resize(size); + memory::copy(get(), data, size); + memory::free(data); + return *this; +} + +template auto string_format::append(const T& value, P&&... p) -> string_format& { + vector::append(value); + return append(forward

    (p)...); +} + +auto string_format::append() -> string_format& { + return *this; +} + +template auto print(P&&... p) -> void { + string s{forward

    (p)...}; + fwrite(s.data(), 1, s.size(), stdout); + fflush(stdout); +} + +template auto print(FILE* fp, P&&... p) -> void { + string s{forward

    (p)...}; + fwrite(s.data(), 1, s.size(), fp); + if(fp == stdout || fp == stderr) fflush(fp); +} + +template auto pad(const T& value, long precision, char padchar) -> string { + string buffer{value}; + if(precision) buffer.size(precision, padchar); + return buffer; +} + +auto hex(uintmax value, long precision, char padchar) -> string { + string buffer; + buffer.resize(sizeof(uintmax) * 2); + char* p = buffer.get(); + + uint size = 0; + do { + uint n = value & 15; + p[size++] = n < 10 ? '0' + n : 'a' + n - 10; + value >>= 4; + } while(value); + buffer.resize(size); + buffer.reverse(); + if(precision) buffer.size(precision, padchar); + return buffer; +} + +auto octal(uintmax value, long precision, char padchar) -> string { + string buffer; + buffer.resize(sizeof(uintmax) * 3); + char* p = buffer.get(); + + uint size = 0; + do { + p[size++] = '0' + (value & 7); + value >>= 3; + } while(value); + buffer.resize(size); + buffer.reverse(); + if(precision) buffer.size(precision, padchar); + return buffer; +} + +auto binary(uintmax value, long precision, char padchar) -> string { + string buffer; + buffer.resize(sizeof(uintmax) * 8); + char* p = buffer.get(); + + uint size = 0; + do { + p[size++] = '0' + (value & 1); + value >>= 1; + } while(value); + buffer.resize(size); + buffer.reverse(); + if(precision) buffer.size(precision, padchar); + return buffer; +} + +} diff --git a/nall/string/markup/bml.hpp b/nall/string/markup/bml.hpp new file mode 100755 index 0000000..3bf05dd --- /dev/null +++ b/nall/string/markup/bml.hpp @@ -0,0 +1,189 @@ +#pragma once + +//BML v1.0 parser +//revision 0.04 + +namespace nall::BML { + +//metadata is used to store nesting level + +struct ManagedNode; +using SharedNode = shared_pointer; + +struct ManagedNode : Markup::ManagedNode { +protected: + //test to verify if a valid character for a node name + auto valid(char p) const -> bool { //A-Z, a-z, 0-9, -. + return p - 'A' < 26u || p - 'a' < 26u || p - '0' < 10u || p - '-' < 2u; + } + + //determine indentation level, without incrementing pointer + auto readDepth(const char* p) -> uint { + uint depth = 0; + while(p[depth] == '\t' || p[depth] == ' ') depth++; + return depth; + } + + //determine indentation level + auto parseDepth(const char*& p) -> uint { + uint depth = readDepth(p); + p += depth; + return depth; + } + + //read name + auto parseName(const char*& p) -> void { + uint length = 0; + while(valid(p[length])) length++; + if(length == 0) throw "Invalid node name"; + _name = slice(p, 0, length); + p += length; + } + + auto parseData(const char*& p, string_view spacing) -> void { + if(*p == '=' && *(p + 1) == '\"') { + uint length = 2; + while(p[length] && p[length] != '\n' && p[length] != '\"') length++; + if(p[length] != '\"') throw "Unescaped value"; + _value = {slice(p, 2, length - 2), "\n"}; + p += length + 1; + } else if(*p == '=') { + uint length = 1; + while(p[length] && p[length] != '\n' && p[length] != '\"' && p[length] != ' ') length++; + if(p[length] == '\"') throw "Illegal character in value"; + _value = {slice(p, 1, length - 1), "\n"}; + p += length; + } else if(*p == ':') { + uint length = 1; + while(p[length] && p[length] != '\n') length++; + _value = {slice(p, 1, length - 1).trimLeft(spacing, 1L), "\n"}; + p += length; + } + } + + //read all attributes for a node + auto parseAttributes(const char*& p, string_view spacing) -> void { + while(*p && *p != '\n') { + if(*p != ' ') throw "Invalid node name"; + while(*p == ' ') p++; //skip excess spaces + if(*(p + 0) == '/' && *(p + 1) == '/') break; //skip comments + + SharedNode node(new ManagedNode); + uint length = 0; + while(valid(p[length])) length++; + if(length == 0) throw "Invalid attribute name"; + node->_name = slice(p, 0, length); + node->parseData(p += length, spacing); + node->_value.trimRight("\n", 1L); + _children.append(node); + } + } + + //read a node and all of its child nodes + auto parseNode(const vector& text, uint& y, string_view spacing) -> void { + const char* p = text[y++]; + _metadata = parseDepth(p); + parseName(p); + parseData(p, spacing); + parseAttributes(p, spacing); + + while(y < text.size()) { + uint depth = readDepth(text[y]); + if(depth <= _metadata) break; + + if(text[y][depth] == ':') { + _value.append(slice(text[y++], depth + 1).trimLeft(spacing, 1L), "\n"); + continue; + } + + SharedNode node(new ManagedNode); + node->parseNode(text, y, spacing); + _children.append(node); + } + + _value.trimRight("\n", 1L); + } + + //read top-level nodes + auto parse(string document, string_view spacing) -> void { + //in order to simplify the parsing logic; we do an initial pass to normalize the data + //the below code will turn '\r\n' into '\n'; skip empty lines; and skip comment lines + char* p = document.get(), *output = p; + while(*p) { + char* origin = p; + bool empty = true; + while(*p) { + //scan for first non-whitespace character. if it's a line feed or comment; skip the line + if(p[0] == ' ' || p[0] == '\t') { p++; continue; } + empty = p[0] == '\r' || p[0] == '\n' || (p[0] == '/' && p[1] == '/'); + break; + } + while(*p) { + if(p[0] == '\r') p[0] = '\n'; //turns '\r\n' into '\n\n' (second '\n' will be skipped) + if(*p++ == '\n') break; //include '\n' in the output to be copied + } + if(empty) continue; + + memory::move(output, origin, p - origin); + output += p - origin; + } + document.resize(document.size() - (p - output)).trimRight("\n"); + if(document.size() == 0) return; //empty document + + auto text = document.split("\n"); + uint y = 0; + while(y < text.size()) { + SharedNode node(new ManagedNode); + node->parseNode(text, y, spacing); + if(node->_metadata > 0) throw "Root nodes cannot be indented"; + _children.append(node); + } + } + + friend auto unserialize(const string&, string_view) -> Markup::Node; +}; + +inline auto unserialize(const string& markup, string_view spacing = {}) -> Markup::Node { + SharedNode node(new ManagedNode); + try { + node->parse(markup, spacing); + } catch(const char* error) { + node.reset(); + } + return (Markup::SharedNode&)node; +} + +inline auto serialize(const Markup::Node& node, string_view spacing = {}, uint depth = 0) -> string { + if(!node.name()) { + string result; + for(auto leaf : node) { + result.append(serialize(leaf, spacing, depth)); + } + return result; + } + + string padding; + padding.resize(depth * 2); + padding.fill(' '); + + vector lines; + if(auto value = node.value()) lines = value.split("\n"); + + string result; + result.append(padding); + result.append(node.name()); + if(lines.size() == 1) result.append(":", spacing, lines[0]); + result.append("\n"); + if(lines.size() > 1) { + padding.append(" "); + for(auto& line : lines) { + result.append(padding, ":", spacing, line, "\n"); + } + } + for(auto leaf : node) { + result.append(serialize(leaf, spacing, depth + 1)); + } + return result; +} + +} diff --git a/nall/string/markup/find.hpp b/nall/string/markup/find.hpp new file mode 100644 index 0000000..0901b0d --- /dev/null +++ b/nall/string/markup/find.hpp @@ -0,0 +1,137 @@ +#pragma once + +namespace nall::Markup { + +auto ManagedNode::_evaluate(string query) const -> bool { + if(!query) return true; + + for(auto& rule : query.split(",")) { + enum class Comparator : uint { ID, EQ, NE, LT, LE, GT, GE }; + auto comparator = Comparator::ID; + if(rule.match("*!=*")) comparator = Comparator::NE; + else if(rule.match("*<=*")) comparator = Comparator::LE; + else if(rule.match("*>=*")) comparator = Comparator::GE; + else if(rule.match ("*=*")) comparator = Comparator::EQ; + else if(rule.match ("*<*")) comparator = Comparator::LT; + else if(rule.match ("*>*")) comparator = Comparator::GT; + + if(comparator == Comparator::ID) { + if(_find(rule).size()) continue; + return false; + } + + vector side; + switch(comparator) { + case Comparator::EQ: side = rule.split ("=", 1L); break; + case Comparator::NE: side = rule.split("!=", 1L); break; + case Comparator::LT: side = rule.split ("<", 1L); break; + case Comparator::LE: side = rule.split("<=", 1L); break; + case Comparator::GT: side = rule.split (">", 1L); break; + case Comparator::GE: side = rule.split(">=", 1L); break; + } + + string data = string{_value}.strip(); + if(side(0)) { + auto result = _find(side(0)); + if(result.size() == 0) return false; + data = result[0].text(); //strips whitespace so rules can match without requiring it + } + + switch(comparator) { + case Comparator::EQ: if(data.match(side(1)) == true) continue; break; + case Comparator::NE: if(data.match(side(1)) == false) continue; break; + case Comparator::LT: if(data.natural() < side(1).natural()) continue; break; + case Comparator::LE: if(data.natural() <= side(1).natural()) continue; break; + case Comparator::GT: if(data.natural() > side(1).natural()) continue; break; + case Comparator::GE: if(data.natural() >= side(1).natural()) continue; break; + } + + return false; + } + + return true; +} + +auto ManagedNode::_find(const string& query) const -> vector { + vector result; + + auto path = query.split("/"); + string name = path.take(0), rule; + uint lo = 0u, hi = ~0u; + + if(name.match("*[*]")) { + auto p = name.trimRight("]", 1L).split("[", 1L); + name = p(0); + if(p(1).find("-")) { + p = p(1).split("-", 1L); + lo = !p(0) ? 0u : p(0).natural(); + hi = !p(1) ? ~0u : p(1).natural(); + } else { + lo = hi = p(1).natural(); + } + } + + if(name.match("*(*)")) { + auto p = name.trimRight(")", 1L).split("(", 1L); + name = p(0); + rule = p(1); + } + + uint position = 0; + for(auto& node : _children) { + if(!node->_name.match(name)) continue; + if(!node->_evaluate(rule)) continue; + + bool inrange = position >= lo && position <= hi; + position++; + if(!inrange) continue; + + if(path.size() == 0) { + result.append(node); + } else for(auto& item : node->_find(path.merge("/"))) { + result.append(item); + } + } + + return result; +} + +//operator[](string) +auto ManagedNode::_lookup(const string& path) const -> Node { + auto result = _find(path); + return result ? result[0] : Node{}; + +/*//faster, but cannot search + if(auto position = path.find("/")) { + auto name = slice(path, 0, *position); + for(auto& node : _children) { + if(name == node->_name) { + return node->_lookup(slice(path, *position + 1)); + } + } + } else for(auto& node : _children) { + if(path == node->_name) return node; + } + return {}; +*/ +} + +auto ManagedNode::_create(const string& path) -> Node { + if(auto position = path.find("/")) { + auto name = slice(path, 0, *position); + for(auto& node : _children) { + if(name == node->_name) { + return node->_create(slice(path, *position + 1)); + } + } + _children.append(new ManagedNode(name)); + return _children.right()->_create(slice(path, *position + 1)); + } + for(auto& node : _children) { + if(path == node->_name) return node; + } + _children.append(new ManagedNode(path)); + return _children.right(); +} + +} diff --git a/nall/string/markup/node.hpp b/nall/string/markup/node.hpp new file mode 100755 index 0000000..528d0a0 --- /dev/null +++ b/nall/string/markup/node.hpp @@ -0,0 +1,147 @@ +#pragma once + +namespace nall::Markup { + +struct Node; +struct ManagedNode; +using SharedNode = shared_pointer; + +struct ManagedNode { + ManagedNode() = default; + ManagedNode(const string& name) : _name(name) {} + ManagedNode(const string& name, const string& value) : _name(name), _value(value) {} + + auto clone() const -> SharedNode { + SharedNode clone{new ManagedNode(_name, _value)}; + for(auto& child : _children) { + clone->_children.append(child->clone()); + } + return clone; + } + + auto copy(SharedNode source) -> void { + _name = source->_name; + _value = source->_value; + _metadata = source->_metadata; + _children.reset(); + for(auto child : source->_children) { + _children.append(child->clone()); + } + } + +protected: + string _name; + string _value; + uintptr _metadata = 0; + vector _children; + + inline auto _evaluate(string query) const -> bool; + inline auto _find(const string& query) const -> vector; + inline auto _lookup(const string& path) const -> Node; + inline auto _create(const string& path) -> Node; + + friend class Node; +}; + +struct Node { + Node() : shared(new ManagedNode) {} + Node(const SharedNode& source) : shared(source ? source : new ManagedNode) {} + Node(const nall::string& name) : shared(new ManagedNode(name)) {} + Node(const nall::string& name, const nall::string& value) : shared(new ManagedNode(name, value)) {} + + auto unique() const -> bool { return shared.unique(); } + auto clone() const -> Node { return shared->clone(); } + auto copy(Node source) -> void { return shared->copy(source.shared); } + + explicit operator bool() const { return shared->_name || shared->_children; } + auto name() const -> nall::string { return shared->_name; } + auto value() const -> nall::string { return shared->_value; } + + auto value(nall::string& target) const -> bool { if(shared) target = string(); return (bool)shared; } + auto value(bool& target) const -> bool { if(shared) target = boolean(); return (bool)shared; } + auto value(int& target) const -> bool { if(shared) target = integer(); return (bool)shared; } + auto value(uint& target) const -> bool { if(shared) target = natural(); return (bool)shared; } + auto value(double& target) const -> bool { if(shared) target = real(); return (bool)shared; } + + auto text() const -> nall::string { return value().strip(); } + auto string() const -> nall::string { return value().strip(); } + auto boolean() const -> bool { return text() == "true"; } + auto integer() const -> int64_t { return text().integer(); } + auto natural() const -> uint64_t { return text().natural(); } + auto real() const -> double { return text().real(); } + + auto text(const nall::string& fallback) const -> nall::string { return bool(*this) ? text() : fallback; } + auto string(const nall::string& fallback) const -> nall::string { return bool(*this) ? string() : fallback; } + auto boolean(bool fallback) const -> bool { return bool(*this) ? boolean() : fallback; } + auto integer(int64_t fallback) const -> int64_t { return bool(*this) ? integer() : fallback; } + auto natural(uint64_t fallback) const -> uint64_t { return bool(*this) ? natural() : fallback; } + auto real(double fallback) const -> double { return bool(*this) ? real() : fallback; } + + auto setName(const nall::string& name = "") -> Node& { shared->_name = name; return *this; } + auto setValue(const nall::string& value = "") -> Node& { shared->_value = value; return *this; } + + auto reset() -> void { shared->_children.reset(); } + auto size() const -> uint { return shared->_children.size(); } + + auto prepend(const Node& node) -> void { shared->_children.prepend(node.shared); } + auto append(const Node& node) -> void { shared->_children.append(node.shared); } + auto remove(const Node& node) -> bool { + for(auto n : range(size())) { + if(node.shared == shared->_children[n]) { + return shared->_children.remove(n), true; + } + } + return false; + } + + auto insert(uint position, const Node& node) -> bool { + if(position > size()) return false; //used > instead of >= to allow indexed-equivalent of append() + return shared->_children.insert(position, node.shared), true; + } + + auto remove(uint position) -> bool { + if(position >= size()) return false; + return shared->_children.remove(position), true; + } + + auto swap(uint x, uint y) -> bool { + if(x >= size() || y >= size()) return false; + return std::swap(shared->_children[x], shared->_children[y]), true; + } + + auto sort(function comparator = [](auto x, auto y) { + return nall::string::compare(x.shared->_name, y.shared->_name) < 0; + }) -> void { + nall::sort(shared->_children.data(), shared->_children.size(), [&](auto x, auto y) { + return comparator(x, y); //this call converts SharedNode objects to Node objects + }); + } + + auto operator[](int position) -> Node { + if(position >= size()) return {}; + return shared->_children[position]; + } + + auto operator[](const nall::string& path) const -> Node { return shared->_lookup(path); } + auto operator()(const nall::string& path) -> Node { return shared->_create(path); } + auto find(const nall::string& query) const -> vector { return shared->_find(query); } + + struct iterator { + auto operator*() -> Node { return {source.shared->_children[position]}; } + auto operator!=(const iterator& source) const -> bool { return position != source.position; } + auto operator++() -> iterator& { return position++, *this; } + iterator(const Node& source, uint position) : source(source), position(position) {} + + private: + const Node& source; + uint position; + }; + + auto begin() const -> iterator { return iterator(*this, 0); } + auto end() const -> iterator { return iterator(*this, size()); } + +protected: + SharedNode shared; +}; + +} diff --git a/nall/string/markup/xml.hpp b/nall/string/markup/xml.hpp new file mode 100755 index 0000000..2710910 --- /dev/null +++ b/nall/string/markup/xml.hpp @@ -0,0 +1,217 @@ +#pragma once + +//XML v1.0 subset parser +//revision 0.04 + +namespace nall::XML { + +//metadata: +// 0 = element +// 1 = attribute + +struct ManagedNode; +using SharedNode = shared_pointer; + +struct ManagedNode : Markup::ManagedNode { +protected: + inline string escape() const { + string result = _value; + result.replace("&", "&"); + result.replace("<", "<"); + result.replace(">", ">"); + if(_metadata == 1) { + result.replace("\'", "'"); + result.replace("\"", """); + } + return result; + } + + inline bool isName(char c) const { + if(c >= 'A' && c <= 'Z') return true; + if(c >= 'a' && c <= 'z') return true; + if(c >= '0' && c <= '9') return true; + if(c == '.' || c == '_') return true; + if(c == '?') return true; + return false; + } + + inline bool isWhitespace(char c) const { + if(c == ' ' || c == '\t') return true; + if(c == '\r' || c == '\n') return true; + return false; + } + + //copy part of string from source document into target string; decode markup while copying + inline void copy(string& target, const char* source, uint length) { + target.reserve(length + 1); + + #if defined(NALL_XML_LITERAL) + memory::copy(target.pointer(), source, length); + target[length] = 0; + return; + #endif + + char* output = target.get(); + while(length) { + if(*source == '&') { + if(!memory::compare(source, "<", 4)) { *output++ = '<'; source += 4; length -= 4; continue; } + if(!memory::compare(source, ">", 4)) { *output++ = '>'; source += 4; length -= 4; continue; } + if(!memory::compare(source, "&", 5)) { *output++ = '&'; source += 5; length -= 5; continue; } + if(!memory::compare(source, "'", 6)) { *output++ = '\''; source += 6; length -= 6; continue; } + if(!memory::compare(source, """, 6)) { *output++ = '\"'; source += 6; length -= 6; continue; } + } + + if(_metadata == 0 && source[0] == '<' && source[1] == '!') { + //comment + if(!memory::compare(source, "", 3)) source++, length--; + source += 3, length -= 3; + continue; + } + + //CDATA + if(!memory::compare(source, "", 3)) *output++ = *source++, length--; + source += 3, length -= 3; + continue; + } + } + + *output++ = *source++, length--; + } + *output = 0; + } + + inline bool parseExpression(const char*& p) { + if(*(p + 1) != '!') return false; + + //comment + if(!memory::compare(p, "", 3)) p++; + if(!*p) throw "unclosed comment"; + p += 3; + return true; + } + + //CDATA + if(!memory::compare(p, "", 3)) p++; + if(!*p) throw "unclosed CDATA"; + p += 3; + return true; + } + + //DOCTYPE + if(!memory::compare(p, "') counter--; + } while(counter); + return true; + } + + return false; + } + + //returns true if tag closes itself (); false if not () + inline bool parseHead(const char*& p) { + //parse name + const char* nameStart = ++p; //skip '<' + while(isName(*p)) p++; + const char* nameEnd = p; + copy(_name, nameStart, nameEnd - nameStart); + if(!_name) throw "missing element name"; + + //parse attributes + while(*p) { + while(isWhitespace(*p)) p++; + if(!*p) throw "unclosed attribute"; + if(*p == '?' || *p == '/' || *p == '>') break; + + //parse attribute name + SharedNode attribute(new ManagedNode); + attribute->_metadata = 1; + + const char* nameStart = p; + while(isName(*p)) p++; + const char* nameEnd = p; + copy(attribute->_name, nameStart, nameEnd - nameStart); + if(!attribute->_name) throw "missing attribute name"; + + //parse attribute data + if(*p++ != '=') throw "missing attribute value"; + char terminal = *p++; + if(terminal != '\'' && terminal != '\"') throw "attribute value not quoted"; + const char* dataStart = p; + while(*p && *p != terminal) p++; + if(!*p) throw "missing attribute data terminal"; + const char* dataEnd = p++; //skip closing terminal + + copy(attribute->_value, dataStart, dataEnd - dataStart); + _children.append(attribute); + } + + //parse closure + if(*p == '?' && *(p + 1) == '>') { p += 2; return true; } + if(*p == '/' && *(p + 1) == '>') { p += 2; return true; } + if(*p == '>') { p += 1; return false; } + throw "invalid element tag"; + } + + //parse element and all of its child elements + inline void parseElement(const char*& p) { + SharedNode node(new ManagedNode); + if(node->parseHead(p) == false) node->parse(p); + _children.append(node); + } + + //return true if matches this node's name + inline bool parseClosureElement(const char*& p) { + if(p[0] != '<' || p[1] != '/') return false; + p += 2; + const char* nameStart = p; + while(*p && *p != '>') p++; + if(*p != '>') throw "unclosed closure element"; + const char* nameEnd = p++; + if(memory::compare(_name.data(), nameStart, nameEnd - nameStart)) throw "closure element name mismatch"; + return true; + } + + //parse contents of an element + inline void parse(const char*& p) { + const char* dataStart = p; + const char* dataEnd = p; + + while(*p) { + while(*p && *p != '<') p++; + if(!*p) break; + dataEnd = p; + if(parseClosureElement(p) == true) break; + if(parseExpression(p) == true) continue; + parseElement(p); + } + + copy(_value, dataStart, dataEnd - dataStart); + } + + friend auto unserialize(const string&) -> Markup::SharedNode; +}; + +inline auto unserialize(const string& markup) -> Markup::SharedNode { + auto node = new ManagedNode; + try { + const char* p = markup; + node->parse(p); + } catch(const char* error) { + delete node; + node = nullptr; + } + return node; +} + +} diff --git a/nall/string/match.hpp b/nall/string/match.hpp new file mode 100755 index 0000000..c1f7969 --- /dev/null +++ b/nall/string/match.hpp @@ -0,0 +1,90 @@ +#pragma once + +namespace nall { + +//todo: these functions are not binary-safe + +auto string::match(string_view source) const -> bool { + const char* s = data(); + const char* p = source.data(); + + const char* cp = nullptr; + const char* mp = nullptr; + 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; +} + +auto string::imatch(string_view source) const -> bool { + static auto chrlower = [](char c) -> char { + return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; + }; + + const char* s = data(); + const char* p = source.data(); + + const char* cp = nullptr; + const char* mp = nullptr; + 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; +} + +auto tokenize(const char* s, const char* p) -> bool { + while(*s) { + if(*p == '*') { + while(*s) if(tokenize(s++, p + 1)) return true; + return !*++p; + } + if(*s++ != *p++) return false; + } + while(*p == '*') p++; + return !*p; +} + +auto tokenize(vector& list, const char* s, const char* p) -> bool { + while(*s) { + if(*p == '*') { + const char* b = s; + while(*s) { + if(tokenize(list, s++, p + 1)) { + list.prepend(slice(b, 0, --s - b)); + return true; + } + } + list.prepend(b); + return !*++p; + } + if(*s++ != *p++) return false; + } + while(*p == '*') { list.prepend(s); p++; } + return !*p; +} + +} diff --git a/nall/string/pascal.hpp b/nall/string/pascal.hpp new file mode 100644 index 0000000..cadfe76 --- /dev/null +++ b/nall/string/pascal.hpp @@ -0,0 +1,79 @@ +#pragma once + +namespace nall { + +struct string_pascal { + using type = string_pascal; + + string_pascal(const char* text = nullptr) { + if(text && *text) { + uint size = strlen(text); + _data = memory::allocate(sizeof(uint) + size + 1); + ((uint*)_data)[0] = size; + memory::copy(_data + sizeof(uint), text, size); + _data[sizeof(uint) + size] = 0; + } + } + + string_pascal(const string& text) { + if(text.size()) { + _data = memory::allocate(sizeof(uint) + text.size() + 1); + ((uint*)_data)[0] = text.size(); + memory::copy(_data + sizeof(uint), text.data(), text.size()); + _data[sizeof(uint) + text.size()] = 0; + } + } + + string_pascal(const string_pascal& source) { operator=(source); } + string_pascal(string_pascal&& source) { operator=(move(source)); } + + ~string_pascal() { + if(_data) memory::free(_data); + } + + explicit operator bool() const { return _data; } + operator const char*() const { return _data ? _data + sizeof(uint) : nullptr; } + operator string() const { return _data ? string{_data + sizeof(uint)} : ""; } + + auto operator=(const string_pascal& source) -> type& { + if(this == &source) return *this; + if(_data) { memory::free(_data); _data = nullptr; } + if(source._data) { + uint size = source.size(); + _data = memory::allocate(sizeof(uint) + size); + memory::copy(_data, source._data, sizeof(uint) + size); + } + return *this; + } + + auto operator=(string_pascal&& source) -> type& { + if(this == &source) return *this; + if(_data) memory::free(_data); + _data = source._data; + source._data = nullptr; + return *this; + } + + auto operator==(string_view source) const -> bool { + return size() == source.size() && memory::compare(data(), source.data(), size()) == 0; + } + + auto operator!=(string_view source) const -> bool { + return size() != source.size() || memory::compare(data(), source.data(), size()) != 0; + } + + auto data() const -> char* { + if(!_data) return nullptr; + return _data + sizeof(uint); + } + + auto size() const -> uint { + if(!_data) return 0; + return ((uint*)_data)[0]; + } + +protected: + char* _data = nullptr; +}; + +} diff --git a/nall/string/replace.hpp b/nall/string/replace.hpp new file mode 100755 index 0000000..d8143a1 --- /dev/null +++ b/nall/string/replace.hpp @@ -0,0 +1,94 @@ +#pragma once + +namespace nall { + +template +auto string::_replace(string_view from, string_view to, long limit) -> string& { + if(limit <= 0 || from.size() == 0) return *this; + + int size = this->size(); + int matches = 0; + int quoted = 0; + + //count matches first, so that we only need to reallocate memory once + //(recording matches would also require memory allocation, so this is not done) + { const char* p = data(); + for(int n = 0; n <= size - (int)from.size();) { + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } + if(_compare(p + n, size - n, from.data(), from.size())) { n++; continue; } + + if(++matches >= limit) break; + n += from.size(); + } + } + if(matches == 0) return *this; + + //in-place overwrite + if(to.size() == from.size()) { + char* p = get(); + + for(int n = 0, remaining = matches, quoted = 0; n <= size - (int)from.size();) { + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } + if(_compare(p + n, size - n, from.data(), from.size())) { n++; continue; } + + memory::copy(p + n, to.data(), to.size()); + + if(!--remaining) break; + n += from.size(); + } + } + + //left-to-right shrink + else if(to.size() < from.size()) { + char* p = get(); + int offset = 0; + int base = 0; + + for(int n = 0, remaining = matches, quoted = 0; n <= size - (int)from.size();) { + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } + if(_compare(p + n, size - n, from.data(), from.size())) { n++; continue; } + + if(offset) memory::move(p + offset, p + base, n - base); + memory::copy(p + offset + (n - base), to.data(), to.size()); + offset += (n - base) + to.size(); + + n += from.size(); + base = n; + if(!--remaining) break; + } + + memory::move(p + offset, p + base, size - base); + resize(size - matches * (from.size() - to.size())); + } + + //right-to-left expand + else if(to.size() > from.size()) { + resize(size + matches * (to.size() - from.size())); + char* p = get(); + + int offset = this->size(); + int base = size; + + for(int n = size, remaining = matches; n >= (int)from.size();) { //quoted reused from parent scope since we are iterating backward + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n--; continue; } if(quoted) { n--; continue; } } + if(_compare(p + n - from.size(), size - n + from.size(), from.data(), from.size())) { n--; continue; } + + memory::move(p + offset - (base - n), p + base - (base - n), base - n); + memory::copy(p + offset - (base - n) - to.size(), to.data(), to.size()); + offset -= (base - n) + to.size(); + + if(!--remaining) break; + n -= from.size(); + base = n; + } + } + + return *this; +} + +auto string::replace(string_view from, string_view to, long limit) -> string& { return _replace<0, 0>(from, to, limit); } +auto string::ireplace(string_view from, string_view to, long limit) -> string& { return _replace<1, 0>(from, to, limit); } +auto string::qreplace(string_view from, string_view to, long limit) -> string& { return _replace<0, 1>(from, to, limit); } +auto string::iqreplace(string_view from, string_view to, long limit) -> string& { return _replace<1, 1>(from, to, limit); } + +}; diff --git a/nall/string/split.hpp b/nall/string/split.hpp new file mode 100755 index 0000000..0ceba68 --- /dev/null +++ b/nall/string/split.hpp @@ -0,0 +1,41 @@ +#pragma once + +namespace nall { + +template +auto vector::_split(string_view source, string_view find, long limit) -> type& { + reset(); + if(limit <= 0 || find.size() == 0) return *this; + + const char* p = source.data(); + int size = source.size(); + int base = 0; + int matches = 0; + + for(int n = 0, quoted = 0; n <= size - (int)find.size();) { + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } + if(string::_compare(p + n, size - n, find.data(), find.size())) { n++; continue; } + if(matches >= limit) break; + + string& s = operator()(matches); + s.resize(n - base); + memory::copy(s.get(), p + base, n - base); + + n += find.size(); + base = n; + matches++; + } + + string& s = operator()(matches); + s.resize(size - base); + memory::copy(s.get(), p + base, size - base); + + return *this; +} + +auto string::split(string_view on, long limit) const -> vector { return vector()._split<0, 0>(*this, on, limit); } +auto string::isplit(string_view on, long limit) const -> vector { return vector()._split<1, 0>(*this, on, limit); } +auto string::qsplit(string_view on, long limit) const -> vector { return vector()._split<0, 1>(*this, on, limit); } +auto string::iqsplit(string_view on, long limit) const -> vector { return vector()._split<1, 1>(*this, on, limit); } + +} diff --git a/nall/string/transform/cml.hpp b/nall/string/transform/cml.hpp new file mode 100755 index 0000000..1e3cf80 --- /dev/null +++ b/nall/string/transform/cml.hpp @@ -0,0 +1,120 @@ +#pragma once + +/* CSS Markup Language (CML) v1.0 parser + * revision 0.02 + */ + +#include + +namespace nall { + +struct CML { + auto& setPath(const string& pathname) { settings.path = pathname; return *this; } + auto& setReader(const function& reader) { settings.reader = reader; return *this; } + + auto parse(const string& filename) -> string; + auto parse(const string& filedata, const string& pathname) -> string; + +private: + struct Settings { + string path; + function reader; + } settings; + + struct State { + string output; + } state; + + struct Variable { + string name; + string value; + }; + vector variables; + bool inMedia = false; + bool inMediaNode = false; + + auto parseDocument(const string& filedata, const string& pathname, uint depth) -> bool; +}; + +inline auto CML::parse(const string& filename) -> string { + if(!settings.path) settings.path = Location::path(filename); + string document = settings.reader ? settings.reader(filename) : string::read(filename); + parseDocument(document, settings.path, 0); + return state.output; +} + +inline auto CML::parse(const string& filedata, const string& pathname) -> string { + settings.path = pathname; + parseDocument(filedata, settings.path, 0); + return state.output; +} + +inline auto CML::parseDocument(const string& filedata, const string& pathname, uint depth) -> bool { + if(depth >= 100) return false; //prevent infinite recursion + + auto vendorAppend = [&](const string& name, const string& value) { + state.output.append(" -moz-", name, ": ", value, ";\n"); + state.output.append(" -webkit-", name, ": ", value, ";\n"); + }; + + for(auto& block : filedata.split("\n\n")) { + auto lines = block.stripRight().split("\n"); + auto name = lines.takeFirst(); + + if(name.beginsWith("include ")) { + name.trimLeft("include ", 1L); + string filename{pathname, name}; + string document = settings.reader ? settings.reader(filename) : string::read(filename); + parseDocument(document, Location::path(filename), depth + 1); + continue; + } + + if(name == "variables") { + for(auto& line : lines) { + auto data = line.split(":", 1L).strip(); + variables.append({data(0), data(1)}); + } + continue; + } + + state.output.append(name, " {\n"); + inMedia = name.beginsWith("@media"); + + for(auto& line : lines) { + if(inMedia && !line.find(": ")) { + if(inMediaNode) state.output.append(" }\n"); + state.output.append(line, " {\n"); + inMediaNode = true; + continue; + } + + auto data = line.split(":", 1L).strip(); + auto name = data(0), value = data(1); + while(auto offset = value.find("var(")) { + bool found = false; + if(auto length = value.findFrom(*offset, ")")) { + string name = slice(value, *offset + 4, *length - 4); + for(auto& variable : variables) { + if(variable.name == name) { + value = {slice(value, 0, *offset), variable.value, slice(value, *offset + *length + 1)}; + found = true; + break; + } + } + } + if(!found) break; + } + state.output.append(inMedia ? " " : " ", name, ": ", value, ";\n"); + if(name == "box-sizing") vendorAppend(name, value); + } + if(inMediaNode) { + state.output.append(" }\n"); + inMediaNode = false; + } + state.output.append("}\n\n"); + } + + return true; +} + +} diff --git a/nall/string/transform/dml.hpp b/nall/string/transform/dml.hpp new file mode 100755 index 0000000..d506135 --- /dev/null +++ b/nall/string/transform/dml.hpp @@ -0,0 +1,346 @@ +#pragma once + +/* Document Markup Language (DML) v1.0 parser + * revision 0.05 + */ + +#include + +namespace nall { + +struct DML { + auto content() const -> string { return state.output; } + + auto& setAllowHTML(bool allowHTML) { settings.allowHTML = allowHTML; return *this; } + auto& setHost(const string& hostname) { settings.host = hostname; return *this; } + auto& setPath(const string& pathname) { settings.path = pathname; return *this; } + auto& setReader(const function& reader) { settings.reader = reader; return *this; } + + auto parse(const string& filedata, const string& pathname) -> string; + auto parse(const string& filename) -> string; + + auto attribute(const string& name) const -> string; + +private: + struct Settings { + bool allowHTML = true; + string host = "localhost"; + string path; + function reader; + } settings; + + struct State { + string output; + } state; + + struct Attribute { + string name; + string value; + }; + vector attributes; + + auto parseDocument(const string& filedata, const string& pathname, uint depth) -> bool; + auto parseBlock(string& block, const string& pathname, uint depth) -> bool; + auto count(const string& text, char value) -> uint; + + auto address(string text) -> string; + auto escape(const string& text) -> string; + auto markup(const string& text) -> string; +}; + +inline auto DML::attribute(const string& name) const -> string { + for(auto& attribute : attributes) { + if(attribute.name == name) return attribute.value; + } + return {}; +} + +inline auto DML::parse(const string& filedata, const string& pathname) -> string { + state = {}; + settings.path = pathname; + parseDocument(filedata, settings.path, 0); + return state.output; +} + +inline auto DML::parse(const string& filename) -> string { + state = {}; + if(!settings.path) settings.path = Location::path(filename); + string document = settings.reader ? settings.reader(filename) : string::read(filename); + parseDocument(document, settings.path, 0); + return state.output; +} + +inline auto DML::parseDocument(const string& filedata, const string& pathname, uint depth) -> bool { + if(depth >= 100) return false; //attempt to prevent infinite recursion with reasonable limit + + auto blocks = filedata.split("\n\n"); + for(auto& block : blocks) parseBlock(block, pathname, depth); + return true; +} + +inline auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool { + if(!block.stripRight()) return true; + auto lines = block.split("\n"); + + //include + if(block.beginsWith("")) { + string filename{pathname, block.trim("", 1L).strip()}; + string document = settings.reader ? settings.reader(filename) : string::read(filename); + parseDocument(document, Location::path(filename), depth + 1); + } + + //attribute + else if(block.beginsWith("? ")) { + for(auto n : range(lines.size())) { + if(!lines[n].beginsWith("? ")) continue; + auto part = lines[n].trimLeft("? ", 1L).split(":", 1L); + if(part.size() != 2) continue; + auto name = part[0].strip(); + auto value = part[1].strip(); + attributes.append({name, value}); + } + } + + //html + else if(block.beginsWith("\n") && settings.allowHTML) { + for(auto n : range(lines.size())) { + if(n == 0 || !lines[n].beginsWith(" ")) continue; + state.output.append(lines[n].trimLeft(" ", 1L), "\n"); + } + } + + //header + else if(auto depth = count(block, '#')) { + auto content = slice(lines.takeLeft(), depth + 1).split("::", 1L).strip(); + auto data = markup(content[0]); + auto name = escape(content(1, data.hash())); + if(depth <= 5) { + state.output.append("", data); + for(auto& line : lines) { + if(count(line, '#') != depth) continue; + state.output.append("", slice(line, depth + 1), ""); + } + state.output.append("\n"); + } + } + + //navigation + else if(count(block, '-')) { + state.output.append("

    \n"); + } + + //list + else if(count(block, '*')) { + uint level = 0; + for(auto& line : lines) { + if(auto depth = count(line, '*')) { + while(level < depth) level++, state.output.append("
      \n"); + while(level > depth) level--, state.output.append("
    \n"); + auto data = markup(slice(line, depth + 1)); + state.output.append("
  • ", data, "
  • \n"); + } + } + while(level--) state.output.append("\n"); + } + + //quote + else if(count(block, '>')) { + uint level = 0; + for(auto& line : lines) { + if(auto depth = count(line, '>')) { + while(level < depth) level++, state.output.append("
    \n"); + while(level > depth) level--, state.output.append("
    \n"); + auto data = markup(slice(line, depth + 1)); + state.output.append(data, "\n"); + } + } + while(level--) state.output.append("\n"); + } + + //code + else if(block.beginsWith(" ")) { + state.output.append("
    ");
    +    for(auto& line : lines) {
    +      if(!line.beginsWith("  ")) continue;
    +      state.output.append(escape(line.trimLeft("  ", 1L)), "\n");
    +    }
    +    state.output.trimRight("\n", 1L).append("
    \n"); + } + + //divider + else if(block.equals("---")) { + state.output.append("
    \n"); + } + + //paragraph + else { + auto content = markup(block); + if(content.beginsWith("")) { + state.output.append(content, "\n"); + } else { + state.output.append("

    ", content, "

    \n"); + } + } + + return true; +} + +inline auto DML::count(const string& text, char value) -> uint { + for(uint n = 0; n < text.size(); n++) { + if(text[n] != value) { + if(text[n] == ' ') return n; + break; + } + } + return 0; +} + +// . => domain +// ./* => domain/* +// ../subdomain => subdomain.domain +// ../subdomain/* => subdomain.domain/* +inline auto DML::address(string s) -> string { + if(s.beginsWith("../")) { + s.trimLeft("../", 1L); + if(auto p = s.find("/")) { + return {"//", s.slice(0, *p), ".", settings.host, s.slice(*p)}; + } else { + return {"//", s, ".", settings.host}; + } + } + if(s.beginsWith("./")) { + s.trimLeft(".", 1L); + return {"//", settings.host, s}; + } + if(s == ".") { + return {"//", settings.host}; + } + return s; +} + +inline auto DML::escape(const string& text) -> string { + string output; + for(auto c : text) { + if(c == '&') { output.append("&"); continue; } + if(c == '<') { output.append("<"); continue; } + if(c == '>') { output.append(">"); continue; } + if(c == '"') { output.append("""); continue; } + output.append(c); + } + return output; +} + +inline auto DML::markup(const string& s) -> string { + string t; + + boolean strong; + boolean emphasis; + boolean insertion; + boolean deletion; + boolean code; + + maybe link; + maybe image; + + for(uint n = 0; n < s.size();) { + char a = s[n]; + char b = s[n + 1]; + + if(!link && !image) { + if(a == '*' && b == '*') { t.append(strong.flip() ? "" : ""); n += 2; continue; } + if(a == '/' && b == '/') { t.append(emphasis.flip() ? "" : ""); n += 2; continue; } + if(a == '_' && b == '_') { t.append(insertion.flip() ? "" : ""); n += 2; continue; } + if(a == '~' && b == '~') { t.append(deletion.flip() ? "" : ""); n += 2; continue; } + if(a == '|' && b == '|') { t.append(code.flip() ? "" : ""); n += 2; continue; } + if(a =='\\' && b =='\\') { t.append("
    "); n += 2; continue; } + + if(a == '[' && b == '[') { n += 2; link = n; continue; } + if(a == '{' && b == '{') { n += 2; image = n; continue; } + } + + if(link && !image && a == ']' && b == ']') { + auto list = slice(s, link(), n - link()).split("::", 1L); + string uri = address(list.last()); + string name = list.size() == 2 ? list.first() : uri.split("//", 1L).last(); + + t.append("", escape(name), ""); + + n += 2; + link = nothing; + continue; + } + + if(image && !link && a == '}' && b == '}') { + auto side = slice(s, image(), n - image()).split("}{", 1L); + auto list = side(0).split("::", 1L); + string uri = address(list.last()); + string name = list.size() == 2 ? list.first() : uri.split("//", 1L).last(); + list = side(1).split("; "); + boolean link, title, caption; + string width, height; + for(auto p : list) { + if(p == "link") { link = true; continue; } + if(p == "title") { title = true; continue; } + if(p == "caption") { caption = true; continue; } + if(p.beginsWith("width:")) { p.trimLeft("width:", 1L); width = p.strip(); continue; } + if(p.beginsWith("height:")) { p.trimLeft("height:", 1L); height = p.strip(); continue; } + } + + if(caption) { + t.append("
    \n"); + if(link) t.append(""); + t.append("\"",\n"); + if(link) t.append("\n"); + t.append("
    ", escape(name), "
    \n"); + t.append("
    "); + } else { + if(link) t.append(""); + t.append("\"","); + if(link) t.append(""); + } + + n += 2; + image = nothing; + continue; + } + + if(link || image) { n++; continue; } + if(a =='\\') { t.append(b); n += 2; continue; } + if(a == '&') { t.append("&"); n++; continue; } + if(a == '<') { t.append("<"); n++; continue; } + if(a == '>') { t.append(">"); n++; continue; } + if(a == '"') { t.append("""); n++; continue; } + t.append(a); n++; continue; + } + + if(strong) t.append(""); + if(emphasis) t.append(""); + if(insertion) t.append(""); + if(deletion) t.append(""); + if(code) t.append("
    "); + + return t; +} + +} diff --git a/nall/string/trim.hpp b/nall/string/trim.hpp new file mode 100755 index 0000000..17823a7 --- /dev/null +++ b/nall/string/trim.hpp @@ -0,0 +1,102 @@ +#pragma once + +namespace nall { + +auto string::trim(string_view lhs, string_view rhs, long limit) -> string& { + trimRight(rhs, limit); + trimLeft(lhs, limit); + return *this; +} + +auto string::trimLeft(string_view lhs, long limit) -> string& { + if(lhs.size() == 0) return *this; + long matches = 0; + while(matches < limit) { + int offset = lhs.size() * matches; + int length = (int)size() - offset; + if(length < (int)lhs.size()) break; + if(memory::compare(data() + offset, lhs.data(), lhs.size()) != 0) break; + matches++; + } + if(matches) remove(0, lhs.size() * matches); + return *this; +} + +auto string::trimRight(string_view rhs, long limit) -> string& { + if(rhs.size() == 0) return *this; + long matches = 0; + while(matches < limit) { + int offset = (int)size() - rhs.size() * (matches + 1); + int length = (int)size() - offset; + if(offset < 0 || length < (int)rhs.size()) break; + if(memory::compare(data() + offset, rhs.data(), rhs.size()) != 0) break; + matches++; + } + if(matches) resize(size() - rhs.size() * matches); + return *this; +} + +auto string::itrim(string_view lhs, string_view rhs, long limit) -> string& { + itrimRight(rhs, limit); + itrimLeft(lhs, limit); + return *this; +} + +auto string::itrimLeft(string_view lhs, long limit) -> string& { + if(lhs.size() == 0) return *this; + long matches = 0; + while(matches < limit) { + int offset = lhs.size() * matches; + int length = (int)size() - offset; + if(length < (int)lhs.size()) break; + if(memory::icompare(data() + offset, lhs.data(), lhs.size()) != 0) break; + matches++; + } + if(matches) remove(0, lhs.size() * matches); + return *this; +} + +auto string::itrimRight(string_view rhs, long limit) -> string& { + if(rhs.size() == 0) return *this; + long matches = 0; + while(matches < limit) { + int offset = (int)size() - rhs.size() * (matches + 1); + int length = (int)size() - offset; + if(offset < 0 || length < (int)rhs.size()) break; + if(memory::icompare(data() + offset, rhs.data(), rhs.size()) != 0) break; + matches++; + } + if(matches) resize(size() - rhs.size() * matches); + return *this; +} + +auto string::strip() -> string& { + stripRight(); + stripLeft(); + return *this; +} + +auto string::stripLeft() -> string& { + uint length = 0; + while(length < size()) { + char input = operator[](length); + if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break; + length++; + } + if(length) remove(0, length); + return *this; +} + +auto string::stripRight() -> string& { + uint length = 0; + while(length < size()) { + bool matched = false; + char input = operator[](size() - length - 1); + if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break; + length++; + } + if(length) resize(size() - length); + return *this; +} + +} diff --git a/nall/string/utf8.hpp b/nall/string/utf8.hpp new file mode 100644 index 0000000..5b04bec --- /dev/null +++ b/nall/string/utf8.hpp @@ -0,0 +1,32 @@ +#pragma once + +namespace nall { + +//note: this function assumes the string contains valid UTF-8 characters +//invalid characters will result in an incorrect result from this function +//invalid case 1: byte 1 == 0b'01xxxxxx +//invalid case 2: bytes 2-4 != 0b'10xxxxxx +//invalid case 3: end of string without bytes 2-4 present +auto characters(string_view self, int offset, int length) -> uint { + uint characters = 0; + if(offset < 0) offset = self.size() - abs(offset); + if(offset >= 0 && offset < self.size()) { + if(length < 0) length = self.size() - offset; + if(length >= 0) { + for(int index = offset; index < offset + length;) { + auto byte = self.data()[index++]; + if((byte & 0b111'00000) == 0b110'00000) index += 1; + if((byte & 0b1111'0000) == 0b1110'0000) index += 2; + if((byte & 0b11111'000) == 0b11110'000) index += 3; + characters++; + } + } + } + return characters; +} + +auto string::characters(int offset, int length) const -> uint { + return nall::characters(*this, offset, length); +} + +} diff --git a/nall/string/utility.hpp b/nall/string/utility.hpp new file mode 100755 index 0000000..4f11fd5 --- /dev/null +++ b/nall/string/utility.hpp @@ -0,0 +1,165 @@ +#pragma once + +namespace nall { + +auto string::read(string_view filename) -> string { + #if !defined(_WIN32) + FILE* fp = fopen(filename, "rb"); + #else + FILE* fp = _wfopen(utf16_t(filename), L"rb"); + #endif + + string result; + if(!fp) return result; + + fseek(fp, 0, SEEK_END); + int filesize = ftell(fp); + if(filesize < 0) return fclose(fp), result; + + rewind(fp); + result.resize(filesize); + (void)fread(result.get(), 1, filesize, fp); + return fclose(fp), result; +} + +auto string::repeat(string_view pattern, uint times) -> string { + string result; + while(times--) result.append(pattern.data()); + return result; +} + +auto string::fill(char fill) -> string& { + memory::fill(get(), size(), fill); + return *this; +} + +auto string::hash() const -> uint { + const char* p = data(); + uint length = size(); + uint result = 5381; + while(length--) result = (result << 5) + result + *p++; + return result; +} + +auto string::remove(uint offset, uint length) -> string& { + char* p = get(); + length = min(length, size()); + memory::move(p + offset, p + offset + length, size() - length); + return resize(size() - length); +} + +auto string::reverse() -> string& { + char* p = get(); + uint length = size(); + uint pivot = length >> 1; + for(int x = 0, y = length - 1; x < pivot && y >= 0; x++, y--) std::swap(p[x], p[y]); + return *this; +} + +//+length => insert/delete from start (right justify) +//-length => insert/delete from end (left justify) +auto string::size(int length, char fill) -> string& { + uint size = this->size(); + if(size == length) return *this; + + bool right = length >= 0; + length = abs(length); + + if(size < length) { //expand + resize(length); + char* p = get(); + uint displacement = length - size; + if(right) memory::move(p + displacement, p, size); + else p += size; + while(displacement--) *p++ = fill; + } else { //shrink + char* p = get(); + uint displacement = size - length; + if(right) memory::move(p, p + displacement, length); + resize(length); + } + + return *this; +} + +auto slice(string_view self, int offset, int length) -> string { + string result; + if(offset < 0) offset = self.size() - abs(offset); + if(offset >= 0 && offset < self.size()) { + if(length < 0) length = self.size() - offset; + if(length >= 0) { + result.resize(length); + memory::copy(result.get(), self.data() + offset, length); + } + } + return result; +} + +auto string::slice(int offset, int length) const -> string { + return nall::slice(*this, offset, length); +} + +template auto fromInteger(char* result, T value) -> char* { + bool negative = value < 0; + if(!negative) value = -value; //negate positive integers to support eg INT_MIN + + char buffer[1 + sizeof(T) * 3]; + uint size = 0; + + do { + int n = value % 10; //-0 to -9 + buffer[size++] = '0' - n; //'0' to '9' + value /= 10; + } while(value); + if(negative) buffer[size++] = '-'; + + for(int x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y]; + result[size] = 0; + return result; +} + +template auto fromNatural(char* result, T value) -> char* { + char buffer[1 + sizeof(T) * 3]; + uint size = 0; + + do { + uint n = value % 10; + buffer[size++] = '0' + n; + value /= 10; + } while(value); + + for(int x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y]; + result[size] = 0; + return 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. +template auto fromReal(char* result, T value) -> uint { + char buffer[256]; + #ifdef _WIN32 + //Windows C-runtime does not support long double via sprintf() + sprintf(buffer, "%f", (double)value); + #else + sprintf(buffer, "%Lf", (long double)value); + #endif + + //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; + } + } + + uint length = strlen(buffer); + if(result) strcpy(result, buffer); + return length + 1; +} + +} diff --git a/nall/string/vector.hpp b/nall/string/vector.hpp new file mode 100755 index 0000000..31f2063 --- /dev/null +++ b/nall/string/vector.hpp @@ -0,0 +1,60 @@ +#pragma once + +namespace nall { + +template auto vector::append(const string& data, P&&... p) -> type& { + vector_base::append(data); + append(forward

    (p)...); + return *this; +} + +auto vector::append() -> type& { + return *this; +} + +auto vector::isort() -> type& { + sort([](const string& x, const string& y) { + return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0; + }); + return *this; +} + +auto vector::find(string_view source) const -> maybe { + for(uint n = 0; n < size(); n++) { + if(operator[](n).equals(source)) return n; + } + return {}; +} + +auto vector::ifind(string_view source) const -> maybe { + for(uint n = 0; n < size(); n++) { + if(operator[](n).iequals(source)) return n; + } + return {}; +} + +auto vector::match(string_view pattern) const -> vector { + vector result; + for(uint n = 0; n < size(); n++) { + if(operator[](n).match(pattern)) result.append(operator[](n)); + } + return result; +} + +auto vector::merge(string_view separator) const -> string { + string output; + for(uint n = 0; n < size(); n++) { + output.append(operator[](n)); + if(n < size() - 1) output.append(separator.data()); + } + return output; +} + +auto vector::strip() -> type& { + for(uint n = 0; n < size(); n++) { + operator[](n).strip(); + } + return *this; +} + +} diff --git a/nall/string/view.hpp b/nall/string/view.hpp new file mode 100755 index 0000000..fe56b9a --- /dev/null +++ b/nall/string/view.hpp @@ -0,0 +1,89 @@ +#pragma once + +namespace nall { + +string_view::string_view() { + _string = nullptr; + _data = ""; + _size = 0; +} + +string_view::string_view(const string_view& source) { + if(this == &source) return; + _string = nullptr; + _data = source._data; + _size = source._size; +} + +string_view::string_view(string_view&& source) { + if(this == &source) return; + _string = source._string; + _data = source._data; + _size = source._size; + source._string = nullptr; +} + +string_view::string_view(const char* data) { + _string = nullptr; + _data = data; + _size = -1; //defer length calculation, as it is often unnecessary +} + +string_view::string_view(const char* data, uint size) { + _string = nullptr; + _data = data; + _size = size; +} + +string_view::string_view(const string& source) { + _string = nullptr; + _data = source.data(); + _size = source.size(); +} + +template +string_view::string_view(P&&... p) { + _string = new string{forward

    (p)...}; + _data = _string->data(); + _size = _string->size(); +} + +string_view::~string_view() { + if(_string) delete _string; +} + +auto string_view::operator=(const string_view& source) -> type& { + if(this == &source) return *this; + _string = nullptr; + _data = source._data; + _size = source._size; + return *this; +}; + +auto string_view::operator=(string_view&& source) -> type& { + if(this == &source) return *this; + _string = source._string; + _data = source._data; + _size = source._size; + source._string = nullptr; + return *this; +}; + +string_view::operator bool() const { + return _size > 0; +} + +string_view::operator const char*() const { + return _data; +} + +auto string_view::data() const -> const char* { + return _data; +} + +auto string_view::size() const -> uint { + if(_size < 0) _size = strlen(_data); + return _size; +} + +} diff --git a/nall/suffix-array.hpp b/nall/suffix-array.hpp new file mode 100644 index 0000000..4cc33ea --- /dev/null +++ b/nall/suffix-array.hpp @@ -0,0 +1,386 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace nall { + +/* + +input: + data = "acaacatat" + 0 "acaacatat" + 1 "caacatat" + 2 "aacatat" + 3 "acatat" + 4 "catat" + 5 "atat" + 6 "tat" + 7 "at" + 8 "t" + 9 "" + +suffix_array: + suffixes = [9,2,0,3,7,5,1,4,8,6] => input + suffixes: + 9 "" + 2 "aacatat" + 0 "acaacatat" + 3 "acatat" + 7 "at" + 5 "atat" + 1 "caacatat" + 4 "catat" + 8 "t" + 6 "tat" + +[auxiliary data structures to represent information lost from suffix trees] + +suffix_array_invert: + inverted = [2,6,1,3,7,5,9,4,8,0] => input + suffixes[inverted]: + 2 "acaacatat" + 6 "caacatat" + 1 "aacatat" + 3 "acatat" + 7 "catat" + 5 "atat" + 9 "tat" + 4 "at" + 8 "t" + 0 "" + +suffix_array_phi: + phi = [2,5,9,0,1,7,8,3,4,0] + +suffix_array_lcp: + prefixes = [0,0,1,3,1,2,0,2,0,1] => lcp[n] == lcp(n, n-1) + "" 0 + "aacatat" 0 + "acaacatat" 1 "a" + "acatat" 3 "aca" + "at" 1 "a" + "atat" 2 "at" + "caacatat" 0 + "catat" 2 "ca" + "t" 0 + "tat" 1 "t" + +suffix_array_plcp: + plcp = [1,0,0,3,2,2,1,1,0,0] + +suffix_array_lrcp: + llcp = [0,0,0,3,0,2,0,2,0,0] => llcp[m] == lcp(l, m) + rlcp = [0,1,1,1,0,0,0,0,0,0] => rlcp[m] == lcp(m, r) + +suffix_array_lpf: + lengths = [0,0,1,3,2,1,0,2,1,0] + offsets = [0,0,0,0,1,3,4,5,6,2] + "acaacatat" (0,-) + "caacatat" (0,-) + "aacatat" (1,0) at 0, match "a" + "acatat" (3,0) at 0, match "aca" + "catat" (2,1) at 1, match "ca" + "atat" (1,3) at 3, match "a" + "tat" (0,-) + "at" (2,5) at 5, match "at" + "t" (1,6) at 6, match "t" + "" (0,-) + +*/ + +// suffix array via induced sorting +// O(n) +inline auto suffix_array(array_view input) -> vector { + return induced_sort(input); +} + +// inverse +// O(n) +inline auto suffix_array_invert(array_view sa) -> vector { + vector isa; + isa.reallocate(sa.size()); + for(int i : range(sa.size())) isa[sa[i]] = i; + return isa; +} + +// auxiliary data structure for plcp and lpf computation +// O(n) +inline auto suffix_array_phi(array_view sa) -> vector { + vector phi; + phi.reallocate(sa.size()); + phi[sa[0]] = 0; + for(int i : range(1, sa.size())) phi[sa[i]] = sa[i - 1]; + return phi; +} + +// longest common prefix: lcp(l, r) +// O(n) +inline auto suffix_array_lcp(int l, int r, array_view sa, array_view input) -> int { + int i = sa[l], j = sa[r], k = 0, size = input.size(); + while(i + k < size && j + k < size && input[i + k] == input[j + k]) k++; + return k; +} + +// longest common prefix: lcp(i, j, k) +// O(n) +inline auto suffix_array_lcp(int i, int j, int k, array_view input) -> int { + int size = input.size(); + while(i + k < size && j + k < size && input[i + k] == input[j + k]) k++; + return k; +} + +// longest common prefix: lcp[n] == lcp(n, n-1) +// O(n) +inline auto suffix_array_lcp(array_view sa, array_view isa, array_view input) -> vector { + int k = 0, size = input.size(); + vector lcp; + lcp.reallocate(size + 1); + for(int i : range(size)) { + if(isa[i] == size) { k = 0; continue; } //the next substring is empty; ignore it + int j = sa[isa[i] + 1]; + while(i + k < size && j + k < size && input[i + k] == input[j + k]) k++; + lcp[1 + isa[i]] = k; + if(k) k--; + } + lcp[0] = 0; + return lcp; +} + +// longest common prefix (from permuted longest common prefix) +// O(n) +inline auto suffix_array_lcp(array_view plcp, array_view sa) -> vector { + vector lcp; + lcp.reallocate(plcp.size()); + for(int i : range(plcp.size())) lcp[i] = plcp[sa[i]]; + return lcp; +} + +// permuted longest common prefix +// O(n) +inline auto suffix_array_plcp(array_view phi, array_view input) -> vector { + vector plcp; + plcp.reallocate(phi.size()); + int k = 0, size = input.size(); + for(int i : range(size)) { + int j = phi[i]; + while(i + k < size && j + k < size && input[i + k] == input[j + k]) k++; + plcp[i] = k; + if(k) k--; + } + return plcp; +} + +// permuted longest common prefix (from longest common prefix) +// O(n) +inline auto suffix_array_plcp(array_view lcp, array_view sa) -> vector { + vector plcp; + plcp.reallocate(lcp.size()); + for(int i : range(lcp.size())) plcp[sa[i]] = lcp[i]; + return plcp; +} + +// longest common prefixes - left + right +// llcp[m] == lcp(l, m) +// rlcp[m] == lcp(m, r) +// O(n) +// requires: lcp -or- plcp+sa +inline auto suffix_array_lrcp(vector& llcp, vector& rlcp, array_view lcp, array_view plcp, array_view sa, array_view input) -> void { + int size = input.size(); + llcp.reset(), llcp.reallocate(size + 1); + rlcp.reset(), rlcp.reallocate(size + 1); + + function recurse = [&](int l, int r) -> int { + if(l >= r - 1) { + if(l >= size) return 0; + if(lcp) return lcp[l]; + return plcp[sa[l]]; + } + int m = l + r >> 1; + llcp[m - 1] = recurse(l, m); + rlcp[m - 1] = recurse(m, r); + return min(llcp[m - 1], rlcp[m - 1]); + }; + recurse(1, size + 1); + + llcp[0] = 0; + rlcp[0] = 0; +} + +// longest previous factor +// O(n) +// optional: plcp +inline auto suffix_array_lpf(vector& lengths, vector& offsets, array_view phi, array_view plcp, array_view input) -> void { + int k = 0, size = input.size(); + lengths.reset(), lengths.resize(size + 1, -1); + offsets.reset(), offsets.resize(size + 1, -1); + + function recurse = [&](int i, int j, int k) -> void { + if(lengths[i] < 0) { + lengths[i] = k; + offsets[i] = j; + } else if(lengths[i] < k) { + if(offsets[i] > j) { + recurse(offsets[i], j, lengths[i]); + } else { + recurse(j, offsets[i], lengths[i]); + } + lengths[i] = k; + offsets[i] = j; + } else { + if(offsets[i] > j) { + recurse(offsets[i], j, k); + } else { + recurse(j, offsets[i], k); + } + } + }; + + for(int i : range(size)) { + int j = phi[i]; + if(plcp) k = plcp[i]; + else while(i + k < size && j + k < size && input[i + k] == input[j + k]) k++; + if(i > j) { + recurse(i, j, k); + } else { + recurse(j, i, k); + } + if(k) k--; + } + + lengths[0] = 0; + offsets[0] = 0; +} + +// O(n log m) +inline auto suffix_array_find(int& length, int& offset, array_view sa, array_view input, array_view match) -> bool { + length = 0, offset = 0; + int l = 0, r = input.size(); + + while(l < r - 1) { + int m = l + r >> 1; + int s = sa[m]; + + int k = 0; + while(k < match.size() && s + k < input.size()) { + if(match[k] != input[s + k]) break; + k++; + } + + if(k > length) { + length = k; + offset = s; + if(k == match.size()) return true; + } + + if(k == match.size() || s + k == input.size()) k--; + + if(match[k] < input[s + k]) { + r = m; + } else { + l = m; + } + } + + return false; +} + +// O(n + log m) +inline auto suffix_array_find(int& length, int& offset, array_view llcp, array_view rlcp, array_view sa, array_view input, array_view match) -> bool { + length = 0, offset = 0; + int l = 0, r = input.size(), k = 0; + + while(l < r - 1) { + int m = l + r >> 1; + int s = sa[m]; + + while(k < match.size() && s + k < input.size()) { + if(match[k] != input[s + k]) break; + k++; + } + + if(k > length) { + length = k; + offset = s; + if(k == match.size()) return true; + } + + if(k == match.size() || s + k == input.size()) k--; + + if(match[k] < input[s + k]) { + r = m; + k = min(k, llcp[m]); + } else { + l = m; + k = min(k, rlcp[m]); + } + } + + return false; +} + +// + +//there are multiple strategies for building the required auxiliary structures for suffix arrays + +struct SuffixArray { + using type = SuffixArray; + + //O(n) + inline SuffixArray(array_view input) : input(input) { + sa = suffix_array(input); + } + + //O(n) + inline auto lrcp() -> type& { + //if(!isa) isa = suffix_array_invert(sa); + //if(!lcp) lcp = suffix_array_lcp(sa, isa, input); + if(!phi) phi = suffix_array_phi(sa); + if(!plcp) plcp = suffix_array_plcp(phi, input); + //if(!lcp) lcp = suffix_array_lcp(plcp, sa); + if(!llcp || !rlcp) suffix_array_lrcp(llcp, rlcp, lcp, plcp, sa, input); + return *this; + } + + //O(n) + inline auto lpf() -> type& { + if(!phi) phi = suffix_array_phi(sa); + //if(!plcp) plcp = suffix_array_plcp(phi, input); + if(!lengths || !offsets) suffix_array_lpf(lengths, offsets, phi, plcp, input); + return *this; + } + + inline auto operator[](int offset) const -> int { + return sa[offset]; + } + + //O(n log m) + //O(n + log m) with lrcp() + inline auto find(int& length, int& offset, array_view match) -> bool { + if(!llcp || !rlcp) return suffix_array_find(length, offset, sa, input, match); //O(n log m) + return suffix_array_find(length, offset, llcp, rlcp, sa, input, match); //O(n + log m) + } + + //O(n) with lpf() + inline auto previous(int& length, int& offset, int address) -> void { + length = lengths[address]; + offset = offsets[address]; + } + + //non-owning reference: SuffixArray is invalidated if memory is freed + array_view input; + + //suffix array and auxiliary data structures + vector sa; //suffix array + vector isa; //inverted suffix array + vector phi; //phi + vector plcp; //permuted longest common prefixes + vector lcp; //longest common prefixes + vector llcp; //longest common prefixes - left + vector rlcp; //longest common prefixes - right + vector lengths; //longest previous factors + vector offsets; //longest previous factors +}; + +} diff --git a/nall/terminal.hpp b/nall/terminal.hpp new file mode 100644 index 0000000..9004163 --- /dev/null +++ b/nall/terminal.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include + +namespace nall::terminal { + +inline auto escapable() -> bool { + #if defined(PLATFORM_WINDOWS) + //todo: colors are supported by Windows 10+ and with alternate terminals (eg msys) + //disabled for now for compatibility with Windows 7 and 8.1's cmd.exe + return false; + #endif + return true; +} + +namespace color { + +template inline auto black(P&&... p) -> string { + if(!escapable()) return string{forward

    (p)...}; + return {"\e[30m", string{forward

    (p)...}, "\e[0m"}; +} + +template inline auto blue(P&&... p) -> string { + if(!escapable()) return string{forward

    (p)...}; + return {"\e[94m", string{forward

    (p)...}, "\e[0m"}; +} + +template inline auto green(P&&... p) -> string { + if(!escapable()) return string{forward

    (p)...}; + return {"\e[92m", string{forward

    (p)...}, "\e[0m"}; +} + +template inline auto cyan(P&&... p) -> string { + if(!escapable()) return string{forward

    (p)...}; + return {"\e[96m", string{forward

    (p)...}, "\e[0m"}; +} + +template inline auto red(P&&... p) -> string { + if(!escapable()) return string{forward

    (p)...}; + return {"\e[91m", string{forward

    (p)...}, "\e[0m"}; +} + +template inline auto magenta(P&&... p) -> string { + if(!escapable()) return string{forward

    (p)...}; + return {"\e[95m", string{forward

    (p)...}, "\e[0m"}; +} + +template inline auto yellow(P&&... p) -> string { + if(!escapable()) return string{forward

    (p)...}; + return {"\e[93m", string{forward

    (p)...}, "\e[0m"}; +} + +template inline auto white(P&&... p) -> string { + if(!escapable()) return string{forward

    (p)...}; + return {"\e[97m", string{forward

    (p)...}, "\e[0m"}; +} + +template inline auto gray(P&&... p) -> string { + if(!escapable()) return string{forward

    (p)...}; + return {"\e[37m", string{forward

    (p)...}, "\e[0m"}; +} + +} + +} diff --git a/nall/thread.hpp b/nall/thread.hpp new file mode 100755 index 0000000..fd33e2d --- /dev/null +++ b/nall/thread.hpp @@ -0,0 +1,137 @@ +#pragma once + +//simple thread library +//primary rationale is that std::thread does not support custom stack sizes +//this is highly critical in certain applications such as threaded web servers +//an added bonus is that it avoids licensing issues on Windows +//win32-pthreads (needed for std::thread) is licensed under the GPL only + +#include +#include +#include + +#if defined(API_POSIX) + +#include + +namespace nall { + +struct thread { + inline auto join() -> void; + + static inline auto create(const function& callback, uintptr parameter = 0, uint stacksize = 0) -> thread; + static inline auto detach() -> void; + static inline auto exit() -> void; + + struct context { + function void> callback; + uintptr parameter = 0; + }; + +private: + pthread_t handle; +}; + +inline auto _threadCallback(void* parameter) -> void* { + auto context = (thread::context*)parameter; + context->callback(context->parameter); + delete context; + return nullptr; +} + +auto thread::join() -> void { + pthread_join(handle, nullptr); +} + +auto thread::create(const function& callback, uintptr parameter, uint stacksize) -> thread { + thread instance; + + auto context = new thread::context; + context->callback = callback; + context->parameter = parameter; + + pthread_attr_t attr; + pthread_attr_init(&attr); + if(stacksize) pthread_attr_setstacksize(&attr, max(PTHREAD_STACK_MIN, stacksize)); + + pthread_create(&instance.handle, &attr, _threadCallback, (void*)context); + return instance; +} + +auto thread::detach() -> void { + pthread_detach(pthread_self()); +} + +auto thread::exit() -> void { + pthread_exit(nullptr); +} + +} + +#elif defined(API_WINDOWS) + +namespace nall { + +struct thread { + inline ~thread(); + inline auto join() -> void; + + static inline auto create(const function& callback, uintptr parameter = 0, uint stacksize = 0) -> thread; + static inline auto detach() -> void; + static inline auto exit() -> void; + + struct context { + function void> callback; + uintptr parameter = 0; + }; + +private: + HANDLE handle = 0; +}; + +inline auto WINAPI _threadCallback(void* parameter) -> DWORD { + auto context = (thread::context*)parameter; + context->callback(context->parameter); + delete context; + return 0; +} + +thread::~thread() { + if(handle) { + CloseHandle(handle); + handle = 0; + } +} + +auto thread::join() -> void { + if(handle) { + WaitForSingleObject(handle, INFINITE); + CloseHandle(handle); + handle = 0; + } +} + +auto thread::create(const function& callback, uintptr parameter, uint stacksize) -> thread { + thread instance; + + auto context = new thread::context; + context->callback = callback; + context->parameter = parameter; + + instance.handle = CreateThread(nullptr, stacksize, _threadCallback, (void*)context, 0, nullptr); + return instance; +} + +auto thread::detach() -> void { + //Windows threads do not use this concept: + //~thread() frees resources via CloseHandle() + //thread continues to run even after handle is closed +} + +auto thread::exit() -> void { + ExitThread(0); +} + +} + +#endif diff --git a/nall/traits.hpp b/nall/traits.hpp new file mode 100755 index 0000000..e260768 --- /dev/null +++ b/nall/traits.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +//pull all type traits used by nall from std namespace into nall namespace +//this removes the requirement to prefix type traits with std:: within nall + +namespace nall { + using std::add_const; + using std::conditional; + using std::conditional_t; + using std::decay; + using std::declval; + using std::enable_if; + using std::enable_if_t; + using std::false_type; + using std::is_floating_point; + using std::is_floating_point_v; + using std::forward; + using std::initializer_list; + using std::is_array; + using std::is_base_of; + using std::is_base_of_v; + using std::is_function; + using std::is_integral; + using std::is_integral_v; + using std::is_same; + using std::is_same_v; + using std::is_signed; + using std::is_signed_v; + using std::is_unsigned; + using std::is_unsigned_v; + using std::move; + using std::nullptr_t; + using std::remove_extent; + using std::remove_reference; + using std::swap; + using std::true_type; +} + +namespace std { + #if INTMAX_BITS >= 128 + template<> struct is_signed : true_type {}; + template<> struct is_unsigned : true_type {}; + #endif +} diff --git a/nall/unique-pointer.hpp b/nall/unique-pointer.hpp new file mode 100644 index 0000000..bd91843 --- /dev/null +++ b/nall/unique-pointer.hpp @@ -0,0 +1,106 @@ +#pragma once + +namespace nall { + +template +struct unique_pointer { + template static auto create(P&&... p) { + return unique_pointer{new T{forward

    (p)...}}; + } + + using type = T; + T* pointer = nullptr; + function deleter; + + unique_pointer(const unique_pointer&) = delete; + auto operator=(const unique_pointer&) -> unique_pointer& = delete; + + unique_pointer(T* pointer = nullptr, const function& deleter = {}) : pointer(pointer), deleter(deleter) {} + ~unique_pointer() { reset(); } + + auto operator=(T* source) -> unique_pointer& { + reset(); + pointer = source; + return *this; + } + + explicit operator bool() const { return pointer; } + + auto operator->() -> T* { return pointer; } + auto operator->() const -> const T* { return pointer; } + + auto operator*() -> T& { return *pointer; } + auto operator*() const -> const T& { return *pointer; } + + auto operator()() -> T& { return *pointer; } + auto operator()() const -> const T& { return *pointer; } + + auto data() -> T* { return pointer; } + auto data() const -> const T* { return pointer; } + + auto release() -> T* { + auto result = pointer; + pointer = nullptr; + return result; + } + + auto reset() -> void { + if(pointer) { + if(deleter) { + deleter(pointer); + } else { + delete pointer; + } + pointer = nullptr; + } + } +}; + +template +struct unique_pointer { + using type = T; + T* pointer = nullptr; + function void> deleter; + + unique_pointer(const unique_pointer&) = delete; + auto operator=(const unique_pointer&) -> unique_pointer& = delete; + + unique_pointer(T* pointer = nullptr, const function& deleter = {}) : pointer(pointer), deleter(deleter) {} + ~unique_pointer() { reset(); } + + auto operator=(T* source) -> unique_pointer& { + reset(); + pointer = source; + return *this; + } + + explicit operator bool() const { return pointer; } + + auto operator()() -> T* { return pointer; } + auto operator()() const -> T* { return pointer; } + + alwaysinline auto operator[](uint offset) -> T& { return pointer[offset]; } + alwaysinline auto operator[](uint offset) const -> const T& { return pointer[offset]; } + + auto data() -> T* { return pointer; } + auto data() const -> const T* { return pointer; } + + auto release() -> T* { + auto result = pointer; + pointer = nullptr; + return result; + } + + auto reset() -> void { + if(pointer) { + if(deleter) { + deleter(pointer); + } else { + delete[] pointer; + } + pointer = nullptr; + } + } +}; + +} diff --git a/nall/utility.hpp b/nall/utility.hpp new file mode 100755 index 0000000..717da4e --- /dev/null +++ b/nall/utility.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +namespace nall { + +using std::tuple; + +template struct base_from_member { + base_from_member(T value) : value(value) {} + T value; +}; + +template struct castable { + operator To&() { return (To&)value; } + operator const To&() const { return (const To&)value; } + operator With&() { return value; } + operator const With&() const { return value; } + auto& operator=(const With& value) { return this->value = value; } + With value; +}; + +template inline auto allocate(uint size, const T& value) -> T* { + T* array = new T[size]; + for(uint i = 0; i < size; i++) array[i] = value; + return array; +} + +} diff --git a/nall/variant.hpp b/nall/variant.hpp new file mode 100644 index 0000000..b08e335 --- /dev/null +++ b/nall/variant.hpp @@ -0,0 +1,148 @@ +#pragma once + +namespace nall { + +template struct variant_size { + static constexpr uint size = max(sizeof(T), variant_size::size); +}; + +template struct variant_size { + static constexpr uint size = sizeof(T); +}; + +template struct variant_index { + static constexpr uint index = is_same_v ? Index : variant_index::index; +}; + +template struct variant_index { + static constexpr uint index = is_same_v ? Index : 0; +}; + +template struct variant_copy { + constexpr variant_copy(uint index, uint assigned, void* target, void* source) { + if(index == assigned) new(target) T(*((T*)source)); + else variant_copy(index + 1, assigned, target, source); + } +}; + +template struct variant_copy { + constexpr variant_copy(uint index, uint assigned, void* target, void* source) { + if(index == assigned) new(target) T(*((T*)source)); + } +}; + +template struct variant_move { + constexpr variant_move(uint index, uint assigned, void* target, void* source) { + if(index == assigned) new(target) T(move(*((T*)source))); + else variant_move(index + 1, assigned, target, source); + } +}; + +template struct variant_move { + constexpr variant_move(uint index, uint assigned, void* target, void* source) { + if(index == assigned) new(target) T(move(*((T*)source))); + } +}; + +template struct variant_destruct { + constexpr variant_destruct(uint index, uint assigned, void* data) { + if(index == assigned) ((T*)data)->~T(); + else variant_destruct(index + 1, assigned, data); + } +}; + +template struct variant_destruct { + constexpr variant_destruct(uint index, uint assigned, void* data) { + if(index == assigned) ((T*)data)->~T(); + } +}; + +template struct variant_equals { + constexpr auto operator()(uint index, uint assigned) const -> bool { + if(index == assigned) return is_same_v; + return variant_equals()(index + 1, assigned); + } +}; + +template struct variant_equals { + constexpr auto operator()(uint index, uint assigned) const -> bool { + if(index == assigned) return is_same_v; + return false; + } +}; + +template struct variant final { //final as destructor is not virtual + variant() : assigned(0) {} + variant(const variant& source) { operator=(source); } + variant(variant&& source) { operator=(move(source)); } + template variant(const T& value) { operator=(value); } + template variant(T&& value) { operator=(move(value)); } + ~variant() { reset(); } + + explicit operator bool() const { return assigned; } + template explicit constexpr operator T&() { return get(); } + template explicit constexpr operator const T&() const { return get(); } + + template constexpr auto is() const -> bool { + return variant_equals()(1, assigned); + } + + template constexpr auto get() -> T& { + static_assert(variant_index<1, T, P...>::index, "type not in variant"); + struct variant_bad_cast{}; + if(!is()) throw variant_bad_cast{}; + return *((T*)data); + } + + template constexpr auto get() const -> const T& { + static_assert(variant_index<1, T, P...>::index, "type not in variant"); + struct variant_bad_cast{}; + if(!is()) throw variant_bad_cast{}; + return *((const T*)data); + } + + template constexpr auto get(const T& fallback) const -> const T& { + if(!is()) return fallback; + return *((const T*)data); + } + + auto reset() -> void { + if(assigned) variant_destruct(1, assigned, (void*)data); + assigned = 0; + } + + auto& operator=(const variant& source) { + reset(); + if(assigned = source.assigned) variant_copy(1, source.assigned, (void*)data, (void*)source.data); + return *this; + } + + auto& operator=(variant&& source) { + reset(); + if(assigned = source.assigned) variant_move(1, source.assigned, (void*)data, (void*)source.data); + source.assigned = 0; + return *this; + } + + template auto& operator=(const T& value) { + static_assert(variant_index<1, T, P...>::index, "type not in variant"); + reset(); + new((void*)&data) T(value); + assigned = variant_index<1, T, P...>::index; + return *this; + } + + template auto& operator=(T&& value) { + static_assert(variant_index<1, T, P...>::index, "type not in variant"); + reset(); + new((void*)&data) T(move(value)); + assigned = variant_index<1, T, P...>::index; + return *this; + } + +private: + alignas(P...) char data[variant_size::size]; + uint assigned; +}; + +} diff --git a/nall/varint.hpp b/nall/varint.hpp new file mode 100755 index 0000000..ee18a03 --- /dev/null +++ b/nall/varint.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include +#include +#include + +namespace nall { + +struct varint { + virtual auto read() -> uint8_t = 0; + virtual auto write(uint8_t) -> void = 0; + + auto readvu() -> uintmax { + uintmax 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 readvs() -> intmax { + uintmax data = readvu(); + bool negate = data & 1; + data >>= 1; + if(negate) data = ~data; + return data; + } + + auto writevu(uintmax data) -> void { + while(true) { + uint8_t x = data & 0x7f; + data >>= 7; + if(data == 0) return write(0x80 | x); + write(x); + data--; + } + } + + auto writevs(intmax data) -> void { + bool negate = data < 0; + if(negate) data = ~data; + data = (data << 1) | negate; + writevu(data); + } +}; + +struct VariadicNatural { + inline VariadicNatural() : mask(~0ull) { assign(0); } + template inline VariadicNatural(const T& value) : mask(~0ull) { assign(value); } + + inline operator uint64_t() const { return data; } + template inline auto& operator=(const T& value) { return assign(value); } + + inline auto operator++(int) { auto value = data; assign(data + 1); return value; } + inline auto operator--(int) { auto value = data; assign(data - 1); return value; } + + inline auto& operator++() { return assign(data + 1); } + inline auto& operator--() { return assign(data - 1); } + + inline auto& operator &=(const uint64_t value) { return assign(data & value); } + inline auto& operator |=(const uint64_t value) { return assign(data | value); } + inline auto& operator ^=(const uint64_t value) { return assign(data ^ value); } + inline auto& operator<<=(const uint64_t value) { return assign(data << value); } + inline auto& operator>>=(const uint64_t value) { return assign(data >> value); } + inline auto& operator +=(const uint64_t value) { return assign(data + value); } + inline auto& operator -=(const uint64_t value) { return assign(data - value); } + inline auto& operator *=(const uint64_t value) { return assign(data * value); } + inline auto& operator /=(const uint64_t value) { return assign(data / value); } + inline auto& operator %=(const uint64_t value) { return assign(data % value); } + + inline auto resize(uint bits) { + assert(bits <= 64); + mask = ~0ull >> (64 - bits); + data &= mask; + } + + inline auto serialize(serializer& s) { + s(data); + s(mask); + } + + struct Reference { + inline Reference(VariadicNatural& self, uint lo, uint hi) : self(self), Lo(lo), Hi(hi) {} + + inline operator uint64_t() const { + const uint64_t RangeBits = Hi - Lo + 1; + const uint64_t RangeMask = (((1ull << RangeBits) - 1) << Lo) & self.mask; + return (self & RangeMask) >> Lo; + } + + inline auto& operator=(const uint64_t value) { + const uint64_t RangeBits = Hi - Lo + 1; + const uint64_t RangeMask = (((1ull << RangeBits) - 1) << Lo) & self.mask; + self.data = (self.data & ~RangeMask) | ((value << Lo) & RangeMask); + return *this; + } + + private: + VariadicNatural& self; + const uint Lo; + const uint Hi; + }; + + inline auto bits(uint lo, uint hi) -> Reference { return {*this, lo < hi ? lo : hi, hi > lo ? hi : lo}; } + inline auto bit(uint index) -> Reference { return {*this, index, index}; } + inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; } + +private: + auto assign(uint64_t value) -> VariadicNatural& { + data = value & mask; + return *this; + } + + uint64_t data; + uint64_t mask; +}; + +} diff --git a/nall/vector.hpp b/nall/vector.hpp new file mode 100644 index 0000000..04ffc53 --- /dev/null +++ b/nall/vector.hpp @@ -0,0 +1,156 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nall { + +template +struct vector_base { + using type = vector_base; + + //core.hpp + vector_base() = default; + vector_base(const initializer_list& values); + vector_base(const type& source); + vector_base(type&& source); + ~vector_base(); + + explicit operator bool() const; + operator array_span(); + operator array_view() const; + template auto capacity() const -> uint64_t; + template auto size() const -> uint64_t; + template auto data() -> Cast*; + template auto data() const -> const Cast*; + + //assign.hpp + auto operator=(const type& source) -> type&; + auto operator=(type&& source) -> type&; + + //compare.hpp + auto operator==(const type& source) const -> bool; + auto operator!=(const type& source) const -> bool; + + //memory.hpp + auto reset() -> void; + auto acquire(const T* data, uint64_t size, uint64_t capacity = 0) -> void; + auto release() -> T*; + + auto reserveLeft(uint64_t capacity) -> bool; + auto reserveRight(uint64_t capacity) -> bool; + auto reserve(uint64_t capacity) -> bool { return reserveRight(capacity); } + + auto reallocateLeft(uint64_t size) -> bool; + auto reallocateRight(uint64_t size) -> bool; + auto reallocate(uint64_t size) -> bool { return reallocateRight(size); } + + auto resizeLeft(uint64_t size, const T& value = T()) -> bool; + auto resizeRight(uint64_t size, const T& value = T()) -> bool; + auto resize(uint64_t size, const T& value = T()) -> bool { return resizeRight(size, value); } + + //access.hpp + alwaysinline auto operator[](uint64_t offset) -> T&; + alwaysinline auto operator[](uint64_t offset) const -> const T&; + + alwaysinline auto operator()(uint64_t offset) -> T&; + alwaysinline auto operator()(uint64_t offset, const T& value) const -> const T&; + + alwaysinline auto left() -> T&; + alwaysinline auto first() -> T& { return left(); } + alwaysinline auto left() const -> const T&; + alwaysinline auto first() const -> const T& { return left(); } + + alwaysinline auto right() -> T&; + alwaysinline auto last() -> T& { return right(); } + alwaysinline auto right() const -> const T&; + alwaysinline auto last() const -> const T& { return right(); } + + //modify.hpp + auto prepend(const T& value) -> void; + auto prepend(T&& value) -> void; + auto prepend(const type& values) -> void; + auto prepend(type&& values) -> void; + + auto append(const T& value) -> void; + auto append(T&& value) -> void; + auto append(const type& values) -> void; + auto append(type&& values) -> void; + + auto insert(uint64_t offset, const T& value) -> void; + + auto removeLeft(uint64_t length = 1) -> void; + auto removeFirst(uint64_t length = 1) -> void { return removeLeft(length); } + auto removeRight(uint64_t length = 1) -> void; + auto removeLast(uint64_t length = 1) -> void { return removeRight(length); } + auto remove(uint64_t offset, uint64_t length = 1) -> void; + auto removeByIndex(uint64_t offset) -> bool; + auto removeByValue(const T& value) -> bool; + + auto takeLeft() -> T; + auto takeFirst() -> T { return move(takeLeft()); } + auto takeRight() -> T; + auto takeLast() -> T { return move(takeRight()); } + auto take(uint64_t offset) -> T; + + //iterator.hpp + auto begin() -> iterator { return {data(), 0}; } + auto end() -> iterator { return {data(), size()}; } + + auto begin() const -> iterator_const { return {data(), 0}; } + auto end() const -> iterator_const { return {data(), size()}; } + + auto rbegin() -> reverse_iterator { return {data(), size() - 1}; } + auto rend() -> reverse_iterator { return {data(), (uint64_t)-1}; } + + auto rbegin() const -> reverse_iterator_const { return {data(), size() - 1}; } + auto rend() const -> reverse_iterator_const { return {data(), (uint64_t)-1}; } + + //utility.hpp + auto fill(const T& value = {}) -> void; + auto sort(const function& comparator = [](auto& lhs, auto& rhs) { return lhs < rhs; }) -> void; + auto reverse() -> void; + auto find(const function& comparator) -> maybe; + auto find(const T& value) const -> maybe; + auto findSorted(const T& value) const -> maybe; + auto foreach(const function& callback) -> void; + auto foreach(const function& callback) -> void; + +protected: + T* _pool = nullptr; //pointer to first initialized element in pool + uint64_t _size = 0; //number of initialized elements in pool + uint64_t _left = 0; //number of allocated elements free on the left of pool + uint64_t _right = 0; //number of allocated elements free on the right of pool +}; + +} + +#define vector vector_base +#include +#include +#include +#include +#include +#include +#include +#include +#undef vector + +namespace nall { + template struct vector : vector_base { + using vector_base::vector_base; + }; +} + +#include diff --git a/nall/vector/access.hpp b/nall/vector/access.hpp new file mode 100644 index 0000000..62f44fb --- /dev/null +++ b/nall/vector/access.hpp @@ -0,0 +1,47 @@ +#pragma once + +namespace nall { + +template auto vector::operator[](uint64_t offset) -> T& { + #ifdef DEBUG + struct out_of_bounds {}; + if(offset >= size()) throw out_of_bounds{}; + #endif + return _pool[offset]; +} + +template auto vector::operator[](uint64_t offset) const -> const T& { + #ifdef DEBUG + struct out_of_bounds {}; + if(offset >= size()) throw out_of_bounds{}; + #endif + return _pool[offset]; +} + +template auto vector::operator()(uint64_t offset) -> T& { + while(offset >= size()) append(T()); + return _pool[offset]; +} + +template auto vector::operator()(uint64_t offset, const T& value) const -> const T& { + if(offset >= size()) return value; + return _pool[offset]; +} + +template auto vector::left() -> T& { + return _pool[0]; +} + +template auto vector::left() const -> const T& { + return _pool[0]; +} + +template auto vector::right() -> T& { + return _pool[_size - 1]; +} + +template auto vector::right() const -> const T& { + return _pool[_size - 1]; +} + +} diff --git a/nall/vector/assign.hpp b/nall/vector/assign.hpp new file mode 100644 index 0000000..2d66149 --- /dev/null +++ b/nall/vector/assign.hpp @@ -0,0 +1,28 @@ +#pragma once + +namespace nall { + +template auto vector::operator=(const vector& source) -> vector& { + if(this == &source) return *this; + _pool = memory::allocate(source._size); + _size = source._size; + _left = 0; + _right = 0; + for(uint64_t n : range(_size)) new(_pool + n) T(source._pool[n]); + return *this; +} + +template auto vector::operator=(vector&& source) -> vector& { + if(this == &source) return *this; + _pool = source._pool; + _size = source._size; + _left = source._left; + _right = source._right; + source._pool = nullptr; + source._size = 0; + source._left = 0; + source._right = 0; + return *this; +} + +} diff --git a/nall/vector/compare.hpp b/nall/vector/compare.hpp new file mode 100644 index 0000000..e2ef4b7 --- /dev/null +++ b/nall/vector/compare.hpp @@ -0,0 +1,18 @@ +#pragma once + +namespace nall { + +template auto vector::operator==(const vector& source) const -> bool { + if(this == &source) return true; + if(size() != source.size()) return false; + for(uint64_t n = 0; n < size(); n++) { + if(operator[](n) != source[n]) return false; + } + return true; +} + +template auto vector::operator!=(const vector& source) const -> bool { + return !operator==(source); +} + +} diff --git a/nall/vector/core.hpp b/nall/vector/core.hpp new file mode 100644 index 0000000..a332928 --- /dev/null +++ b/nall/vector/core.hpp @@ -0,0 +1,50 @@ +#pragma once + +namespace nall { + +template vector::vector(const initializer_list& values) { + reserveRight(values.size()); + for(auto& value : values) append(value); +} + +template vector::vector(const vector& source) { + operator=(source); +} + +template vector::vector(vector&& source) { + operator=(move(source)); +} + +template vector::~vector() { + reset(); +} + +template vector::operator bool() const { + return _size; +} + +template vector::operator array_span() { + return {data(), size()}; +} + +template vector::operator array_view() const { + return {data(), size()}; +} + +template template auto vector::capacity() const -> uint64_t { + return (_left + _size + _right) * sizeof(T) / sizeof(Cast); +} + +template template auto vector::size() const -> uint64_t { + return _size * sizeof(T) / sizeof(Cast); +} + +template template auto vector::data() -> Cast* { + return (Cast*)_pool; +} + +template template auto vector::data() const -> const Cast* { + return (const Cast*)_pool; +} + +} diff --git a/nall/vector/iterator.hpp b/nall/vector/iterator.hpp new file mode 100644 index 0000000..67afb01 --- /dev/null +++ b/nall/vector/iterator.hpp @@ -0,0 +1,57 @@ +#pragma once + +namespace nall { + +template +struct vector_iterator { + vector_iterator(vector& self, uint64_t offset) : self(self), offset(offset) {} + auto operator*() -> T& { return self.operator[](offset); } + auto operator->() -> T* { return self.operator[](offset); } + auto operator!=(const vector_iterator& source) const -> bool { return offset != source.offset; } + auto operator++() -> vector_iterator& { return offset++, *this; } + +private: + vector& self; + uint64_t offset; +}; + +template +struct vector_iterator_const { + vector_iterator_const(const vector& self, uint64_t offset) : self(self), offset(offset) {} + auto operator*() -> const T& { return self.operator[](offset); } + auto operator->() -> T* { return self.operator[](offset); } + auto operator!=(const vector_iterator_const& source) const -> bool { return offset != source.offset; } + auto operator++() -> vector_iterator_const& { return offset++, *this; } + +private: + const vector& self; + uint64_t offset; +}; + +template +struct vector_reverse_iterator { + vector_reverse_iterator(vector& self, uint64_t offset) : self(self), offset(offset) {} + auto operator*() -> T& { return self.operator[](offset); } + auto operator->() -> T* { return self.operator[](offset); } + auto operator!=(const vector_reverse_iterator& source) const -> bool { return offset != source.offset; } + auto operator++() -> vector_reverse_iterator& { return offset--, *this; } + +private: + vector& self; + uint64_t offset; +}; + +template +struct vector_reverse_iterator_const { + vector_reverse_iterator_const(const vector& self, uint64_t offset) : self(self), offset(offset) {} + auto operator*() -> const T& { return self.operator[](offset); } + auto operator->() -> T* { return self.operator[](offset); } + auto operator!=(const vector_reverse_iterator_const& source) const -> bool { return offset != source.offset; } + auto operator++() -> vector_reverse_iterator_const& { return offset--, *this; } + +private: + const vector& self; + uint64_t offset; +}; + +} diff --git a/nall/vector/memory.hpp b/nall/vector/memory.hpp new file mode 100644 index 0000000..15d7dd4 --- /dev/null +++ b/nall/vector/memory.hpp @@ -0,0 +1,147 @@ +#pragma once + +namespace nall { + +//nall::vector acts internally as a deque (double-ended queue) +//it does this because it's essentially free to do so, only costing an extra integer in sizeof(vector) + +template auto vector::reset() -> void { + if(!_pool) return; + + for(uint64_t n : range(_size)) _pool[n].~T(); + memory::free(_pool - _left); + + _pool = nullptr; + _size = 0; + _left = 0; + _right = 0; +} + +//acquire ownership of allocated memory + +template auto vector::acquire(const T* data, uint64_t size, uint64_t capacity) -> void { + reset(); + _pool = data; + _size = size; + _left = 0; + _right = capacity ? capacity : size; +} + +//release ownership of allocated memory + +template auto vector::release() -> T* { + auto pool = _pool; + _pool = nullptr; + _size = 0; + _left = 0; + _right = 0; + return pool; +} + +//reserve allocates memory for objects, but does not initialize them +//when the vector desired size is known, this can be used to avoid growing the capacity dynamically +//reserve will not actually shrink the capacity, only expand it +//shrinking the capacity would destroy objects, and break amortized growth with reallocate and resize + +template auto vector::reserveLeft(uint64_t capacity) -> bool { + if(_size + _left >= capacity) return false; + + uint64_t left = bit::round(capacity); + auto pool = memory::allocate(left + _right) + (left - _size); + for(uint64_t n : range(_size)) new(pool + n) T(move(_pool[n])); + memory::free(_pool - _left); + + _pool = pool; + _left = left - _size; + + return true; +} + +template auto vector::reserveRight(uint64_t capacity) -> bool { + if(_size + _right >= capacity) return false; + + uint64_t right = bit::round(capacity); + auto pool = memory::allocate(_left + right) + _left; + for(uint64_t n : range(_size)) new(pool + n) T(move(_pool[n])); + memory::free(_pool - _left); + + _pool = pool; + _right = right - _size; + + return true; +} + +//reallocation is meant for POD types, to avoid the overhead of initialization +//do not use with non-POD types, or they will not be properly constructed or destructed + +template auto vector::reallocateLeft(uint64_t size) -> bool { + if(size < _size) { //shrink + _pool += _size - size; + _left += _size - size; + _size = size; + return true; + } + if(size > _size) { //grow + reserveLeft(size); + _pool -= size - _size; + _left -= size - _size; + _size = size; + return true; + } + return false; +} + +template auto vector::reallocateRight(uint64_t size) -> bool { + if(size < _size) { //shrink + _right += _size - size; + _size = size; + return true; + } + if(size > _size) { //grow + reserveRight(size); + _right -= size - _size; + _size = size; + return true; + } + return false; +} + +//resize is meant for non-POD types, and will properly construct objects + +template auto vector::resizeLeft(uint64_t size, const T& value) -> bool { + if(size < _size) { //shrink + for(uint64_t n : range(_size - size)) _pool[n].~T(); + _pool += _size - size; + _left += _size - size; + _size = size; + return true; + } + if(size > _size) { //grow + reserveLeft(size); + _pool -= size - _size; + for(uint64_t n : nall::reverse(range(size - _size))) new(_pool + n) T(value); + _left -= size - _size; + _size = size; + return true; + } + return false; +} + +template auto vector::resizeRight(uint64_t size, const T& value) -> bool { + if(size < _size) { //shrink + for(uint64_t n : range(size, _size)) _pool[n].~T(); + _right += _size - size; + _size = size; + return true; + } + if(size > _size) { //grow + reserveRight(size); + for(uint64_t n : range(_size, size)) new(_pool + n) T(value); + _right -= size - _size; + _size = size; + return true; + } + return false; +} + +} diff --git a/nall/vector/modify.hpp b/nall/vector/modify.hpp new file mode 100644 index 0000000..3386125 --- /dev/null +++ b/nall/vector/modify.hpp @@ -0,0 +1,137 @@ +#pragma once + +namespace nall { + +template auto vector::prepend(const T& value) -> void { + reserveLeft(size() + 1); + new(--_pool) T(value); + _left--; + _size++; +} + +template auto vector::prepend(T&& value) -> void { + reserveLeft(size() + 1); + new(--_pool) T(move(value)); + _left--; + _size++; +} + +template auto vector::prepend(const vector& values) -> void { + reserveLeft(size() + values.size()); + _pool -= values.size(); + for(uint64_t n : range(values)) new(_pool + n) T(values[n]); + _left -= values.size(); + _size += values.size(); +} + +template auto vector::prepend(vector&& values) -> void { + reserveLeft(size() + values.size()); + _pool -= values.size(); + for(uint64_t n : range(values)) new(_pool + n) T(move(values[n])); + _left -= values.size(); + _size += values.size(); +} + +// + +template auto vector::append(const T& value) -> void { + reserveRight(size() + 1); + new(_pool + _size) T(value); + _right--; + _size++; +} + +template auto vector::append(T&& value) -> void { + reserveRight(size() + 1); + new(_pool + _size) T(move(value)); + _right--; + _size++; +} + +template auto vector::append(const vector& values) -> void { + reserveRight(size() + values.size()); + for(uint64_t n : range(values.size())) new(_pool + _size + n) T(values[n]); + _right -= values.size(); + _size += values.size(); +} + +template auto vector::append(vector&& values) -> void { + reserveRight(size() + values.size()); + for(uint64_t n : range(values.size())) new(_pool + _size + n) T(move(values[n])); + _right -= values.size(); + _size += values.size(); +} + +// + +template auto vector::insert(uint64_t offset, const T& value) -> void { + if(offset == 0) return prepend(value); + if(offset == size() - 1) return append(value); + reserveRight(size() + 1); + _size++; + for(int64_t n = size() - 1; n > offset; n--) { + _pool[n] = move(_pool[n - 1]); + } + new(_pool + offset) T(value); +} + +// + +template auto vector::removeLeft(uint64_t length) -> void { + if(length > size()) length = size(); + resizeLeft(size() - length); +} + +template auto vector::removeRight(uint64_t length) -> void { + if(length > size()) length = size(); + resizeRight(size() - length); +} + +template auto vector::remove(uint64_t offset, uint64_t length) -> void { + if(offset == 0) return removeLeft(length); + if(offset == size() - 1) return removeRight(length); + + for(uint64_t n = offset; n < size(); n++) { + if(n + length < size()) { + _pool[n] = move(_pool[n + length]); + } else { + _pool[n].~T(); + } + } + _size -= length; +} + +template auto vector::removeByIndex(uint64_t index) -> bool { + if(index < size()) return remove(index), true; + return false; +} + +template auto vector::removeByValue(const T& value) -> bool { + if(auto index = find(value)) return remove(*index), true; + return false; +} + +// + +template auto vector::takeLeft() -> T { + T value = move(_pool[0]); + removeLeft(); + return value; +} + +template auto vector::takeRight() -> T { + T value = move(_pool[size() - 1]); + removeRight(); + return value; +} + +template auto vector::take(uint64_t offset) -> T { + if(offset == 0) return takeLeft(); + if(offset == size() - 1) return takeRight(); + + T value = move(_pool[offset]); + remove(offset); + return value; +} + +} diff --git a/nall/vector/specialization/uint8_t.hpp b/nall/vector/specialization/uint8_t.hpp new file mode 100644 index 0000000..8ec5cad --- /dev/null +++ b/nall/vector/specialization/uint8_t.hpp @@ -0,0 +1,38 @@ +#pragma once + +namespace nall { + +template<> struct vector : vector_base { + using type = vector; + using vector_base::vector_base; + + template auto appendl(U value, uint size) -> void { + for(uint byte : range(size)) append(uint8_t(value >> byte * 8)); + } + + template auto appendm(U value, uint size) -> void { + for(uint byte : nall::reverse(range(size))) append(uint8_t(value >> byte * 8)); + } + + //note: string_view is not declared here yet ... + auto appends(array_view memory) -> void { + for(uint8_t byte : memory) append(byte); + } + + template auto readl(int offset, uint size) -> U { + if(offset < 0) offset = this->size() - abs(offset); + U value = 0; + for(uint byte : range(size)) value |= (U)operator[](offset + byte) << byte * 8; + return value; + } + + auto view(uint offset, uint length) -> array_view { + #ifdef DEBUG + struct out_of_bounds {}; + if(offset + length >= size()) throw out_of_bounds{}; + #endif + return {data() + offset, length}; + } +}; + +} diff --git a/nall/vector/utility.hpp b/nall/vector/utility.hpp new file mode 100644 index 0000000..635f52e --- /dev/null +++ b/nall/vector/utility.hpp @@ -0,0 +1,47 @@ +#pragma once + +namespace nall { + +template auto vector::fill(const T& value) -> void { + for(uint64_t n : range(size())) _pool[n] = value; +} + +template auto vector::sort(const function& comparator) -> void { + nall::sort(_pool, _size, comparator); +} + +template auto vector::reverse() -> void { + vector reversed; + for(uint64_t n : range(size())) reversed.prepend(_pool[n]); + operator=(move(reversed)); +} + +template auto vector::find(const function& comparator) -> maybe { + for(uint64_t n : range(size())) if(comparator(_pool[n])) return n; + return nothing; +} + +template auto vector::find(const T& value) const -> maybe { + for(uint64_t n : range(size())) if(_pool[n] == value) return n; + return nothing; +} + +template auto vector::findSorted(const T& value) const -> maybe { + int64_t l = 0, r = size() - 1; + while(l <= r) { + int64_t m = l + (r - l >> 1); + if(value == _pool[m]) return m; + value < _pool[m] ? r = m - 1 : l = m + 1; + } + return nothing; +} + +template auto vector::foreach(const function& callback) -> void { + for(uint64_t n : range(size())) callback(_pool[n]); +} + +template auto vector::foreach(const function& callback) -> void { + for(uint64_t n : range(size())) callback(n, _pool[n]); +} + +} diff --git a/nall/vfs.hpp b/nall/vfs.hpp new file mode 100644 index 0000000..8039678 --- /dev/null +++ b/nall/vfs.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/nall/vfs/fs/file.hpp b/nall/vfs/fs/file.hpp new file mode 100644 index 0000000..bcac705 --- /dev/null +++ b/nall/vfs/fs/file.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include + +namespace nall::vfs::fs { + +struct file : vfs::file { + static auto open(string location_, mode mode_) -> shared_pointer { + auto instance = shared_pointer{new file}; + if(!instance->_open(location_, mode_)) return {}; + return instance; + } + + auto size() const -> uintmax override { + return _fp.size(); + } + + auto offset() const -> uintmax override { + return _fp.offset(); + } + + auto seek(intmax offset_, index index_) -> void override { + _fp.seek(offset_, (uint)index_); + } + + auto read() -> uint8_t override { + return _fp.read(); + } + + auto write(uint8_t data_) -> void override { + _fp.write(data_); + } + + auto flush() -> void override { + _fp.flush(); + } + +private: + file() = default; + file(const file&) = delete; + auto operator=(const file&) -> file& = delete; + + auto _open(string location_, mode mode_) -> bool { + if(!_fp.open(location_, (uint)mode_)) return false; + return true; + } + + file_buffer _fp; +}; + +} diff --git a/nall/vfs/memory/file.hpp b/nall/vfs/memory/file.hpp new file mode 100644 index 0000000..e5af580 --- /dev/null +++ b/nall/vfs/memory/file.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include +#include + +namespace nall::vfs::memory { + +struct file : vfs::file { + ~file() { delete[] _data; } + + static auto open(const void* data, uintmax size) -> shared_pointer { + auto instance = shared_pointer{new file}; + instance->_open((const uint8_t*)data, size); + return instance; + } + + static auto open(string location, bool decompress = false) -> shared_pointer { + auto instance = shared_pointer{new file}; + if(decompress && location.iendsWith(".zip")) { + Decode::ZIP archive; + if(archive.open(location) && archive.file.size() == 1) { + auto memory = archive.extract(archive.file.first()); + instance->_open(memory.data(), memory.size()); + return instance; + } + } + auto memory = nall::file::read(location); + instance->_open(memory.data(), memory.size()); + return instance; + } + + auto data() const -> const uint8_t* { return _data; } + auto size() const -> uintmax override { return _size; } + auto offset() const -> uintmax override { return _offset; } + + auto seek(intmax offset, index mode) -> void override { + if(mode == index::absolute) _offset = (uintmax)offset; + if(mode == index::relative) _offset += (intmax)offset; + } + + auto read() -> uint8_t override { + if(_offset >= _size) return 0x00; + return _data[_offset++]; + } + + auto write(uint8_t data) -> void override { + if(_offset >= _size) return; + _data[_offset++] = data; + } + +private: + file() = default; + file(const file&) = delete; + auto operator=(const file&) -> file& = delete; + + auto _open(const uint8_t* data, uintmax size) -> void { + _size = size; + _data = new uint8_t[size]; + nall::memory::copy(_data, data, size); + } + + uint8_t* _data = nullptr; + uintmax _size = 0; + uintmax _offset = 0; +}; + +} diff --git a/nall/vfs/vfs.hpp b/nall/vfs/vfs.hpp new file mode 100644 index 0000000..56488be --- /dev/null +++ b/nall/vfs/vfs.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include +#include + +namespace nall::vfs { + +struct file { + enum class mode : uint { read, write, modify, create }; + enum class index : uint { absolute, relative }; + + virtual ~file() = default; + + virtual auto size() const -> uintmax = 0; + virtual auto offset() const -> uintmax = 0; + + virtual auto seek(intmax offset, index = index::absolute) -> void = 0; + virtual auto read() -> uint8_t = 0; + virtual auto write(uint8_t data) -> void = 0; + virtual auto flush() -> void {} + + auto end() const -> bool { + return offset() >= size(); + } + + auto read(void* vdata, uintmax bytes) -> void { + auto data = (uint8_t*)vdata; + while(bytes--) *data++ = read(); + } + + auto readl(uint bytes) -> uintmax { + uintmax data = 0; + for(auto n : range(bytes)) data |= (uintmax)read() << n * 8; + return data; + } + + auto readm(uint bytes) -> uintmax { + uintmax data = 0; + for(auto n : range(bytes)) data = data << 8 | read(); + return data; + } + + auto reads() -> string { + string s; + s.resize(size()); + read(s.get(), s.size()); + return s; + } + + auto write(const void* vdata, uintmax bytes) -> void { + auto data = (const uint8_t*)vdata; + while(bytes--) write(*data++); + } + + auto writel(uintmax data, uint bytes) -> void { + for(auto n : range(bytes)) write(data), data >>= 8; + } + + auto writem(uintmax data, uint bytes) -> void { + for(auto n : reverse(range(bytes))) write(data >> n * 8); + } + + auto writes(const string& s) -> void { + write(s.data(), s.size()); + } +}; + +} + +#include +#include diff --git a/nall/view.hpp b/nall/view.hpp new file mode 100644 index 0000000..ce874ce --- /dev/null +++ b/nall/view.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace nall { + +template struct view; + +} diff --git a/nall/windows/detour.hpp b/nall/windows/detour.hpp new file mode 100755 index 0000000..d4f304c --- /dev/null +++ b/nall/windows/detour.hpp @@ -0,0 +1,189 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace nall { + +#define Copy 0 +#define RelNear 1 + +struct detour { + static auto insert(const string& moduleName, const string& functionName, void*& source, void* target) -> bool; + static auto remove(const string& moduleName, const string& functionName, void*& source) -> bool; + +protected: + static auto length(const uint8* function) -> uint; + static auto mirror(uint8* target, const uint8* source) -> uint; + + struct opcode { + uint16 prefix; + uint length; + uint mode; + uint16 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 +}; + +auto detour::insert(const string& moduleName, const string& functionName, void*& source, void* target) -> bool { + HMODULE module = GetModuleHandleW(utf16_t(moduleName)); + if(!module) return false; + + uint8* sourceData = (uint8_t*)GetProcAddress(module, functionName); + if(!sourceData) return false; + + uint 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(uint n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " "); + output.trimRight(" ", 1L); + MessageBoxA(0, output, "nall::detour", MB_OK); + #endif + return false; + } + + auto mirrorData = new uint8[512](); + detour::mirror(mirrorData, sourceData); + + DWORD privileges; + VirtualProtect((void*)mirrorData, 512, PAGE_EXECUTE_READWRITE, &privileges); + VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges); + uint64_t address = (uint64_t)target - ((uint64_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; +} + +auto detour::remove(const string& moduleName, const string& functionName, void*& source) -> bool { + HMODULE module = GetModuleHandleW(utf16_t(moduleName)); + if(!module) return false; + + auto sourceData = (uint8*)GetProcAddress(module, functionName); + if(!sourceData) return false; + + auto mirrorData = (uint8*)source; + if(mirrorData == sourceData) return false; //hook was never installed + + uint length = detour::length(256 + mirrorData); + if(length < 5) return false; + + DWORD privileges; + VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges); + for(uint n = 0; n < length; n++) sourceData[n] = mirrorData[256 + n]; + VirtualProtect((void*)sourceData, 256, privileges, &privileges); + + source = (void*)sourceData; + delete[] mirrorData; + return true; +} + +auto detour::length(const uint8* function) -> uint { + uint 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; +} + +auto detour::mirror(uint8* target, const uint8* source) -> uint { + const uint8* entryPoint = source; + for(uint n = 0; n < 256; n++) target[256 + n] = source[n]; + + uint size = detour::length(source); + while(size) { + detour::opcode* opcode = nullptr; + foreach(op, detour::opcodes) { + if(*source == op.prefix) { + opcode = &op; + break; + } + } + + switch(opcode->mode) { + case Copy: + for(uint n = 0; n < opcode->length; n++) *target++ = *source++; + break; + case RelNear: { + source++; + uint64_t sourceAddress = (uint64_t)source + 1 + (int8)*source; + *target++ = opcode->modify; + if(opcode->modify >> 8) *target++ = opcode->modify >> 8; + uint64_t targetAddress = (uint64_t)target + 4; + uint64_t address = sourceAddress - targetAddress; + *target++ = address >> 0; + *target++ = address >> 8; + *target++ = address >> 16; + *target++ = address >> 24; + source += 2; + } break; + } + + size -= opcode->length; + } + + uint64_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 + +} diff --git a/nall/windows/guard.hpp b/nall/windows/guard.hpp new file mode 100644 index 0000000..353874c --- /dev/null +++ b/nall/windows/guard.hpp @@ -0,0 +1,34 @@ +#ifndef NALL_WINDOWS_GUARD_HPP +#define NALL_WINDOWS_GUARD_HPP + +#define boolean WindowsBoolean +#define interface WindowsInterface + +#undef UNICODE +#undef WINVER +#undef WIN32_LEAN_AND_LEAN +#undef _WIN32_WINNT +#undef _WIN32_IE +#undef __MSVCRT_VERSION__ +#undef NOMINMAX +#undef PATH_MAX + +#define UNICODE +#define WINVER 0x0601 +#define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT WINVER +#define _WIN32_IE WINVER +#define __MSVCRT_VERSION__ WINVER +#define NOMINMAX +#define PATH_MAX 260 + +#else +#undef NALL_WINDOWS_GUARD_HPP + +#undef boolean +#undef interface + +#undef far +#undef near + +#endif diff --git a/nall/windows/guid.hpp b/nall/windows/guid.hpp new file mode 100755 index 0000000..314683d --- /dev/null +++ b/nall/windows/guid.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace nall { + +inline auto guid() -> string { + GUID guidInstance; + CoCreateGuid(&guidInstance); + + wchar_t guidString[39]; + StringFromGUID2(guidInstance, guidString, 39); + + return (char*)utf8_t(guidString); +} + +} diff --git a/nall/windows/launcher.hpp b/nall/windows/launcher.hpp new file mode 100755 index 0000000..1ae13c3 --- /dev/null +++ b/nall/windows/launcher.hpp @@ -0,0 +1,91 @@ +#pragma once + +namespace nall { + +//launch a new process and inject specified DLL into it + +auto launch(const char* applicationName, const char* libraryName, uint32 entryPoint) -> bool { + //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 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)((entryPoint + 14) >> 0); + entryHook[2] = (uint8)((entryPoint + 14) >> 8); + entryHook[3] = (uint8)((entryPoint + 14) >> 16); + entryHook[4] = (uint8)((entryPoint + 14) >> 24); + + auto pLoadLibraryW = (uint32)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; +} + +} diff --git a/nall/windows/registry.hpp b/nall/windows/registry.hpp new file mode 100755 index 0000000..09e1b96 --- /dev/null +++ b/nall/windows/registry.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include +#include + +#include +#undef interface +#ifndef KEY_WOW64_64KEY + #define KEY_WOW64_64KEY 0x0100 +#endif +#ifndef KEY_WOW64_32KEY + #define KEY_WOW64_32KEY 0x0200 +#endif + +#ifndef NWR_FLAGS + #define NWR_FLAGS KEY_WOW64_64KEY +#endif + +#ifndef NWR_SIZE + #define NWR_SIZE 4096 +#endif + +namespace nall { + +struct registry { + static auto exists(const string& name) -> bool { + auto part = name.split("\\"); + HKEY handle, rootKey = root(part.takeLeft()); + string node = part.takeRight(); + string path = part.merge("\\"); + if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { + wchar_t data[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + LONG result = RegQueryValueExW(handle, utf16_t(node), nullptr, nullptr, (LPBYTE)&data, (LPDWORD)&size); + RegCloseKey(handle); + if(result == ERROR_SUCCESS) return true; + } + return false; + } + + static auto read(const string& name) -> string { + auto part = name.split("\\"); + HKEY handle, rootKey = root(part.takeLeft()); + string node = part.takeRight(); + string path = part.merge("\\"); + if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { + wchar_t data[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + LONG result = RegQueryValueExW(handle, utf16_t(node), nullptr, nullptr, (LPBYTE)&data, (LPDWORD)&size); + RegCloseKey(handle); + if(result == ERROR_SUCCESS) return (const char*)utf8_t(data); + } + return ""; + } + + static auto write(const string& name, const string& data = "") -> void { + auto part = name.split("\\"); + HKEY handle, rootKey = root(part.takeLeft()); + string node = part.takeRight(), path; + DWORD disposition; + for(uint n = 0; n < part.size(); n++) { + path.append(part[n]); + if(RegCreateKeyExW(rootKey, utf16_t(path), 0, nullptr, 0, NWR_FLAGS | KEY_ALL_ACCESS, nullptr, &handle, &disposition) == ERROR_SUCCESS) { + if(n == part.size() - 1) { + RegSetValueExW(handle, utf16_t(node), 0, REG_SZ, (BYTE*)(wchar_t*)utf16_t(data), (data.length() + 1) * sizeof(wchar_t)); + } + RegCloseKey(handle); + } + path.append("\\"); + } + } + + static auto remove(const string& name) -> bool { + auto part = name.split("\\"); + HKEY rootKey = root(part.takeLeft()); + string node = part.takeRight(); + string path = part.merge("\\"); + if(!node) return SHDeleteKeyW(rootKey, utf16_t(path)) == ERROR_SUCCESS; + return SHDeleteValueW(rootKey, utf16_t(path), utf16_t(node)) == ERROR_SUCCESS; + } + + static auto contents(const string& name) -> vector { + vector result; + auto part = name.split("\\"); + HKEY handle, rootKey = root(part.takeLeft()); + part.removeRight(); + string path = part.merge("\\"); + if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { + DWORD folders, nodes; + RegQueryInfoKey(handle, nullptr, nullptr, nullptr, &folders, nullptr, nullptr, &nodes, nullptr, nullptr, nullptr, nullptr); + for(uint n = 0; n < folders; n++) { + wchar_t name[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + RegEnumKeyEx(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr); + result.append(string{(const char*)utf8_t(name), "\\"}); + } + for(uint n = 0; n < nodes; n++) { + wchar_t name[NWR_SIZE] = L""; + DWORD size = NWR_SIZE * sizeof(wchar_t); + RegEnumValueW(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr); + result.append((const char*)utf8_t(name)); + } + RegCloseKey(handle); + } + return result; + } + +private: + static auto root(const string& name) -> HKEY { + if(name == "HKCR") return HKEY_CLASSES_ROOT; + if(name == "HKCC") return HKEY_CURRENT_CONFIG; + if(name == "HKCU") return HKEY_CURRENT_USER; + if(name == "HKLM") return HKEY_LOCAL_MACHINE; + if(name == "HKU" ) return HKEY_USERS; + return nullptr; + } +}; + +} diff --git a/nall/windows/service.hpp b/nall/windows/service.hpp new file mode 100644 index 0000000..fa5d87f --- /dev/null +++ b/nall/windows/service.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace nall { + +struct service { + explicit operator bool() const { return false; } + auto command(const string& name, const string& command) -> bool { return false; } + auto receive() -> string { return ""; } + auto name() const -> string { return ""; } + auto stop() const -> bool { return false; } +}; + +} diff --git a/nall/windows/shared-memory.hpp b/nall/windows/shared-memory.hpp new file mode 100644 index 0000000..aa74a70 --- /dev/null +++ b/nall/windows/shared-memory.hpp @@ -0,0 +1,27 @@ +#pragma once + +namespace nall { + +struct shared_memory { + shared_memory() = default; + shared_memory(const shared_memory&) = delete; + auto operator=(const shared_memory&) -> shared_memory& = delete; + + ~shared_memory() { + reset(); + } + + explicit operator bool() const { return false; } + auto empty() const -> bool { return true; } + auto size() const -> uint { return 0; } + auto acquired() const -> bool { return false; } + auto acquire() -> uint8_t* { return nullptr; } + auto release() -> void {} + auto reset() -> void {} + auto create(const string& name, uint size) -> bool { return false; } + auto remove() -> void {} + auto open(const string& name, uint size) -> bool { return false; } + auto close() -> void {} +}; + +} diff --git a/nall/windows/utf8.hpp b/nall/windows/utf8.hpp new file mode 100755 index 0000000..98d98fe --- /dev/null +++ b/nall/windows/utf8.hpp @@ -0,0 +1,86 @@ +#pragma once + +using uint = unsigned; + +namespace nall { + //UTF-8 to UTF-16 + struct utf16_t { + utf16_t(const char* s = "") { operator=(s); } + ~utf16_t() { reset(); } + + utf16_t(const utf16_t&) = delete; + auto operator=(const utf16_t&) -> utf16_t& = delete; + + auto operator=(const char* s) -> utf16_t& { + reset(); + if(!s) s = ""; + length = MultiByteToWideChar(CP_UTF8, 0, s, -1, nullptr, 0); + buffer = new wchar_t[length + 1]; + MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length); + buffer[length] = 0; + return *this; + } + + operator wchar_t*() { return buffer; } + operator const wchar_t*() const { return buffer; } + + auto reset() -> void { + delete[] buffer; + length = 0; + } + + auto data() -> wchar_t* { return buffer; } + auto data() const -> const wchar_t* { return buffer; } + + auto size() const -> uint { return length; } + + private: + wchar_t* buffer = nullptr; + uint length = 0; + }; + + //UTF-16 to UTF-8 + struct utf8_t { + utf8_t(const wchar_t* s = L"") { operator=(s); } + ~utf8_t() { reset(); } + + utf8_t(const utf8_t&) = delete; + auto operator=(const utf8_t&) -> utf8_t& = delete; + + auto operator=(const wchar_t* s) -> utf8_t& { + reset(); + if(!s) s = L""; + length = WideCharToMultiByte(CP_UTF8, 0, s, -1, nullptr, 0, nullptr, nullptr); + buffer = new char[length + 1]; + WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, nullptr, nullptr); + buffer[length] = 0; + return *this; + } + + auto reset() -> void { + delete[] buffer; + length = 0; + } + + operator char*() { return buffer; } + operator const char*() const { return buffer; } + + auto data() -> char* { return buffer; } + auto data() const -> const char* { return buffer; } + + auto size() const -> uint { return length; } + + private: + char* buffer = nullptr; + uint length = 0; + }; + + inline auto utf8_arguments(int& argc, char**& argv) -> void { + wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); + argv = new char*[argc + 1](); + for(uint i = 0; i < argc; i++) { + argv[i] = new char[PATH_MAX]; + strcpy(argv[i], nall::utf8_t(wargv[i])); + } + } +} diff --git a/nall/xorg/clipboard.hpp b/nall/xorg/clipboard.hpp new file mode 100644 index 0000000..09f06fd --- /dev/null +++ b/nall/xorg/clipboard.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace nall::Clipboard { + +auto clear() -> void { + XDisplay display; + if(auto atom = XInternAtom(display, "CLIPBOARD", XlibTrue)) { + XSetSelectionOwner(display, atom, XlibNone, XlibCurrentTime); + } +} + +} diff --git a/nall/xorg/guard.hpp b/nall/xorg/guard.hpp new file mode 100755 index 0000000..2ff49b7 --- /dev/null +++ b/nall/xorg/guard.hpp @@ -0,0 +1,51 @@ +#ifndef NALL_XORG_GUARD_HPP +#define NALL_XORG_GUARD_HPP + +#define Atom XlibAtom +#define Display XlibDisplay +#define Font XlibFont +#define Screen XlibScreen +#define Window XlibWindow + +#else +#undef NALL_XORG_GUARD_HPP + +#undef Atom +#undef Display +#undef Font +#undef Screen +#undef Window + +#undef Above +#undef Below +#undef Bool + +#ifndef NALL_XORG_GUARD_CONSTANTS +#define NALL_XORG_GUARD_CONSTANTS +enum XlibConstants : int { + XlibButton1 = Button1, + XlibButton2 = Button2, + XlibButton3 = Button3, + XlibButton4 = Button4, + XlibButton5 = Button5, + XlibCurrentTime = CurrentTime, + XlibFalse = False, + XlibNone = None, + XlibTrue = True, +}; +#endif + +#undef Button1 +#undef Button2 +#undef Button3 +#undef Button4 +#undef Button5 +#undef CurrentTime +#undef False +#undef None +#undef True + +#undef MAX +#undef MIN + +#endif diff --git a/nall/xorg/xorg.hpp b/nall/xorg/xorg.hpp new file mode 100755 index 0000000..b93eef0 --- /dev/null +++ b/nall/xorg/xorg.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +struct XDisplay { + XDisplay() { _display = XOpenDisplay(nullptr); } + ~XDisplay() { XCloseDisplay(_display); } + operator XlibDisplay*() const { return _display; } + +private: + XlibDisplay* _display; +}; diff --git a/processor/arm7tdmi/algorithms.cpp b/processor/arm7tdmi/algorithms.cpp new file mode 100644 index 0000000..d646e17 --- /dev/null +++ b/processor/arm7tdmi/algorithms.cpp @@ -0,0 +1,96 @@ +auto ARM7TDMI::ADD(uint32 source, uint32 modify, bool carry) -> uint32 { + uint32 result = source + modify + carry; + if(cpsr().t || (opcode & 1 << 20)) { + uint32 overflow = ~(source ^ modify) & (source ^ result); + cpsr().v = 1 << 31 & (overflow); + cpsr().c = 1 << 31 & (overflow ^ source ^ modify ^ result); + cpsr().z = result == 0; + cpsr().n = result >> 31; + } + return result; +} + +auto ARM7TDMI::ASR(uint32 source, uint8 shift) -> uint32 { + carry = cpsr().c; + if(shift == 0) return source; + carry = shift > 32 ? source & 1 << 31 : source & 1 << shift - 1; + source = shift > 31 ? (int32)source >> 31 : (int32)source >> shift; + return source; +} + +auto ARM7TDMI::BIT(uint32 result) -> uint32 { + if(cpsr().t || (opcode & 1 << 20)) { + cpsr().c = carry; + cpsr().z = result == 0; + cpsr().n = result >> 31; + } + return result; +} + +auto ARM7TDMI::LSL(uint32 source, uint8 shift) -> uint32 { + carry = cpsr().c; + if(shift == 0) return source; + carry = shift > 32 ? 0 : source & 1 << 32 - shift; + source = shift > 31 ? 0 : source << shift; + return source; +} + +auto ARM7TDMI::LSR(uint32 source, uint8 shift) -> uint32 { + carry = cpsr().c; + if(shift == 0) return source; + carry = shift > 32 ? 0 : source & 1 << shift - 1; + source = shift > 31 ? 0 : source >> shift; + return source; +} + +auto ARM7TDMI::MUL(uint32 product, uint32 multiplicand, uint32 multiplier) -> uint32 { + idle(); + if(multiplier >> 8 && multiplier >> 8 != 0xffffff) idle(); + if(multiplier >> 16 && multiplier >> 16 != 0xffff) idle(); + if(multiplier >> 24 && multiplier >> 24 != 0xff) idle(); + product += multiplicand * multiplier; + if(cpsr().t || (opcode & 1 << 20)) { + cpsr().z = product == 0; + cpsr().n = product >> 31; + } + return product; +} + +auto ARM7TDMI::ROR(uint32 source, uint8 shift) -> uint32 { + carry = cpsr().c; + if(shift == 0) return source; + if(shift &= 31) source = source << 32 - shift | source >> shift; + carry = source & 1 << 31; + return source; +} + +auto ARM7TDMI::RRX(uint32 source) -> uint32 { + carry = source & 1; + return cpsr().c << 31 | source >> 1; +} + +auto ARM7TDMI::SUB(uint32 source, uint32 modify, bool carry) -> uint32 { + return ADD(source, ~modify, carry); +} + +auto ARM7TDMI::TST(uint4 mode) -> bool { + switch(mode) { + case 0: return cpsr().z == 1; //EQ (equal) + case 1: return cpsr().z == 0; //NE (not equal) + case 2: return cpsr().c == 1; //CS (carry set) + case 3: return cpsr().c == 0; //CC (carry clear) + case 4: return cpsr().n == 1; //MI (negative) + case 5: return cpsr().n == 0; //PL (positive) + case 6: return cpsr().v == 1; //VS (overflow) + case 7: return cpsr().v == 0; //VC (no overflow) + case 8: return cpsr().c == 1 && cpsr().z == 0; //HI (unsigned higher) + case 9: return cpsr().c == 0 || cpsr().z == 1; //LS (unsigned lower or same) + case 10: return cpsr().n == cpsr().v; //GE (signed greater than or equal) + case 11: return cpsr().n != cpsr().v; //LT (signed less than) + case 12: return cpsr().z == 0 && cpsr().n == cpsr().v; //GT (signed greater than) + case 13: return cpsr().z == 1 || cpsr().n != cpsr().v; //LE (signed less than or equal) + case 14: return true; //AL (always) + case 15: return false; //NV (never) + } + unreachable; +} diff --git a/processor/arm7tdmi/arm7tdmi.cpp b/processor/arm7tdmi/arm7tdmi.cpp new file mode 100644 index 0000000..e3dc0d2 --- /dev/null +++ b/processor/arm7tdmi/arm7tdmi.cpp @@ -0,0 +1,30 @@ +#include +#include "arm7tdmi.hpp" + +namespace Processor { + +#include "registers.cpp" +#include "memory.cpp" +#include "algorithms.cpp" +#include "instruction.cpp" +#include "instructions-arm.cpp" +#include "instructions-thumb.cpp" +#include "serialization.cpp" +#include "disassembler.cpp" + +ARM7TDMI::ARM7TDMI() { + armInitialize(); + thumbInitialize(); +} + +auto ARM7TDMI::power() -> void { + processor = {}; + processor.r15.modify = [&] { pipeline.reload = true; }; + pipeline = {}; + carry = 0; + irq = 0; + cpsr().f = 1; + exception(PSR::SVC, 0x00); +} + +} diff --git a/processor/arm7tdmi/arm7tdmi.hpp b/processor/arm7tdmi/arm7tdmi.hpp new file mode 100644 index 0000000..3140775 --- /dev/null +++ b/processor/arm7tdmi/arm7tdmi.hpp @@ -0,0 +1,285 @@ +//ARMv4 (ARM7TDMI) + +#pragma once + +namespace Processor { + +struct ARM7TDMI { + enum : uint { + Nonsequential = 1 << 0, //N cycle + Sequential = 1 << 1, //S cycle + Prefetch = 1 << 2, //instruction fetch + Byte = 1 << 3, // 8-bit access + Half = 1 << 4, //16-bit access + Word = 1 << 5, //32-bit access + Load = 1 << 6, //load operation + Store = 1 << 7, //store operation + Signed = 1 << 8, //sign-extend + }; + + virtual auto step(uint clocks) -> void = 0; + virtual auto sleep() -> void = 0; + virtual auto get(uint mode, uint32 address) -> uint32 = 0; + virtual auto set(uint mode, uint32 address, uint32 word) -> void = 0; + + //arm7tdmi.cpp + ARM7TDMI(); + auto power() -> void; + + //registers.cpp + struct GPR; + struct PSR; + inline auto r(uint4) -> GPR&; + inline auto cpsr() -> PSR&; + inline auto spsr() -> PSR&; + inline auto privileged() const -> bool; + inline auto exception() const -> bool; + + //memory.cpp + auto idle() -> void; + auto read(uint mode, uint32 address) -> uint32; + auto load(uint mode, uint32 address) -> uint32; + auto write(uint mode, uint32 address, uint32 word) -> void; + auto store(uint mode, uint32 address, uint32 word) -> void; + + //algorithms.cpp + auto ADD(uint32, uint32, bool) -> uint32; + auto ASR(uint32, uint8) -> uint32; + auto BIT(uint32) -> uint32; + auto LSL(uint32, uint8) -> uint32; + auto LSR(uint32, uint8) -> uint32; + auto MUL(uint32, uint32, uint32) -> uint32; + auto ROR(uint32, uint8) -> uint32; + auto RRX(uint32) -> uint32; + auto SUB(uint32, uint32, bool) -> uint32; + auto TST(uint4) -> bool; + + //instruction.cpp + auto fetch() -> void; + auto instruction() -> void; + auto exception(uint mode, uint32 address) -> void; + auto armInitialize() -> void; + auto thumbInitialize() -> void; + + //instructions-arm.cpp + auto armALU(uint4 mode, uint4 target, uint4 source, uint32 data) -> void; + auto armMoveToStatus(uint4 field, uint1 source, uint32 data) -> void; + + auto armInstructionBranch(int24, uint1) -> void; + auto armInstructionBranchExchangeRegister(uint4) -> void; + auto armInstructionDataImmediate(uint8, uint4, uint4, uint4, uint1, uint4) -> void; + auto armInstructionDataImmediateShift(uint4, uint2, uint5, uint4, uint4, uint1, uint4) -> void; + auto armInstructionDataRegisterShift(uint4, uint2, uint4, uint4, uint4, uint1, uint4) -> void; + auto armInstructionLoadImmediate(uint8, uint1, uint4, uint4, uint1, uint1, uint1) -> void; + auto armInstructionLoadRegister(uint4, uint1, uint4, uint4, uint1, uint1, uint1) -> void; + auto armInstructionMemorySwap(uint4, uint4, uint4, uint1) -> void; + auto armInstructionMoveHalfImmediate(uint8, uint4, uint4, uint1, uint1, uint1, uint1) -> void; + auto armInstructionMoveHalfRegister(uint4, uint4, uint4, uint1, uint1, uint1, uint1) -> void; + auto armInstructionMoveImmediateOffset(uint12, uint4, uint4, uint1, uint1, uint1, uint1, uint1) -> void; + auto armInstructionMoveMultiple(uint16, uint4, uint1, uint1, uint1, uint1, uint1) -> void; + auto armInstructionMoveRegisterOffset(uint4, uint2, uint5, uint4, uint4, uint1, uint1, uint1, uint1, uint1) -> void; + auto armInstructionMoveToRegisterFromStatus(uint4, uint1) -> void; + auto armInstructionMoveToStatusFromImmediate(uint8, uint4, uint4, uint1) -> void; + auto armInstructionMoveToStatusFromRegister(uint4, uint4, uint1) -> void; + auto armInstructionMultiply(uint4, uint4, uint4, uint4, uint1, uint1) -> void; + auto armInstructionMultiplyLong(uint4, uint4, uint4, uint4, uint1, uint1, uint1) -> void; + auto armInstructionSoftwareInterrupt(uint24 immediate) -> void; + auto armInstructionUndefined() -> void; + + //instructions-thumb.cpp + auto thumbInstructionALU(uint3, uint3, uint4) -> void; + auto thumbInstructionALUExtended(uint4, uint4, uint2) -> void; + auto thumbInstructionAddRegister(uint8, uint3, uint1) -> void; + auto thumbInstructionAdjustImmediate(uint3, uint3, uint3, uint1) -> void; + auto thumbInstructionAdjustRegister(uint3, uint3, uint3, uint1) -> void; + auto thumbInstructionAdjustStack(uint7, uint1) -> void; + auto thumbInstructionBranchExchange(uint4) -> void; + auto thumbInstructionBranchFarPrefix(int11) -> void; + auto thumbInstructionBranchFarSuffix(uint11) -> void; + auto thumbInstructionBranchNear(int11) -> void; + auto thumbInstructionBranchTest(int8, uint4) -> void; + auto thumbInstructionImmediate(uint8, uint3, uint2) -> void; + auto thumbInstructionLoadLiteral(uint8, uint3) -> void; + auto thumbInstructionMoveByteImmediate(uint3, uint3, uint5, uint1) -> void; + auto thumbInstructionMoveHalfImmediate(uint3, uint3, uint5, uint1) -> void; + auto thumbInstructionMoveMultiple(uint8, uint3, uint1) -> void; + auto thumbInstructionMoveRegisterOffset(uint3, uint3, uint3, uint3) -> void; + auto thumbInstructionMoveStack(uint8, uint3, uint1) -> void; + auto thumbInstructionMoveWordImmediate(uint3, uint3, uint5, uint1) -> void; + auto thumbInstructionShiftImmediate(uint3, uint3, uint5, uint2) -> void; + auto thumbInstructionSoftwareInterrupt(uint8) -> void; + auto thumbInstructionStackMultiple(uint8, uint1, uint1) -> void; + auto thumbInstructionUndefined() -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + //disassembler.cpp + auto disassemble(maybe pc = nothing, maybe thumb = nothing) -> string; + auto disassembleRegisters() -> string; + + struct GPR { + inline operator uint32_t() const { return data; } + inline auto operator=(const GPR& value) -> GPR& { return operator=(value.data); } + + inline auto operator=(uint32 value) -> GPR& { + data = value; + if(modify) modify(); + return *this; + } + + uint32 data; + function void> modify; + }; + + struct PSR { + enum : uint { + USR = 0x10, //user + FIQ = 0x11, //fast interrupt + IRQ = 0x12, //interrupt + SVC = 0x13, //service + ABT = 0x17, //abort + UND = 0x1b, //undefined + SYS = 0x1f, //system + }; + + inline operator uint32_t() const { + return m << 0 | t << 5 | f << 6 | i << 7 | v << 28 | c << 29 | z << 30 | n << 31; + } + + inline auto operator=(uint32 data) -> PSR& { + m = data >> 0 & 31; + t = data >> 5 & 1; + f = data >> 6 & 1; + i = data >> 7 & 1; + v = data >> 28 & 1; + c = data >> 29 & 1; + z = data >> 30 & 1; + n = data >> 31 & 1; + return *this; + } + + //serialization.cpp + auto serialize(serializer&) -> void; + + uint5 m; //mode + boolean t; //thumb + boolean f; //fiq + boolean i; //irq + boolean v; //overflow + boolean c; //carry + boolean z; //zero + boolean n; //negative + }; + + struct Processor { + //serialization.cpp + auto serialize(serializer&) -> void; + + GPR r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15; + PSR cpsr; + + struct FIQ { + GPR r8, r9, r10, r11, r12, r13, r14; + PSR spsr; + } fiq; + + struct IRQ { + GPR r13, r14; + PSR spsr; + } irq; + + struct SVC { + GPR r13, r14; + PSR spsr; + } svc; + + struct ABT { + GPR r13, r14; + PSR spsr; + } abt; + + struct UND { + GPR r13, r14; + PSR spsr; + } und; + } processor; + + struct Pipeline { + //serialization.cpp + auto serialize(serializer&) -> void; + + struct Instruction { + uint32 address; + uint32 instruction; + boolean thumb; //not used by fetch stage + }; + + uint1 reload = 1; + uint1 nonsequential = 1; + Instruction fetch; + Instruction decode; + Instruction execute; + } pipeline; + + uint32 opcode; + boolean carry; + boolean irq; + + function void> armInstruction[4096]; + function void> thumbInstruction[65536]; + + //disassembler.cpp + auto armDisassembleBranch(int24, uint1) -> string; + auto armDisassembleBranchExchangeRegister(uint4) -> string; + auto armDisassembleDataImmediate(uint8, uint4, uint4, uint4, uint1, uint4) -> string; + auto armDisassembleDataImmediateShift(uint4, uint2, uint5, uint4, uint4, uint1, uint4) -> string; + auto armDisassembleDataRegisterShift(uint4, uint2, uint4, uint4, uint4, uint1, uint4) -> string; + auto armDisassembleLoadImmediate(uint8, uint1, uint4, uint4, uint1, uint1, uint1) -> string; + auto armDisassembleLoadRegister(uint4, uint1, uint4, uint4, uint1, uint1, uint1) -> string; + auto armDisassembleMemorySwap(uint4, uint4, uint4, uint1) -> string; + auto armDisassembleMoveHalfImmediate(uint8, uint4, uint4, uint1, uint1, uint1, uint1) -> string; + auto armDisassembleMoveHalfRegister(uint4, uint4, uint4, uint1, uint1, uint1, uint1) -> string; + auto armDisassembleMoveImmediateOffset(uint12, uint4, uint4, uint1, uint1, uint1, uint1, uint1) -> string; + auto armDisassembleMoveMultiple(uint16, uint4, uint1, uint1, uint1, uint1, uint1) -> string; + auto armDisassembleMoveRegisterOffset(uint4, uint2, uint5, uint4, uint4, uint1, uint1, uint1, uint1, uint1) -> string; + auto armDisassembleMoveToRegisterFromStatus(uint4, uint1) -> string; + auto armDisassembleMoveToStatusFromImmediate(uint8, uint4, uint4, uint1) -> string; + auto armDisassembleMoveToStatusFromRegister(uint4, uint4, uint1) -> string; + auto armDisassembleMultiply(uint4, uint4, uint4, uint4, uint1, uint1) -> string; + auto armDisassembleMultiplyLong(uint4, uint4, uint4, uint4, uint1, uint1, uint1) -> string; + auto armDisassembleSoftwareInterrupt(uint24) -> string; + auto armDisassembleUndefined() -> string; + + auto thumbDisassembleALU(uint3, uint3, uint4) -> string; + auto thumbDisassembleALUExtended(uint4, uint4, uint2) -> string; + auto thumbDisassembleAddRegister(uint8, uint3, uint1) -> string; + auto thumbDisassembleAdjustImmediate(uint3, uint3, uint3, uint1) -> string; + auto thumbDisassembleAdjustRegister(uint3, uint3, uint3, uint1) -> string; + auto thumbDisassembleAdjustStack(uint7, uint1) -> string; + auto thumbDisassembleBranchExchange(uint4) -> string; + auto thumbDisassembleBranchFarPrefix(int11) -> string; + auto thumbDisassembleBranchFarSuffix(uint11) -> string; + auto thumbDisassembleBranchNear(int11) -> string; + auto thumbDisassembleBranchTest(int8, uint4) -> string; + auto thumbDisassembleImmediate(uint8, uint3, uint2) -> string; + auto thumbDisassembleLoadLiteral(uint8, uint3) -> string; + auto thumbDisassembleMoveByteImmediate(uint3, uint3, uint5, uint1) -> string; + auto thumbDisassembleMoveHalfImmediate(uint3, uint3, uint5, uint1) -> string; + auto thumbDisassembleMoveMultiple(uint8, uint3, uint1) -> string; + auto thumbDisassembleMoveRegisterOffset(uint3, uint3, uint3, uint3) -> string; + auto thumbDisassembleMoveStack(uint8, uint3, uint1) -> string; + auto thumbDisassembleMoveWordImmediate(uint3, uint3, uint5, uint1) -> string; + auto thumbDisassembleShiftImmediate(uint3, uint3, uint5, uint2) -> string; + auto thumbDisassembleSoftwareInterrupt(uint8) -> string; + auto thumbDisassembleStackMultiple(uint8, uint1, uint1) -> string; + auto thumbDisassembleUndefined() -> string; + + function string> armDisassemble[4096]; + function string> thumbDisassemble[65536]; + + uint32 _pc; + string _c; +}; + +} diff --git a/processor/arm7tdmi/disassembler.cpp b/processor/arm7tdmi/disassembler.cpp new file mode 100644 index 0000000..6f70097 --- /dev/null +++ b/processor/arm7tdmi/disassembler.cpp @@ -0,0 +1,413 @@ +static const string _r[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" +}; +static const string _conditions[] = { + "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "", "nv", +}; +#define _s save ? "s" : "" +#define _move(mode) (mode == 13 || mode == 15) +#define _comp(mode) (mode >= 8 && mode <= 11) +#define _math(mode) (mode <= 7 || mode == 12 || mode == 14) + +auto ARM7TDMI::disassemble(maybe pc, maybe thumb) -> string { + if(!pc) pc = pipeline.execute.address; + if(!thumb) thumb = cpsr().t; + + _pc = pc(); + if(!thumb()) { + uint32 opcode = read(Word | Nonsequential, _pc & ~3); + uint12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4; + _c = _conditions[opcode >> 28]; + return {hex(_pc, 8L), " ", armDisassemble[index](opcode)}; + } else { + uint16 opcode = read(Half | Nonsequential, _pc & ~1); + return {hex(_pc, 8L), " ", thumbDisassemble[opcode]()}; + } +} + +auto ARM7TDMI::disassembleRegisters() -> string { + string output; + for(uint n : range(16)) { + output.append(_r[n], ":", hex(r(n), 8L), " "); + } + + output.append("cpsr:"); + output.append(cpsr().n ? "N" : "n"); + output.append(cpsr().z ? "Z" : "z"); + output.append(cpsr().c ? "C" : "c"); + output.append(cpsr().v ? "V" : "v", "/"); + output.append(cpsr().i ? "I" : "i"); + output.append(cpsr().f ? "F" : "f"); + output.append(cpsr().t ? "T" : "t", "/"); + output.append(hex(cpsr().m, 2L)); + if(cpsr().m == PSR::USR || cpsr().m == PSR::SYS) return output; + + output.append(" spsr:"); + output.append(spsr().n ? "N" : "n"); + output.append(spsr().z ? "Z" : "z"); + output.append(spsr().c ? "C" : "c"); + output.append(spsr().v ? "V" : "v", "/"); + output.append(spsr().i ? "I" : "i"); + output.append(spsr().f ? "F" : "f"); + output.append(spsr().t ? "T" : "t", "/"); + output.append(hex(spsr().m, 2L)); + return output; +} + +// + +auto ARM7TDMI::armDisassembleBranch +(int24 displacement, uint1 link) -> string { + return {"b", link ? "l" : "", _c, " 0x", hex(_pc + 8 + displacement * 4, 8L)}; +} + +auto ARM7TDMI::armDisassembleBranchExchangeRegister +(uint4 m) -> string { + return {"bx", _c, " ", _r[m]}; +} + +auto ARM7TDMI::armDisassembleDataImmediate +(uint8 immediate, uint4 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> string { + static const string opcode[] = { + "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", + "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn", + }; + uint32 data = immediate >> (shift << 1) | immediate << 32 - (shift << 1); + return {opcode[mode], _c, + _move(mode) ? string{_s, " ", _r[d]} : string{}, + _comp(mode) ? string{" ", _r[n]} : string{}, + _math(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{}, + ",#0x", hex(data, 8L)}; +} + +auto ARM7TDMI::armDisassembleDataImmediateShift +(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> string { + static const string opcode[] = { + "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", + "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn", + }; + return {opcode[mode], _c, + _move(mode) ? string{_s, " ", _r[d]} : string{}, + _comp(mode) ? string{" ", _r[n]} : string{}, + _math(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{}, + ",", _r[m], + type == 0 && shift ? string{" lsl #", shift} : string{}, + type == 1 ? string{" lsr #", shift ? (uint)shift : 32} : string{}, + type == 2 ? string{" asr #", shift ? (uint)shift : 32} : string{}, + type == 3 && shift ? string{" ror #", shift} : string{}, + type == 3 && !shift ? " rrx" : ""}; +} + +auto ARM7TDMI::armDisassembleDataRegisterShift +(uint4 m, uint2 type, uint4 s, uint4 d, uint4 n, uint1 save, uint4 mode) -> string { + static const string opcode[] = { + "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", + "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn", + }; + return {opcode[mode], _c, + _move(mode) ? string{_s, " ", _r[d]} : string{}, + _comp(mode) ? string{" ", _r[n]} : string{}, + _math(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{}, + ",", _r[m], " ", + type == 0 ? "lsl" : "", + type == 1 ? "lsr" : "", + type == 2 ? "asr" : "", + type == 3 ? "ror" : "", + " ", _r[s]}; +} + +auto ARM7TDMI::armDisassembleLoadImmediate +(uint8 immediate, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> string { + string data; + if(n == 15) data = {" =0x", hex(read((half ? Half : Byte) | Nonsequential, + _pc + 8 + (up ? +immediate : -immediate)), half ? 4L : 2L)}; + + return {"ldr", _c, half ? "sh" : "sb", " ", + _r[d], ",[", _r[n], + pre == 0 ? "]" : "", + immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{}, + pre == 1 ? "]" : "", + pre == 0 || writeback ? "!" : "", data}; +} + +auto ARM7TDMI::armDisassembleLoadRegister +(uint4 m, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> string { + return {"ldr", _c, half ? "sh" : "sb", " ", + _r[d], ",[", _r[n], + pre == 0 ? "]" : "", + ",", up ? "+" : "-", _r[m], + pre == 1 ? "]" : "", + pre == 0 || writeback ? "!" : ""}; +} + +auto ARM7TDMI::armDisassembleMemorySwap +(uint4 m, uint4 d, uint4 n, uint1 byte) -> string { + return {"swp", _c, byte ? "b" : "", " ", _r[d], ",", _r[m], ",[", _r[n], "]"}; +} + +auto ARM7TDMI::armDisassembleMoveHalfImmediate +(uint8 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> string { + string data; + if(n == 15) data = {" =0x", hex(read(Half | Nonsequential, _pc + (up ? +immediate : -immediate)), 4L)}; + + return {mode ? "ldr" : "str", _c, "h ", + _r[d], ",[", _r[n], + pre == 0 ? "]" : "", + immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{}, + pre == 1 ? "]" : "", + pre == 0 || writeback ? "!" : "", data}; +} + +auto ARM7TDMI::armDisassembleMoveHalfRegister +(uint4 m, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> string { + return {mode ? "ldr" : "str", _c, "h ", + _r[d], ",[", _r[n], + pre == 0 ? "]" : "", + ",", up ? "+" : "-", _r[m], + pre == 1 ? "]" : "", + pre == 0 || writeback ? "!" : ""}; +} + +auto ARM7TDMI::armDisassembleMoveImmediateOffset +(uint12 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> string { + string data; + if(n == 15) data = {" =0x", hex(read((byte ? Byte : Word) | Nonsequential, + _pc + 8 + (up ? +immediate : -immediate)), byte ? 2L : 4L)}; + return {mode ? "ldr" : "str", _c, byte ? "b" : "", " ", _r[d], ",[", _r[n], + pre == 0 ? "]" : "", + immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 3L)} : string{}, + pre == 1 ? "]" : "", + pre == 0 || writeback ? "!" : "", data}; +} + +auto ARM7TDMI::armDisassembleMoveMultiple +(uint16 list, uint4 n, uint1 mode, uint1 writeback, uint1 type, uint1 up, uint1 pre) -> string { + string registers; + for(auto index : range(16)) { + if((list & 1 << index)) registers.append(_r[index], ","); + } + registers.trimRight(",", 1L); + return {mode ? "ldm" : "stm", _c, + up == 0 && pre == 0 ? "da" : "", + up == 0 && pre == 1 ? "db" : "", + up == 1 && pre == 0 ? "ia" : "", + up == 1 && pre == 1 ? "ib" : "", + " ", _r[n], writeback ? "!" : "", + ",{", registers, "}", type ? "^" : ""}; +} + +auto ARM7TDMI::armDisassembleMoveRegisterOffset +(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> string { + return {mode ? "ldr" : "str", _c, byte ? "b" : "", " ", _r[d], ",[", _r[n], + pre == 0 ? "]" : "", + ",", up ? "+" : "-", _r[m], + type == 0 && shift ? string{" lsl #", shift} : string{}, + type == 1 ? string{" lsr #", shift ? (uint)shift : 32} : string{}, + type == 2 ? string{" asr #", shift ? (uint)shift : 32} : string{}, + type == 3 && shift ? string{" ror #", shift} : string{}, + type == 3 && !shift ? " rrx" : "", + pre == 1 ? "]" : "", + pre == 0 || writeback ? "!" : ""}; +} + +auto ARM7TDMI::armDisassembleMoveToRegisterFromStatus +(uint4 d, uint1 mode) -> string { + return {"mrs", _c, " ", _r[d], ",", mode ? "spsr" : "cpsr"}; +} + +auto ARM7TDMI::armDisassembleMoveToStatusFromImmediate +(uint8 immediate, uint4 rotate, uint4 field, uint1 mode) -> string { + uint32 data = immediate >> (rotate << 1) | immediate << 32 - (rotate << 1); + return {"msr", _c, " ", mode ? "spsr:" : "cpsr:", + field.bit(0) ? "c" : "", + field.bit(1) ? "x" : "", + field.bit(2) ? "s" : "", + field.bit(3) ? "f" : "", + ",#0x", hex(data, 8L)}; +} + +auto ARM7TDMI::armDisassembleMoveToStatusFromRegister +(uint4 m, uint4 field, uint1 mode) -> string { + return {"msr", _c, " ", mode ? "spsr:" : "cpsr:", + field.bit(0) ? "c" : "", + field.bit(1) ? "x" : "", + field.bit(2) ? "s" : "", + field.bit(3) ? "f" : "", + ",", _r[m]}; +} + +auto ARM7TDMI::armDisassembleMultiply +(uint4 m, uint4 s, uint4 n, uint4 d, uint1 save, uint1 accumulate) -> string { + if(accumulate) { + return {"mla", _c, _s, " ", _r[d], ",", _r[m], ",", _r[s], ",", _r[n]}; + } else { + return {"mul", _c, _s, " ", _r[d], ",", _r[m], ",", _r[s]}; + } +} + +auto ARM7TDMI::armDisassembleMultiplyLong +(uint4 m, uint4 s, uint4 l, uint4 h, uint1 save, uint1 accumulate, uint1 sign) -> string { + return {sign ? "s" : "u", accumulate ? "mlal" : "mull", _c, _s, " ", + _r[l], ",", _r[h], ",", _r[m], ",", _r[s]}; +} + +auto ARM7TDMI::armDisassembleSoftwareInterrupt +(uint24 immediate) -> string { + return {"swi #0x", hex(immediate, 6L)}; +} + +auto ARM7TDMI::armDisassembleUndefined +() -> string { + return {"undefined"}; +} + +// + +auto ARM7TDMI::thumbDisassembleALU +(uint3 d, uint3 m, uint4 mode) -> string { + static const string opcode[] = { + "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", + "tst", "neg", "cmp", "cmn", "orr", "mul", "bic", "mvn", + }; + return {opcode[mode], " ", _r[d], ",", _r[m]}; +} + +auto ARM7TDMI::thumbDisassembleALUExtended +(uint4 d, uint4 m, uint2 mode) -> string { + static const string opcode[] = {"add", "sub", "mov"}; + if(d == 8 && m == 8 && mode == 2) return {"nop"}; + return {opcode[mode], " ", _r[d], ",", _r[m]}; +} + +auto ARM7TDMI::thumbDisassembleAddRegister +(uint8 immediate, uint3 d, uint1 mode) -> string { + return {"add ", _r[d], ",", mode ? "sp" : "pc", ",#0x", hex(immediate, 2L)}; +} + +auto ARM7TDMI::thumbDisassembleAdjustImmediate +(uint3 d, uint3 n, uint3 immediate, uint1 mode) -> string { + return {!mode ? "add" : "sub", " ", _r[d], ",", _r[n], ",#", immediate}; +} + +auto ARM7TDMI::thumbDisassembleAdjustRegister +(uint3 d, uint3 n, uint3 m, uint1 mode) -> string { + return {!mode ? "add" : "sub", " ", _r[d], ",", _r[n], ",", _r[m]}; +} + +auto ARM7TDMI::thumbDisassembleAdjustStack +(uint7 immediate, uint1 mode) -> string { + return {!mode ? "add" : "sub", " sp,#0x", hex(immediate * 4, 3L)}; +} + +auto ARM7TDMI::thumbDisassembleBranchExchange +(uint4 m) -> string { + return {"bx ", _r[m]}; +} + +auto ARM7TDMI::thumbDisassembleBranchFarPrefix +(int11 displacementHi) -> string { + uint11 displacementLo = read(Half | Nonsequential, (_pc & ~1) + 2); + int22 displacement = displacementHi << 11 | displacementLo << 0; + uint32 address = _pc + 4 + displacement * 2; + return {"bl 0x", hex(address, 8L)}; +} + +auto ARM7TDMI::thumbDisassembleBranchFarSuffix +(uint11 displacement) -> string { + return {"bl (suffix)"}; +} + +auto ARM7TDMI::thumbDisassembleBranchNear +(int11 displacement) -> string { + uint32 address = _pc + 4 + displacement * 2; + return {"b 0x", hex(address, 8L)}; +} + +auto ARM7TDMI::thumbDisassembleBranchTest +(int8 displacement, uint4 condition) -> string { + uint32 address = _pc + 4 + displacement * 2; + return {"b", _conditions[condition], " 0x", hex(address, 8L)}; +} + +auto ARM7TDMI::thumbDisassembleImmediate +(uint8 immediate, uint3 d, uint2 mode) -> string { + static const string opcode[] = {"mov", "cmp", "add", "sub"}; + return {opcode[mode], " ", _r[d], ",#0x", hex(immediate, 2L)}; +} + +auto ARM7TDMI::thumbDisassembleLoadLiteral +(uint8 displacement, uint3 d) -> string { + uint32 address = ((_pc + 4) & ~3) + (displacement << 2); + uint32 data = read(Word | Nonsequential, address); + return {"ldr ", _r[d], ",[pc,#0x", hex(address, 8L), "] =0x", hex(data, 8L)}; +} + +auto ARM7TDMI::thumbDisassembleMoveByteImmediate +(uint3 d, uint3 n, uint5 offset, uint1 mode) -> string { + return {mode ? "ldrb" : "strb", " ", _r[d], ",[", _r[n], ",#0x", hex(offset, 2L), "]"}; +} + +auto ARM7TDMI::thumbDisassembleMoveHalfImmediate +(uint3 d, uint3 n, uint5 offset, uint1 mode) -> string { + return {mode ? "ldrh" : "strh", " ", _r[d], ",[", _r[n], ",#0x", hex(offset * 2, 2L), "]"}; +} + +auto ARM7TDMI::thumbDisassembleMoveMultiple +(uint8 list, uint3 n, uint1 mode) -> string { + string registers; + for(uint m : range(8)) { + if((list & 1 << m)) registers.append(_r[m], ","); + } + registers.trimRight(",", 1L); + return {mode ? "ldmia" : "stmia", " ", _r[n], "!,{", registers, "}"}; +} + +auto ARM7TDMI::thumbDisassembleMoveRegisterOffset +(uint3 d, uint3 n, uint3 m, uint3 mode) -> string { + static const string opcode[] = {"str", "strh", "strb", "ldsb", "ldr", "ldrh", "ldrb", "ldsh"}; + return {opcode[mode], " ", _r[d], ",[", _r[n], ",", _r[m], "]"}; +} + +auto ARM7TDMI::thumbDisassembleMoveStack +(uint8 immediate, uint3 d, uint1 mode) -> string { + return {mode ? "ldr" : "str", " ", _r[d], ",[sp,#0x", hex(immediate * 4, 3L), "]"}; +} + +auto ARM7TDMI::thumbDisassembleMoveWordImmediate +(uint3 d, uint3 n, uint5 offset, uint1 mode) -> string { + return {mode ? "ldr" : "str", " ", _r[d], ",[", _r[n], ",#0x", hex(offset * 4, 2L), "]"}; +} + +auto ARM7TDMI::thumbDisassembleShiftImmediate +(uint3 d, uint3 m, uint5 immediate, uint2 mode) -> string { + static const string opcode[] = {"lsl", "lsr", "asr"}; + return {opcode[mode], " ", _r[d], ",", _r[m], ",#", immediate}; +} + +auto ARM7TDMI::thumbDisassembleSoftwareInterrupt +(uint8 immediate) -> string { + return {"swi #0x", hex(immediate, 2L)}; +} + +auto ARM7TDMI::thumbDisassembleStackMultiple +(uint8 list, uint1 lrpc, uint1 mode) -> string { + string registers; + for(uint m : range(8)) { + if((list & 1 << m)) registers.append(_r[m], ","); + } + if(lrpc) registers.append(!mode ? "lr," : "pc,"); + registers.trimRight(",", 1L); + return {!mode ? "push" : "pop", " {", registers, "}"}; +} + +auto ARM7TDMI::thumbDisassembleUndefined +() -> string { + return {"undefined"}; +} + +#undef _s +#undef _move +#undef _comp +#undef _save diff --git a/processor/arm7tdmi/instruction.cpp b/processor/arm7tdmi/instruction.cpp new file mode 100644 index 0000000..f622b0e --- /dev/null +++ b/processor/arm7tdmi/instruction.cpp @@ -0,0 +1,544 @@ +auto ARM7TDMI::fetch() -> void { + pipeline.execute = pipeline.decode; + pipeline.decode = pipeline.fetch; + pipeline.decode.thumb = cpsr().t; + + uint sequential = Sequential; + if(pipeline.nonsequential) { + pipeline.nonsequential = false; + sequential = Nonsequential; + } + + uint mask = !cpsr().t ? 3 : 1; + uint size = !cpsr().t ? Word : Half; + + r(15).data += size >> 3; + pipeline.fetch.address = r(15) & ~mask; + pipeline.fetch.instruction = read(Prefetch | size | sequential, pipeline.fetch.address); +} + +auto ARM7TDMI::instruction() -> void { + uint mask = !cpsr().t ? 3 : 1; + uint size = !cpsr().t ? Word : Half; + + if(pipeline.reload) { + pipeline.reload = false; + r(15).data &= ~mask; + pipeline.fetch.address = r(15) & ~mask; + pipeline.fetch.instruction = read(Prefetch | size | Nonsequential, pipeline.fetch.address); + fetch(); + } + fetch(); + + if(irq && !cpsr().i) { + exception(PSR::IRQ, 0x18); + if(pipeline.execute.thumb) r(14).data += 2; + return; + } + + opcode = pipeline.execute.instruction; + if(!pipeline.execute.thumb) { + if(!TST(opcode >> 28)) return; + uint12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4; + armInstruction[index](opcode); + } else { + thumbInstruction[(uint16)opcode](); + } +} + +auto ARM7TDMI::exception(uint mode, uint32 address) -> void { + auto psr = cpsr(); + cpsr().m = mode; + spsr() = psr; + cpsr().t = 0; + if(cpsr().m == PSR::FIQ) cpsr().f = 1; + cpsr().i = 1; + r(14) = pipeline.decode.address; + r(15) = address; +} + +auto ARM7TDMI::armInitialize() -> void { + #define bind(id, name, ...) { \ + uint index = (id & 0x0ff00000) >> 16 | (id & 0x000000f0) >> 4; \ + assert(!armInstruction[index]); \ + armInstruction[index] = [&](uint32 opcode) { return armInstruction##name(arguments); }; \ + armDisassemble[index] = [&](uint32 opcode) { return armDisassemble##name(arguments); }; \ + } + + #define pattern(s) \ + std::integral_constant::value + + #define bit1(value, index) (value >> index & 1) + #define bits(value, lo, hi) (value >> lo & (1ull << (hi - lo + 1)) - 1) + + #define arguments \ + bits(opcode, 0,23), /* displacement */ \ + bit1(opcode,24) /* link */ + for(uint4 displacementLo : range(16)) + for(uint4 displacementHi : range(16)) + for(uint1 link : range(2)) { + auto opcode = pattern(".... 101? ???? ???? ???? ???? ???? ????") + | displacementLo << 4 | displacementHi << 20 | link << 24; + bind(opcode, Branch); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3) /* m */ + { + auto opcode = pattern(".... 0001 0010 ---- ---- ---- 0001 ????"); + bind(opcode, BranchExchangeRegister); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 7), /* immediate */ \ + bits(opcode, 8,11), /* shift */ \ + bits(opcode,12,15), /* d */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,20), /* save */ \ + bits(opcode,21,24) /* mode */ + for(uint4 shiftHi : range(16)) + for(uint1 save : range(2)) + for(uint4 mode : range(16)) { + if(mode >= 8 && mode <= 11 && !save) continue; //TST, TEQ, CMP, CMN + auto opcode = pattern(".... 001? ???? ???? ???? ???? ???? ????") | shiftHi << 4 | save << 20 | mode << 21; + bind(opcode, DataImmediate); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3), /* m */ \ + bits(opcode, 5, 6), /* type */ \ + bits(opcode, 7,11), /* shift */ \ + bits(opcode,12,15), /* d */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,20), /* save */ \ + bits(opcode,21,24) /* mode */ + for(uint2 type : range(4)) + for(uint1 shiftLo : range(2)) + for(uint1 save : range(2)) + for(uint4 mode : range(16)) { + if(mode >= 8 && mode <= 11 && !save) continue; //TST, TEQ, CMP, CMN + auto opcode = pattern(".... 000? ???? ???? ???? ???? ???0 ????") | type << 5 | shiftLo << 7 | save << 20 | mode << 21; + bind(opcode, DataImmediateShift); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3), /* m */ \ + bits(opcode, 5, 6), /* type */ \ + bits(opcode, 8,11), /* s */ \ + bits(opcode,12,15), /* d */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,20), /* save */ \ + bits(opcode,21,24) /* mode */ + for(uint2 type : range(4)) + for(uint1 save : range(2)) + for(uint4 mode : range(16)) { + if(mode >= 8 && mode <= 11 && !save) continue; //TST, TEQ, CMP, CMN + auto opcode = pattern(".... 000? ???? ???? ???? ???? 0??1 ????") | type << 5 | save << 20 | mode << 21; + bind(opcode, DataRegisterShift); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3) << 0 | bits(opcode, 8,11) << 4, /* immediate */ \ + bit1(opcode, 5), /* half */ \ + bits(opcode,12,15), /* d */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,21), /* writeback */ \ + bit1(opcode,23), /* up */ \ + bit1(opcode,24) /* pre */ + for(uint1 half : range(2)) + for(uint1 writeback : range(2)) + for(uint1 up : range(2)) + for(uint1 pre : range(2)) { + auto opcode = pattern(".... 000? ?1?1 ???? ???? ???? 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24; + bind(opcode, LoadImmediate); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3), /* m */ \ + bit1(opcode, 5), /* half */ \ + bits(opcode,12,15), /* d */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,21), /* writeback */ \ + bit1(opcode,23), /* up */ \ + bit1(opcode,24) /* pre */ + for(uint1 half : range(2)) + for(uint1 writeback : range(2)) + for(uint1 up : range(2)) + for(uint1 pre : range(2)) { + auto opcode = pattern(".... 000? ?0?1 ???? ???? ---- 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24; + bind(opcode, LoadRegister); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3), /* m */ \ + bits(opcode,12,15), /* d */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,22) /* byte */ + for(uint1 byte : range(2)) { + auto opcode = pattern(".... 0001 0?00 ???? ???? ---- 1001 ????") | byte << 22; + bind(opcode, MemorySwap); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3) << 0 | bits(opcode, 8,11) << 4, /* immediate */ \ + bits(opcode,12,15), /* d */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,20), /* mode */ \ + bit1(opcode,21), /* writeback */ \ + bit1(opcode,23), /* up */ \ + bit1(opcode,24) /* pre */ + for(uint1 mode : range(2)) + for(uint1 writeback : range(2)) + for(uint1 up : range(2)) + for(uint1 pre : range(2)) { + auto opcode = pattern(".... 000? ?1?? ???? ???? ???? 1011 ????") | mode << 20 | writeback << 21 | up << 23 | pre << 24; + bind(opcode, MoveHalfImmediate); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3), /* m */ \ + bits(opcode,12,15), /* d */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,20), /* mode */ \ + bit1(opcode,21), /* writeback */ \ + bit1(opcode,23), /* up */ \ + bit1(opcode,24) /* pre */ + for(uint1 mode : range(2)) + for(uint1 writeback : range(2)) + for(uint1 up : range(2)) + for(uint1 pre : range(2)) { + auto opcode = pattern(".... 000? ?0?? ???? ???? ---- 1011 ????") | mode << 20 | writeback << 21 | up << 23 | pre << 24; + bind(opcode, MoveHalfRegister); + } + #undef arguments + + #define arguments \ + bits(opcode, 0,11), /* immediate */ \ + bits(opcode,12,15), /* d */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,20), /* mode */ \ + bit1(opcode,21), /* writeback */ \ + bit1(opcode,22), /* byte */ \ + bit1(opcode,23), /* up */ \ + bit1(opcode,24) /* pre */ + for(uint4 immediatePart : range(16)) + for(uint1 mode : range(2)) + for(uint1 writeback : range(2)) + for(uint1 byte : range(2)) + for(uint1 up : range(2)) + for(uint1 pre : range(2)) { + auto opcode = pattern(".... 010? ???? ???? ???? ???? ???? ????") + | immediatePart << 4 | mode << 20 | writeback << 21 | byte << 22 | up << 23 | pre << 24; + bind(opcode, MoveImmediateOffset); + } + #undef arguments + + #define arguments \ + bits(opcode, 0,15), /* list */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,20), /* mode */ \ + bit1(opcode,21), /* writeback */ \ + bit1(opcode,22), /* type */ \ + bit1(opcode,23), /* up */ \ + bit1(opcode,24) /* pre */ + for(uint4 listPart : range(16)) + for(uint1 mode : range(2)) + for(uint1 writeback : range(2)) + for(uint1 type : range(2)) + for(uint1 up : range(2)) + for(uint1 pre : range(2)) { + auto opcode = pattern(".... 100? ???? ???? ???? ???? ???? ????") + | listPart << 4 | mode << 20 | writeback << 21 | type << 22 | up << 23 | pre << 24; + bind(opcode, MoveMultiple); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3), /* m */ \ + bits(opcode, 5, 6), /* type */ \ + bits(opcode, 7,11), /* shift */ \ + bits(opcode,12,15), /* d */ \ + bits(opcode,16,19), /* n */ \ + bit1(opcode,20), /* mode */ \ + bit1(opcode,21), /* writeback */ \ + bit1(opcode,22), /* byte */ \ + bit1(opcode,23), /* up */ \ + bit1(opcode,24) /* pre */ + for(uint2 type : range(4)) + for(uint1 shiftLo : range(2)) + for(uint1 mode : range(2)) + for(uint1 writeback : range(2)) + for(uint1 byte : range(2)) + for(uint1 up : range(2)) + for(uint1 pre : range(2)) { + auto opcode = pattern(".... 011? ???? ???? ???? ???? ???0 ????") + | type << 5 | shiftLo << 7 | mode << 20 | writeback << 21 | byte << 22 | up << 23 | pre << 24; + bind(opcode, MoveRegisterOffset); + } + #undef arguments + + #define arguments \ + bits(opcode,12,15), /* d */ \ + bit1(opcode,22) /* mode */ + for(uint1 mode : range(2)) { + auto opcode = pattern(".... 0001 0?00 ---- ???? ---- 0000 ----") | mode << 22; + bind(opcode, MoveToRegisterFromStatus); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 7), /* immediate */ \ + bits(opcode, 8,11), /* rotate */ \ + bits(opcode,16,19), /* field */ \ + bit1(opcode,22) /* mode */ + for(uint4 immediateHi : range(16)) + for(uint1 mode : range(2)) { + auto opcode = pattern(".... 0011 0?10 ???? ---- ???? ???? ????") | immediateHi << 4 | mode << 22; + bind(opcode, MoveToStatusFromImmediate); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3), /* m */ \ + bits(opcode,16,19), /* field */ \ + bit1(opcode,22) /* mode */ + for(uint1 mode : range(2)) { + auto opcode = pattern(".... 0001 0?10 ???? ---- ---- 0000 ????") | mode << 22; + bind(opcode, MoveToStatusFromRegister); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3), /* m */ \ + bits(opcode, 8,11), /* s */ \ + bits(opcode,12,15), /* n */ \ + bits(opcode,16,19), /* d */ \ + bit1(opcode,20), /* save */ \ + bit1(opcode,21) /* accumulate */ + for(uint1 save : range(2)) + for(uint1 accumulate : range(2)) { + auto opcode = pattern(".... 0000 00?? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21; + bind(opcode, Multiply); + } + #undef arguments + + #define arguments \ + bits(opcode, 0, 3), /* m */ \ + bits(opcode, 8,11), /* s */ \ + bits(opcode,12,15), /* l */ \ + bits(opcode,16,19), /* h */ \ + bit1(opcode,20), /* save */ \ + bit1(opcode,21), /* accumulate */ \ + bit1(opcode,22) /* sign */ + for(uint1 save : range(2)) + for(uint1 accumulate : range(2)) + for(uint1 sign : range(2)) { + auto opcode = pattern(".... 0000 1??? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21 | sign << 22; + bind(opcode, MultiplyLong); + } + #undef arguments + + #define arguments \ + bits(opcode, 0,23) /* immediate */ + for(uint4 immediateLo : range(16)) + for(uint4 immediateHi : range(16)) { + auto opcode = pattern(".... 1111 ???? ???? ???? ???? ???? ????") | immediateLo << 4 | immediateHi << 20; + bind(opcode, SoftwareInterrupt); + } + #undef arguments + + #define arguments + for(uint12 id : range(4096)) { + if(armInstruction[id]) continue; + auto opcode = pattern(".... ???? ???? ---- ---- ---- ???? ----") | bits(id,0,3) << 4 | bits(id,4,11) << 20; + bind(opcode, Undefined); + } + #undef arguments + + #undef bind + #undef pattern +} + +auto ARM7TDMI::thumbInitialize() -> void { + #define bind(id, name, ...) { \ + assert(!thumbInstruction[id]); \ + thumbInstruction[id] = [=] { return thumbInstruction##name(__VA_ARGS__); }; \ + thumbDisassemble[id] = [=] { return thumbDisassemble##name(__VA_ARGS__); }; \ + } + + #define pattern(s) \ + std::integral_constant::value + + for(uint3 d : range(8)) + for(uint3 m : range(8)) + for(uint4 mode : range(16)) { + auto opcode = pattern("0100 00?? ???? ????") | d << 0 | m << 3 | mode << 6; + bind(opcode, ALU, d, m, mode); + } + + for(uint4 d : range(16)) + for(uint4 m : range(16)) + for(uint2 mode : range(4)) { + if(mode == 3) continue; + auto opcode = pattern("0100 01?? ???? ????") | bits(d,0,2) << 0 | m << 3 | bit1(d,3) << 7 | mode << 8; + bind(opcode, ALUExtended, d, m, mode); + } + + for(uint8 immediate : range(256)) + for(uint3 d : range(8)) + for(uint1 mode : range(2)) { + auto opcode = pattern("1010 ???? ???? ????") | immediate << 0 | d << 8 | mode << 11; + bind(opcode, AddRegister, immediate, d, mode); + } + + for(uint3 d : range(8)) + for(uint3 n : range(8)) + for(uint3 immediate : range(8)) + for(uint1 mode : range(2)) { + auto opcode = pattern("0001 11?? ???? ????") | d << 0 | n << 3 | immediate << 6 | mode << 9; + bind(opcode, AdjustImmediate, d, n, immediate, mode); + } + + for(uint3 d : range(8)) + for(uint3 n : range(8)) + for(uint3 m : range(8)) + for(uint1 mode : range(2)) { + auto opcode = pattern("0001 10?? ???? ????") | d << 0 | n << 3 | m << 6 | mode << 9; + bind(opcode, AdjustRegister, d, n, m, mode); + } + + for(uint7 immediate : range(128)) + for(uint1 mode : range(2)) { + auto opcode = pattern("1011 0000 ???? ????") | immediate << 0 | mode << 7; + bind(opcode, AdjustStack, immediate, mode); + } + + for(uint3 _ : range(8)) + for(uint4 m : range(16)) { + auto opcode = pattern("0100 0111 0??? ?---") | _ << 0 | m << 3; + bind(opcode, BranchExchange, m); + } + + for(uint11 displacement : range(2048)) { + auto opcode = pattern("1111 0??? ???? ????") | displacement << 0; + bind(opcode, BranchFarPrefix, displacement); + } + + for(uint11 displacement : range(2048)) { + auto opcode = pattern("1111 1??? ???? ????") | displacement << 0; + bind(opcode, BranchFarSuffix, displacement); + } + + for(uint11 displacement : range(2048)) { + auto opcode = pattern("1110 0??? ???? ????") | displacement << 0; + bind(opcode, BranchNear, displacement); + } + + for(uint8 displacement : range(256)) + for(uint4 condition : range(16)) { + if(condition == 15) continue; //BNV + auto opcode = pattern("1101 ???? ???? ????") | displacement << 0 | condition << 8; + bind(opcode, BranchTest, displacement, condition); + } + + for(uint8 immediate : range(256)) + for(uint3 d : range(8)) + for(uint2 mode : range(4)) { + auto opcode = pattern("001? ???? ???? ????") | immediate << 0 | d << 8 | mode << 11; + bind(opcode, Immediate, immediate, d, mode); + } + + for(uint8 displacement : range(256)) + for(uint3 d : range(8)) { + auto opcode = pattern("0100 1??? ???? ????") | displacement << 0 | d << 8; + bind(opcode, LoadLiteral, displacement, d); + } + + for(uint3 d : range(8)) + for(uint3 n : range(8)) + for(uint5 immediate : range(32)) + for(uint1 mode : range(2)) { + auto opcode = pattern("0111 ???? ???? ????") | d << 0 | n << 3 | immediate << 6 | mode << 11; + bind(opcode, MoveByteImmediate, d, n, immediate, mode); + } + + for(uint3 d : range(8)) + for(uint3 n : range(8)) + for(uint5 immediate : range(32)) + for(uint1 mode : range(2)) { + auto opcode = pattern("1000 ???? ???? ????") | d << 0 | n << 3 | immediate << 6 | mode << 11; + bind(opcode, MoveHalfImmediate, d, n, immediate, mode); + } + + for(uint8 list : range(256)) + for(uint3 n : range(8)) + for(uint1 mode : range(2)) { + auto opcode = pattern("1100 ???? ???? ????") | list << 0 | n << 8 | mode << 11; + bind(opcode, MoveMultiple, list, n, mode); + } + + for(uint3 d : range(8)) + for(uint3 n : range(8)) + for(uint3 m : range(8)) + for(uint3 mode : range(8)) { + auto opcode = pattern("0101 ???? ???? ????") | d << 0 | n << 3 | m << 6 | mode << 9; + bind(opcode, MoveRegisterOffset, d, n, m, mode); + } + + for(uint8 immediate : range(256)) + for(uint3 d : range(8)) + for(uint1 mode : range(2)) { + auto opcode = pattern("1001 ???? ???? ????") | immediate << 0 | d << 8 | mode << 11; + bind(opcode, MoveStack, immediate, d, mode); + } + + for(uint3 d : range(8)) + for(uint3 n : range(8)) + for(uint5 offset : range(32)) + for(uint1 mode : range(2)) { + auto opcode = pattern("0110 ???? ???? ????") | d << 0 | n << 3 | offset << 6 | mode << 11; + bind(opcode, MoveWordImmediate, d, n, offset, mode); + } + + for(uint3 d : range(8)) + for(uint3 m : range(8)) + for(uint5 immediate : range(32)) + for(uint2 mode : range(4)) { + if(mode == 3) continue; + auto opcode = pattern("000? ???? ???? ????") | d << 0 | m << 3 | immediate << 6 | mode << 11; + bind(opcode, ShiftImmediate, d, m, immediate, mode); + } + + for(uint8 immediate : range(256)) { + auto opcode = pattern("1101 1111 ???? ????") | immediate << 0; + bind(opcode, SoftwareInterrupt, immediate); + } + + for(uint8 list : range(256)) + for(uint1 lrpc : range(2)) + for(uint1 mode : range(2)) { + auto opcode = pattern("1011 ?10? ???? ????") | list << 0 | lrpc << 8 | mode << 11; + bind(opcode, StackMultiple, list, lrpc, mode); + } + + for(uint16 id : range(65536)) { + if(thumbInstruction[id]) continue; + auto opcode = pattern("???? ???? ???? ????") | id << 0; + bind(opcode, Undefined); + } + + #undef bit1 + #undef bits + + #undef bind + #undef pattern +} diff --git a/processor/arm7tdmi/instructions-arm.cpp b/processor/arm7tdmi/instructions-arm.cpp new file mode 100644 index 0000000..bdafc5e --- /dev/null +++ b/processor/arm7tdmi/instructions-arm.cpp @@ -0,0 +1,314 @@ +auto ARM7TDMI::armALU(uint4 mode, uint4 d, uint4 n, uint32 rm) -> void { + uint32 rn = r(n); + + switch(mode) { + case 0: r(d) = BIT(rn & rm); break; //AND + case 1: r(d) = BIT(rn ^ rm); break; //EOR + case 2: r(d) = SUB(rn, rm, 1); break; //SUB + case 3: r(d) = SUB(rm, rn, 1); break; //RSB + case 4: r(d) = ADD(rn, rm, 0); break; //ADD + case 5: r(d) = ADD(rn, rm, cpsr().c); break; //ADC + case 6: r(d) = SUB(rn, rm, cpsr().c); break; //SBC + case 7: r(d) = SUB(rm, rn, cpsr().c); break; //RSC + case 8: BIT(rn & rm); break; //TST + case 9: BIT(rn ^ rm); break; //TEQ + case 10: SUB(rn, rm, 1); break; //CMP + case 11: ADD(rn, rm, 0); break; //CMN + case 12: r(d) = BIT(rn | rm); break; //ORR + case 13: r(d) = BIT(rm); break; //MOV + case 14: r(d) = BIT(rn & ~rm); break; //BIC + case 15: r(d) = BIT(~rm); break; //MVN + } + + if(exception() && d == 15 && (opcode & 1 << 20)) { + cpsr() = spsr(); + } +} + +auto ARM7TDMI::armMoveToStatus(uint4 field, uint1 mode, uint32 data) -> void { + if(mode && (cpsr().m == PSR::USR || cpsr().m == PSR::SYS)) return; + PSR& psr = mode ? spsr() : cpsr(); + + if(field & 1) { + if(mode || privileged()) { + psr.m = data >> 0 & 31; + psr.t = data >> 5 & 1; + psr.f = data >> 6 & 1; + psr.i = data >> 7 & 1; + if(!mode && psr.t) r(15).data += 2; + } + } + + if(field & 8) { + psr.v = data >> 28 & 1; + psr.c = data >> 29 & 1; + psr.z = data >> 30 & 1; + psr.n = data >> 31 & 1; + } +} + +// + +auto ARM7TDMI::armInstructionBranch +(int24 displacement, uint1 link) -> void { + if(link) r(14) = r(15) - 4; + r(15) = r(15) + displacement * 4; +} + +auto ARM7TDMI::armInstructionBranchExchangeRegister +(uint4 m) -> void { + uint32 address = r(m); + cpsr().t = address & 1; + r(15) = address; +} + +auto ARM7TDMI::armInstructionDataImmediate +(uint8 immediate, uint4 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> void { + uint32 data = immediate; + carry = cpsr().c; + if(shift) data = ROR(data, shift << 1); + armALU(mode, d, n, data); +} + +auto ARM7TDMI::armInstructionDataImmediateShift +(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> void { + uint32 rm = r(m); + carry = cpsr().c; + + switch(type) { + case 0: rm = LSL(rm, shift); break; + case 1: rm = LSR(rm, shift ? (uint)shift : 32); break; + case 2: rm = ASR(rm, shift ? (uint)shift : 32); break; + case 3: rm = shift ? ROR(rm, shift) : RRX(rm); break; + } + + armALU(mode, d, n, rm); +} + +auto ARM7TDMI::armInstructionDataRegisterShift +(uint4 m, uint2 type, uint4 s, uint4 d, uint4 n, uint1 save, uint4 mode) -> void { + uint8 rs = r(s) + (s == 15 ? 4 : 0); + uint32 rm = r(m) + (m == 15 ? 4 : 0); + carry = cpsr().c; + + switch(type) { + case 0: rm = LSL(rm, rs < 33 ? rs : (uint8)33); break; + case 1: rm = LSR(rm, rs < 33 ? rs : (uint8)33); break; + case 2: rm = ASR(rm, rs < 32 ? rs : (uint8)32); break; + case 3: if(rs) rm = ROR(rm, rs & 31 ? uint(rs & 31) : 32); break; + } + + armALU(mode, d, n, rm); +} + +auto ARM7TDMI::armInstructionLoadImmediate +(uint8 immediate, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> void { + uint32 rn = r(n); + uint32 rd = r(d); + + if(pre == 1) rn = up ? rn + immediate : rn - immediate; + rd = load((half ? Half : Byte) | Nonsequential | Signed, rn); + if(pre == 0) rn = up ? rn + immediate : rn - immediate; + + if(pre == 0 || writeback) r(n) = rn; + r(d) = rd; +} + +auto ARM7TDMI::armInstructionLoadRegister +(uint4 m, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> void { + uint32 rn = r(n); + uint32 rm = r(m); + uint32 rd = r(d); + + if(pre == 1) rn = up ? rn + rm : rn - rm; + rd = load((half ? Half : Byte) | Nonsequential | Signed, rn); + if(pre == 0) rn = up ? rn + rm : rn - rm; + + if(pre == 0 || writeback) r(n) = rn; + r(d) = rd; +} + +auto ARM7TDMI::armInstructionMemorySwap +(uint4 m, uint4 d, uint4 n, uint1 byte) -> void { + uint32 word = load((byte ? Byte : Word) | Nonsequential, r(n)); + store((byte ? Byte : Word) | Nonsequential, r(n), r(m)); + r(d) = word; +} + +auto ARM7TDMI::armInstructionMoveHalfImmediate +(uint8 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> void { + uint32 rn = r(n); + uint32 rd = r(d); + + if(pre == 1) rn = up ? rn + immediate : rn - immediate; + if(mode == 1) rd = load(Half | Nonsequential, rn); + if(mode == 0) store(Half | Nonsequential, rn, rd); + if(pre == 0) rn = up ? rn + immediate : rn - immediate; + + if(pre == 0 || writeback) r(n) = rn; + if(mode == 1) r(d) = rd; +} + +auto ARM7TDMI::armInstructionMoveHalfRegister +(uint4 m, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> void { + uint32 rn = r(n); + uint32 rm = r(m); + uint32 rd = r(d); + + if(pre == 1) rn = up ? rn + rm : rn - rm; + if(mode == 1) rd = load(Half | Nonsequential, rn); + if(mode == 0) store(Half | Nonsequential, rn, rd); + if(pre == 0) rn = up ? rn + rm : rn - rm; + + if(pre == 0 || writeback) r(n) = rn; + if(mode == 1) r(d) = rd; +} + +auto ARM7TDMI::armInstructionMoveImmediateOffset +(uint12 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> void { + uint32 rn = r(n); + uint32 rd = r(d); + + if(pre == 1) rn = up ? rn + immediate : rn - immediate; + if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn); + if(mode == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd); + if(pre == 0) rn = up ? rn + immediate : rn - immediate; + + if(pre == 0 || writeback) r(n) = rn; + if(mode == 1) r(d) = rd; +} + +auto ARM7TDMI::armInstructionMoveMultiple +(uint16 list, uint4 n, uint1 mode, uint1 writeback, uint1 type, uint1 up, uint1 pre) -> void { + uint32 rn = r(n); + if(pre == 0 && up == 1) rn = rn + 0; //IA + if(pre == 1 && up == 1) rn = rn + 4; //IB + if(pre == 1 && up == 0) rn = rn - bit::count(list) * 4 + 0; //DB + if(pre == 0 && up == 0) rn = rn - bit::count(list) * 4 + 4; //DA + + if(writeback && mode == 1) { + if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA,IB + if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA,DB + } + + auto cpsrMode = cpsr().m; + bool usr = false; + if(type && mode == 1 && !(list & 0x8000)) usr = true; + if(type && mode == 0) usr = true; + if(usr) cpsr().m = PSR::USR; + + uint sequential = Nonsequential; + for(uint m : range(16)) { + if(!(list & 1 << m)) continue; + if(mode == 1) r(m) = read(Word | sequential, rn); + if(mode == 0) write(Word | sequential, rn, r(m)); + rn += 4; + sequential = Sequential; + } + + if(usr) cpsr().m = cpsrMode; + + if(mode) { + idle(); + if(type && (list & 0x8000) && cpsr().m != PSR::USR && cpsr().m != PSR::SYS) { + cpsr() = spsr(); + } + } else { + pipeline.nonsequential = true; + } + + if(writeback && mode == 0) { + if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA,IB + if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA,DB + } +} + +auto ARM7TDMI::armInstructionMoveRegisterOffset +(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> void { + uint32 rm = r(m); + uint32 rd = r(d); + uint32 rn = r(n); + carry = cpsr().c; + + switch(type) { + case 0: rm = LSL(rm, shift); break; + case 1: rm = LSR(rm, shift ? (uint)shift : 32); break; + case 2: rm = ASR(rm, shift ? (uint)shift : 32); break; + case 3: rm = shift ? ROR(rm, shift) : RRX(rm); break; + } + + if(pre == 1) rn = up ? rn + rm : rn - rm; + if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn); + if(mode == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd); + if(pre == 0) rn = up ? rn + rm : rn - rm; + + if(pre == 0 || writeback) r(n) = rn; + if(mode == 1) r(d) = rd; +} + +auto ARM7TDMI::armInstructionMoveToRegisterFromStatus +(uint4 d, uint1 mode) -> void { + if(mode && (cpsr().m == PSR::USR || cpsr().m == PSR::SYS)) return; + r(d) = mode ? spsr() : cpsr(); +} + +auto ARM7TDMI::armInstructionMoveToStatusFromImmediate +(uint8 immediate, uint4 rotate, uint4 field, uint1 mode) -> void { + uint32 data = immediate; + if(rotate) data = ROR(data, rotate << 1); + armMoveToStatus(field, mode, data); +} + +auto ARM7TDMI::armInstructionMoveToStatusFromRegister +(uint4 m, uint4 field, uint1 mode) -> void { + armMoveToStatus(field, mode, r(m)); +} + +auto ARM7TDMI::armInstructionMultiply +(uint4 m, uint4 s, uint4 n, uint4 d, uint1 save, uint1 accumulate) -> void { + if(accumulate) idle(); + r(d) = MUL(accumulate ? r(n) : 0, r(m), r(s)); +} + +auto ARM7TDMI::armInstructionMultiplyLong +(uint4 m, uint4 s, uint4 l, uint4 h, uint1 save, uint1 accumulate, uint1 sign) -> void { + uint64 rm = r(m); + uint64 rs = r(s); + + idle(); + idle(); + if(accumulate) idle(); + + if(sign) { + if(rs >> 8 && rs >> 8 != 0xffffff) idle(); + if(rs >> 16 && rs >> 16 != 0xffff) idle(); + if(rs >> 24 && rs >> 24 != 0xff) idle(); + rm = (int32)rm; + rs = (int32)rs; + } else { + if(rs >> 8) idle(); + if(rs >> 16) idle(); + if(rs >> 24) idle(); + } + + uint64 rd = rm * rs; + if(accumulate) rd += (uint64)r(h) << 32 | (uint64)r(l) << 0; + + r(h) = rd >> 32; + r(l) = rd >> 0; + + if(save) { + cpsr().z = rd == 0; + cpsr().n = rd >> 63 & 1; + } +} + +auto ARM7TDMI::armInstructionSoftwareInterrupt +(uint24 immediate) -> void { + exception(PSR::SVC, 0x08); +} + +auto ARM7TDMI::armInstructionUndefined +() -> void { + exception(PSR::UND, 0x04); +} diff --git a/processor/arm7tdmi/instructions-thumb.cpp b/processor/arm7tdmi/instructions-thumb.cpp new file mode 100644 index 0000000..1dc1f5e --- /dev/null +++ b/processor/arm7tdmi/instructions-thumb.cpp @@ -0,0 +1,225 @@ +auto ARM7TDMI::thumbInstructionALU +(uint3 d, uint3 m, uint4 mode) -> void { + switch(mode) { + case 0: r(d) = BIT(r(d) & r(m)); break; //AND + case 1: r(d) = BIT(r(d) ^ r(m)); break; //EOR + case 2: r(d) = BIT(LSL(r(d), r(m))); break; //LSL + case 3: r(d) = BIT(LSR(r(d), r(m))); break; //LSR + case 4: r(d) = BIT(ASR(r(d), r(m))); break; //ASR + case 5: r(d) = ADD(r(d), r(m), cpsr().c); break; //ADC + case 6: r(d) = SUB(r(d), r(m), cpsr().c); break; //SBC + case 7: r(d) = BIT(ROR(r(d), r(m))); break; //ROR + case 8: BIT(r(d) & r(m)); break; //TST + case 9: r(d) = SUB(0, r(m), 1); break; //NEG + case 10: SUB(r(d), r(m), 1); break; //CMP + case 11: ADD(r(d), r(m), 0); break; //CMN + case 12: r(d) = BIT(r(d) | r(m)); break; //ORR + case 13: r(d) = MUL(0, r(m), r(d)); break; //MUL + case 14: r(d) = BIT(r(d) & ~r(m)); break; //BIC + case 15: r(d) = BIT(~r(m)); break; //MVN + } +} + +auto ARM7TDMI::thumbInstructionALUExtended +(uint4 d, uint4 m, uint2 mode) -> void { + switch(mode) { + case 0: r(d) = r(d) + r(m); break; //ADD + case 1: SUB(r(d), r(m), 1); break; //SUBS + case 2: r(d) = r(m); break; //MOV + } +} + +auto ARM7TDMI::thumbInstructionAddRegister +(uint8 immediate, uint3 d, uint1 mode) -> void { + switch(mode) { + case 0: r(d) = (r(15) & ~3) + immediate * 4; break; //ADD pc + case 1: r(d) = r(13) + immediate * 4; break; //ADD sp + } +} + +auto ARM7TDMI::thumbInstructionAdjustImmediate +(uint3 d, uint3 n, uint3 immediate, uint1 mode) -> void { + switch(mode) { + case 0: r(d) = ADD(r(n), immediate, 0); break; //ADD + case 1: r(d) = SUB(r(n), immediate, 1); break; //SUB + } +} + +auto ARM7TDMI::thumbInstructionAdjustRegister +(uint3 d, uint3 n, uint3 m, uint1 mode) -> void { + switch(mode) { + case 0: r(d) = ADD(r(n), r(m), 0); break; //ADD + case 1: r(d) = SUB(r(n), r(m), 1); break; //SUB + } +} + +auto ARM7TDMI::thumbInstructionAdjustStack +(uint7 immediate, uint1 mode) -> void { + switch(mode) { + case 0: r(13) = r(13) + immediate * 4; break; //ADD + case 1: r(13) = r(13) - immediate * 4; break; //SUB + } +} + +auto ARM7TDMI::thumbInstructionBranchExchange +(uint4 m) -> void { + uint32 address = r(m); + cpsr().t = address & 1; + r(15) = address; +} + +auto ARM7TDMI::thumbInstructionBranchFarPrefix +(int11 displacement) -> void { + r(14) = r(15) + (displacement * 2 << 11); +} + +auto ARM7TDMI::thumbInstructionBranchFarSuffix +(uint11 displacement) -> void { + r(15) = r(14) + (displacement * 2); + r(14) = pipeline.decode.address | 1; +} + +auto ARM7TDMI::thumbInstructionBranchNear +(int11 displacement) -> void { + r(15) = r(15) + displacement * 2; +} + +auto ARM7TDMI::thumbInstructionBranchTest +(int8 displacement, uint4 condition) -> void { + if(!TST(condition)) return; + r(15) = r(15) + displacement * 2; +} + +auto ARM7TDMI::thumbInstructionImmediate +(uint8 immediate, uint3 d, uint2 mode) -> void { + switch(mode) { + case 0: r(d) = BIT(immediate); break; //MOV + case 1: SUB(r(d), immediate, 1); break; //CMP + case 2: r(d) = ADD(r(d), immediate, 0); break; //ADD + case 3: r(d) = SUB(r(d), immediate, 1); break; //SUB + } +} + +auto ARM7TDMI::thumbInstructionLoadLiteral +(uint8 displacement, uint3 d) -> void { + uint32 address = (r(15) & ~3) + (displacement << 2); + r(d) = load(Word | Nonsequential, address); +} + +auto ARM7TDMI::thumbInstructionMoveByteImmediate +(uint3 d, uint3 n, uint5 offset, uint1 mode) -> void { + switch(mode) { + case 0: store(Byte | Nonsequential, r(n) + offset, r(d)); break; //STRB + case 1: r(d) = load(Byte | Nonsequential, r(n) + offset); break; //LDRB + } +} + +auto ARM7TDMI::thumbInstructionMoveHalfImmediate +(uint3 d, uint3 n, uint5 offset, uint1 mode) -> void { + switch(mode) { + case 0: store(Half | Nonsequential, r(n) + offset * 2, r(d)); break; //STRH + case 1: r(d) = load(Half | Nonsequential, r(n) + offset * 2); break; //LDRH + } +} + +auto ARM7TDMI::thumbInstructionMoveMultiple +(uint8 list, uint3 n, uint1 mode) -> void { + uint32 rn = r(n); + + for(uint m : range(8)) { + if(!(list & 1 << m)) continue; + switch(mode) { + case 0: write(Word | Nonsequential, rn, r(m)); break; //STMIA + case 1: r(m) = read(Word | Nonsequential, rn); break; //LDMIA + } + rn += 4; + } + + if(mode == 0 || !(list & 1 << n)) r(n) = rn; + if(mode == 1) idle(); +} + +auto ARM7TDMI::thumbInstructionMoveRegisterOffset +(uint3 d, uint3 n, uint3 m, uint3 mode) -> void { + switch(mode) { + case 0: store(Word | Nonsequential, r(n) + r(m), r(d)); break; //STR + case 1: store(Half | Nonsequential, r(n) + r(m), r(d)); break; //STRH + case 2: store(Byte | Nonsequential, r(n) + r(m), r(d)); break; //STRB + case 3: r(d) = load(Byte | Nonsequential | Signed, r(n) + r(m)); break; //LDSB + case 4: r(d) = load(Word | Nonsequential, r(n) + r(m)); break; //LDR + case 5: r(d) = load(Half | Nonsequential, r(n) + r(m)); break; //LDRH + case 6: r(d) = load(Byte | Nonsequential, r(n) + r(m)); break; //LDRB + case 7: r(d) = load(Half | Nonsequential | Signed, r(n) + r(m)); break; //LDSH + } +} + +auto ARM7TDMI::thumbInstructionMoveStack +(uint8 immediate, uint3 d, uint1 mode) -> void { + switch(mode) { + case 0: store(Word | Nonsequential, r(13) + immediate * 4, r(d)); break; //STR + case 1: r(d) = load(Word | Nonsequential, r(13) + immediate * 4); break; //LDR + } +} + +auto ARM7TDMI::thumbInstructionMoveWordImmediate +(uint3 d, uint3 n, uint5 offset, uint1 mode) -> void { + switch(mode) { + case 0: store(Word | Nonsequential, r(n) + offset * 4, r(d)); break; //STR + case 1: r(d) = load(Word | Nonsequential, r(n) + offset * 4); break; //LDR + } +} + +auto ARM7TDMI::thumbInstructionShiftImmediate +(uint3 d, uint3 m, uint5 immediate, uint2 mode) -> void { + switch(mode) { + case 0: r(d) = BIT(LSL(r(m), immediate)); break; //LSL + case 1: r(d) = BIT(LSR(r(m), immediate ? (uint)immediate : 32)); break; //LSR + case 2: r(d) = BIT(ASR(r(m), immediate ? (uint)immediate : 32)); break; //ASR + } +} + +auto ARM7TDMI::thumbInstructionSoftwareInterrupt +(uint8 immediate) -> void { + exception(PSR::SVC, 0x08); +} + +auto ARM7TDMI::thumbInstructionStackMultiple +(uint8 list, uint1 lrpc, uint1 mode) -> void { + uint32 sp; + switch(mode) { + case 0: sp = r(13) - (bit::count(list) + lrpc) * 4; break; //PUSH + case 1: sp = r(13); //POP + } + + uint sequential = Nonsequential; + for(uint m : range(8)) { + if(!(list & 1 << m)) continue; + switch(mode) { + case 0: write(Word | sequential, sp, r(m)); break; //PUSH + case 1: r(m) = read(Word | sequential, sp); break; //POP + } + sp += 4; + sequential = Sequential; + } + + if(lrpc) { + switch(mode) { + case 0: write(Word | sequential, sp, r(14)); break; //PUSH + case 1: r(15) = read(Word | sequential, sp); break; //POP + } + sp += 4; + } + + if(mode == 1) { + idle(); + r(13) = r(13) + (bit::count(list) + lrpc) * 4; //POP + } else { + pipeline.nonsequential = true; + r(13) = r(13) - (bit::count(list) + lrpc) * 4; //PUSH + } +} + +auto ARM7TDMI::thumbInstructionUndefined +() -> void { + exception(PSR::UND, 0x04); +} diff --git a/processor/arm7tdmi/memory.cpp b/processor/arm7tdmi/memory.cpp new file mode 100644 index 0000000..aaeb73b --- /dev/null +++ b/processor/arm7tdmi/memory.cpp @@ -0,0 +1,40 @@ +auto ARM7TDMI::idle() -> void { + pipeline.nonsequential = true; + sleep(); +} + +auto ARM7TDMI::read(uint mode, uint32 address) -> uint32 { + return get(mode, address); +} + +auto ARM7TDMI::load(uint mode, uint32 address) -> uint32 { + pipeline.nonsequential = true; + auto word = get(Load | mode, address); + if(mode & Half) { + address &= 1; + word = mode & Signed ? (uint32)(int16)word : (uint32)(uint16)word; + } + if(mode & Byte) { + address &= 0; + word = mode & Signed ? (uint32)(int8)word : (uint32)(uint8)word; + } + if(mode & Signed) { + word = ASR(word, (address & 3) << 3); + } else { + word = ROR(word, (address & 3) << 3); + } + idle(); + return word; +} + +auto ARM7TDMI::write(uint mode, uint32 address, uint32 word) -> void { + pipeline.nonsequential = true; + return set(mode, address, word); +} + +auto ARM7TDMI::store(uint mode, uint32 address, uint32 word) -> void { + pipeline.nonsequential = true; + if(mode & Half) { word &= 0xffff; word |= word << 16; } + if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; } + return set(Store | mode, address, word); +} diff --git a/processor/arm7tdmi/registers.cpp b/processor/arm7tdmi/registers.cpp new file mode 100644 index 0000000..848f088 --- /dev/null +++ b/processor/arm7tdmi/registers.cpp @@ -0,0 +1,58 @@ +auto ARM7TDMI::r(uint4 index) -> GPR& { + switch(index) { + case 0: return processor.r0; + case 1: return processor.r1; + case 2: return processor.r2; + case 3: return processor.r3; + case 4: return processor.r4; + case 5: return processor.r5; + case 6: return processor.r6; + case 7: return processor.r7; + case 8: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r8 : processor.r8; + case 9: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r9 : processor.r9; + case 10: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r10 : processor.r10; + case 11: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r11 : processor.r11; + case 12: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r12 : processor.r12; + case 13: switch(processor.cpsr.m) { + case PSR::FIQ: return processor.fiq.r13; + case PSR::IRQ: return processor.irq.r13; + case PSR::SVC: return processor.svc.r13; + case PSR::ABT: return processor.abt.r13; + case PSR::UND: return processor.und.r13; + default: return processor.r13; + } + case 14: switch(processor.cpsr.m) { + case PSR::FIQ: return processor.fiq.r14; + case PSR::IRQ: return processor.irq.r14; + case PSR::SVC: return processor.svc.r14; + case PSR::ABT: return processor.abt.r14; + case PSR::UND: return processor.und.r14; + default: return processor.r14; + } + case 15: return processor.r15; + } + unreachable; +} + +auto ARM7TDMI::cpsr() -> PSR& { + return processor.cpsr; +} + +auto ARM7TDMI::spsr() -> PSR& { + switch(processor.cpsr.m) { + case PSR::FIQ: return processor.fiq.spsr; + case PSR::IRQ: return processor.irq.spsr; + case PSR::SVC: return processor.svc.spsr; + case PSR::ABT: return processor.abt.spsr; + case PSR::UND: return processor.und.spsr; + } + throw; +} + +auto ARM7TDMI::privileged() const -> bool { + return processor.cpsr.m != PSR::USR; +} + +auto ARM7TDMI::exception() const -> bool { + return privileged() && processor.cpsr.m != PSR::SYS; +} diff --git a/processor/arm7tdmi/serialization.cpp b/processor/arm7tdmi/serialization.cpp new file mode 100644 index 0000000..b80a2e8 --- /dev/null +++ b/processor/arm7tdmi/serialization.cpp @@ -0,0 +1,71 @@ +auto ARM7TDMI::serialize(serializer& s) -> void { + processor.serialize(s); + pipeline.serialize(s); + s.boolean(carry); + s.boolean(irq); +} + +auto ARM7TDMI::Processor::serialize(serializer& s) -> void { + s.integer(r0.data); + s.integer(r1.data); + s.integer(r2.data); + s.integer(r3.data); + s.integer(r4.data); + s.integer(r5.data); + s.integer(r6.data); + s.integer(r7.data); + s.integer(r8.data); + s.integer(r9.data); + s.integer(r10.data); + s.integer(r11.data); + s.integer(r12.data); + s.integer(r13.data); + s.integer(r14.data); + s.integer(r15.data); + cpsr.serialize(s); + s.integer(fiq.r8.data); + s.integer(fiq.r9.data); + s.integer(fiq.r10.data); + s.integer(fiq.r11.data); + s.integer(fiq.r12.data); + s.integer(fiq.r13.data); + s.integer(fiq.r14.data); + fiq.spsr.serialize(s); + s.integer(irq.r13.data); + s.integer(irq.r14.data); + irq.spsr.serialize(s); + s.integer(svc.r13.data); + s.integer(svc.r14.data); + svc.spsr.serialize(s); + s.integer(abt.r13.data); + s.integer(abt.r14.data); + abt.spsr.serialize(s); + s.integer(und.r13.data); + s.integer(und.r14.data); + und.spsr.serialize(s); +} + +auto ARM7TDMI::PSR::serialize(serializer& s) -> void { + s.integer(m); + s.boolean(t); + s.boolean(f); + s.boolean(i); + s.boolean(v); + s.boolean(c); + s.boolean(z); + s.boolean(n); +} + +auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void { + s.integer(reload); + s.integer(nonsequential); + s.integer(fetch.address); + s.integer(fetch.instruction); + s.boolean(fetch.thumb); + s.integer(decode.address); + s.integer(decode.instruction); + s.boolean(decode.thumb); + s.integer(execute.address); + s.integer(execute.instruction); + s.boolean(execute.thumb); +} diff --git a/processor/gsu/disassembler.cpp b/processor/gsu/disassembler.cpp new file mode 100644 index 0000000..75254b4 --- /dev/null +++ b/processor/gsu/disassembler.cpp @@ -0,0 +1,268 @@ +auto GSU::disassembleOpcode(char* output) -> void { + *output = 0; + + switch(regs.sfr.alt2 << 1 | regs.sfr.alt1 << 0) { + case 0: disassembleALT0(output); break; + case 1: disassembleALT1(output); break; + case 2: disassembleALT2(output); break; + case 3: disassembleALT3(output); break; + } + + uint 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 read((regs.pbr << 16) + regs.r[15] + 0) +#define op2 read((regs.pbr << 16) + regs.r[15] + 1) + +auto GSU::disassembleALT0(char* output) -> void { + 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"); break; + 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); +} + +auto GSU::disassembleALT1(char* output) -> void { + 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); +} + +auto GSU::disassembleALT2(char* output) -> void { + 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); +} + +auto GSU::disassembleALT3(char* output) -> void { + 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 diff --git a/processor/gsu/gsu.cpp b/processor/gsu/gsu.cpp new file mode 100644 index 0000000..78a255c --- /dev/null +++ b/processor/gsu/gsu.cpp @@ -0,0 +1,39 @@ +#include +#include "gsu.hpp" + +//note: multiplication results *may* sometimes be invalid when both CLSR and MS0 are set +//the product of multiplication in this mode (21mhz + fast-multiply) has not been analyzed; +//however, the timing of this mode has been confirmed to work as specified below + +namespace Processor { + +#include "instruction.cpp" +#include "instructions.cpp" +#include "serialization.cpp" +#include "disassembler.cpp" + +auto GSU::power() -> void { + for(auto& r : regs.r) { + r.data = 0x0000; + r.modified = false; + } + + 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(); +} + +} diff --git a/processor/gsu/gsu.hpp b/processor/gsu/gsu.hpp new file mode 100644 index 0000000..61fbe4c --- /dev/null +++ b/processor/gsu/gsu.hpp @@ -0,0 +1,85 @@ +#pragma once + +namespace Processor { + +struct GSU { + #include "registers.hpp" + + virtual auto step(uint clocks) -> void = 0; + + virtual auto stop() -> void = 0; + virtual auto color(uint8 source) -> uint8 = 0; + virtual auto plot(uint8 x, uint8 y) -> void = 0; + virtual auto rpix(uint8 x, uint8 y) -> uint8 = 0; + + virtual auto pipe() -> uint8 = 0; + virtual auto syncROMBuffer() -> void = 0; + virtual auto readROMBuffer() -> uint8 = 0; + virtual auto syncRAMBuffer() -> void = 0; + virtual auto readRAMBuffer(uint16 addr) -> uint8 = 0; + virtual auto writeRAMBuffer(uint16 addr, uint8 data) -> void = 0; + virtual auto flushCache() -> void = 0; + + virtual auto read(uint addr, uint8 data = 0x00) -> uint8 = 0; + virtual auto write(uint addr, uint8 data) -> void = 0; + + //gsu.cpp + auto power() -> void; + + //instructions.cpp + auto instructionADD_ADC(uint n) -> void; + auto instructionALT1() -> void; + auto instructionALT2() -> void; + auto instructionALT3() -> void; + auto instructionAND_BIC(uint n) -> void; + auto instructionASR_DIV2() -> void; + auto instructionBranch(bool c) -> void; + auto instructionCACHE() -> void; + auto instructionCOLOR_CMODE() -> void; + auto instructionDEC(uint n) -> void; + auto instructionFMULT_LMULT() -> void; + auto instructionFROM_MOVES(uint n) -> void; + auto instructionGETB() -> void; + auto instructionGETC_RAMB_ROMB() -> void; + auto instructionHIB() -> void; + auto instructionIBT_LMS_SMS(uint n) -> void; + auto instructionINC(uint n) -> void; + auto instructionIWT_LM_SM(uint n) -> void; + auto instructionJMP_LJMP(uint n) -> void; + auto instructionLINK(uint n) -> void; + auto instructionLoad(uint n) -> void; + auto instructionLOB() -> void; + auto instructionLOOP() -> void; + auto instructionLSR() -> void; + auto instructionMERGE() -> void; + auto instructionMULT_UMULT(uint n) -> void; + auto instructionNOP() -> void; + auto instructionNOT() -> void; + auto instructionOR_XOR(uint n) -> void; + auto instructionPLOT_RPIX() -> void; + auto instructionROL() -> void; + auto instructionROR() -> void; + auto instructionSBK() -> void; + auto instructionSEX() -> void; + auto instructionStore(uint n) -> void; + auto instructionSTOP() -> void; + auto instructionSUB_SBC_CMP(uint n) -> void; + auto instructionSWAP() -> void; + auto instructionTO_MOVE(uint n) -> void; + auto instructionWITH(uint n) -> void; + + //switch.cpp + auto instruction(uint8 opcode) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + //disassembler.cpp + auto disassembleOpcode(char* output) -> void; + auto disassembleALT0(char* output) -> void; + auto disassembleALT1(char* output) -> void; + auto disassembleALT2(char* output) -> void; + auto disassembleALT3(char* output) -> void; +}; + +} diff --git a/processor/gsu/instruction.cpp b/processor/gsu/instruction.cpp new file mode 100644 index 0000000..969e611 --- /dev/null +++ b/processor/gsu/instruction.cpp @@ -0,0 +1,94 @@ +auto GSU::instruction(uint8 opcode) -> void { + #define op(id, name, ...) \ + case id: return instruction##name(__VA_ARGS__); \ + + #define op4(id, name) \ + case id+ 0: return instruction##name((uint4)opcode); \ + case id+ 1: return instruction##name((uint4)opcode); \ + case id+ 2: return instruction##name((uint4)opcode); \ + case id+ 3: return instruction##name((uint4)opcode); \ + + #define op6(id, name) \ + op4(id, name) \ + case id+ 4: return instruction##name((uint4)opcode); \ + case id+ 5: return instruction##name((uint4)opcode); \ + + #define op12(id, name) \ + op6(id, name) \ + case id+ 6: return instruction##name((uint4)opcode); \ + case id+ 7: return instruction##name((uint4)opcode); \ + case id+ 8: return instruction##name((uint4)opcode); \ + case id+ 9: return instruction##name((uint4)opcode); \ + case id+10: return instruction##name((uint4)opcode); \ + case id+11: return instruction##name((uint4)opcode); \ + + #define op15(id, name) \ + op12(id, name) \ + case id+12: return instruction##name((uint4)opcode); \ + case id+13: return instruction##name((uint4)opcode); \ + case id+14: return instruction##name((uint4)opcode); \ + + #define op16(id, name) \ + op15(id, name) \ + case id+15: return instruction##name((uint4)opcode); \ + + switch(opcode) { + op (0x00, STOP) + op (0x01, NOP) + op (0x02, CACHE) + op (0x03, LSR) + op (0x04, ROL) + op (0x05, Branch, 1) //bra + op (0x06, Branch, (regs.sfr.s ^ regs.sfr.ov) == 0) //blt + op (0x07, Branch, (regs.sfr.s ^ regs.sfr.ov) == 1) //bge + op (0x08, Branch, regs.sfr.z == 0) //bne + op (0x09, Branch, regs.sfr.z == 1) //beq + op (0x0a, Branch, regs.sfr.s == 0) //bpl + op (0x0b, Branch, regs.sfr.s == 1) //bmi + op (0x0c, Branch, regs.sfr.cy == 0) //bcc + op (0x0d, Branch, regs.sfr.cy == 1) //bcs + op (0x0e, Branch, regs.sfr.ov == 0) //bvc + op (0x0f, Branch, regs.sfr.ov == 1) //bvs + op16(0x10, TO_MOVE) + op16(0x20, WITH) + op12(0x30, Store) + op (0x3c, LOOP) + op (0x3d, ALT1) + op (0x3e, ALT2) + op (0x3f, ALT3) + op12(0x40, Load) + op (0x4c, PLOT_RPIX) + op (0x4d, SWAP) + op (0x4e, COLOR_CMODE) + op (0x4f, NOT) + op16(0x50, ADD_ADC) + op16(0x60, SUB_SBC_CMP) + op (0x70, MERGE) + op15(0x71, AND_BIC) + op16(0x80, MULT_UMULT) + op (0x90, SBK) + op4 (0x91, LINK) + op (0x95, SEX) + op (0x96, ASR_DIV2) + op (0x97, ROR) + op6 (0x98, JMP_LJMP) + op (0x9e, LOB) + op (0x9f, FMULT_LMULT) + op16(0xa0, IBT_LMS_SMS) + op16(0xb0, FROM_MOVES) + op (0xc0, HIB) + op15(0xc1, OR_XOR) + op15(0xd0, INC) + op (0xdf, GETC_RAMB_ROMB) + op15(0xe0, DEC) + op (0xef, GETB) + op16(0xf0, IWT_LM_SM) + } + + #undef op + #undef op4 + #undef op6 + #undef op12 + #undef op15 + #undef op16 +} diff --git a/processor/gsu/instructions.cpp b/processor/gsu/instructions.cpp new file mode 100644 index 0000000..56e89d4 --- /dev/null +++ b/processor/gsu/instructions.cpp @@ -0,0 +1,424 @@ +//$00 stop +auto GSU::instructionSTOP() -> void { + if(regs.cfgr.irq == 0) { + regs.sfr.irq = 1; + stop(); + } + regs.sfr.g = 0; + regs.pipeline = 0x01; //nop + regs.reset(); +} + +//$01 nop +auto GSU::instructionNOP() -> void { + regs.reset(); +} + +//$02 cache +auto GSU::instructionCACHE() -> void { + if(regs.cbr != (regs.r[15] & 0xfff0)) { + regs.cbr = regs.r[15] & 0xfff0; + flushCache(); + } + regs.reset(); +} + +//$03 lsr +auto GSU::instructionLSR() -> void { + 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 +auto GSU::instructionROL() -> void { + 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 +//$06 blt e +//$07 bge e +//$08 bne e +//$09 beq e +//$0a bpl e +//$0b bmi e +//$0c bcc e +//$0d bcs e +//$0e bvc e +//$0f bvs e +auto GSU::instructionBranch(bool take) -> void { + auto displacement = (int8)pipe(); + if(take) regs.r[15] += displacement; +} + +//$10-1f(b0) to rN +//$10-1f(b1) move rN +auto GSU::instructionTO_MOVE(uint n) -> void { + if(!regs.sfr.b) { + regs.dreg = n; + } else { + regs.r[n] = regs.sr(); + regs.reset(); + } +} + +//$20-2f with rN +auto GSU::instructionWITH(uint n) -> void { + regs.sreg = n; + regs.dreg = n; + regs.sfr.b = 1; +} + +//$30-3b(alt0) stw (rN) +//$30-3b(alt1) stb (rN) +auto GSU::instructionStore(uint n) -> void { + regs.ramaddr = regs.r[n]; + writeRAMBuffer(regs.ramaddr, regs.sr()); + if(!regs.sfr.alt1) writeRAMBuffer(regs.ramaddr ^ 1, regs.sr() >> 8); + regs.reset(); +} + +//$3c loop +auto GSU::instructionLOOP() -> void { + 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 +auto GSU::instructionALT1() -> void { + regs.sfr.b = 0; + regs.sfr.alt1 = 1; +} + +//$3e alt2 +auto GSU::instructionALT2() -> void { + regs.sfr.b = 0; + regs.sfr.alt2 = 1; +} + +//$3f alt3 +auto GSU::instructionALT3() -> void { + regs.sfr.b = 0; + regs.sfr.alt1 = 1; + regs.sfr.alt2 = 1; +} + +//$40-4b(alt0) ldw (rN) +//$40-4b(alt1) ldb (rN) +auto GSU::instructionLoad(uint n) -> void { + regs.ramaddr = regs.r[n]; + regs.dr() = readRAMBuffer(regs.ramaddr); + if(!regs.sfr.alt1) regs.dr() |= readRAMBuffer(regs.ramaddr ^ 1) << 8; + regs.reset(); +} + +//$4c(alt0) plot +//$4c(alt1) rpix +auto GSU::instructionPLOT_RPIX() -> void { + if(!regs.sfr.alt1) { + plot(regs.r[1], regs.r[2]); + regs.r[1]++; + } else { + 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 +auto GSU::instructionSWAP() -> void { + 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 +//$4e(alt1) cmode +auto GSU::instructionCOLOR_CMODE() -> void { + if(!regs.sfr.alt1) { + regs.colr = color(regs.sr()); + } else { + regs.por = regs.sr(); + } + regs.reset(); +} + +//$4f not +auto GSU::instructionNOT() -> void { + regs.dr() = ~regs.sr(); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$50-5f(alt0) add rN +//$50-5f(alt1) adc rN +//$50-5f(alt2) add #N +//$50-5f(alt3) adc #N +auto GSU::instructionADD_ADC(uint n) -> void { + if(!regs.sfr.alt2) n = regs.r[n]; + int r = regs.sr() + n + (regs.sfr.alt1 ? regs.sfr.cy : 0); + regs.sfr.ov = ~(regs.sr() ^ n) & (n ^ r) & 0x8000; + regs.sfr.s = (r & 0x8000); + regs.sfr.cy = (r >= 0x10000); + regs.sfr.z = ((uint16)r == 0); + regs.dr() = r; + regs.reset(); +} + +//$60-6f(alt0) sub rN +//$60-6f(alt1) sbc rN +//$60-6f(alt2) sub #N +//$60-6f(alt3) cmp rN +auto GSU::instructionSUB_SBC_CMP(uint n) -> void { + if(!regs.sfr.alt2 || regs.sfr.alt1) n = regs.r[n]; + int r = regs.sr() - n - (!regs.sfr.alt2 && regs.sfr.alt1 ? !regs.sfr.cy : 0); + regs.sfr.ov = (regs.sr() ^ n) & (regs.sr() ^ r) & 0x8000; + regs.sfr.s = (r & 0x8000); + regs.sfr.cy = (r >= 0); + regs.sfr.z = ((uint16)r == 0); + if(!regs.sfr.alt2 || !regs.sfr.alt1) regs.dr() = r; + regs.reset(); +} + +//$70 merge +auto GSU::instructionMERGE() -> void { + 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 +//$71-7f(alt1) bic rN +//$71-7f(alt2) and #N +//$71-7f(alt3) bic #N +auto GSU::instructionAND_BIC(uint n) -> void { + if(!regs.sfr.alt2) n = regs.r[n]; + regs.dr() = regs.sr() & (regs.sfr.alt1 ? ~n : n); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$80-8f(alt0) mult rN +//$80-8f(alt1) umult rN +//$80-8f(alt2) mult #N +//$80-8f(alt3) umult #N +auto GSU::instructionMULT_UMULT(uint n) -> void { + if(!regs.sfr.alt2) n = regs.r[n]; + regs.dr() = (!regs.sfr.alt1 ? uint16((int8)regs.sr() * (int8)n) : uint16((uint8)regs.sr() * (uint8)n)); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); + if(!regs.cfgr.ms0) step(regs.clsr ? 1 : 2); +} + +//$90 sbk +auto GSU::instructionSBK() -> void { + writeRAMBuffer(regs.ramaddr ^ 0, regs.sr() >> 0); + writeRAMBuffer(regs.ramaddr ^ 1, regs.sr() >> 8); + regs.reset(); +} + +//$91-94 link #N +auto GSU::instructionLINK(uint n) -> void { + regs.r[11] = regs.r[15] + n; + regs.reset(); +} + +//$95 sex +auto GSU::instructionSEX() -> void { + regs.dr() = (int8)regs.sr(); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$96(alt0) asr +//$96(alt1) div2 +auto GSU::instructionASR_DIV2() -> void { + regs.sfr.cy = (regs.sr() & 1); + regs.dr() = ((int16)regs.sr() >> 1) + (regs.sfr.alt1 ? ((regs.sr() + 1) >> 16) : 0); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$97 ror +auto GSU::instructionROR() -> void { + 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 +//$98-9d(alt1) ljmp rN +auto GSU::instructionJMP_LJMP(uint n) -> void { + if(!regs.sfr.alt1) { + regs.r[15] = regs.r[n]; + } else { + regs.pbr = regs.r[n] & 0x7f; + regs.r[15] = regs.sr(); + regs.cbr = regs.r[15] & 0xfff0; + flushCache(); + } + regs.reset(); +} + +//$9e lob +auto GSU::instructionLOB() -> void { + regs.dr() = regs.sr() & 0xff; + regs.sfr.s = (regs.dr() & 0x80); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$9f(alt0) fmult +//$9f(alt1) lmult +auto GSU::instructionFMULT_LMULT() -> void { + uint32 result = (int16)regs.sr() * (int16)regs.r[6]; + if(regs.sfr.alt1) 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(); + step((regs.cfgr.ms0 ? 3 : 7) * (regs.clsr ? 1 : 2)); +} + +//$a0-af(alt0) ibt rN,#pp +//$a0-af(alt1) lms rN,(yy) +//$a0-af(alt2) sms (yy),rN +auto GSU::instructionIBT_LMS_SMS(uint n) -> void { + if(regs.sfr.alt1) { + regs.ramaddr = pipe() << 1; + uint8 lo = readRAMBuffer(regs.ramaddr ^ 0) << 0; + regs.r[n] = readRAMBuffer(regs.ramaddr ^ 1) << 8 | lo; + } else if(regs.sfr.alt2) { + regs.ramaddr = pipe() << 1; + writeRAMBuffer(regs.ramaddr ^ 0, regs.r[n] >> 0); + writeRAMBuffer(regs.ramaddr ^ 1, regs.r[n] >> 8); + } else { + regs.r[n] = (int8)pipe(); + } + regs.reset(); +} + +//$b0-bf(b0) from rN +//$b0-bf(b1) moves rN +auto GSU::instructionFROM_MOVES(uint n) -> void { + if(!regs.sfr.b) { + 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 +auto GSU::instructionHIB() -> void { + regs.dr() = regs.sr() >> 8; + regs.sfr.s = (regs.dr() & 0x80); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$c1-cf(alt0) or rN +//$c1-cf(alt1) xor rN +//$c1-cf(alt2) or #N +//$c1-cf(alt3) xor #N +auto GSU::instructionOR_XOR(uint n) -> void { + if(!regs.sfr.alt2) n = regs.r[n]; + regs.dr() = (!regs.sfr.alt1 ? (regs.sr() | n) : (regs.sr() ^ n)); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$d0-de inc rN +auto GSU::instructionINC(uint n) -> void { + regs.r[n]++; + regs.sfr.s = (regs.r[n] & 0x8000); + regs.sfr.z = (regs.r[n] == 0); + regs.reset(); +} + +//$df(alt0) getc +//$df(alt2) ramb +//$df(alt3) romb +auto GSU::instructionGETC_RAMB_ROMB() -> void { + if(!regs.sfr.alt2) { + regs.colr = color(readROMBuffer()); + } else if(!regs.sfr.alt1) { + syncRAMBuffer(); + regs.rambr = regs.sr() & 0x01; + } else { + syncROMBuffer(); + regs.rombr = regs.sr() & 0x7f; + } + regs.reset(); +} + +//$e0-ee dec rN +auto GSU::instructionDEC(uint n) -> void { + regs.r[n]--; + regs.sfr.s = (regs.r[n] & 0x8000); + regs.sfr.z = (regs.r[n] == 0); + regs.reset(); +} + +//$ef(alt0) getb +//$ef(alt1) getbh +//$ef(alt2) getbl +//$ef(alt3) getbs +auto GSU::instructionGETB() -> void { + switch(regs.sfr.alt2 << 1 | regs.sfr.alt1 << 0) { + case 0: regs.dr() = readROMBuffer(); break; + case 1: regs.dr() = readROMBuffer() << 8 | (uint8)regs.sr(); break; + case 2: regs.dr() = (regs.sr() & 0xff00) | readROMBuffer(); break; + case 3: regs.dr() = (int8)readROMBuffer(); break; + } + regs.reset(); +} + +//$f0-ff(alt0) iwt rN,#xx +//$f0-ff(alt1) lm rN,(xx) +//$f0-ff(alt2) sm (xx),rN +auto GSU::instructionIWT_LM_SM(uint n) -> void { + if(regs.sfr.alt1) { + regs.ramaddr = pipe() << 0; + regs.ramaddr |= pipe() << 8; + uint8 lo = readRAMBuffer(regs.ramaddr ^ 0) << 0; + regs.r[n] = readRAMBuffer(regs.ramaddr ^ 1) << 8 | lo; + } else if(regs.sfr.alt2) { + regs.ramaddr = pipe() << 0; + regs.ramaddr |= pipe() << 8; + writeRAMBuffer(regs.ramaddr ^ 0, regs.r[n] >> 0); + writeRAMBuffer(regs.ramaddr ^ 1, regs.r[n] >> 8); + } else { + uint8 lo = pipe(); + regs.r[n] = pipe() << 8 | lo; + } + regs.reset(); +} diff --git a/processor/gsu/registers.hpp b/processor/gsu/registers.hpp new file mode 100644 index 0000000..60492c9 --- /dev/null +++ b/processor/gsu/registers.hpp @@ -0,0 +1,164 @@ +struct Register { + uint16 data = 0; + bool modified = false; + + inline operator uint() const { + return data; + } + + inline auto assign(uint value) -> uint16 { + modified = true; + return data = value; + } + + inline auto operator++() { return assign(data + 1); } + inline auto operator--() { return assign(data - 1); } + inline auto operator++(int) { uint r = data; assign(data + 1); return r; } + inline auto operator--(int) { uint r = data; assign(data - 1); return r; } + inline auto operator = (uint i) { return assign(i); } + inline auto operator |= (uint i) { return assign(data | i); } + inline auto operator ^= (uint i) { return assign(data ^ i); } + inline auto operator &= (uint i) { return assign(data & i); } + inline auto operator <<= (uint i) { return assign(data << i); } + inline auto operator >>= (uint i) { return assign(data >> i); } + inline auto operator += (uint i) { return assign(data + i); } + inline auto operator -= (uint i) { return assign(data - i); } + inline auto operator *= (uint i) { return assign(data * i); } + inline auto operator /= (uint i) { return assign(data / i); } + inline auto operator %= (uint i) { return assign(data % i); } + + inline auto operator = (const Register& value) { return assign(value); } + + Register() = default; + Register(const Register&) = delete; +}; + +struct SFR { + uint16_t data = 0; + + BitField<16, 1> z {&data}; //zero flag + BitField<16, 2> cy {&data}; //carry flag + BitField<16, 3> s {&data}; //sign flag + BitField<16, 4> ov {&data}; //overflow flag + BitField<16, 5> g {&data}; //go flag + BitField<16, 6> r {&data}; //ROM r14 flag + BitField<16, 8> alt1{&data}; //alt1 instruction mode + BitField<16, 9> alt2{&data}; //alt2 instruction mode + BitField<16,10> il {&data}; //immediate lower 8-bit flag + BitField<16,11> ih {&data}; //immediate upper 8-bit flag + BitField<16,12> b {&data}; //with flag + BitField<16,15> irq {&data}; //interrupt flag + + BitRange<16,8,9> alt{&data}; //composite instruction mode + + inline operator uint() const { return data & 0x9f7e; } + inline auto& operator=(const uint value) { return data = value, *this; } +}; + +struct SCMR { + uint ht; + bool ron; + bool ran; + uint md; + + operator uint() const { + return ((ht >> 1) << 5) | (ron << 4) | (ran << 3) | ((ht & 1) << 2) | (md); + } + + auto& operator=(uint data) { + ht = (bool)(data & 0x20) << 1; + ht |= (bool)(data & 0x04) << 0; + ron = data & 0x10; + ran = data & 0x08; + md = data & 0x03; + return *this; + } +}; + +struct POR { + bool obj; + bool freezehigh; + bool highnibble; + bool dither; + bool transparent; + + operator uint() const { + return (obj << 4) | (freezehigh << 3) | (highnibble << 2) | (dither << 1) | (transparent); + } + + auto& operator=(uint data) { + obj = data & 0x10; + freezehigh = data & 0x08; + highnibble = data & 0x04; + dither = data & 0x02; + transparent = data & 0x01; + return *this; + } +}; + +struct CFGR { + bool irq; + bool ms0; + + operator uint() const { + return (irq << 7) | (ms0 << 5); + } + + auto& operator=(uint data) { + irq = data & 0x80; + ms0 = data & 0x20; + return *this; + } +}; + +struct Registers { + uint8 pipeline; + uint16 ramaddr; + + Register r[16]; //general purpose registers + SFR 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 scmr; //screen mode register + uint8 colr; //color register + POR por; //plot option register + bool bramr; //back-up RAM register + uint8 vcr; //version code register + CFGR cfgr; //config register + bool clsr; //clock select register + + uint romcl; //clock ticks until romdr is valid + uint8 romdr; //ROM buffer data register + + uint ramcl; //clock ticks until ramdr is valid + uint16 ramar; //RAM buffer address register + uint8 ramdr; //RAM buffer data register + + uint sreg; + uint dreg; + auto& sr() { return r[sreg]; } //source register (from) + auto& dr() { return r[dreg]; } //destination register (to) + + auto reset() -> void { + sfr.b = 0; + sfr.alt1 = 0; + sfr.alt2 = 0; + + sreg = 0; + dreg = 0; + } +} regs; + +struct Cache { + uint8 buffer[512]; + bool valid[32]; +} cache; + +struct PixelCache { + uint16 offset; + uint8 bitpend; + uint8 data[8]; +} pixelcache[2]; diff --git a/processor/gsu/serialization.cpp b/processor/gsu/serialization.cpp new file mode 100644 index 0000000..816b22b --- /dev/null +++ b/processor/gsu/serialization.cpp @@ -0,0 +1,56 @@ +auto GSU::serialize(serializer& s) -> void { + s.integer(regs.pipeline); + s.integer(regs.ramaddr); + + for(auto n : range(16)) { + s.integer(regs.r[n].data); + s.integer(regs.r[n].modified); + } + + s.integer(regs.sfr.data); + 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(uint n : range(2)) { + s.integer(pixelcache[n].offset); + s.integer(pixelcache[n].bitpend); + s.array(pixelcache[n].data); + } +} diff --git a/processor/hg51b/hg51b.cpp b/processor/hg51b/hg51b.cpp new file mode 100644 index 0000000..499f187 --- /dev/null +++ b/processor/hg51b/hg51b.cpp @@ -0,0 +1,125 @@ +#include +#include "hg51b.hpp" + +namespace Processor { + +#include "registers.cpp" +#include "instruction.cpp" +#include "instructions.cpp" +#include "serialization.cpp" + +auto HG51B::lock() -> void { + io.lock = 1; +} + +auto HG51B::halt() -> void { + io.halt = 1; +} + +auto HG51B::wait(uint24 address) -> uint { + if(isROM(address)) return 1 + io.wait.rom; + if(isRAM(address)) return 1 + io.wait.ram; + return 1; +} + +auto HG51B::main() -> void { + if(io.lock) return step(1); + if(io.suspend.enable) return suspend(); + if(io.cache.enable) return cache(), void(); + if(io.dma.enable) return dma(); + if(io.halt) return step(1); + return execute(); +} + +auto HG51B::step(uint clocks) -> void { + if(io.bus.enable) { + if(io.bus.pending > clocks) { + io.bus.pending -= clocks; + } else { + io.bus.enable = 0; + io.bus.pending = 0; + if(io.bus.reading) io.bus.reading = 0, r.mdr = read(io.bus.address); + if(io.bus.writing) io.bus.writing = 0, write(io.bus.address, r.mdr); + } + } +} + +auto HG51B::execute() -> void { + if(!cache()) return halt(); + auto opcode = programRAM[io.cache.page][r.pc]; + advance(); + step(1); + instructionTable[opcode](); +} + +auto HG51B::advance() -> void { + if(++r.pc == 0) { + if(io.cache.page == 1) return halt(); + io.cache.page = 1; + if(io.cache.lock[io.cache.page]) return halt(); + r.pb = r.p; + if(!cache()) return halt(); + } +} + +auto HG51B::suspend() -> void { + if(!io.suspend.duration) return step(1); //indefinite + step(io.suspend.duration); + io.suspend.duration = 0; + io.suspend.enable = 0; +} + +auto HG51B::cache() -> bool { + uint24 address = io.cache.base + r.pb * 512; + + //try to use the current page ... + if(io.cache.address[io.cache.page] == address) return io.cache.enable = 0, true; + //if it's not valid, try to use the other page ... + io.cache.page ^= 1; + if(io.cache.address[io.cache.page] == address) return io.cache.enable = 0, true; + //if it's not valid, try to load into the other page ... + if(io.cache.lock[io.cache.page]) io.cache.page ^= 1; + //if it's locked, try to load into the first page ... + if(io.cache.lock[io.cache.page]) return io.cache.enable = 0, false; + + io.cache.address[io.cache.page] = address; + for(uint offset : range(256)) { + step(wait(address)); + programRAM[io.cache.page][offset] = read(address++) << 0; + programRAM[io.cache.page][offset] |= read(address++) << 8; + } + return io.cache.enable = 0, true; +} + +auto HG51B::dma() -> void { + for(uint offset : range(io.dma.length)) { + uint24 source = io.dma.source + offset; + uint24 target = io.dma.target + offset; + + if(isROM(source) && isROM(target)) return lock(); + if(isRAM(source) && isRAM(target)) return lock(); + + step(wait(source)); + auto data = read(source); + + step(wait(target)); + write(target, data); + } + + io.dma.enable = 0; +} + +auto HG51B::running() const -> bool { + return io.cache.enable || io.dma.enable || io.bus.pending || !io.halt; +} + +auto HG51B::busy() const -> bool { + return io.cache.enable || io.dma.enable || io.bus.pending; +} + +auto HG51B::power() -> void { + r = {}; + io = {}; +} + +} diff --git a/processor/hg51b/hg51b.hpp b/processor/hg51b/hg51b.hpp new file mode 100644 index 0000000..daae9e8 --- /dev/null +++ b/processor/hg51b/hg51b.hpp @@ -0,0 +1,182 @@ +#pragma once + +//Hitachi HG51B S169 + +namespace Processor { + +struct HG51B { + //instruction.cpp + HG51B(); + + //hg51b.cpp + virtual auto step(uint clocks) -> void; + virtual auto isROM(uint address) -> bool = 0; + virtual auto isRAM(uint address) -> bool = 0; + virtual auto read(uint address) -> uint8 = 0; + virtual auto write(uint address, uint8 data) -> void = 0; + virtual auto lock() -> void; + virtual auto halt() -> void; + auto wait(uint24 address) -> uint; + auto main() -> void; + auto execute() -> void; + auto advance() -> void; + auto suspend() -> void; + auto cache() -> bool; + auto dma() -> void; + auto running() const -> bool; + auto busy() const -> bool; + + auto power() -> void; + + //instructions.cpp + auto push() -> void; + auto pull() -> void; + + auto algorithmADD(uint24 x, uint24 y) -> uint24; + auto algorithmAND(uint24 x, uint24 y) -> uint24; + auto algorithmASR(uint24 a, uint5 s) -> uint24; + auto algorithmMUL(int24 x, int24 y) -> uint48; + auto algorithmOR(uint24 x, uint24 y) -> uint24; + auto algorithmROR(uint24 a, uint5 s) -> uint24; + auto algorithmSHL(uint24 a, uint5 s) -> uint24; + auto algorithmSHR(uint24 a, uint5 s) -> uint24; + auto algorithmSUB(uint24 x, uint24 y) -> uint24; + auto algorithmSX(uint24 x) -> uint24; + auto algorithmXNOR(uint24 x, uint24 y) -> uint24; + auto algorithmXOR(uint24 x, uint24 y) -> uint24; + + auto instructionADD(uint7 reg, uint5 shift) -> void; + auto instructionADD(uint8 imm, uint5 shift) -> void; + auto instructionAND(uint7 reg, uint5 shift) -> void; + auto instructionAND(uint8 imm, uint5 shift) -> void; + auto instructionASR(uint7 reg) -> void; + auto instructionASR(uint5 imm) -> void; + auto instructionCLEAR() -> void; + auto instructionCMP(uint7 reg, uint5 shift) -> void; + auto instructionCMP(uint8 imm, uint5 shift) -> void; + auto instructionCMPR(uint7 reg, uint5 shift) -> void; + auto instructionCMPR(uint8 imm, uint5 shift) -> void; + auto instructionHALT() -> void; + auto instructionINC(uint24& reg) -> void; + auto instructionJMP(uint8 data, uint1 far, const uint1& take) -> void; + auto instructionJSR(uint8 data, uint1 far, const uint1& take) -> void; + auto instructionLD(uint24& out, uint7 reg) -> void; + auto instructionLD(uint15& out, uint4 reg) -> void; + auto instructionLD(uint24& out, uint8 imm) -> void; + auto instructionLD(uint15& out, uint8 imm) -> void; + auto instructionLDL(uint15& out, uint8 imm) -> void; + auto instructionLDH(uint15& out, uint7 imm) -> void; + auto instructionMUL(uint7 reg) -> void; + auto instructionMUL(uint8 imm) -> void; + auto instructionNOP() -> void; + auto instructionOR(uint7 reg, uint5 shift) -> void; + auto instructionOR(uint8 imm, uint5 shift) -> void; + auto instructionRDRAM(uint2 byte, uint24& a) -> void; + auto instructionRDRAM(uint2 byte, uint8 imm) -> void; + auto instructionRDROM(uint24& reg) -> void; + auto instructionRDROM(uint10 imm) -> void; + auto instructionROR(uint7 reg) -> void; + auto instructionROR(uint5 imm) -> void; + auto instructionRTS() -> void; + auto instructionSHL(uint7 reg) -> void; + auto instructionSHL(uint5 imm) -> void; + auto instructionSHR(uint7 reg) -> void; + auto instructionSHR(uint5 imm) -> void; + auto instructionSKIP(uint1 take, const uint1& flag) -> void; + auto instructionST(uint7 reg, uint24& in) -> void; + auto instructionSUB(uint7 reg, uint5 shift) -> void; + auto instructionSUB(uint8 imm, uint5 shift) -> void; + auto instructionSUBR(uint7 reg, uint5 shift) -> void; + auto instructionSUBR(uint8 imm, uint5 shift) -> void; + auto instructionSWAP(uint24& a, uint4 reg) -> void; + auto instructionSXB() -> void; + auto instructionSXW() -> void; + auto instructionWAIT() -> void; + auto instructionWRRAM(uint2 byte, uint24& a) -> void; + auto instructionWRRAM(uint2 byte, uint8 imm) -> void; + auto instructionXNOR(uint7 reg, uint5 shift) -> void; + auto instructionXNOR(uint8 imm, uint5 shift) -> void; + auto instructionXOR(uint7 reg, uint5 shift) -> void; + auto instructionXOR(uint8 imm, uint5 shift) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + uint16 programRAM[2][256]; //instruction cache + uint24 dataROM[1024]; + uint8 dataRAM[3072]; + + //registers.cpp + auto readRegister(uint7 address) -> uint24; + auto writeRegister(uint7 address, uint24 data) -> void; + +protected: + struct Registers { + uint15 pb; //program bank + uint8 pc; //program counter + + boolean n; //negative + boolean z; //zero + boolean c; //carry + boolean v; //overflow + boolean i; //interrupt + + uint24 a; //accumulator + uint15 p; //page register + uint48 mul; //multiplier + uint24 mdr; //bus memory data register + uint24 rom; //data ROM data buffer + uint24 ram; //data RAM data buffer + uint24 mar; //bus memory address register + uint24 dpr; //data RAM address pointer + uint24 gpr[16]; //general purpose registers + } r; + + struct IO { + uint1 lock; + uint1 halt = 1; + uint1 irq; //0 = enable, 1 = disable + uint1 rom = 1; //0 = 2 ROMs, 1 = 1 ROM + uint8 vector[32]; + + struct Wait { + uint3 rom = 3; + uint3 ram = 3; + } wait; + + struct Suspend { + uint1 enable; + uint8 duration; + } suspend; + + struct Cache { + uint1 enable; + uint1 page; + uint1 lock[2]; + uint24 address[2]; //cache address is in bytes; so 24-bit + uint24 base; //base address is also in bytes + uint15 pb; + uint8 pc; + } cache; + + struct DMA { + uint1 enable; + uint24 source; + uint24 target; + uint16 length; + } dma; + + struct Bus { + uint1 enable; + uint1 reading; + uint1 writing; + uint4 pending; + uint24 address; + } bus; + } io; + + uint23 stack[8]; + function instructionTable[65536]; +}; + +} diff --git a/processor/hg51b/instruction.cpp b/processor/hg51b/instruction.cpp new file mode 100644 index 0000000..f3e51d0 --- /dev/null +++ b/processor/hg51b/instruction.cpp @@ -0,0 +1,639 @@ +HG51B::HG51B() { + #define bind(id, name, ...) { \ + if(instructionTable[id]) throw; \ + instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \ + } + + #define pattern(s) \ + std::integral_constant::value + + static const uint5 shifts[] = {0, 1, 8, 16}; + + //NOP + for(uint10 null : range(1024)) { + auto opcode = pattern("0000 00.. .... ...."); + bind(opcode | null << 0, NOP); + } + + //??? + for(uint10 null : range(1024)) { + auto opcode = pattern("0000 01.. .... ...."); + bind(opcode | null << 0, NOP); + } + + //JMP imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0000 10f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, 1); + } + + //JMP EQ,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0000 11f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.z); + } + + //JMP GE,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0001 00f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.c); + } + + //JMP MI,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0001 01f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.n); + } + + //JMP VS,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0001 10f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.v); + } + + //WAIT + for(uint10 null : range(1024)) { + auto opcode = pattern("0001 11.. .... ...."); + bind(opcode | null << 0, WAIT); + } + + //??? + for(uint10 null : range(1024)) { + auto opcode = pattern("0010 00.. .... ...."); + bind(opcode | null << 0, NOP); + } + + //SKIP V + for(uint1 take : range( 2)) + for(uint7 null : range(128)) { + auto opcode = pattern("0010 0100 .... ...t"); + bind(opcode | take << 0 | null << 1, SKIP, take, r.v); + } + + //SKIP C + for(uint1 take : range( 2)) + for(uint7 null : range(128)) { + auto opcode = pattern("0010 0101 .... ...t"); + bind(opcode | take << 0 | null << 1, SKIP, take, r.c); + } + + //SKIP Z + for(uint1 take : range( 2)) + for(uint7 null : range(128)) { + auto opcode = pattern("0010 0110 .... ...t"); + bind(opcode | take << 0 | null << 1, SKIP, take, r.z); + } + + //SKIP N + for(uint1 take : range( 2)) + for(uint7 null : range(128)) { + auto opcode = pattern("0010 0111 .... ...t"); + bind(opcode | take << 0 | null << 1, SKIP, take, r.n); + } + + //JSR + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0010 10f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, 1); + } + + //JSR EQ,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0010 11f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.z); + } + + //JSR GE,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0011 00f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.c); + } + + //JSR MI,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0011 01f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.n); + } + + //JSR VS,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0011 10f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.v); + } + + //RTS + for(uint10 null : range(1024)) { + auto opcode = pattern("0011 11.. .... ...."); + bind(opcode | null << 0, RTS); + } + + //INC MAR + for(uint10 null : range(1024)) { + auto opcode = pattern("0100 00.. .... ...."); + bind(opcode | null << 0, INC, r.mar); + } + + //??? + for(uint10 null : range(1024)) { + auto opcode = pattern("0100 01.. .... ...."); + bind(opcode | null << 0, NOP); + } + + //CMPR A< void { + 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] = r.pb << 8 | r.pc << 0; +} + +auto HG51B::pull() -> void { + auto 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; + + r.pb = pc >> 8; + r.pc = pc >> 0; +} + +// + +auto HG51B::algorithmADD(uint24 x, uint24 y) -> uint24 { + int z = x + y; + r.n = z & 0x800000; + r.z = (uint24)z == 0; + r.c = z > 0xffffff; + r.v = ~(x ^ y) & (x ^ z) & 0x800000; + return z; +} + +auto HG51B::algorithmAND(uint24 x, uint24 y) -> uint24 { + x = x & y; + r.n = x & 0x800000; + r.z = x == 0; + return x; +} + +auto HG51B::algorithmASR(uint24 a, uint5 s) -> uint24 { + if(s > 24) s = 0; + a = (int24)a >> s; + r.n = a & 0x800000; + r.z = a == 0; + return a; +} + +auto HG51B::algorithmMUL(int24 x, int24 y) -> uint48 { + return (int48)x * (int48)y; +} + +auto HG51B::algorithmOR(uint24 x, uint24 y) -> uint24 { + x = x | y; + r.n = x & 0x800000; + r.z = x == 0; + return x; +} + +auto HG51B::algorithmROR(uint24 a, uint5 s) -> uint24 { + if(s > 24) s = 0; + a = (a >> s) | (a << 24 - s); + r.n = a & 0x800000; + r.z = a == 0; + return a; +} + +auto HG51B::algorithmSHL(uint24 a, uint5 s) -> uint24 { + if(s > 24) s = 0; + a = a << s; + r.n = a & 0x800000; + r.z = a == 0; + return a; +} + +auto HG51B::algorithmSHR(uint24 a, uint5 s) -> uint24 { + if(s > 24) s = 0; + a = a >> s; + r.n = a & 0x800000; + r.z = a == 0; + return a; +} + +auto HG51B::algorithmSUB(uint24 x, uint24 y) -> uint24 { + int z = x - y; + r.n = z & 0x800000; + r.z = (uint24)z == 0; + r.c = z >= 0; + r.v = ~(x ^ y) & (x ^ z) & 0x800000; + return z; +} + +auto HG51B::algorithmSX(uint24 x) -> uint24 { + r.n = x & 0x800000; + r.z = x == 0; + return x; +} + +auto HG51B::algorithmXNOR(uint24 x, uint24 y) -> uint24 { + x = ~x ^ y; + r.n = x & 0x800000; + r.z = x == 0; + return x; +} + +auto HG51B::algorithmXOR(uint24 x, uint24 y) -> uint24 { + x = x ^ y; + r.n = x & 0x800000; + r.z = x == 0; + return x; +} + +// + +auto HG51B::instructionADD(uint7 reg, uint5 shift) -> void { + r.a = algorithmADD(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionADD(uint8 imm, uint5 shift) -> void { + r.a = algorithmADD(r.a << shift, imm); +} + +auto HG51B::instructionAND(uint7 reg, uint5 shift) -> void { + r.a = algorithmAND(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionAND(uint8 imm, uint5 shift) -> void { + r.a = algorithmAND(r.a << shift, imm); +} + +auto HG51B::instructionASR(uint7 reg) -> void { + r.a = algorithmASR(r.a, readRegister(reg)); +} + +auto HG51B::instructionASR(uint5 imm) -> void { + r.a = algorithmASR(r.a, imm); +} + +auto HG51B::instructionCLEAR() -> void { + r.a = 0; + r.p = 0; + r.ram = 0; + r.dpr = 0; +} + +auto HG51B::instructionCMP(uint7 reg, uint5 shift) -> void { + algorithmSUB(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionCMP(uint8 imm, uint5 shift) -> void { + algorithmSUB(r.a << shift, imm); +} + +auto HG51B::instructionCMPR(uint7 reg, uint5 shift) -> void { + algorithmSUB(readRegister(reg), r.a << shift); +} + +auto HG51B::instructionCMPR(uint8 imm, uint5 shift) -> void { + algorithmSUB(imm, r.a << shift); +} + +auto HG51B::instructionHALT() -> void { + halt(); +} + +auto HG51B::instructionINC(uint24& reg) -> void { + reg++; +} + +auto HG51B::instructionJMP(uint8 data, uint1 far, const uint1& take) -> void { + if(!take) return; + if(far) r.pb = r.p; + r.pc = data; + step(2); +} + +auto HG51B::instructionJSR(uint8 data, uint1 far, const uint1& take) -> void { + if(!take) return; + push(); + if(far) r.pb = r.p; + r.pc = data; + step(2); +} + +auto HG51B::instructionLD(uint24& out, uint7 reg) -> void { + out = readRegister(reg); +} + +auto HG51B::instructionLD(uint15& out, uint4 reg) -> void { + out = r.gpr[reg]; +} + +auto HG51B::instructionLD(uint24& out, uint8 imm) -> void { + out = imm; +} + +auto HG51B::instructionLD(uint15& out, uint8 imm) -> void { + out = imm; +} + +auto HG51B::instructionLDL(uint15& out, uint8 imm) -> void { + out = out & 0x7f00 | imm << 0; +} + +auto HG51B::instructionLDH(uint15& out, uint7 imm) -> void { + out = out & 0x00ff | (imm & 0x7f) << 8; +} + +auto HG51B::instructionMUL(uint7 reg) -> void { + r.mul = algorithmMUL(r.a, readRegister(reg)); +} + +auto HG51B::instructionMUL(uint8 imm) -> void { + r.mul = algorithmMUL(r.a, imm); +} + +auto HG51B::instructionNOP() -> void { +} + +auto HG51B::instructionOR(uint7 reg, uint5 shift) -> void { + r.a = algorithmOR(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionOR(uint8 imm, uint5 shift) -> void { + r.a = algorithmOR(r.a << shift, imm); +} + +auto HG51B::instructionRDRAM(uint2 byte, uint24& a) -> void { + uint12 address = a; + if(address >= 0xc00) address -= 0x400; + r.ram.byte(byte) = dataRAM[address]; +} + +auto HG51B::instructionRDRAM(uint2 byte, uint8 imm) -> void { + uint12 address = r.dpr + imm; + if(address >= 0xc00) address -= 0x400; + r.ram.byte(byte) = dataRAM[address]; +} + +auto HG51B::instructionRDROM(uint24& reg) -> void { + r.rom = dataROM[(uint10)reg]; +} + +auto HG51B::instructionRDROM(uint10 imm) -> void { + r.rom = dataROM[imm]; +} + +auto HG51B::instructionROR(uint7 reg) -> void { + r.a = algorithmROR(r.a, readRegister(reg)); +} + +auto HG51B::instructionROR(uint5 imm) -> void { + r.a = algorithmROR(r.a, imm); +} + +auto HG51B::instructionRTS() -> void { + pull(); + step(2); +} + +auto HG51B::instructionSKIP(uint1 take, const uint1& flag) -> void { + if(flag != take) return; + advance(); + step(1); +} + +auto HG51B::instructionSHL(uint7 reg) -> void { + r.a = algorithmSHL(r.a, readRegister(reg)); +} + +auto HG51B::instructionSHL(uint5 imm) -> void { + r.a = algorithmSHL(r.a, imm); +} + +auto HG51B::instructionSHR(uint7 reg) -> void { + r.a = algorithmSHR(r.a, readRegister(reg)); +} + +auto HG51B::instructionSHR(uint5 imm) -> void { + r.a = algorithmSHR(r.a, imm); +} + +auto HG51B::instructionST(uint7 reg, uint24& in) -> void { + writeRegister(reg, in); +} + +auto HG51B::instructionSUB(uint7 reg, uint5 shift) -> void { + r.a = algorithmSUB(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionSUB(uint8 imm, uint5 shift) -> void { + r.a = algorithmSUB(r.a << shift, imm); +} + +auto HG51B::instructionSUBR(uint7 reg, uint5 shift) -> void { + r.a = algorithmSUB(readRegister(reg), r.a << shift); +} + +auto HG51B::instructionSUBR(uint8 imm, uint5 shift) -> void { + r.a = algorithmSUB(imm, r.a << shift); +} + +auto HG51B::instructionSWAP(uint24& a, uint4 reg) -> void { + swap(a, r.gpr[reg]); +} + +auto HG51B::instructionSXB() -> void { + r.a = algorithmSX((int8)r.a); +} + +auto HG51B::instructionSXW() -> void { + r.a = algorithmSX((int16)r.a); +} + +auto HG51B::instructionWAIT() -> void { + if(!io.bus.enable) return; + return step(io.bus.pending); +} + +auto HG51B::instructionWRRAM(uint2 byte, uint24& a) -> void { + uint12 address = a; + if(address >= 0xc00) address -= 0x400; + dataRAM[address] = r.ram.byte(byte); +} + +auto HG51B::instructionWRRAM(uint2 byte, uint8 imm) -> void { + uint12 address = r.dpr + imm; + if(address >= 0xc00) address -= 0x400; + dataRAM[address] = r.ram.byte(byte); +} + +auto HG51B::instructionXNOR(uint7 reg, uint5 shift) -> void { + r.a = algorithmXNOR(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionXNOR(uint8 imm, uint5 shift) -> void { + r.a = algorithmXNOR(r.a << shift, imm); +} + +auto HG51B::instructionXOR(uint7 reg, uint5 shift) -> void { + r.a = algorithmXOR(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionXOR(uint8 imm, uint5 shift) -> void { + r.a = algorithmXOR(r.a << shift, imm); +} diff --git a/processor/hg51b/registers.cpp b/processor/hg51b/registers.cpp new file mode 100644 index 0000000..65bb42b --- /dev/null +++ b/processor/hg51b/registers.cpp @@ -0,0 +1,106 @@ +auto HG51B::readRegister(uint7 address) -> uint24 { + switch(address) { + case 0x01: return r.mul >> 24 & 0xffffff; + case 0x02: return r.mul >> 0 & 0xffffff; + case 0x03: return r.mdr; + case 0x08: return r.rom; + case 0x0c: return r.ram; + case 0x13: return r.mar; + case 0x1c: return r.dpr; + case 0x20: return r.pc; + case 0x28: return r.p; + case 0x2e: + io.bus.enable = 1; + io.bus.reading = 1; + io.bus.pending = 1 + io.wait.rom; + io.bus.address = r.mar; + return 0x000000; + case 0x2f: + io.bus.enable = 1; + io.bus.reading = 1; + io.bus.pending = 1 + io.wait.ram; + io.bus.address = r.mar; + return 0x000000; + + //constant registers + 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; + + //general purpose registers + case 0x60: case 0x70: return r.gpr[ 0]; + case 0x61: case 0x71: return r.gpr[ 1]; + case 0x62: case 0x72: return r.gpr[ 2]; + case 0x63: case 0x73: return r.gpr[ 3]; + case 0x64: case 0x74: return r.gpr[ 4]; + case 0x65: case 0x75: return r.gpr[ 5]; + case 0x66: case 0x76: return r.gpr[ 6]; + case 0x67: case 0x77: return r.gpr[ 7]; + case 0x68: case 0x78: return r.gpr[ 8]; + case 0x69: case 0x79: return r.gpr[ 9]; + case 0x6a: case 0x7a: return r.gpr[10]; + case 0x6b: case 0x7b: return r.gpr[11]; + case 0x6c: case 0x7c: return r.gpr[12]; + case 0x6d: case 0x7d: return r.gpr[13]; + case 0x6e: case 0x7e: return r.gpr[14]; + case 0x6f: case 0x7f: return r.gpr[15]; + } + + return 0x000000; //verified +} + +auto HG51B::writeRegister(uint7 address, uint24 data) -> void { + switch(address) { + case 0x01: r.mul = r.mul & 0xffffffull | data << 24; return; + case 0x02: r.mul = r.mul & ~0xffffffull | data << 0; return; + case 0x03: r.mdr = data; return; + case 0x08: r.rom = data; return; + case 0x0c: r.ram = data; return; + case 0x13: r.mar = data; return; + case 0x1c: r.dpr = data; return; + case 0x20: r.pc = data; return; + case 0x28: r.p = data; return; + case 0x2e: + io.bus.enable = 1; + io.bus.writing = 1; + io.bus.pending = 1 + io.wait.rom; + io.bus.address = r.mar; + return; + case 0x2f: + io.bus.enable = 1; + io.bus.writing = 1; + io.bus.pending = 1 + io.wait.ram; + io.bus.address = r.mar; + return; + + case 0x60: case 0x70: r.gpr[ 0] = data; return; + case 0x61: case 0x71: r.gpr[ 1] = data; return; + case 0x62: case 0x72: r.gpr[ 2] = data; return; + case 0x63: case 0x73: r.gpr[ 3] = data; return; + case 0x64: case 0x74: r.gpr[ 4] = data; return; + case 0x65: case 0x75: r.gpr[ 5] = data; return; + case 0x66: case 0x76: r.gpr[ 6] = data; return; + case 0x67: case 0x77: r.gpr[ 7] = data; return; + case 0x68: case 0x78: r.gpr[ 8] = data; return; + case 0x69: case 0x79: r.gpr[ 9] = data; return; + case 0x6a: case 0x7a: r.gpr[10] = data; return; + case 0x6b: case 0x7b: r.gpr[11] = data; return; + case 0x6c: case 0x7c: r.gpr[12] = data; return; + case 0x6d: case 0x7d: r.gpr[13] = data; return; + case 0x6e: case 0x7e: r.gpr[14] = data; return; + case 0x6f: case 0x7f: r.gpr[15] = data; return; + } +} diff --git a/processor/hg51b/serialization.cpp b/processor/hg51b/serialization.cpp new file mode 100644 index 0000000..d8fd4ee --- /dev/null +++ b/processor/hg51b/serialization.cpp @@ -0,0 +1,57 @@ +auto HG51B::serialize(serializer& s) -> void { + s.array(programRAM[0]); + s.array(programRAM[1]); + s.array(dataRAM); + + s.integer(r.pb); + s.integer(r.pc); + + s.boolean(r.n); + s.boolean(r.z); + s.boolean(r.c); + s.boolean(r.v); + s.boolean(r.i); + + s.integer(r.a); + s.integer(r.p); + s.integer(r.mul); + s.integer(r.mdr); + s.integer(r.rom); + s.integer(r.ram); + s.integer(r.mar); + s.integer(r.dpr); + s.array(r.gpr); + + s.integer(io.lock); + s.integer(io.halt); + s.integer(io.irq); + s.integer(io.rom); + s.array(io.vector); + + s.integer(io.wait.rom); + s.integer(io.wait.ram); + + s.integer(io.suspend.enable); + s.integer(io.suspend.duration); + + s.integer(io.cache.enable); + s.integer(io.cache.page); + s.array(io.cache.lock); + s.array(io.cache.address); + s.integer(io.cache.base); + s.integer(io.cache.pb); + s.integer(io.cache.pc); + + s.integer(io.dma.enable); + s.integer(io.dma.source); + s.integer(io.dma.target); + s.integer(io.dma.length); + + s.integer(io.bus.enable); + s.integer(io.bus.reading); + s.integer(io.bus.writing); + s.integer(io.bus.pending); + s.integer(io.bus.address); + + s.array(stack); +} diff --git a/processor/processor.hpp b/processor/processor.hpp new file mode 100644 index 0000000..b549982 --- /dev/null +++ b/processor/processor.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/processor/spc700/algorithms.cpp b/processor/spc700/algorithms.cpp new file mode 100644 index 0000000..d7e3745 --- /dev/null +++ b/processor/spc700/algorithms.cpp @@ -0,0 +1,130 @@ +auto SPC700::algorithmADC(uint8 x, uint8 y) -> uint8 { + int z = x + y + CF; + CF = z > 0xff; + ZF = (uint8)z == 0; + HF = (x ^ y ^ z) & 0x10; + VF = ~(x ^ y) & (x ^ z) & 0x80; + NF = z & 0x80; + return z; +} + +auto SPC700::algorithmAND(uint8 x, uint8 y) -> uint8 { + x &= y; + ZF = x == 0; + NF = x & 0x80; + return x; +} + +auto SPC700::algorithmASL(uint8 x) -> uint8 { + CF = x & 0x80; + x <<= 1; + ZF = x == 0; + NF = x & 0x80; + return x; +} + +auto SPC700::algorithmCMP(uint8 x, uint8 y) -> uint8 { + int z = x - y; + CF = z >= 0; + ZF = (uint8)z == 0; + NF = z & 0x80; + return x; +} + +auto SPC700::algorithmDEC(uint8 x) -> uint8 { + x--; + ZF = x == 0; + NF = x & 0x80; + return x; +} + +auto SPC700::algorithmEOR(uint8 x, uint8 y) -> uint8 { + x ^= y; + ZF = x == 0; + NF = x & 0x80; + return x; +} + +auto SPC700::algorithmINC(uint8 x) -> uint8 { + x++; + ZF = x == 0; + NF = x & 0x80; + return x; +} + +auto SPC700::algorithmLD(uint8 x, uint8 y) -> uint8 { + ZF = y == 0; + NF = y & 0x80; + return y; +} + +auto SPC700::algorithmLSR(uint8 x) -> uint8 { + CF = x & 0x01; + x >>= 1; + ZF = x == 0; + NF = x & 0x80; + return x; +} + +auto SPC700::algorithmOR(uint8 x, uint8 y) -> uint8 { + x |= y; + ZF = x == 0; + NF = x & 0x80; + return x; +} + +auto SPC700::algorithmROL(uint8 x) -> uint8 { + bool carry = CF; + CF = x & 0x80; + x = x << 1 | carry; + ZF = x == 0; + NF = x & 0x80; + return x; +} + +auto SPC700::algorithmROR(uint8 x) -> uint8 { + bool carry = CF; + CF = x & 0x01; + x = carry << 7 | x >> 1; + ZF = x == 0; + NF = x & 0x80; + return x; +} + +auto SPC700::algorithmSBC(uint8 x, uint8 y) -> uint8 { + return algorithmADC(x, ~y); +} + +// + +auto SPC700::algorithmADW(uint16 x, uint16 y) -> uint16 { + uint16 z; + CF = 0; + z = algorithmADC(x, y); + z |= algorithmADC(x >> 8, y >> 8) << 8; + ZF = z == 0; + return z; +} + +auto SPC700::algorithmCPW(uint16 x, uint16 y) -> uint16 { + int z = x - y; + CF = z >= 0; + ZF = (uint16)z == 0; + NF = z & 0x8000; + return x; +} + +auto SPC700::algorithmLDW(uint16 x, uint16 y) -> uint16 { + ZF = y == 0; + NF = y & 0x8000; + return y; +} + +auto SPC700::algorithmSBW(uint16 x, uint16 y) -> uint16 { + uint16 z; + CF = 1; + z = algorithmSBC(x, y); + z |= algorithmSBC(x >> 8, y >> 8) << 8; + ZF = z == 0; + return z; +} diff --git a/processor/spc700/disassembler.cpp b/processor/spc700/disassembler.cpp new file mode 100644 index 0000000..1251cb7 --- /dev/null +++ b/processor/spc700/disassembler.cpp @@ -0,0 +1,305 @@ +auto SPC700::disassemble(uint16 addr, bool p) -> string { + auto read = [&](uint16 addr) -> uint8 { + return readDisassembler(addr); + }; + + auto relative = [&](uint length, int8 offset) -> uint16 { + uint16 pc = addr + length; + return pc + offset; + }; + + auto a = [&] { return hex((read(addr + 1) << 0) + (read(addr + 2) << 8), 4L); }; + auto b = [&](uint n) { return hex(read(addr + 1 + n), 2L); }; + auto rel = [&](uint r, uint n = 0) { return hex(addr + r + (int8)read(addr + 1 + n), 4L); }; + auto dp = [&](uint n) { return hex((p << 8) + read(addr + 1 + n), 3L); }; + auto ab = [&] { + uint n = (read(addr + 1) << 0) + (read(addr + 2) << 8); + return string{hex(n & 0x1fff, 4L), ":", hex(n >> 13, 1L)}; + }; + + auto mnemonic = [&]() -> string { + switch(read(addr)) { + case 0x00: return { "nop" }; + case 0x01: return { "jst $ffde" }; + case 0x02: return { "set $", dp(0), ":0" }; + case 0x03: return { "bbs $", dp(0), ":0=$", rel(+3, 1) }; + case 0x04: return { "ora $", dp(0) }; + case 0x05: return { "ora $", a() }; + case 0x06: return { "ora (x)" }; + case 0x07: return { "ora ($", dp(0), ",x)" }; + case 0x08: return { "ora #$", b(0) }; + case 0x09: return { "orr $", dp(1), "=$", dp(0) }; + case 0x0a: return { "orc $", ab() }; + case 0x0b: return { "asl $", dp(0) }; + case 0x0c: return { "asl $", a() }; + case 0x0d: return { "php" }; + case 0x0e: return { "tsb $", a() }; + case 0x0f: return { "brk" }; + case 0x10: return { "bpl $", rel(+2) }; + case 0x11: return { "jst $ffdc" }; + case 0x12: return { "clr $", dp(0), ":0" }; + case 0x13: return { "bbc $", dp(0), ":0=$", rel(+3, 1) }; + case 0x14: return { "ora $", dp(0), ",x" }; + case 0x15: return { "ora $", a(), ",x" }; + case 0x16: return { "ora $", a(), ",y" }; + case 0x17: return { "ora ($", dp(0), "),y" }; + case 0x18: return { "orr $", dp(1), "=#$", b(0) }; + case 0x19: return { "orr (x)=(y)" }; + case 0x1a: return { "dew $", dp(0) }; + case 0x1b: return { "asl $", dp(0), ",x" }; + case 0x1c: return { "asl" }; + case 0x1d: return { "dex" }; + case 0x1e: return { "cpx $", a() }; + case 0x1f: return { "jmp ($", a(), ",x)" }; + case 0x20: return { "clp" }; + case 0x21: return { "jst $ffda" }; + case 0x22: return { "set $", dp(0), ":1" }; + case 0x23: return { "bbs $", dp(0), ":1=$", rel(+3, 1) }; + case 0x24: return { "and $", dp(0) }; + case 0x25: return { "and $", a() }; + case 0x26: return { "and (x)" }; + case 0x27: return { "and ($", dp(0), ",x)" }; + case 0x28: return { "and #$", b(0) }; + case 0x29: return { "and $", dp(1), "=$", dp(0) }; + case 0x2a: return { "orc !$", ab() }; + case 0x2b: return { "rol $", dp(0) }; + case 0x2c: return { "rol $", a() }; + case 0x2d: return { "pha" }; + case 0x2e: return { "bne $", dp(0), "=$", rel(+3, 1) }; + case 0x2f: return { "bra $", rel(+2) }; + case 0x30: return { "bmi $", rel(+2) }; + case 0x31: return { "jst $ffd8" }; + case 0x32: return { "clr $", dp(0), ":1" }; + case 0x33: return { "bbc $", dp(0), ":1=$", rel(+3, 1) }; + case 0x34: return { "and $", dp(0), ",x" }; + case 0x35: return { "and $", a(), ",x" }; + case 0x36: return { "and $", a(), ",y" }; + case 0x37: return { "and ($", dp(0), "),y" }; + case 0x38: return { "and $", dp(1), "=#$", b(0) }; + case 0x39: return { "and (x)=(y)" }; + case 0x3a: return { "inw $", dp(0) }; + case 0x3b: return { "rol $", dp(0), ",x" }; + case 0x3c: return { "rol" }; + case 0x3d: return { "inx" }; + case 0x3e: return { "cpx $", dp(0) }; + case 0x3f: return { "jsr $", a() }; + case 0x40: return { "sep" }; + case 0x41: return { "jst $ffd6" }; + case 0x42: return { "set $", dp(0), ":2" }; + case 0x43: return { "bbs $", dp(0), ":2=$", rel(+3, 1) }; + case 0x44: return { "eor $", dp(0) }; + case 0x45: return { "eor $", a() }; + case 0x46: return { "eor (x)" }; + case 0x47: return { "eor ($", dp(0), ",x)" }; + case 0x48: return { "eor #$", b(0) }; + case 0x49: return { "eor $", dp(1), "=$", dp(0) }; + case 0x4a: return { "and $", ab() }; + case 0x4b: return { "lsr $", dp(0) }; + case 0x4c: return { "lsr $", a() }; + case 0x4d: return { "phx" }; + case 0x4e: return { "trb $", a() }; + case 0x4f: return { "jsp $ff", b(0) }; + case 0x50: return { "bvc $", rel(+2) }; + case 0x51: return { "jst $ffd4" }; + case 0x52: return { "clr $", dp(0), ":2" }; + case 0x53: return { "bbc $", dp(0), ":2=$", rel(+3, 1) }; + case 0x54: return { "eor $", dp(0), ",x" }; + case 0x55: return { "eor $", a(), ",x" }; + case 0x56: return { "eor $", a(), ",y" }; + case 0x57: return { "eor ($", dp(0), "),y" }; + case 0x58: return { "eor $", dp(1), "=#$", b(0) }; + case 0x59: return { "eor (x)=(y)" }; + case 0x5a: return { "cpw $", a() }; + case 0x5b: return { "lsr $", dp(0), ",x" }; + case 0x5c: return { "lsr" }; + case 0x5d: return { "tax" }; + case 0x5e: return { "cpy $", a() }; + case 0x5f: return { "jmp $", a() }; + case 0x60: return { "clc" }; + case 0x61: return { "jst $ffd2" }; + case 0x62: return { "set $", dp(0), ":3" }; + case 0x63: return { "bbs $", dp(0), ":3=$", rel(+3, 1) }; + case 0x64: return { "cmp $", dp(0) }; + case 0x65: return { "cmp $", a() }; + case 0x66: return { "cmp (x)" }; + case 0x67: return { "cmp ($", dp(0), ",x)" }; + case 0x68: return { "cmp #$", b(0) }; + case 0x69: return { "cmp $", dp(1), "=$", dp(0) }; + case 0x6a: return { "and !$", ab() }; + case 0x6b: return { "ror $", dp(0) }; + case 0x6c: return { "ror $", a() }; + case 0x6d: return { "phy" }; + case 0x6e: return { "bne --$", dp(0), "=$", rel(+3, 1) }; + case 0x6f: return { "rts" }; + case 0x70: return { "bvs $", rel(+2) }; + case 0x71: return { "jst $ffd0" }; + case 0x72: return { "clr $", dp(0), ":3" }; + case 0x73: return { "bbc $", dp(0), ":3=$", rel(+3, 1) }; + case 0x74: return { "cmp $", dp(0), ",x" }; + case 0x75: return { "cmp $", a(), ",x" }; + case 0x76: return { "cmp $", a(), ",y" }; + case 0x77: return { "cmp ($", dp(0), "),y" }; + case 0x78: return { "cmp $", dp(1), "=#$", b(0) }; + case 0x79: return { "cmp (x)=(y)" }; + case 0x7a: return { "adw $", a() }; + case 0x7b: return { "ror $", dp(0), ",x" }; + case 0x7c: return { "ror" }; + case 0x7d: return { "txa" }; + case 0x7e: return { "cpy $", dp(0) }; + case 0x7f: return { "rti" }; + case 0x80: return { "sec" }; + case 0x81: return { "jst $ffce" }; + case 0x82: return { "set $", dp(0), ":4" }; + case 0x83: return { "bbs $", dp(0), ":4=$", rel(+3, 1) }; + case 0x84: return { "adc $", dp(0) }; + case 0x85: return { "adc $", a() }; + case 0x86: return { "adc (x)" }; + case 0x87: return { "adc ($", dp(0), ",x)" }; + case 0x88: return { "adc #$", b(0) }; + case 0x89: return { "adc $", dp(1), "=$", dp(0) }; + case 0x8a: return { "eor $", ab() }; + case 0x8b: return { "dec $", dp(0) }; + case 0x8c: return { "dec $", a() }; + case 0x8d: return { "ldy #$", b(0) }; + case 0x8e: return { "plp" }; + case 0x8f: return { "str $", dp(1), "=#$", b(0) }; + case 0x90: return { "bcc $", rel(+2) }; + case 0x91: return { "jst $ffcc" }; + case 0x92: return { "clr $", dp(0), ":4" }; + case 0x93: return { "bbc $", dp(0), ":4=$", rel(+3, 1) }; + case 0x94: return { "adc $", dp(0), ",x" }; + case 0x95: return { "adc $", a(), ",x" }; + case 0x96: return { "adc $", a(), ",y" }; + case 0x97: return { "adc ($", dp(0), "),y" }; + case 0x98: return { "adc $", dp(1), "=#$", b(0) }; + case 0x99: return { "adc (x)=(y)" }; + case 0x9a: return { "sbw $", a() }; + case 0x9b: return { "dec $", dp(0), ",x" }; + case 0x9c: return { "dec" }; + case 0x9d: return { "tsx" }; + case 0x9e: return { "div" }; + case 0x9f: return { "xcn" }; + case 0xa0: return { "sei" }; + case 0xa1: return { "jst $ffca" }; + case 0xa2: return { "set $", dp(0), ":5" }; + case 0xa3: return { "bbs $", dp(0), ":5=$", rel(+3, 1) }; + case 0xa4: return { "sbc $", dp(0) }; + case 0xa5: return { "sbc $", a() }; + case 0xa6: return { "sbc (x)" }; + case 0xa7: return { "sbc ($", dp(0), ",x)" }; + case 0xa8: return { "sbc #$", b(0) }; + case 0xa9: return { "sbc $", dp(1), "=$", dp(0) }; + case 0xaa: return { "ldc $", ab() }; + case 0xab: return { "inc $", dp(0) }; + case 0xac: return { "inc $", a() }; + case 0xad: return { "cpy #$", b(0) }; + case 0xae: return { "pla" }; + case 0xaf: return { "sta (x++)" }; + case 0xb0: return { "bcs $", rel(+2) }; + case 0xb1: return { "jst $ffc8" }; + case 0xb2: return { "clr $", dp(0), ":5" }; + case 0xb3: return { "bbc $", dp(0), ":5=$", rel(+3, 1) }; + case 0xb4: return { "sbc $", dp(0), ",x" }; + case 0xb5: return { "sbc $", a(), ",x" }; + case 0xb6: return { "sbc $", a(), ",y" }; + case 0xb7: return { "sbc ($", dp(0), "),y" }; + case 0xb8: return { "sbc $", dp(1), "=#$", b(0) }; + case 0xb9: return { "sbc (x)=(y)" }; + case 0xba: return { "ldw $", dp(0) }; + case 0xbb: return { "inc $", dp(0), ",x" }; + case 0xbc: return { "inc" }; + case 0xbd: return { "txs" }; + case 0xbe: return { "das" }; + case 0xbf: return { "lda (x++)" }; + case 0xc0: return { "cli" }; + case 0xc1: return { "jst $ffc6" }; + case 0xc2: return { "set $", dp(0), ":6" }; + case 0xc3: return { "bbs $", dp(0), ":6=$", rel(+3, 1) }; + case 0xc4: return { "sta $", dp(0) }; + case 0xc5: return { "sta $", a() }; + case 0xc6: return { "sta (x)" }; + case 0xc7: return { "sta ($", dp(0), ",x)" }; + case 0xc8: return { "cpx #$", b(0) }; + case 0xc9: return { "stx $", a() }; + case 0xca: return { "stc $", ab() }; + case 0xcb: return { "sty $", dp(0) }; + case 0xcc: return { "sty $", a() }; + case 0xcd: return { "ldx #$", b(0) }; + case 0xce: return { "plx" }; + case 0xcf: return { "mul" }; + case 0xd0: return { "bne $", rel(+2) }; + case 0xd1: return { "jst $ffc4" }; + case 0xd2: return { "clr $", dp(0), ":6" }; + case 0xd3: return { "bbc $", dp(0), ":6=$", rel(+3, 1) }; + case 0xd4: return { "sta $", dp(0), ",x" }; + case 0xd5: return { "sta $", a(), ",x" }; + case 0xd6: return { "sta $", a(), ",y" }; + case 0xd7: return { "sta ($", dp(0), "),y" }; + case 0xd8: return { "stx $", dp(0) }; + case 0xd9: return { "stx $", dp(0), ",y" }; + case 0xda: return { "stw $", dp(0) }; + case 0xdb: return { "sty $", dp(0), ",x" }; + case 0xdc: return { "dey" }; + case 0xdd: return { "tya" }; + case 0xde: return { "bne $", dp(0), ",x=$", rel(+3, 1) }; + case 0xdf: return { "daa" }; + case 0xe0: return { "clv" }; + case 0xe1: return { "jst $ffc2" }; + case 0xe2: return { "set $", dp(0), ":7" }; + case 0xe3: return { "bbs $", dp(0), ":7=$", rel(+3, 1) }; + case 0xe4: return { "lda $", dp(0) }; + case 0xe5: return { "lda $", a() }; + case 0xe6: return { "lda (x)" }; + case 0xe7: return { "lda ($", dp(0), ",x)" }; + case 0xe8: return { "lda #$", b(0) }; + case 0xe9: return { "ldx $", a() }; + case 0xea: return { "not $", ab() }; + case 0xeb: return { "ldy $", dp(0) }; + case 0xec: return { "ldy $", a() }; + case 0xed: return { "cmc" }; + case 0xee: return { "ply" }; + case 0xef: return { "wai" }; + case 0xf0: return { "beq $", rel(+2) }; + case 0xf1: return { "jst $ffc0" }; + case 0xf2: return { "clr $", dp(0), ":7" }; + case 0xf3: return { "bbc $", dp(0), ":7=$", rel(+3, 1) }; + case 0xf4: return { "lda $", dp(0), ",x" }; + case 0xf5: return { "lda $", a(), ",x" }; + case 0xf6: return { "lda $", a(), ",y" }; + case 0xf7: return { "lda ($", dp(0), "),y" }; + case 0xf8: return { "ldx $", dp(0) }; + case 0xf9: return { "ldx $", dp(0), ",y" }; + case 0xfa: return { "str $", dp(1), "=$", dp(0) }; + case 0xfb: return { "ldy $", dp(0), ",x" }; + case 0xfc: return { "iny" }; + case 0xfd: return { "tay" }; + case 0xfe: return { "bne --y=$", rel(+2) }; + case 0xff: return { "stp" }; + } + throw; + }; + + string output = {"..", hex(addr, 4L), " ", mnemonic()}; + + uint length = output.length(); + while(length++ < 30) output.append(" "); + + output.append( + "YA:", hex(YA, 4L), + " A:", hex(A, 2L), + " X:", hex(X, 2L), + " Y:", hex(Y, 2L), + " S:", hex(S, 2L), + " ", + NF ? "N" : "n", + VF ? "V" : "v", + PF ? "P" : "p", + BF ? "B" : "b", + HF ? "H" : "h", + IF ? "I" : "i", + ZF ? "Z" : "z", + CF ? "C" : "c" + ); + + return output; +} diff --git a/processor/spc700/instruction.cpp b/processor/spc700/instruction.cpp new file mode 100644 index 0000000..4d04d88 --- /dev/null +++ b/processor/spc700/instruction.cpp @@ -0,0 +1,266 @@ +#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__); +#define fp(name) &SPC700::algorithm##name + +auto SPC700::instruction() -> void { + switch(fetch()) { + op(0x00, NoOperation) + op(0x01, CallTable, 0) + op(0x02, AbsoluteBitSet, 0, true) + op(0x03, BranchBit, 0, true) + op(0x04, DirectRead, fp(OR), A) + op(0x05, AbsoluteRead, fp(OR), A) + op(0x06, IndirectXRead, fp(OR)) + op(0x07, IndexedIndirectRead, fp(OR), X) + op(0x08, ImmediateRead, fp(OR), A) + op(0x09, DirectDirectModify, fp(OR)) + op(0x0a, AbsoluteBitModify, 0) + op(0x0b, DirectModify, fp(ASL)) + op(0x0c, AbsoluteModify, fp(ASL)) + op(0x0d, Push, P) + op(0x0e, TestSetBitsAbsolute, true) + op(0x0f, Break) + op(0x10, Branch, NF == 0) + op(0x11, CallTable, 1) + op(0x12, AbsoluteBitSet, 0, false) + op(0x13, BranchBit, 0, false) + op(0x14, DirectIndexedRead, fp(OR), A, X) + op(0x15, AbsoluteIndexedRead, fp(OR), X) + op(0x16, AbsoluteIndexedRead, fp(OR), Y) + op(0x17, IndirectIndexedRead, fp(OR), Y) + op(0x18, DirectImmediateModify, fp(OR)) + op(0x19, IndirectXWriteIndirectY, fp(OR)) + op(0x1a, DirectModifyWord, -1) + op(0x1b, DirectIndexedModify, fp(ASL), X) + op(0x1c, ImpliedModify, fp(ASL), A) + op(0x1d, ImpliedModify, fp(DEC), X) + op(0x1e, AbsoluteRead, fp(CMP), X) + op(0x1f, JumpIndirectX) + op(0x20, FlagSet, PF, false) + op(0x21, CallTable, 2) + op(0x22, AbsoluteBitSet, 1, true) + op(0x23, BranchBit, 1, true) + op(0x24, DirectRead, fp(AND), A) + op(0x25, AbsoluteRead, fp(AND), A) + op(0x26, IndirectXRead, fp(AND)) + op(0x27, IndexedIndirectRead, fp(AND), X) + op(0x28, ImmediateRead, fp(AND), A) + op(0x29, DirectDirectModify, fp(AND)) + op(0x2a, AbsoluteBitModify, 1) + op(0x2b, DirectModify, fp(ROL)) + op(0x2c, AbsoluteModify, fp(ROL)) + op(0x2d, Push, A) + op(0x2e, BranchNotDirect) + op(0x2f, Branch, true) + op(0x30, Branch, NF == 1) + op(0x31, CallTable, 3) + op(0x32, AbsoluteBitSet, 1, false) + op(0x33, BranchBit, 1, false) + op(0x34, DirectIndexedRead, fp(AND), A, X) + op(0x35, AbsoluteIndexedRead, fp(AND), X) + op(0x36, AbsoluteIndexedRead, fp(AND), Y) + op(0x37, IndirectIndexedRead, fp(AND), Y) + op(0x38, DirectImmediateModify, fp(AND)) + op(0x39, IndirectXWriteIndirectY, fp(AND)) + op(0x3a, DirectModifyWord, +1) + op(0x3b, DirectIndexedModify, fp(ROL), X) + op(0x3c, ImpliedModify, fp(ROL), A) + op(0x3d, ImpliedModify, fp(INC), X) + op(0x3e, DirectRead, fp(CMP), X) + op(0x3f, CallAbsolute) + op(0x40, FlagSet, PF, true) + op(0x41, CallTable, 4) + op(0x42, AbsoluteBitSet, 2, true) + op(0x43, BranchBit, 2, true) + op(0x44, DirectRead, fp(EOR), A) + op(0x45, AbsoluteRead, fp(EOR), A) + op(0x46, IndirectXRead, fp(EOR)) + op(0x47, IndexedIndirectRead, fp(EOR), X) + op(0x48, ImmediateRead, fp(EOR), A) + op(0x49, DirectDirectModify, fp(EOR)) + op(0x4a, AbsoluteBitModify, 2) + op(0x4b, DirectModify, fp(LSR)) + op(0x4c, AbsoluteModify, fp(LSR)) + op(0x4d, Push, X) + op(0x4e, TestSetBitsAbsolute, false) + op(0x4f, CallPage) + op(0x50, Branch, VF == 0) + op(0x51, CallTable, 5) + op(0x52, AbsoluteBitSet, 2, false) + op(0x53, BranchBit, 2, false) + op(0x54, DirectIndexedRead, fp(EOR), A, X) + op(0x55, AbsoluteIndexedRead, fp(EOR), X) + op(0x56, AbsoluteIndexedRead, fp(EOR), Y) + op(0x57, IndirectIndexedRead, fp(EOR), Y) + op(0x58, DirectImmediateModify, fp(EOR)) + op(0x59, IndirectXWriteIndirectY, fp(EOR)) + op(0x5a, DirectCompareWord, fp(CPW)) + op(0x5b, DirectIndexedModify, fp(LSR), X) + op(0x5c, ImpliedModify, fp(LSR), A) + op(0x5d, Transfer, A, X) + op(0x5e, AbsoluteRead, fp(CMP), Y) + op(0x5f, JumpAbsolute) + op(0x60, FlagSet, CF, false) + op(0x61, CallTable, 6) + op(0x62, AbsoluteBitSet, 3, true) + op(0x63, BranchBit, 3, true) + op(0x64, DirectRead, fp(CMP), A) + op(0x65, AbsoluteRead, fp(CMP), A) + op(0x66, IndirectXRead, fp(CMP)) + op(0x67, IndexedIndirectRead, fp(CMP), X) + op(0x68, ImmediateRead, fp(CMP), A) + op(0x69, DirectDirectCompare, fp(CMP)) + op(0x6a, AbsoluteBitModify, 3) + op(0x6b, DirectModify, fp(ROR)) + op(0x6c, AbsoluteModify, fp(ROR)) + op(0x6d, Push, Y) + op(0x6e, BranchNotDirectDecrement) + op(0x6f, ReturnSubroutine) + op(0x70, Branch, VF == 1) + op(0x71, CallTable, 7) + op(0x72, AbsoluteBitSet, 3, false) + op(0x73, BranchBit, 3, false) + op(0x74, DirectIndexedRead, fp(CMP), A, X) + op(0x75, AbsoluteIndexedRead, fp(CMP), X) + op(0x76, AbsoluteIndexedRead, fp(CMP), Y) + op(0x77, IndirectIndexedRead, fp(CMP), Y) + op(0x78, DirectImmediateCompare, fp(CMP)) + op(0x79, IndirectXCompareIndirectY, fp(CMP)) + op(0x7a, DirectReadWord, fp(ADW)) + op(0x7b, DirectIndexedModify, fp(ROR), X) + op(0x7c, ImpliedModify, fp(ROR), A) + op(0x7d, Transfer, X, A) + op(0x7e, DirectRead, fp(CMP), Y) + op(0x7f, ReturnInterrupt) + op(0x80, FlagSet, CF, true) + op(0x81, CallTable, 8) + op(0x82, AbsoluteBitSet, 4, true) + op(0x83, BranchBit, 4, true) + op(0x84, DirectRead, fp(ADC), A) + op(0x85, AbsoluteRead, fp(ADC), A) + op(0x86, IndirectXRead, fp(ADC)) + op(0x87, IndexedIndirectRead, fp(ADC), X) + op(0x88, ImmediateRead, fp(ADC), A) + op(0x89, DirectDirectModify, fp(ADC)) + op(0x8a, AbsoluteBitModify, 4) + op(0x8b, DirectModify, fp(DEC)) + op(0x8c, AbsoluteModify, fp(DEC)) + op(0x8d, ImmediateRead, fp(LD), Y) + op(0x8e, PullP) + op(0x8f, DirectImmediateWrite) + op(0x90, Branch, CF == 0) + op(0x91, CallTable, 9) + op(0x92, AbsoluteBitSet, 4, false) + op(0x93, BranchBit, 4, false) + op(0x94, DirectIndexedRead, fp(ADC), A, X) + op(0x95, AbsoluteIndexedRead, fp(ADC), X) + op(0x96, AbsoluteIndexedRead, fp(ADC), Y) + op(0x97, IndirectIndexedRead, fp(ADC), Y) + op(0x98, DirectImmediateModify, fp(ADC)) + op(0x99, IndirectXWriteIndirectY, fp(ADC)) + op(0x9a, DirectReadWord, fp(SBW)) + op(0x9b, DirectIndexedModify, fp(DEC), X) + op(0x9c, ImpliedModify, fp(DEC), A) + op(0x9d, Transfer, S, X) + op(0x9e, Divide) + op(0x9f, ExchangeNibble) + op(0xa0, FlagSet, IF, true) + op(0xa1, CallTable, 10) + op(0xa2, AbsoluteBitSet, 5, true) + op(0xa3, BranchBit, 5, true) + op(0xa4, DirectRead, fp(SBC), A) + op(0xa5, AbsoluteRead, fp(SBC), A) + op(0xa6, IndirectXRead, fp(SBC)) + op(0xa7, IndexedIndirectRead, fp(SBC), X) + op(0xa8, ImmediateRead, fp(SBC), A) + op(0xa9, DirectDirectModify, fp(SBC)) + op(0xaa, AbsoluteBitModify, 5) + op(0xab, DirectModify, fp(INC)) + op(0xac, AbsoluteModify, fp(INC)) + op(0xad, ImmediateRead, fp(CMP), Y) + op(0xae, Pull, A) + op(0xaf, IndirectXIncrementWrite, A) + op(0xb0, Branch, CF == 1) + op(0xb1, CallTable, 11) + op(0xb2, AbsoluteBitSet, 5, false) + op(0xb3, BranchBit, 5, false) + op(0xb4, DirectIndexedRead, fp(SBC), A, X) + op(0xb5, AbsoluteIndexedRead, fp(SBC), X) + op(0xb6, AbsoluteIndexedRead, fp(SBC), Y) + op(0xb7, IndirectIndexedRead, fp(SBC), Y) + op(0xb8, DirectImmediateModify, fp(SBC)) + op(0xb9, IndirectXWriteIndirectY, fp(SBC)) + op(0xba, DirectReadWord, fp(LDW)) + op(0xbb, DirectIndexedModify, fp(INC), X) + op(0xbc, ImpliedModify, fp(INC), A) + op(0xbd, Transfer, X, S) + op(0xbe, DecimalAdjustSub) + op(0xbf, IndirectXIncrementRead, A) + op(0xc0, FlagSet, IF, false) + op(0xc1, CallTable, 12) + op(0xc2, AbsoluteBitSet, 6, true) + op(0xc3, BranchBit, 6, true) + op(0xc4, DirectWrite, A) + op(0xc5, AbsoluteWrite, A) + op(0xc6, IndirectXWrite, A) + op(0xc7, IndexedIndirectWrite, A, X) + op(0xc8, ImmediateRead, fp(CMP), X) + op(0xc9, AbsoluteWrite, X) + op(0xca, AbsoluteBitModify, 6) + op(0xcb, DirectWrite, Y) + op(0xcc, AbsoluteWrite, Y) + op(0xcd, ImmediateRead, fp(LD), X) + op(0xce, Pull, X) + op(0xcf, Multiply) + op(0xd0, Branch, ZF == 0) + op(0xd1, CallTable, 13) + op(0xd2, AbsoluteBitSet, 6, false) + op(0xd3, BranchBit, 6, false) + op(0xd4, DirectIndexedWrite, A, X) + op(0xd5, AbsoluteIndexedWrite, X) + op(0xd6, AbsoluteIndexedWrite, Y) + op(0xd7, IndirectIndexedWrite, A, Y) + op(0xd8, DirectWrite, X) + op(0xd9, DirectIndexedWrite, X, Y) + op(0xda, DirectWriteWord) + op(0xdb, DirectIndexedWrite, Y, X) + op(0xdc, ImpliedModify, fp(DEC), Y) + op(0xdd, Transfer, Y, A) + op(0xde, BranchNotDirectIndexed, X) + op(0xdf, DecimalAdjustAdd) + op(0xe0, OverflowClear) + op(0xe1, CallTable, 14) + op(0xe2, AbsoluteBitSet, 7, true) + op(0xe3, BranchBit, 7, true) + op(0xe4, DirectRead, fp(LD), A) + op(0xe5, AbsoluteRead, fp(LD), A) + op(0xe6, IndirectXRead, fp(LD)) + op(0xe7, IndexedIndirectRead, fp(LD), X) + op(0xe8, ImmediateRead, fp(LD), A) + op(0xe9, AbsoluteRead, fp(LD), X) + op(0xea, AbsoluteBitModify, 7) + op(0xeb, DirectRead, fp(LD), Y) + op(0xec, AbsoluteRead, fp(LD), Y) + op(0xed, ComplementCarry) + op(0xee, Pull, Y) + op(0xef, Wait) + op(0xf0, Branch, ZF == 1) + op(0xf1, CallTable, 15) + op(0xf2, AbsoluteBitSet, 7, false) + op(0xf3, BranchBit, 7, false) + op(0xf4, DirectIndexedRead, fp(LD), A, X) + op(0xf5, AbsoluteIndexedRead, fp(LD), X) + op(0xf6, AbsoluteIndexedRead, fp(LD), Y) + op(0xf7, IndirectIndexedRead, fp(LD), Y) + op(0xf8, DirectRead, fp(LD), X) + op(0xf9, DirectIndexedRead, fp(LD), X, Y) + op(0xfa, DirectDirectWrite) + op(0xfb, DirectIndexedRead, fp(LD), Y, X) + op(0xfc, ImpliedModify, fp(INC), Y) + op(0xfd, Transfer, A, Y) + op(0xfe, BranchNotYDecrement) + op(0xff, Stop) + } +} + +#undef op +#undef fp diff --git a/processor/spc700/instructions.cpp b/processor/spc700/instructions.cpp new file mode 100644 index 0000000..d784489 --- /dev/null +++ b/processor/spc700/instructions.cpp @@ -0,0 +1,592 @@ +auto SPC700::instructionAbsoluteBitModify(uint3 mode) -> void { + uint16 address = fetch(); + address |= fetch() << 8; + uint3 bit = address >> 13; + address &= 0x1fff; + uint8 data = read(address); + switch(mode) { + case 0: //or addr:bit + idle(); + CF |= bool(data & 1 << bit); + break; + case 1: //or !addr:bit + idle(); + CF |= !bool(data & 1 << bit); + break; + case 2: //and addr:bit + CF &= bool(data & 1 << bit); + break; + case 3: //and !addr:bit + CF &= !bool(data & 1 << bit); + break; + case 4: //eor addr:bit + idle(); + CF ^= bool(data & 1 << bit); + break; + case 5: //ld addr:bit + CF = bool(data & 1 << bit); + break; + case 6: //st addr:bit + idle(); + data &= ~(1 << bit); + data |= CF << bit; + write(address, data); + break; + case 7: //not addr:bit + data ^= 1 << bit; + write(address, data); + break; + } +} + +auto SPC700::instructionAbsoluteBitSet(uint3 bit, bool value) -> void { + uint8 address = fetch(); + uint8 data = load(address); + data &= ~(1 << bit); + data |= value << bit; + store(address, data); +} + +auto SPC700::instructionAbsoluteRead(fpb op, uint8& target) -> void { + uint16 address = fetch(); + address |= fetch() << 8; + uint8 data = read(address); + target = alu(target, data); +} + +auto SPC700::instructionAbsoluteModify(fps op) -> void { + uint16 address = fetch(); + address |= fetch() << 8; + uint8 data = read(address); + write(address, alu(data)); +} + +auto SPC700::instructionAbsoluteWrite(uint8& data) -> void { + uint16 address = fetch(); + address |= fetch() << 8; + read(address); + write(address, data); +} + +auto SPC700::instructionAbsoluteIndexedRead(fpb op, uint8& index) -> void { + uint16 address = fetch(); + address |= fetch() << 8; + idle(); + uint8 data = read(address + index); + A = alu(A, data); +} + +auto SPC700::instructionAbsoluteIndexedWrite(uint8& index) -> void { + uint16 address = fetch(); + address |= fetch() << 8; + idle(); + read(address + index); + write(address + index, A); +} + +auto SPC700::instructionBranch(bool take) -> void { + uint8 data = fetch(); + if(!take) return; + idle(); + idle(); + PC += (int8)data; +} + +auto SPC700::instructionBranchBit(uint3 bit, bool match) -> void { + uint8 address = fetch(); + uint8 data = load(address); + idle(); + uint8 displacement = fetch(); + if(bool(data & 1 << bit) != match) return; + idle(); + idle(); + PC += (int8)displacement; +} + +auto SPC700::instructionBranchNotDirect() -> void { + uint8 address = fetch(); + uint8 data = load(address); + idle(); + uint8 displacement = fetch(); + if(A == data) return; + idle(); + idle(); + PC += (int8)displacement; +} + +auto SPC700::instructionBranchNotDirectDecrement() -> void { + uint8 address = fetch(); + uint8 data = load(address); + store(address, --data); + uint8 displacement = fetch(); + if(data == 0) return; + idle(); + idle(); + PC += (int8)displacement; +} + +auto SPC700::instructionBranchNotDirectIndexed(uint8& index) -> void { + uint8 address = fetch(); + idle(); + uint8 data = load(address + index); + idle(); + uint8 displacement = fetch(); + if(A == data) return; + idle(); + idle(); + PC += (int8)displacement; +} + +auto SPC700::instructionBranchNotYDecrement() -> void { + read(PC); + idle(); + uint8 displacement = fetch(); + if(--Y == 0) return; + idle(); + idle(); + PC += (int8)displacement; +} + +auto SPC700::instructionBreak() -> void { + read(PC); + push(PC >> 8); + push(PC >> 0); + push(P); + idle(); + uint16 address = read(0xffde + 0); + address |= read(0xffde + 1) << 8; + PC = address; + IF = 0; + BF = 1; +} + +auto SPC700::instructionCallAbsolute() -> void { + uint16 address = fetch(); + address |= fetch() << 8; + idle(); + push(PC >> 8); + push(PC >> 0); + idle(); + idle(); + PC = address; +} + +auto SPC700::instructionCallPage() -> void { + uint8 address = fetch(); + idle(); + push(PC >> 8); + push(PC >> 0); + idle(); + PC = 0xff00 | address; +} + +auto SPC700::instructionCallTable(uint4 vector) -> void { + read(PC); + idle(); + push(PC >> 8); + push(PC >> 0); + idle(); + uint16 address = 0xffde - (vector << 1); + uint16 pc = read(address + 0); + pc |= read(address + 1) << 8; + PC = pc; +} + +auto SPC700::instructionComplementCarry() -> void { + read(PC); + idle(); + CF = !CF; +} + +auto SPC700::instructionDecimalAdjustAdd() -> void { + read(PC); + idle(); + if(CF || A > 0x99) { + A += 0x60; + CF = 1; + } + if(HF || (A & 15) > 0x09) { + A += 0x06; + } + ZF = A == 0; + NF = A & 0x80; +} + +auto SPC700::instructionDecimalAdjustSub() -> void { + read(PC); + idle(); + if(!CF || A > 0x99) { + A -= 0x60; + CF = 0; + } + if(!HF || (A & 15) > 0x09) { + A -= 0x06; + } + ZF = A == 0; + NF = A & 0x80; +} + +auto SPC700::instructionDirectRead(fpb op, uint8& target) -> void { + uint8 address = fetch(); + uint8 data = load(address); + target = alu(target, data); +} + +auto SPC700::instructionDirectModify(fps op) -> void { + uint8 address = fetch(); + uint8 data = load(address); + store(address, alu(data)); +} + +auto SPC700::instructionDirectWrite(uint8& data) -> void { + uint8 address = fetch(); + load(address); + store(address, data); +} + +auto SPC700::instructionDirectDirectCompare(fpb op) -> void { + uint8 source = fetch(); + uint8 rhs = load(source); + uint8 target = fetch(); + uint8 lhs = load(target); + lhs = alu(lhs, rhs); + idle(); +} + +auto SPC700::instructionDirectDirectModify(fpb op) -> void { + uint8 source = fetch(); + uint8 rhs = load(source); + uint8 target = fetch(); + uint8 lhs = load(target); + lhs = alu(lhs, rhs); + store(target, lhs); +} + +auto SPC700::instructionDirectDirectWrite() -> void { + uint8 source = fetch(); + uint8 data = load(source); + uint8 target = fetch(); + store(target, data); +} + +auto SPC700::instructionDirectImmediateCompare(fpb op) -> void { + uint8 immediate = fetch(); + uint8 address = fetch(); + uint8 data = load(address); + data = alu(data, immediate); + idle(); +} + +auto SPC700::instructionDirectImmediateModify(fpb op) -> void { + uint8 immediate = fetch(); + uint8 address = fetch(); + uint8 data = load(address); + data = alu(data, immediate); + store(address, data); +} + +auto SPC700::instructionDirectImmediateWrite() -> void { + uint8 immediate = fetch(); + uint8 address = fetch(); + load(address); + store(address, immediate); +} + +auto SPC700::instructionDirectCompareWord(fpw op) -> void { + uint8 address = fetch(); + uint16 data = load(address + 0); + data |= load(address + 1) << 8; + YA = alu(YA, data); +} + +auto SPC700::instructionDirectReadWord(fpw op) -> void { + uint8 address = fetch(); + uint16 data = load(address + 0); + idle(); + data |= load(address + 1) << 8; + YA = alu(YA, data); +} + +auto SPC700::instructionDirectModifyWord(int adjust) -> void { + uint8 address = fetch(); + uint16 data = load(address + 0) + adjust; + store(address + 0, data >> 0); + data += load(address + 1) << 8; + store(address + 1, data >> 8); + ZF = data == 0; + NF = data & 0x8000; +} + +auto SPC700::instructionDirectWriteWord() -> void { + uint8 address = fetch(); + load(address + 0); + store(address + 0, A); + store(address + 1, Y); +} + +auto SPC700::instructionDirectIndexedRead(fpb op, uint8& target, uint8& index) -> void { + uint8 address = fetch(); + idle(); + uint8 data = load(address + index); + target = alu(target, data); +} + +auto SPC700::instructionDirectIndexedModify(fps op, uint8& index) -> void { + uint8 address = fetch(); + idle(); + uint8 data = load(address + index); + store(address + index, alu(data)); +} + +auto SPC700::instructionDirectIndexedWrite(uint8& data, uint8& index) -> void { + uint8 address = fetch(); + idle(); + load(address + index); + store(address + index, data); +} + +auto SPC700::instructionDivide() -> void { + read(PC); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + uint16 ya = YA; + //overflow set if quotient >= 256 + HF = (Y & 15) >= (X & 15); + VF = Y >= X; + if(Y < (X << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + A = ya / X; + Y = ya % X; + } else { + //otherwise, the quotient won't fit into VF + A + //this emulates the odd behavior of the S-SMP in this case + A = 255 - (ya - (X << 9)) / (256 - X); + Y = X + (ya - (X << 9)) % (256 - X); + } + //result is set based on a (quotient) only + ZF = A == 0; + NF = A & 0x80; +} + +auto SPC700::instructionExchangeNibble() -> void { + read(PC); + idle(); + idle(); + idle(); + A = A >> 4 | A << 4; + ZF = A == 0; + NF = A & 0x80; +} + +auto SPC700::instructionFlagSet(bool& flag, bool value) -> void { + read(PC); + if(&flag == &IF) idle(); + flag = value; +} + +auto SPC700::instructionImmediateRead(fpb op, uint8& target) -> void { + uint8 data = fetch(); + target = alu(target, data); +} + +auto SPC700::instructionImpliedModify(fps op, uint8& target) -> void { + read(PC); + target = alu(target); +} + +auto SPC700::instructionIndexedIndirectRead(fpb op, uint8& index) -> void { + uint8 indirect = fetch(); + idle(); + uint16 address = load(indirect + index + 0); + address |= load(indirect + index + 1) << 8; + uint8 data = read(address); + A = alu(A, data); +} + +auto SPC700::instructionIndexedIndirectWrite(uint8& data, uint8& index) -> void { + uint8 indirect = fetch(); + idle(); + uint16 address = load(indirect + index + 0); + address |= load(indirect + index + 1) << 8; + read(address); + write(address, data); +} + +auto SPC700::instructionIndirectIndexedRead(fpb op, uint8& index) -> void { + uint8 indirect = fetch(); + uint16 address = load(indirect + 0); + address |= load(indirect + 1) << 8; + idle(); + uint8 data = read(address + index); + A = alu(A, data); +} + +auto SPC700::instructionIndirectIndexedWrite(uint8& data, uint8& index) -> void { + uint8 indirect = fetch(); + uint16 address = load(indirect + 0); + address |= load(indirect + 1) << 8; + idle(); + read(address + index); + write(address + index, data); +} + +auto SPC700::instructionIndirectXRead(fpb op) -> void { + read(PC); + uint8 data = load(X); + A = alu(A, data); +} + +auto SPC700::instructionIndirectXWrite(uint8& data) -> void { + read(PC); + load(X); + store(X, data); +} + +auto SPC700::instructionIndirectXIncrementRead(uint8& data) -> void { + read(PC); + data = load(X++); + idle(); //quirk: consumes extra idle cycle compared to most read instructions + ZF = data == 0; + NF = data & 0x80; +} + +auto SPC700::instructionIndirectXIncrementWrite(uint8& data) -> void { + read(PC); + idle(); //quirk: not a read cycle as with most write instructions + store(X++, data); +} + +auto SPC700::instructionIndirectXCompareIndirectY(fpb op) -> void { + read(PC); + uint8 rhs = load(Y); + uint8 lhs = load(X); + lhs = alu(lhs, rhs); + idle(); +} + +auto SPC700::instructionIndirectXWriteIndirectY(fpb op) -> void { + read(PC); + uint8 rhs = load(Y); + uint8 lhs = load(X); + lhs = alu(lhs, rhs); + store(X, lhs); +} + +auto SPC700::instructionJumpAbsolute() -> void { + uint16 address = fetch(); + address |= fetch() << 8; + PC = address; +} + +auto SPC700::instructionJumpIndirectX() -> void { + uint16 address = fetch(); + address |= fetch() << 8; + idle(); + uint16 pc = read(address + X + 0); + pc |= read(address + X + 1) << 8; + PC = pc; +} + +auto SPC700::instructionMultiply() -> void { + read(PC); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + uint16 ya = Y * A; + A = ya >> 0; + Y = ya >> 8; + //result is set based on y (high-byte) only + ZF = Y == 0; + NF = Y & 0x80; +} + +auto SPC700::instructionNoOperation() -> void { + read(PC); +} + +auto SPC700::instructionOverflowClear() -> void { + read(PC); + HF = 0; + VF = 0; +} + +auto SPC700::instructionPull(uint8& data) -> void { + read(PC); + idle(); + data = pull(); +} + +auto SPC700::instructionPullP() -> void { + read(PC); + idle(); + P = pull(); +} + +auto SPC700::instructionPush(uint8 data) -> void { + read(PC); + push(data); + idle(); +} + +auto SPC700::instructionReturnInterrupt() -> void { + read(PC); + idle(); + P = pull(); + uint16 address = pull(); + address |= pull() << 8; + PC = address; +} + +auto SPC700::instructionReturnSubroutine() -> void { + read(PC); + idle(); + uint16 address = pull(); + address |= pull() << 8; + PC = address; +} + +auto SPC700::instructionStop() -> void { + r.stop = true; + while(r.stop && !synchronizing()) { + read(PC); + idle(); + } +} + +auto SPC700::instructionTestSetBitsAbsolute(bool set) -> void { + uint16 address = fetch(); + address |= fetch() << 8; + uint8 data = read(address); + ZF = (A - data) == 0; + NF = (A - data) & 0x80; + read(address); + write(address, set ? data | A : data & ~A); +} + +auto SPC700::instructionTransfer(uint8& from, uint8& to) -> void { + read(PC); + to = from; + if(&to == &S) return; + ZF = to == 0; + NF = to & 0x80; +} + +auto SPC700::instructionWait() -> void { + r.wait = true; + while(r.wait && !synchronizing()) { + read(PC); + idle(); + } +} diff --git a/processor/spc700/memory.cpp b/processor/spc700/memory.cpp new file mode 100644 index 0000000..3c0f92a --- /dev/null +++ b/processor/spc700/memory.cpp @@ -0,0 +1,19 @@ +auto SPC700::fetch() -> uint8 { + return read(PC++); +} + +auto SPC700::load(uint8 address) -> uint8 { + return read(PF << 8 | address); +} + +auto SPC700::store(uint8 address, uint8 data) -> void { + return write(PF << 8 | address, data); +} + +auto SPC700::pull() -> uint8 { + return read(1 << 8 | ++S); +} + +auto SPC700::push(uint8 data) -> void { + return write(1 << 8 | S--, data); +} diff --git a/processor/spc700/serialization.cpp b/processor/spc700/serialization.cpp new file mode 100644 index 0000000..2c258f5 --- /dev/null +++ b/processor/spc700/serialization.cpp @@ -0,0 +1,17 @@ +auto SPC700::serialize(serializer& s) -> void { + s.integer(r.pc.w); + s.integer(r.ya.w); + s.integer(r.x); + s.integer(r.s); + s.integer(r.p.c); + s.integer(r.p.z); + s.integer(r.p.i); + s.integer(r.p.h); + s.integer(r.p.b); + s.integer(r.p.p); + s.integer(r.p.v); + s.integer(r.p.n); + + s.integer(r.wait); + s.integer(r.stop); +} diff --git a/processor/spc700/spc700.cpp b/processor/spc700/spc700.cpp new file mode 100644 index 0000000..69ec693 --- /dev/null +++ b/processor/spc700/spc700.cpp @@ -0,0 +1,62 @@ +#include +#include "spc700.hpp" + +namespace Processor { + +#define PC r.pc.w +#define YA r.ya.w +#define A r.ya.byte.l +#define X r.x +#define Y r.ya.byte.h +#define S r.s +#define P r.p + +#define CF r.p.c +#define ZF r.p.z +#define IF r.p.i +#define HF r.p.h +#define BF r.p.b +#define PF r.p.p +#define VF r.p.v +#define NF r.p.n + +#define alu (this->*op) + +#include "memory.cpp" +#include "algorithms.cpp" +#include "instructions.cpp" +#include "instruction.cpp" +#include "serialization.cpp" +#include "disassembler.cpp" + +auto SPC700::power() -> void { + PC = 0x0000; + YA = 0x0000; + X = 0x00; + S = 0xef; + P = 0x02; + + r.wait = false; + r.stop = false; +} + +#undef PC +#undef YA +#undef A +#undef X +#undef Y +#undef S +#undef P + +#undef CF +#undef ZF +#undef IF +#undef HF +#undef BF +#undef PF +#undef VF +#undef NF + +#undef alu + +} diff --git a/processor/spc700/spc700.hpp b/processor/spc700/spc700.hpp new file mode 100644 index 0000000..788e036 --- /dev/null +++ b/processor/spc700/spc700.hpp @@ -0,0 +1,164 @@ +#pragma once + +namespace Processor { + +struct SPC700 { + virtual auto idle() -> void = 0; + virtual auto read(uint16 address) -> uint8 = 0; + virtual auto write(uint16 address, uint8 data) -> void = 0; + virtual auto synchronizing() const -> bool = 0; + + virtual auto readDisassembler(uint16 address) -> uint8 { return 0; } + + //spc700.cpp + auto power() -> void; + + //memory.cpp + inline auto fetch() -> uint8; + inline auto load(uint8 address) -> uint8; + inline auto store(uint8 address, uint8 data) -> void; + inline auto pull() -> uint8; + inline auto push(uint8 data) -> void; + + //instruction.cpp + auto instruction() -> void; + + //algorithms.cpp + auto algorithmADC(uint8, uint8) -> uint8; + auto algorithmAND(uint8, uint8) -> uint8; + auto algorithmASL(uint8) -> uint8; + auto algorithmCMP(uint8, uint8) -> uint8; + auto algorithmDEC(uint8) -> uint8; + auto algorithmEOR(uint8, uint8) -> uint8; + auto algorithmINC(uint8) -> uint8; + auto algorithmLD (uint8, uint8) -> uint8; + auto algorithmLSR(uint8) -> uint8; + auto algorithmOR (uint8, uint8) -> uint8; + auto algorithmROL(uint8) -> uint8; + auto algorithmROR(uint8) -> uint8; + auto algorithmSBC(uint8, uint8) -> uint8; + auto algorithmADW(uint16, uint16) -> uint16; + auto algorithmCPW(uint16, uint16) -> uint16; + auto algorithmLDW(uint16, uint16) -> uint16; + auto algorithmSBW(uint16, uint16) -> uint16; + + //instructions.cpp + using fps = auto (SPC700::*)(uint8) -> uint8; + using fpb = auto (SPC700::*)(uint8, uint8) -> uint8; + using fpw = auto (SPC700::*)(uint16, uint16) -> uint16; + + auto instructionAbsoluteBitModify(uint3) -> void; + auto instructionAbsoluteBitSet(uint3, bool) -> void; + auto instructionAbsoluteRead(fpb, uint8&) -> void; + auto instructionAbsoluteModify(fps) -> void; + auto instructionAbsoluteWrite(uint8&) -> void; + auto instructionAbsoluteIndexedRead(fpb, uint8&) -> void; + auto instructionAbsoluteIndexedWrite(uint8&) -> void; + auto instructionBranch(bool) -> void; + auto instructionBranchBit(uint3, bool) -> void; + auto instructionBranchNotDirect() -> void; + auto instructionBranchNotDirectDecrement() -> void; + auto instructionBranchNotDirectIndexed(uint8&) -> void; + auto instructionBranchNotYDecrement() -> void; + auto instructionBreak() -> void; + auto instructionCallAbsolute() -> void; + auto instructionCallPage() -> void; + auto instructionCallTable(uint4) -> void; + auto instructionComplementCarry() -> void; + auto instructionDecimalAdjustAdd() -> void; + auto instructionDecimalAdjustSub() -> void; + auto instructionDirectRead(fpb, uint8&) -> void; + auto instructionDirectModify(fps) -> void; + auto instructionDirectWrite(uint8&) -> void; + auto instructionDirectDirectCompare(fpb) -> void; + auto instructionDirectDirectModify(fpb) -> void; + auto instructionDirectDirectWrite() -> void; + auto instructionDirectImmediateCompare(fpb) -> void; + auto instructionDirectImmediateModify(fpb) -> void; + auto instructionDirectImmediateWrite() -> void; + auto instructionDirectCompareWord(fpw) -> void; + auto instructionDirectReadWord(fpw) -> void; + auto instructionDirectModifyWord(int) -> void; + auto instructionDirectWriteWord() -> void; + auto instructionDirectIndexedRead(fpb, uint8&, uint8&) -> void; + auto instructionDirectIndexedModify(fps, uint8&) -> void; + auto instructionDirectIndexedWrite(uint8&, uint8&) -> void; + auto instructionDivide() -> void; + auto instructionExchangeNibble() -> void; + auto instructionFlagSet(bool&, bool) -> void; + auto instructionImmediateRead(fpb, uint8&) -> void; + auto instructionImpliedModify(fps, uint8&) -> void; + auto instructionIndexedIndirectRead(fpb, uint8&) -> void; + auto instructionIndexedIndirectWrite(uint8&, uint8&) -> void; + auto instructionIndirectIndexedRead(fpb, uint8&) -> void; + auto instructionIndirectIndexedWrite(uint8&, uint8&) -> void; + auto instructionIndirectXRead(fpb) -> void; + auto instructionIndirectXWrite(uint8&) -> void; + auto instructionIndirectXIncrementRead(uint8&) -> void; + auto instructionIndirectXIncrementWrite(uint8&) -> void; + auto instructionIndirectXCompareIndirectY(fpb) -> void; + auto instructionIndirectXWriteIndirectY(fpb) -> void; + auto instructionJumpAbsolute() -> void; + auto instructionJumpIndirectX() -> void; + auto instructionMultiply() -> void; + auto instructionNoOperation() -> void; + auto instructionOverflowClear() -> void; + auto instructionPull(uint8&) -> void; + auto instructionPullP() -> void; + auto instructionPush(uint8) -> void; + auto instructionReturnInterrupt() -> void; + auto instructionReturnSubroutine() -> void; + auto instructionStop() -> void; + auto instructionTestSetBitsAbsolute(bool) -> void; + auto instructionTransfer(uint8&, uint8&) -> void; + auto instructionWait() -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + //disassembler.cpp + auto disassemble(uint16 address, bool p) -> string; + + struct Flags { + bool c = 0; //carry + bool z = 0; //zero + bool i = 0; //interrupt disable + bool h = 0; //half-carry + bool b = 0; //break + bool p = 0; //page + bool v = 0; //overflow + bool n = 0; //negative + + inline operator uint() const { + return c << 0 | z << 1 | i << 2 | h << 3 | b << 4 | p << 5 | v << 6 | n << 7; + } + + inline auto& operator=(uint8 data) { + c = data & 0x01; + z = data & 0x02; + i = data & 0x04; + h = data & 0x08; + b = data & 0x10; + p = data & 0x20; + v = data & 0x40; + n = data & 0x80; + return *this; + } + }; + + struct Registers { + union Pair { + Pair() : w(0) {} + uint16 w; + struct Byte { uint8 order_lsb2(l, h); } byte; + } pc, ya; + uint8 x = 0; + uint8 s = 0; + Flags p; + + bool wait = 0; + bool stop = 0; + } r; +}; + +} diff --git a/processor/upd96050/disassembler.cpp b/processor/upd96050/disassembler.cpp new file mode 100644 index 0000000..8fb6452 --- /dev/null +++ b/processor/upd96050/disassembler.cpp @@ -0,0 +1,192 @@ +auto uPD96050::disassemble(uint14 ip) -> string { + string output = {hex(ip, 4L), " "}; + 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(dphm, 1L)); + } + + 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(jp, 4L)); + } + + if(type == 3) { //LD + output.append("ld "); + uint16 id = opcode >> 6; + uint4 dst = opcode >> 0; + + output.append("$", hex(id, 4L), ","); + + 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; +} diff --git a/processor/upd96050/instructions.cpp b/processor/upd96050/instructions.cpp new file mode 100644 index 0000000..5ac63a8 --- /dev/null +++ b/processor/upd96050/instructions.cpp @@ -0,0 +1,245 @@ +auto uPD96050::exec() -> void { + uint24 opcode = programROM[regs.pc++]; + switch(opcode >> 22) { + case 0: execOP(opcode); break; + case 1: execRT(opcode); break; + case 2: execJP(opcode); break; + case 3: execLD(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 +} + +auto uPD96050::execOP(uint24 opcode) -> void { + 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 - flags.a.s1; break; //ASL ignored; always SA1 + 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; + boolean 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 = flags.a; c = flags.b.c; break; + case 1: q = regs.b; flag = flags.b; c = flags.a.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.z = r == 0; + flag.s0 = r & 0x8000; + if(!flag.ov1) flag.s1 = flag.s0; + + switch(alu) { + + case 1: //OR + case 2: //AND + case 3: //XOR + case 10: //CMP + case 13: //SHL2 + case 14: //SHL4 + case 15: { //XCHG + flag.ov0 = 0; + flag.ov1 = 0; + flag.c = 0; + break; + } + + case 4: //SUB + case 5: //ADD + case 6: //SBB + case 7: //ADC + case 8: //DEC + case 9: { //INC + 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; + } + flag.ov1 = flag.ov0 & flag.ov1 ? flag.s0 == flag.s1 : flag.ov0 | flag.ov1; + break; + } + + case 11: { //SHR1 (ASR) + flag.ov0 = 0; + flag.ov1 = 0; + flag.c = q & 1; + break; + } + + case 12: { //SHL1 (ROL) + flag.ov0 = 0; + flag.ov1 = 0; + flag.c = q >> 15; + break; + } + + } + + switch(asl) { + case 0: regs.a = r; flags.a = flag; break; + case 1: regs.b = r; flags.b = flag; break; + } + } + + execLD(idb << 6 | dst); + + if(dst != 4) { //if LD does not write to DP + 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(dst != 5) { //if LD does not write to RP + if(rpdcr) regs.rp--; + } +} + +auto uPD96050::execRT(uint24 opcode) -> void { + execOP(opcode); + regs.pc = regs.stack[--regs.sp]; +} + +auto uPD96050::execJP(uint24 opcode) -> void { + 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(flags.a.c == 0) regs.pc = jp; return; //JNCA + case 0x082: if(flags.a.c == 1) regs.pc = jp; return; //JCA + case 0x084: if(flags.b.c == 0) regs.pc = jp; return; //JNCB + case 0x086: if(flags.b.c == 1) regs.pc = jp; return; //JCB + + case 0x088: if(flags.a.z == 0) regs.pc = jp; return; //JNZA + case 0x08a: if(flags.a.z == 1) regs.pc = jp; return; //JZA + case 0x08c: if(flags.b.z == 0) regs.pc = jp; return; //JNZB + case 0x08e: if(flags.b.z == 1) regs.pc = jp; return; //JZB + + case 0x090: if(flags.a.ov0 == 0) regs.pc = jp; return; //JNOVA0 + case 0x092: if(flags.a.ov0 == 1) regs.pc = jp; return; //JOVA0 + case 0x094: if(flags.b.ov0 == 0) regs.pc = jp; return; //JNOVB0 + case 0x096: if(flags.b.ov0 == 1) regs.pc = jp; return; //JOVB0 + + case 0x098: if(flags.a.ov1 == 0) regs.pc = jp; return; //JNOVA1 + case 0x09a: if(flags.a.ov1 == 1) regs.pc = jp; return; //JOVA1 + case 0x09c: if(flags.b.ov1 == 0) regs.pc = jp; return; //JNOVB1 + case 0x09e: if(flags.b.ov1 == 1) regs.pc = jp; return; //JOVB1 + + case 0x0a0: if(flags.a.s0 == 0) regs.pc = jp; return; //JNSA0 + case 0x0a2: if(flags.a.s0 == 1) regs.pc = jp; return; //JSA0 + case 0x0a4: if(flags.b.s0 == 0) regs.pc = jp; return; //JNSB0 + case 0x0a6: if(flags.b.s0 == 1) regs.pc = jp; return; //JSB0 + + case 0x0a8: if(flags.a.s1 == 0) regs.pc = jp; return; //JNSA1 + case 0x0aa: if(flags.a.s1 == 1) regs.pc = jp; return; //JSA1 + case 0x0ac: if(flags.b.s1 == 0) regs.pc = jp; return; //JNSB1 + case 0x0ae: if(flags.b.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 + + //serial input/output acknowledge not emulated + case 0x0b4: if(regs.sr.siack == 0) regs.pc = jp; return; //JNSIAK + case 0x0b6: if(regs.sr.siack == 1) regs.pc = jp; return; //JSIAK + case 0x0b8: if(regs.sr.soack == 0) regs.pc = jp; return; //JNSOAK + case 0x0ba: if(regs.sr.soack == 1) regs.pc = jp; return; //JSOAK + + 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 + } +} + +auto uPD96050::execLD(uint24 opcode) -> void { + 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; + } +} diff --git a/processor/upd96050/memory.cpp b/processor/upd96050/memory.cpp new file mode 100644 index 0000000..1d3df9a --- /dev/null +++ b/processor/upd96050/memory.cpp @@ -0,0 +1,64 @@ +auto uPD96050::readSR() -> uint8 { + return regs.sr >> 8; +} + +auto uPD96050::writeSR(uint8 data) -> void { +} + +auto uPD96050::readDR() -> uint8 { + 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; + } +} + +auto uPD96050::writeDR(uint8 data) -> void { + 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); + } +} + +auto uPD96050::readDP(uint12 addr) -> uint8 { + bool hi = addr & 1; + addr = (addr >> 1) & 2047; + + if(hi == false) { + return dataRAM[addr] >> 0; + } else { + return dataRAM[addr] >> 8; + } +} + +auto uPD96050::writeDP(uint12 addr, uint8 data) -> void { + 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); + } +} diff --git a/processor/upd96050/serialization.cpp b/processor/upd96050/serialization.cpp new file mode 100644 index 0000000..43dac5f --- /dev/null +++ b/processor/upd96050/serialization.cpp @@ -0,0 +1,51 @@ +auto uPD96050::serialize(serializer& s) -> void { + s.array(dataRAM); + regs.serialize(s); + flags.a.serialize(s); + flags.b.serialize(s); +} + +auto uPD96050::Flag::serialize(serializer& s) -> void { + s.boolean(ov0); + s.boolean(ov1); + s.boolean(z); + s.boolean(c); + s.boolean(s0); + s.boolean(s1); +} + +auto uPD96050::Status::serialize(serializer& s) -> void { + s.boolean(p0); + s.boolean(p1); + s.boolean(ei); + s.boolean(sic); + s.boolean(soc); + s.boolean(drc); + s.boolean(dma); + s.boolean(drs); + s.boolean(usf0); + s.boolean(usf1); + s.boolean(rqm); + s.boolean(siack); + s.boolean(soack); +} + +auto uPD96050::Registers::serialize(serializer& s) -> void { + s.array(stack); + s.integer(pc); + s.integer(rp); + s.integer(dp); + s.integer(sp); + s.integer(si); + s.integer(so); + s.integer(k); + s.integer(l); + s.integer(m); + s.integer(n); + s.integer(a); + s.integer(b); + s.integer(tr); + s.integer(trb); + s.integer(dr); + sr.serialize(s); +} diff --git a/processor/upd96050/upd96050.cpp b/processor/upd96050/upd96050.cpp new file mode 100644 index 0000000..e6cf261 --- /dev/null +++ b/processor/upd96050/upd96050.cpp @@ -0,0 +1,48 @@ +#include +#include "upd96050.hpp" + +namespace Processor { + +#include "instructions.cpp" +#include "memory.cpp" +#include "disassembler.cpp" +#include "serialization.cpp" + +auto uPD96050::power() -> void { + if(revision == Revision::uPD7725) { + regs.pc.resize(11); + regs.rp.resize(10); + regs.dp.resize( 8); + } + + if(revision == Revision::uPD96050) { + regs.pc.resize(14); + regs.rp.resize(11); + regs.dp.resize(11); + } + + for(auto n : range(16)) regs.stack[n] = 0x0000; + regs.pc = 0x0000; + regs.rp = 0x0000; + regs.dp = 0x0000; + regs.sp = 0x0; + regs.si = 0x0000; + regs.so = 0x0000; + regs.k = 0x0000; + regs.l = 0x0000; + regs.m = 0x0000; + regs.n = 0x0000; + regs.a = 0x0000; + regs.b = 0x0000; + regs.tr = 0x0000; + regs.trb = 0x0000; + regs.dr = 0x0000; + regs.sr = 0x0000; + regs.sr.siack = 0; + regs.sr.soack = 0; + + flags.a = 0x0000; + flags.b = 0x0000; +} + +} diff --git a/processor/upd96050/upd96050.hpp b/processor/upd96050/upd96050.hpp new file mode 100644 index 0000000..fe99d7a --- /dev/null +++ b/processor/upd96050/upd96050.hpp @@ -0,0 +1,128 @@ +//NEC uPD7725 +//NEC uPD96050 + +#pragma once + +namespace Processor { + +struct uPD96050 { + auto power() -> void; + auto exec() -> void; + auto serialize(serializer&) -> void; + + auto execOP(uint24 opcode) -> void; + auto execRT(uint24 opcode) -> void; + auto execJP(uint24 opcode) -> void; + auto execLD(uint24 opcode) -> void; + + auto readSR() -> uint8; + auto writeSR(uint8 data) -> void; + + auto readDR() -> uint8; + auto writeDR(uint8 data) -> void; + + auto readDP(uint12 addr) -> uint8; + auto writeDP(uint12 addr, uint8 data) -> void; + + auto disassemble(uint14 ip) -> string; + + enum class Revision : uint { uPD7725, uPD96050 } revision; + uint24 programROM[16384]; + uint16 dataROM[2048]; + uint16 dataRAM[2048]; + + struct Flag { + inline operator uint() const { + return ov0 << 0 | ov1 << 1 | z << 2 | c << 3 | s0 << 4 | s1 << 5; + } + + inline auto operator=(uint16 data) -> Flag& { + ov0 = data >> 0 & 1; + ov1 = data >> 1 & 1; + z = data >> 2 & 1; + c = data >> 3 & 1; + s0 = data >> 4 & 1; + s1 = data >> 5 & 1; + return *this; + } + + auto serialize(serializer&) -> void; + + boolean ov0; //overflow 0 + boolean ov1; //overflow 1 + boolean z; //zero + boolean c; //carry + boolean s0; //sign 0 + boolean s1; //sign 1 + }; + + struct Status { + inline operator uint() const { + bool _drs = drs & !drc; //when DRC=1, DRS=0 + return p0 << 0 | p1 << 1 | ei << 7 | sic << 8 | soc << 9 | drc << 10 + | dma << 11 | _drs << 12 | usf0 << 13 | usf1 << 14 | rqm << 15; + } + + inline auto operator=(uint16 data) -> Status& { + p0 = data >> 0 & 1; + p1 = data >> 1 & 1; + ei = data >> 7 & 1; + sic = data >> 8 & 1; + soc = data >> 9 & 1; + drc = data >> 10 & 1; + dma = data >> 11 & 1; + drs = data >> 12 & 1; + usf0 = data >> 13 & 1; + usf1 = data >> 14 & 1; + rqm = data >> 15 & 1; + return *this; + } + + auto serialize(serializer&) -> void; + + boolean p0; //output port 0 + boolean p1; //output port 1 + boolean ei; //enable interrupts + boolean sic; //serial input control (0 = 16-bit; 1 = 8-bit) + boolean soc; //serial output control (0 = 16-bit; 1 = 8-bit) + boolean drc; //data register size (0 = 16-bit; 1 = 8-bit) + boolean dma; //data register DMA mode + boolean drs; //data register status (1 = active; 0 = stopped) + boolean usf0; //user flag 0 + boolean usf1; //user flag 1 + boolean rqm; //request for master (=1 on internal access; =0 on external access) + + //internal + boolean siack; //serial input acknowledge + boolean soack; //serial output acknowledge + }; + + struct Registers { + auto serialize(serializer&) -> void; + + uint16 stack[16]; //LIFO + VariadicNatural pc; //program counter + VariadicNatural rp; //ROM pointer + VariadicNatural dp; //data pointer + uint4 sp; //stack pointer + uint16 si; //serial input + uint16 so; //serial output + int16 k; + int16 l; + int16 m; + int16 n; + int16 a; //accumulator + int16 b; //accumulator + uint16 tr; //temporary register + uint16 trb; //temporary register + uint16 dr; //data register + Status sr; //status register + } regs; + + struct Flags { + Flag a; + Flag b; + } flags; +}; + +} diff --git a/processor/wdc65816/algorithms.cpp b/processor/wdc65816/algorithms.cpp new file mode 100755 index 0000000..f4eacc3 --- /dev/null +++ b/processor/wdc65816/algorithms.cpp @@ -0,0 +1,363 @@ +auto WDC65816::algorithmADC8(uint8 data) -> uint8 { + int result; + + if(!DF) { + result = A.l + data + CF; + } else { + result = (A.l & 0x0f) + (data & 0x0f) + (CF << 0); + if(result > 0x09) result += 0x06; + CF = result > 0x0f; + result = (A.l & 0xf0) + (data & 0xf0) + (CF << 4) + (result & 0x0f); + } + + VF = ~(A.l ^ data) & (A.l ^ result) & 0x80; + if(DF && result > 0x9f) result += 0x60; + CF = result > 0xff; + ZF = (uint8)result == 0; + NF = result & 0x80; + + return A.l = result; +} + +auto WDC65816::algorithmADC16(uint16 data) -> uint16 { + int result; + + if(!DF) { + result = A.w + data + CF; + } else { + result = (A.w & 0x000f) + (data & 0x000f) + (CF << 0); + if(result > 0x0009) result += 0x0006; + CF = result > 0x000f; + result = (A.w & 0x00f0) + (data & 0x00f0) + (CF << 4) + (result & 0x000f); + if(result > 0x009f) result += 0x0060; + CF = result > 0x00ff; + result = (A.w & 0x0f00) + (data & 0x0f00) + (CF << 8) + (result & 0x00ff); + if(result > 0x09ff) result += 0x0600; + CF = result > 0x0fff; + result = (A.w & 0xf000) + (data & 0xf000) + (CF << 12) + (result & 0x0fff); + } + + VF = ~(A.w ^ data) & (A.w ^ result) & 0x8000; + if(DF && result > 0x9fff) result += 0x6000; + CF = result > 0xffff; + ZF = (uint16)result == 0; + NF = result & 0x8000; + + return A.w = result; +} + +auto WDC65816::algorithmAND8(uint8 data) -> uint8 { + A.l &= data; + ZF = A.l == 0; + NF = A.l & 0x80; + return A.l; +} + +auto WDC65816::algorithmAND16(uint16 data) -> uint16 { + A.w &= data; + ZF = A.w == 0; + NF = A.w & 0x8000; + return A.w; +} + +auto WDC65816::algorithmASL8(uint8 data) -> uint8 { + CF = data & 0x80; + data <<= 1; + ZF = data == 0; + NF = data & 0x80; + return data; +} + +auto WDC65816::algorithmASL16(uint16 data) -> uint16 { + CF = data & 0x8000; + data <<= 1; + ZF = data == 0; + NF = data & 0x8000; + return data; +} + +auto WDC65816::algorithmBIT8(uint8 data) -> uint8 { + ZF = (data & A.l) == 0; + VF = data & 0x40; + NF = data & 0x80; + return data; +} + +auto WDC65816::algorithmBIT16(uint16 data) -> uint16 { + ZF = (data & A.w) == 0; + VF = data & 0x4000; + NF = data & 0x8000; + return data; +} + +auto WDC65816::algorithmCMP8(uint8 data) -> uint8 { + int result = A.l - data; + CF = result >= 0; + ZF = (uint8)result == 0; + NF = result & 0x80; + return result; +} + +auto WDC65816::algorithmCMP16(uint16 data) -> uint16 { + int result = A.w - data; + CF = result >= 0; + ZF = (uint16)result == 0; + NF = result & 0x8000; + return result; +} + +auto WDC65816::algorithmCPX8(uint8 data) -> uint8 { + int result = X.l - data; + CF = result >= 0; + ZF = (uint8)result == 0; + NF = result & 0x80; + return result; +} + +auto WDC65816::algorithmCPX16(uint16 data) -> uint16 { + int result = X.w - data; + CF = result >= 0; + ZF = (uint16)result == 0; + NF = result & 0x8000; + return result; +} + +auto WDC65816::algorithmCPY8(uint8 data) -> uint8 { + int result = Y.l - data; + CF = result >= 0; + ZF = (uint8)result == 0; + NF = result & 0x80; + return result; +} + +auto WDC65816::algorithmCPY16(uint16 data) -> uint16 { + int result = Y.w - data; + CF = result >= 0; + ZF = (uint16)result == 0; + NF = result & 0x8000; + return result; +} + +auto WDC65816::algorithmDEC8(uint8 data) -> uint8 { + data--; + ZF = data == 0; + NF = data & 0x80; + return data; +} + +auto WDC65816::algorithmDEC16(uint16 data) -> uint16 { + data--; + ZF = data == 0; + NF = data & 0x8000; + return data; +} + +auto WDC65816::algorithmEOR8(uint8 data) -> uint8 { + A.l ^= data; + ZF = A.l == 0; + NF = A.l & 0x80; + return A.l; +} + +auto WDC65816::algorithmEOR16(uint16 data) -> uint16 { + A.w ^= data; + ZF = A.w == 0; + NF = A.w & 0x8000; + return A.w; +} + +auto WDC65816::algorithmINC8(uint8 data) -> uint8 { + data++; + ZF = data == 0; + NF = data & 0x80; + return data; +} + +auto WDC65816::algorithmINC16(uint16 data) -> uint16 { + data++; + ZF = data == 0; + NF = data & 0x8000; + return data; +} + +auto WDC65816::algorithmLDA8(uint8 data) -> uint8 { + A.l = data; + ZF = A.l == 0; + NF = A.l & 0x80; + return data; +} + +auto WDC65816::algorithmLDA16(uint16 data) -> uint16 { + A.w = data; + ZF = A.w == 0; + NF = A.w & 0x8000; + return data; +} + +auto WDC65816::algorithmLDX8(uint8 data) -> uint8 { + X.l = data; + ZF = X.l == 0; + NF = X.l & 0x80; + return data; +} + +auto WDC65816::algorithmLDX16(uint16 data) -> uint16 { + X.w = data; + ZF = X.w == 0; + NF = X.w & 0x8000; + return data; +} + +auto WDC65816::algorithmLDY8(uint8 data) -> uint8 { + Y.l = data; + ZF = Y.l == 0; + NF = Y.l & 0x80; + return data; +} + +auto WDC65816::algorithmLDY16(uint16 data) -> uint16 { + Y.w = data; + ZF = Y.w == 0; + NF = Y.w & 0x8000; + return data; +} + +auto WDC65816::algorithmLSR8(uint8 data) -> uint8 { + CF = data & 1; + data >>= 1; + ZF = data == 0; + NF = data & 0x80; + return data; +} + +auto WDC65816::algorithmLSR16(uint16 data) -> uint16 { + CF = data & 1; + data >>= 1; + ZF = data == 0; + NF = data & 0x8000; + return data; +} + +auto WDC65816::algorithmORA8(uint8 data) -> uint8 { + A.l |= data; + ZF = A.l == 0; + NF = A.l & 0x80; + return A.l; +} + +auto WDC65816::algorithmORA16(uint16 data) -> uint16 { + A.w |= data; + ZF = A.w == 0; + NF = A.w & 0x8000; + return A.w; +} + +auto WDC65816::algorithmROL8(uint8 data) -> uint8 { + bool carry = CF; + CF = data & 0x80; + data = data << 1 | carry; + ZF = data == 0; + NF = data & 0x80; + return data; +} + +auto WDC65816::algorithmROL16(uint16 data) -> uint16 { + bool carry = CF; + CF = data & 0x8000; + data = data << 1 | carry; + ZF = data == 0; + NF = data & 0x8000; + return data; +} + +auto WDC65816::algorithmROR8(uint8 data) -> uint8 { + bool carry = CF; + CF = data & 1; + data = carry << 7 | data >> 1; + ZF = data == 0; + NF = data & 0x80; + return data; +} + +auto WDC65816::algorithmROR16(uint16 data) -> uint16 { + bool carry = CF; + CF = data & 1; + data = carry << 15 | data >> 1; + ZF = data == 0; + NF = data & 0x8000; + return data; +} + +auto WDC65816::algorithmSBC8(uint8 data) -> uint8 { + int result; + data = ~data; + + if(!DF) { + result = A.l + data + CF; + } else { + result = (A.l & 0x0f) + (data & 0x0f) + (CF << 0); + if(result <= 0x0f) result -= 0x06; + CF = result > 0x0f; + result = (A.l & 0xf0) + (data & 0xf0) + (CF << 4) + (result & 0x0f); + } + + VF = ~(A.l ^ data) & (A.l ^ result) & 0x80; + if(DF && result <= 0xff) result -= 0x60; + CF = result > 0xff; + ZF = (uint8)result == 0; + NF = result & 0x80; + + return A.l = result; +} + +auto WDC65816::algorithmSBC16(uint16 data) -> uint16 { + int result; + data = ~data; + + if(!DF) { + result = A.w + data + CF; + } else { + result = (A.w & 0x000f) + (data & 0x000f) + (CF << 0); + if(result <= 0x000f) result -= 0x0006; + CF = result > 0x000f; + result = (A.w & 0x00f0) + (data & 0x00f0) + (CF << 4) + (result & 0x000f); + if(result <= 0x00ff) result -= 0x0060; + CF = result > 0x00ff; + result = (A.w & 0x0f00) + (data & 0x0f00) + (CF << 8) + (result & 0x00ff); + if(result <= 0x0fff) result -= 0x0600; + CF = result > 0x0fff; + result = (A.w & 0xf000) + (data & 0xf000) + (CF << 12) + (result & 0x0fff); + } + + VF = ~(A.w ^ data) & (A.w ^ result) & 0x8000; + if(DF && result <= 0xffff) result -= 0x6000; + CF = result > 0xffff; + ZF = (uint16)result == 0; + NF = result & 0x8000; + + return A.w = result; +} + +auto WDC65816::algorithmTRB8(uint8 data) -> uint8 { + ZF = (data & A.l) == 0; + data &= ~A.l; + return data; +} + +auto WDC65816::algorithmTRB16(uint16 data) -> uint16 { + ZF = (data & A.w) == 0; + data &= ~A.w; + return data; +} + +auto WDC65816::algorithmTSB8(uint8 data) -> uint8 { + ZF = (data & A.l) == 0; + data |= A.l; + return data; +} + +auto WDC65816::algorithmTSB16(uint16 data) -> uint16 { + ZF = (data & A.w) == 0; + data |= A.w; + return data; +} diff --git a/processor/wdc65816/disassembler.cpp b/processor/wdc65816/disassembler.cpp new file mode 100755 index 0000000..8d8a9c0 --- /dev/null +++ b/processor/wdc65816/disassembler.cpp @@ -0,0 +1,474 @@ +auto WDC65816::disassemble() -> string { + return disassemble(r.pc.d, r.e, r.p.m, r.p.x); +} + +auto WDC65816::disassemble(uint24 address, bool e, bool m, bool x) -> string { + string s; + + uint24 pc = address; + s = {hex(pc, 6), " "}; + + string name; + string operand; + maybe effective; + + auto read = [&](uint24 address) -> uint8 { + //$00-3f,80-bf:2000-5fff: do not attempt to read I/O registers from the disassembler: + //this is because such reads are much more likely to have side effects to emulation. + if((address & 0x40ffff) >= 0x2000 && (address & 0x40ffff) <= 0x5fff) return 0x00; + return readDisassembler(address); + }; + + auto readByte = [&](uint24 address) -> uint8 { + return read(address); + }; + auto readWord = [&](uint24 address) -> uint16 { + uint16 data = readByte(address + 0) << 0; + return data | readByte(address + 1) << 8; + }; + auto readLong = [&](uint24 address) -> uint24 { + uint24 data = readByte(address + 0) << 0; + return data | readWord(address + 1) << 8; + }; + + auto opcode = read(address); address.bit(0,15)++; + auto operand0 = read(address); address.bit(0,15)++; + auto operand1 = read(address); address.bit(0,15)++; + auto operand2 = read(address); address.bit(0,15)++; + + uint8 operandByte = operand0 << 0; + uint16 operandWord = operand0 << 0 | operand1 << 8; + uint24 operandLong = operand0 << 0 | operand1 << 8 | operand2 << 16; + + auto absolute = [&]() -> string { + effective = r.b << 16 | operandWord; + return {"$", hex(operandWord, 4L)}; + }; + + auto absolutePC = [&]() -> string { + effective = pc & 0xff0000 | operandWord; + return {"$", hex(operandWord, 4L)}; + }; + + auto absoluteX = [&]() -> string { + effective = (r.b << 16) + operandWord + r.x.w; + return {"$", hex(operandWord, 4L), ",x"}; + }; + + auto absoluteY = [&]() -> string { + effective = (r.b << 16) + operandWord + r.y.w; + return {"$", hex(operandWord, 4L), ",y"}; + }; + + auto absoluteLong = [&]() -> string { + effective = operandLong; + return {"$", hex(operandLong, 6L)}; + }; + + auto absoluteLongX = [&]() -> string { + effective = operandLong + r.x.w; + return {"$", hex(operandLong, 6L), ",x"}; + }; + + auto direct = [&]() -> string { + effective = uint16(r.d.w + operandByte); + return {"$", hex(operandByte, 2L)}; + }; + + auto directX = [&]() -> string { + effective = uint16(r.d.w + operandByte + r.x.w); + return {"$", hex(operandByte, 2L), ",x"}; + }; + + auto directY = [&]() -> string { + effective = uint16(r.d.w + operandByte + r.y.w); + return {"$", hex(operandByte, 2L), ",y"}; + }; + + auto immediate = [&]() -> string { + return {"#$", hex(operandByte, 2L)}; + }; + + auto immediateA = [&]() -> string { + return {"#$", m ? hex(operandByte, 2L) : hex(operandWord, 4L)}; + }; + + auto immediateX = [&]() -> string { + return {"#$", x ? hex(operandByte, 2L) : hex(operandWord, 4L)}; + }; + + auto implied = [&]() -> string { + return {}; + }; + + auto indexedIndirectX = [&]() -> string { + effective = uint16(r.d.w + operandByte + r.x.w); + effective = r.b << 16 | readWord(*effective); + return {"($", hex(operandByte, 2L), ",x)"}; + }; + + auto indirect = [&]() -> string { + effective = uint16(r.d.w + operandByte); + effective = (r.b << 16) + readWord(*effective); + return {"($", hex(operandByte, 2L), ")"}; + }; + + auto indirectPC = [&]() -> string { + effective = operandWord; + effective = pc & 0xff0000 | readWord(*effective); + return {"($", hex(operandWord, 4L), ")"}; + }; + + auto indirectX = [&]() -> string { + effective = operandWord; + effective = pc & 0xff0000 | uint16(*effective + r.x.w); + effective = pc & 0xff0000 | readWord(*effective); + return {"($", hex(operandWord, 4L), ",x)"}; + }; + + auto indirectIndexedY = [&]() -> string { + effective = uint16(r.d.w + operandByte); + effective = (r.b << 16) + readWord(*effective) + r.y.w; + return {"($", hex(operandByte, 2L), "),y"}; + }; + + auto indirectLong = [&]() -> string { + effective = uint16(r.d.w + operandByte); + effective = readLong(*effective); + return {"[$", hex(operandByte, 2L), "]"}; + }; + + auto indirectLongPC = [&]() -> string { + effective = readLong(operandWord); + return {"[$", hex(operandWord, 4L), "]"}; + }; + + auto indirectLongY = [&]() -> string { + effective = uint16(r.d.w + operandByte); + effective = readLong(*effective) + r.y.w; + return {"[$", hex(operandByte, 2L), "],y"}; + }; + + auto move = [&]() -> string { + return {"$", hex(operand0, 2L), "=$", hex(operand1, 2L)}; + }; + + auto relative = [&]() -> string { + effective = pc & 0xff0000 | uint16(pc + 2 + (int8)operandByte); + return {"$", hex(*effective, 4L)}; + }; + + auto relativeWord = [&]() -> string { + effective = pc & 0xff0000 | uint16(pc + 3 + (int16)operandWord); + return {"$", hex(*effective, 4L)}; + }; + + auto stack = [&]() -> string { + effective = uint16(r.s.w + operandByte); + return {"$", hex(operandByte, 2L), ",s"}; + }; + + auto stackIndirect = [&]() -> string { + effective = uint16(operandByte + r.s.w); + effective = (r.b << 16) + readWord(*effective) + r.y.w; + return {"($", hex(operandByte, 2L), ",s),y"}; + }; + + #define op(id, label, function) case id: name = label; operand = function(); break; + switch(opcode) { + op(0x00, "brk", immediate) + op(0x01, "ora", indexedIndirectX) + op(0x02, "cop", immediate) + op(0x03, "ora", stack) + op(0x04, "tsb", direct) + op(0x05, "ora", direct) + op(0x06, "asl", direct) + op(0x07, "ora", indirectLong) + op(0x08, "php", implied) + op(0x09, "ora", immediateA) + op(0x0a, "asl", implied) + op(0x0b, "phd", implied) + op(0x0c, "tsb", absolute) + op(0x0d, "ora", absolute) + op(0x0e, "asl", absolute) + op(0x0f, "ora", absoluteLong) + op(0x10, "bpl", relative) + op(0x11, "ora", indirectIndexedY) + op(0x12, "ora", indirect) + op(0x13, "ora", stackIndirect) + op(0x14, "trb", direct) + op(0x15, "ora", directX) + op(0x16, "asl", directX) + op(0x17, "ora", indirectLongY) + op(0x18, "clc", implied) + op(0x19, "ora", absoluteY) + op(0x1a, "inc", implied) + op(0x1b, "tas", implied) + op(0x1c, "trb", absolute) + op(0x1d, "ora", absoluteX) + op(0x1e, "asl", absoluteX) + op(0x1f, "ora", absoluteLongX) + + op(0x20, "jsr", absolutePC) + op(0x21, "and", indexedIndirectX) + op(0x22, "jsl", absoluteLong) + op(0x23, "and", stack) + op(0x24, "bit", direct) + op(0x25, "and", direct) + op(0x26, "rol", direct) + op(0x27, "and", indirectLong) + op(0x28, "plp", implied) + op(0x29, "and", immediateA) + op(0x2a, "rol", implied) + op(0x2b, "pld", implied) + op(0x2c, "bit", absolute) + op(0x2d, "and", absolute) + op(0x2e, "rol", absolute) + op(0x2f, "and", absoluteLong) + op(0x30, "bmi", relative) + op(0x31, "and", indirectIndexedY) + op(0x32, "and", indirect) + op(0x33, "and", stackIndirect) + op(0x34, "bit", directX) + op(0x35, "and", directX) + op(0x36, "rol", directX) + op(0x37, "and", indirectLongY) + op(0x38, "sec", implied) + op(0x39, "and", absoluteY) + op(0x3a, "dec", implied) + op(0x3b, "tsa", implied) + op(0x3c, "bit", absoluteX) + op(0x3d, "and", absoluteX) + op(0x3e, "rol", absoluteX) + op(0x3f, "and", absoluteLongX) + + op(0x40, "rti", implied) + op(0x41, "eor", indexedIndirectX) + op(0x42, "wdm", immediate) + op(0x43, "eor", stack) + op(0x44, "mvp", move) + op(0x45, "eor", direct) + op(0x46, "lsr", direct) + op(0x47, "eor", indirectLong) + op(0x48, "pha", implied) + op(0x49, "eor", immediateA) + op(0x4a, "lsr", implied) + op(0x4b, "phk", implied) + op(0x4c, "jmp", absolutePC) + op(0x4d, "eor", absolute) + op(0x4e, "lsr", absolute) + op(0x4f, "eor", absoluteLong) + op(0x50, "bvc", relative) + op(0x51, "eor", indirectIndexedY) + op(0x52, "eor", indirect) + op(0x53, "eor", stackIndirect) + op(0x54, "mvn", move) + op(0x55, "eor", directX) + op(0x56, "lsr", directX) + op(0x57, "eor", indirectLongY) + op(0x58, "cli", implied) + op(0x59, "eor", absoluteY) + op(0x5a, "phy", implied) + op(0x5b, "tad", implied) + op(0x5c, "jml", absoluteLong) + op(0x5d, "eor", absoluteX) + op(0x5e, "lsr", absoluteX) + op(0x5f, "eor", absoluteLongX) + + op(0x60, "rts", implied) + op(0x61, "adc", indexedIndirectX) + op(0x62, "per", absolute) + op(0x63, "adc", stack) + op(0x64, "stz", direct) + op(0x65, "adc", direct) + op(0x66, "ror", direct) + op(0x67, "adc", indirectLong) + op(0x68, "pla", implied) + op(0x69, "adc", immediateA) + op(0x6a, "ror", implied) + op(0x6b, "rtl", implied) + op(0x6c, "jmp", indirectPC) + op(0x6d, "adc", absolute) + op(0x6e, "ror", absolute) + op(0x6f, "adc", absoluteLong) + op(0x70, "bvs", relative) + op(0x71, "adc", indirectIndexedY) + op(0x72, "adc", indirect) + op(0x73, "adc", stackIndirect) + op(0x74, "stz", directX) + op(0x75, "adc", directX) + op(0x76, "ror", directX) + op(0x77, "adc", indirectLongY) + op(0x78, "sei", implied) + op(0x79, "adc", absoluteY) + op(0x7a, "ply", implied) + op(0x7b, "tda", implied) + op(0x7c, "jmp", indirectX) + op(0x7d, "adc", absoluteX) + op(0x7e, "ror", absoluteX) + op(0x7f, "adc", absoluteLongX) + + op(0x80, "bra", relative) + op(0x81, "sta", indexedIndirectX) + op(0x82, "brl", relativeWord) + op(0x83, "sta", stack) + op(0x84, "sty", direct) + op(0x85, "sta", direct) + op(0x86, "stx", direct) + op(0x87, "sta", indirectLong) + op(0x88, "dey", implied) + op(0x89, "bit", immediateA) + op(0x8a, "txa", implied) + op(0x8b, "phb", implied) + op(0x8c, "sty", absolute) + op(0x8d, "sta", absolute) + op(0x8e, "stx", absolute) + op(0x8f, "sta", absoluteLong) + op(0x90, "bcc", relative) + op(0x91, "sta", indirectIndexedY) + op(0x92, "sta", indirect) + op(0x93, "sta", stackIndirect) + op(0x94, "sty", directX) + op(0x95, "sta", directX) + op(0x96, "stx", directY) + op(0x97, "sta", indirectLongY) + op(0x98, "tya", implied) + op(0x99, "sta", absoluteY) + op(0x9a, "txs", implied) + op(0x9b, "txy", implied) + op(0x9c, "stz", absolute) + op(0x9d, "sta", absoluteX) + op(0x9e, "stz", absoluteX) + op(0x9f, "sta", absoluteLongX) + + op(0xa0, "ldy", immediateX) + op(0xa1, "lda", indexedIndirectX) + op(0xa2, "ldx", immediateX) + op(0xa3, "lda", stack) + op(0xa4, "ldy", direct) + op(0xa5, "lda", direct) + op(0xa6, "ldx", direct) + op(0xa7, "lda", indirectLong) + op(0xa8, "tay", implied) + op(0xa9, "lda", immediateA) + op(0xaa, "tax", implied) + op(0xab, "plb", implied) + op(0xac, "ldy", absolute) + op(0xad, "lda", absolute) + op(0xae, "ldx", absolute) + op(0xaf, "lda", absoluteLong) + op(0xb0, "bcs", relative) + op(0xb1, "lda", indirectIndexedY) + op(0xb2, "lda", indirect) + op(0xb3, "lda", stackIndirect) + op(0xb4, "ldy", directX) + op(0xb5, "lda", directX) + op(0xb6, "ldx", directY) + op(0xb7, "lda", indirectLongY) + op(0xb8, "clv", implied) + op(0xb9, "lda", absoluteY) + op(0xba, "tsx", implied) + op(0xbb, "tyx", implied) + op(0xbc, "ldy", absoluteX) + op(0xbd, "lda", absoluteX) + op(0xbe, "ldx", absoluteY) + op(0xbf, "lda", absoluteLongX) + + op(0xc0, "cpy", immediateX) + op(0xc1, "cmp", indexedIndirectX) + op(0xc2, "rep", immediate) + op(0xc3, "cmp", stack) + op(0xc4, "cpy", direct) + op(0xc5, "cmp", direct) + op(0xc6, "dec", direct) + op(0xc7, "cmp", indirectLong) + op(0xc8, "iny", implied) + op(0xc9, "cmp", immediateA) + op(0xca, "dex", implied) + op(0xcb, "wai", implied) + op(0xcc, "cpy", absolute) + op(0xcd, "cmp", absolute) + op(0xce, "dec", absolute) + op(0xcf, "cmp", absoluteLong) + op(0xd0, "bne", relative) + op(0xd1, "cmp", indirectIndexedY) + op(0xd2, "cmp", indirect) + op(0xd3, "cmp", stackIndirect) + op(0xd4, "pei", indirect) + op(0xd5, "cmp", directX) + op(0xd6, "dec", directX) + op(0xd7, "cmp", indirectLongY) + op(0xd8, "cld", implied) + op(0xd9, "cmp", absoluteY) + op(0xda, "phx", implied) + op(0xdb, "stp", implied) + op(0xdc, "jmp", indirectLongPC) + op(0xdd, "cmp", absoluteX) + op(0xde, "dec", absoluteX) + op(0xdf, "cmp", absoluteLongX) + + op(0xe0, "cpx", immediateX) + op(0xe1, "sbc", indexedIndirectX) + op(0xe2, "sep", immediate) + op(0xe3, "sbc", stack) + op(0xe4, "cpx", direct) + op(0xe5, "sbc", direct) + op(0xe6, "inc", direct) + op(0xe7, "sbc", indirectLong) + op(0xe8, "inx", implied) + op(0xe9, "sbc", immediateA) + op(0xea, "nop", implied) + op(0xeb, "xba", implied) + op(0xec, "cpx", absolute) + op(0xed, "sbc", absolute) + op(0xee, "inc", absolute) + op(0xef, "sbc", absoluteLong) + op(0xf0, "beq", relative) + op(0xf1, "sbc", indirectIndexedY) + op(0xf2, "sbc", indirect) + op(0xf3, "sbc", stackIndirect) + op(0xf4, "pea", absolute) + op(0xf5, "sbc", directX) + op(0xf6, "inc", directX) + op(0xf7, "sbc", indirectLongY) + op(0xf8, "sed", implied) + op(0xf9, "sbc", absoluteY) + op(0xfa, "plx", implied) + op(0xfb, "xce", implied) + op(0xfc, "jsr", indirectX) + op(0xfd, "sbc", absoluteX) + op(0xfe, "inc", absoluteX) + op(0xff, "sbc", absoluteLongX) + } + #undef op + + s.append(name, " ", operand); + while(s.size() < 23) s.append(" "); + if(effective) s.append("[", hex(*effective, 6L), "]"); + while(s.size() < 31) s.append(" "); + + s.append(" A:", hex(r.a.w, 4L)); + s.append(" X:", hex(r.x.w, 4L)); + s.append(" Y:", hex(r.y.w, 4L)); + s.append(" S:", hex(r.s.w, 4L)); + s.append(" D:", hex(r.d.w, 4L)); + s.append(" B:", hex(r.b , 2L)); + + if(e) { + s.append(' ', + r.p.n ? 'N' : 'n', r.p.v ? 'V' : 'v', + r.p.m ? '1' : '0', r.p.x ? 'B' : 'b', + r.p.d ? 'D' : 'd', r.p.i ? 'I' : 'i', + r.p.z ? 'Z' : 'z', r.p.c ? 'C' : 'c' + ); + } else { + s.append(' ', + r.p.n ? 'N' : 'n', r.p.v ? 'V' : 'v', + r.p.m ? 'M' : 'm', r.p.x ? 'X' : 'x', + r.p.d ? 'D' : 'd', r.p.i ? 'I' : 'i', + r.p.z ? 'Z' : 'z', r.p.c ? 'C' : 'c' + ); + } + + return s; +} diff --git a/processor/wdc65816/instruction.cpp b/processor/wdc65816/instruction.cpp new file mode 100644 index 0000000..1d39fa2 --- /dev/null +++ b/processor/wdc65816/instruction.cpp @@ -0,0 +1,64 @@ +auto WDC65816::interrupt() -> void { + read(PC.d); + idle(); +N push(PC.b); + push(PC.h); + push(PC.l); + push(EF ? P & ~0x10 : P); + IF = 1; + DF = 0; + PC.l = read(r.vector + 0); +L PC.h = read(r.vector + 1); + PC.b = 0x00; + idleJump(); +} + +//both the accumulator and index registers can independently be in either 8-bit or 16-bit mode. +//controlled via the M/X flags, this changes the execution details of various instructions. +//rather than implement four instruction tables for all possible combinations of these bits, +//instead use macro abuse to generate all four tables based off of a single template table. +auto WDC65816::instruction() -> void { + //a = instructions unaffected by M/X flags + //m = instructions affected by M flag (1 = 8-bit; 0 = 16-bit) + //x = instructions affected by X flag (1 = 8-bit; 0 = 16-bit) + + #define opA(id, name, ...) case id: return instruction##name(__VA_ARGS__); + if(MF) { + #define opM(id, name, ...) case id: return instruction##name##8(__VA_ARGS__); + #define m(name) &WDC65816::algorithm##name##8 + if(XF) { + #define opX(id, name, ...) case id: return instruction##name##8(__VA_ARGS__); + #define x(name) &WDC65816::algorithm##name##8 + #include "instruction.hpp" + #undef opX + #undef x + } else { + #define opX(id, name, ...) case id: return instruction##name##16(__VA_ARGS__); + #define x(name) &WDC65816::algorithm##name##16 + #include "instruction.hpp" + #undef opX + #undef x + } + #undef opM + #undef m + } else { + #define opM(id, name, ...) case id: return instruction##name##16(__VA_ARGS__); + #define m(name) &WDC65816::algorithm##name##16 + if(XF) { + #define opX(id, name, ...) case id: return instruction##name##8(__VA_ARGS__); + #define x(name) &WDC65816::algorithm##name##8 + #include "instruction.hpp" + #undef opX + #undef x + } else { + #define opX(id, name, ...) case id: return instruction##name##16(__VA_ARGS__); + #define x(name) &WDC65816::algorithm##name##16 + #include "instruction.hpp" + #undef opX + #undef x + } + #undef opM + #undef m + } + #undef opA +} diff --git a/processor/wdc65816/instruction.hpp b/processor/wdc65816/instruction.hpp new file mode 100644 index 0000000..3469310 --- /dev/null +++ b/processor/wdc65816/instruction.hpp @@ -0,0 +1,258 @@ + switch(fetch()) { + opA(0x00, Interrupt, EF ? (r16)0xfffe : (r16)0xffe6) //emulation mode lacks BRK vector; uses IRQ vector instead + opM(0x01, IndexedIndirectRead, m(ORA)) + opA(0x02, Interrupt, EF ? (r16)0xfff4 : (r16)0xffe4) + opM(0x03, StackRead, m(ORA)) + opM(0x04, DirectModify, m(TSB)) + opM(0x05, DirectRead, m(ORA)) + opM(0x06, DirectModify, m(ASL)) + opM(0x07, IndirectLongRead, m(ORA)) + opA(0x08, Push8, (r16)P) + opM(0x09, ImmediateRead, m(ORA)) + opM(0x0a, ImpliedModify, m(ASL), A) + opA(0x0b, PushD) + opM(0x0c, BankModify, m(TSB)) + opM(0x0d, BankRead, m(ORA)) + opM(0x0e, BankModify, m(ASL)) + opM(0x0f, LongRead, m(ORA)) + opA(0x10, Branch, NF == 0) + opM(0x11, IndirectIndexedRead, m(ORA)) + opM(0x12, IndirectRead, m(ORA)) + opM(0x13, IndirectStackRead, m(ORA)) + opM(0x14, DirectModify, m(TRB)) + opM(0x15, DirectRead, m(ORA), X) + opM(0x16, DirectIndexedModify, m(ASL)) + opM(0x17, IndirectLongRead, m(ORA), Y) + opA(0x18, ClearFlag, CF) + opM(0x19, BankRead, m(ORA), Y) + opM(0x1a, ImpliedModify, m(INC), A) + opA(0x1b, TransferCS) + opM(0x1c, BankModify, m(TRB)) + opM(0x1d, BankRead, m(ORA), X) + opM(0x1e, BankIndexedModify, m(ASL)) + opM(0x1f, LongRead, m(ORA), X) + opA(0x20, CallShort) + opM(0x21, IndexedIndirectRead, m(AND)) + opA(0x22, CallLong) + opM(0x23, StackRead, m(AND)) + opM(0x24, DirectRead, m(BIT)) + opM(0x25, DirectRead, m(AND)) + opM(0x26, DirectModify, m(ROL)) + opM(0x27, IndirectLongRead, m(AND)) + opA(0x28, PullP) + opM(0x29, ImmediateRead, m(AND)) + opM(0x2a, ImpliedModify, m(ROL), A) + opA(0x2b, PullD) + opM(0x2c, BankRead, m(BIT)) + opM(0x2d, BankRead, m(AND)) + opM(0x2e, BankModify, m(ROL)) + opM(0x2f, LongRead, m(AND)) + opA(0x30, Branch, NF == 1) + opM(0x31, IndirectIndexedRead, m(AND)) + opM(0x32, IndirectRead, m(AND)) + opM(0x33, IndirectStackRead, m(AND)) + opM(0x34, DirectRead, m(BIT), X) + opM(0x35, DirectRead, m(AND), X) + opM(0x36, DirectIndexedModify, m(ROL)) + opM(0x37, IndirectLongRead, m(AND), Y) + opA(0x38, SetFlag, CF) + opM(0x39, BankRead, m(AND), Y) + opM(0x3a, ImpliedModify, m(DEC), A) + opA(0x3b, Transfer16, S, A) + opM(0x3c, BankRead, m(BIT), X) + opM(0x3d, BankRead, m(AND), X) + opM(0x3e, BankIndexedModify, m(ROL)) + opM(0x3f, LongRead, m(AND), X) + opA(0x40, ReturnInterrupt) + opM(0x41, IndexedIndirectRead, m(EOR)) + opA(0x42, Prefix) + opM(0x43, StackRead, m(EOR)) + opX(0x44, BlockMove, -1) + opM(0x45, DirectRead, m(EOR)) + opM(0x46, DirectModify, m(LSR)) + opM(0x47, IndirectLongRead, m(EOR)) + opM(0x48, Push, A) + opM(0x49, ImmediateRead, m(EOR)) + opM(0x4a, ImpliedModify, m(LSR), A) + opA(0x4b, Push8, (r16)PC.b) + opA(0x4c, JumpShort) + opM(0x4d, BankRead, m(EOR)) + opM(0x4e, BankModify, m(LSR)) + opM(0x4f, LongRead, m(EOR)) + opA(0x50, Branch, VF == 0) + opM(0x51, IndirectIndexedRead, m(EOR)) + opM(0x52, IndirectRead, m(EOR)) + opM(0x53, IndirectStackRead, m(EOR)) + opX(0x54, BlockMove, +1) + opM(0x55, DirectRead, m(EOR), X) + opM(0x56, DirectIndexedModify, m(LSR)) + opM(0x57, IndirectLongRead, m(EOR), Y) + opA(0x58, ClearFlag, IF) + opM(0x59, BankRead, m(EOR), Y) + opX(0x5a, Push, Y) + opA(0x5b, Transfer16, A, D) + opA(0x5c, JumpLong) + opM(0x5d, BankRead, m(EOR), X) + opM(0x5e, BankIndexedModify, m(LSR)) + opM(0x5f, LongRead, m(EOR), X) + opA(0x60, ReturnShort) + opM(0x61, IndexedIndirectRead, m(ADC)) + opA(0x62, PushEffectiveRelativeAddress) + opM(0x63, StackRead, m(ADC)) + opM(0x64, DirectWrite, Z) + opM(0x65, DirectRead, m(ADC)) + opM(0x66, DirectModify, m(ROR)) + opM(0x67, IndirectLongRead, m(ADC)) + opM(0x68, Pull, A) + opM(0x69, ImmediateRead, m(ADC)) + opM(0x6a, ImpliedModify, m(ROR), A) + opA(0x6b, ReturnLong) + opA(0x6c, JumpIndirect) + opM(0x6d, BankRead, m(ADC)) + opM(0x6e, BankModify, m(ROR)) + opM(0x6f, LongRead, m(ADC)) + opA(0x70, Branch, VF == 1) + opM(0x71, IndirectIndexedRead, m(ADC)) + opM(0x72, IndirectRead, m(ADC)) + opM(0x73, IndirectStackRead, m(ADC)) + opM(0x74, DirectWrite, Z, X) + opM(0x75, DirectRead, m(ADC), X) + opM(0x76, DirectIndexedModify, m(ROR)) + opM(0x77, IndirectLongRead, m(ADC), Y) + opA(0x78, SetFlag, IF) + opM(0x79, BankRead, m(ADC), Y) + opX(0x7a, Pull, Y) + opA(0x7b, Transfer16, D, A) + opA(0x7c, JumpIndexedIndirect) + opM(0x7d, BankRead, m(ADC), X) + opM(0x7e, BankIndexedModify, m(ROR)) + opM(0x7f, LongRead, m(ADC), X) + opA(0x80, Branch) + opM(0x81, IndexedIndirectWrite) + opA(0x82, BranchLong) + opM(0x83, StackWrite) + opX(0x84, DirectWrite, Y) + opM(0x85, DirectWrite, A) + opX(0x86, DirectWrite, X) + opM(0x87, IndirectLongWrite) + opX(0x88, ImpliedModify, x(DEC), Y) + opM(0x89, BitImmediate) + opM(0x8a, Transfer, X, A) + opA(0x8b, Push8, (r16)B) + opX(0x8c, BankWrite, Y) + opM(0x8d, BankWrite, A) + opX(0x8e, BankWrite, X) + opM(0x8f, LongWrite) + opA(0x90, Branch, CF == 0) + opM(0x91, IndirectIndexedWrite) + opM(0x92, IndirectWrite) + opM(0x93, IndirectStackWrite) + opX(0x94, DirectWrite, Y, X) + opM(0x95, DirectWrite, A, X) + opX(0x96, DirectWrite, X, Y) + opM(0x97, IndirectLongWrite, Y) + opM(0x98, Transfer, Y, A) + opM(0x99, BankWrite, A, Y) + opA(0x9a, TransferXS) + opX(0x9b, Transfer, X, Y) + opM(0x9c, BankWrite, Z) + opM(0x9d, BankWrite, A, X) + opM(0x9e, BankWrite, Z, X) + opM(0x9f, LongWrite, X) + opX(0xa0, ImmediateRead, x(LDY)) + opM(0xa1, IndexedIndirectRead, m(LDA)) + opX(0xa2, ImmediateRead, x(LDX)) + opM(0xa3, StackRead, m(LDA)) + opX(0xa4, DirectRead, x(LDY)) + opM(0xa5, DirectRead, m(LDA)) + opX(0xa6, DirectRead, x(LDX)) + opM(0xa7, IndirectLongRead, m(LDA)) + opX(0xa8, Transfer, A, Y) + opM(0xa9, ImmediateRead, m(LDA)) + opX(0xaa, Transfer, A, X) + opA(0xab, PullB) + opX(0xac, BankRead, x(LDY)) + opM(0xad, BankRead, m(LDA)) + opX(0xae, BankRead, x(LDX)) + opM(0xaf, LongRead, m(LDA)) + opA(0xb0, Branch, CF == 1) + opM(0xb1, IndirectIndexedRead, m(LDA)) + opM(0xb2, IndirectRead, m(LDA)) + opM(0xb3, IndirectStackRead, m(LDA)) + opX(0xb4, DirectRead, x(LDY), X) + opM(0xb5, DirectRead, m(LDA), X) + opX(0xb6, DirectRead, x(LDX), Y) + opM(0xb7, IndirectLongRead, m(LDA), Y) + opA(0xb8, ClearFlag, VF) + opM(0xb9, BankRead, m(LDA), Y) + opX(0xba, TransferSX) + opX(0xbb, Transfer, Y, X) + opX(0xbc, BankRead, x(LDY), X) + opM(0xbd, BankRead, m(LDA), X) + opX(0xbe, BankRead, x(LDX), Y) + opM(0xbf, LongRead, m(LDA), X) + opX(0xc0, ImmediateRead, x(CPY)) + opM(0xc1, IndexedIndirectRead, m(CMP)) + opA(0xc2, ResetP) + opM(0xc3, StackRead, m(CMP)) + opX(0xc4, DirectRead, x(CPY)) + opM(0xc5, DirectRead, m(CMP)) + opM(0xc6, DirectModify, m(DEC)) + opM(0xc7, IndirectLongRead, m(CMP)) + opX(0xc8, ImpliedModify, x(INC), Y) + opM(0xc9, ImmediateRead, m(CMP)) + opX(0xca, ImpliedModify, x(DEC), X) + opA(0xcb, Wait) + opX(0xcc, BankRead, x(CPY)) + opM(0xcd, BankRead, m(CMP)) + opM(0xce, BankModify, m(DEC)) + opM(0xcf, LongRead, m(CMP)) + opA(0xd0, Branch, ZF == 0) + opM(0xd1, IndirectIndexedRead, m(CMP)) + opM(0xd2, IndirectRead, m(CMP)) + opM(0xd3, IndirectStackRead, m(CMP)) + opA(0xd4, PushEffectiveIndirectAddress) + opM(0xd5, DirectRead, m(CMP), X) + opM(0xd6, DirectIndexedModify, m(DEC)) + opM(0xd7, IndirectLongRead, m(CMP), Y) + opA(0xd8, ClearFlag, DF) + opM(0xd9, BankRead, m(CMP), Y) + opX(0xda, Push, X) + opA(0xdb, Stop) + opA(0xdc, JumpIndirectLong) + opM(0xdd, BankRead, m(CMP), X) + opM(0xde, BankIndexedModify, m(DEC)) + opM(0xdf, LongRead, m(CMP), X) + opX(0xe0, ImmediateRead, x(CPX)) + opM(0xe1, IndexedIndirectRead, m(SBC)) + opA(0xe2, SetP) + opM(0xe3, StackRead, m(SBC)) + opX(0xe4, DirectRead, x(CPX)) + opM(0xe5, DirectRead, m(SBC)) + opM(0xe6, DirectModify, m(INC)) + opM(0xe7, IndirectLongRead, m(SBC)) + opX(0xe8, ImpliedModify, x(INC), X) + opM(0xe9, ImmediateRead, m(SBC)) + opA(0xea, NoOperation) + opA(0xeb, ExchangeBA) + opX(0xec, BankRead, x(CPX)) + opM(0xed, BankRead, m(SBC)) + opM(0xee, BankModify, m(INC)) + opM(0xef, LongRead, m(SBC)) + opA(0xf0, Branch, ZF == 1) + opM(0xf1, IndirectIndexedRead, m(SBC)) + opM(0xf2, IndirectRead, m(SBC)) + opM(0xf3, IndirectStackRead, m(SBC)) + opA(0xf4, PushEffectiveAddress) + opM(0xf5, DirectRead, m(SBC), X) + opM(0xf6, DirectIndexedModify, m(INC)) + opM(0xf7, IndirectLongRead, m(SBC), Y) + opA(0xf8, SetFlag, DF) + opM(0xf9, BankRead, m(SBC), Y) + opX(0xfa, Pull, X) + opA(0xfb, ExchangeCE) + opA(0xfc, CallIndexedIndirect) + opM(0xfd, BankRead, m(SBC), X) + opM(0xfe, BankIndexedModify, m(INC)) + opM(0xff, LongRead, m(SBC), X) + } diff --git a/processor/wdc65816/instructions-modify.cpp b/processor/wdc65816/instructions-modify.cpp new file mode 100755 index 0000000..9359352 --- /dev/null +++ b/processor/wdc65816/instructions-modify.cpp @@ -0,0 +1,93 @@ +auto WDC65816::instructionImpliedModify8(alu8 op, r16& M) -> void { +L idleIRQ(); + M.l = alu(M.l); +} + +auto WDC65816::instructionImpliedModify16(alu16 op, r16& M) -> void { +L idleIRQ(); + M.w = alu(M.w); +} + +auto WDC65816::instructionBankModify8(alu8 op) -> void { + V.l = fetch(); + V.h = fetch(); + W.l = readBank(V.w + 0); + idle(); + W.l = alu(W.l); +L writeBank(V.w + 0, W.l); +} + +auto WDC65816::instructionBankModify16(alu16 op) -> void { + V.l = fetch(); + V.h = fetch(); + W.l = readBank(V.w + 0); + W.h = readBank(V.w + 1); + idle(); + W.w = alu(W.w); + writeBank(V.w + 1, W.h); +L writeBank(V.w + 0, W.l); +} + +auto WDC65816::instructionBankIndexedModify8(alu8 op) -> void { + V.l = fetch(); + V.h = fetch(); + idle(); + W.l = readBank(V.w + X.w + 0); + idle(); + W.l = alu(W.l); +L writeBank(V.w + X.w + 0, W.l); +} + +auto WDC65816::instructionBankIndexedModify16(alu16 op) -> void { + V.l = fetch(); + V.h = fetch(); + idle(); + W.l = readBank(V.w + X.w + 0); + W.h = readBank(V.w + X.w + 1); + idle(); + W.w = alu(W.w); + writeBank(V.w + X.w + 1, W.h); +L writeBank(V.w + X.w + 0, W.l); +} + +auto WDC65816::instructionDirectModify8(alu8 op) -> void { + U.l = fetch(); + idle2(); + W.l = readDirect(U.l + 0); + idle(); + W.l = alu(W.l); +L writeDirect(U.l + 0, W.l); +} + +auto WDC65816::instructionDirectModify16(alu16 op) -> void { + U.l = fetch(); + idle2(); + W.l = readDirect(U.l + 0); + W.h = readDirect(U.l + 1); + idle(); + W.w = alu(W.w); + writeDirect(U.l + 1, W.h); +L writeDirect(U.l + 0, W.l); +} + +auto WDC65816::instructionDirectIndexedModify8(alu8 op) -> void { + U.l = fetch(); + idle2(); + idle(); + W.l = readDirect(U.l + X.w + 0); + idle(); + W.l = alu(W.l); +L writeDirect(U.l + X.w + 0, W.l); +} + +auto WDC65816::instructionDirectIndexedModify16(alu16 op) -> void { + U.l = fetch(); + idle2(); + idle(); + W.l = readDirect(U.l + X.w + 0); + W.h = readDirect(U.l + X.w + 1); + idle(); + W.w = alu(W.w); + writeDirect(U.l + X.w + 1, W.h); +L writeDirect(U.l + X.w + 0, W.l); +} diff --git a/processor/wdc65816/instructions-other.cpp b/processor/wdc65816/instructions-other.cpp new file mode 100755 index 0000000..c7290ea --- /dev/null +++ b/processor/wdc65816/instructions-other.cpp @@ -0,0 +1,247 @@ +auto WDC65816::instructionBitImmediate8() -> void { +L U.l = fetch(); + ZF = (U.l & A.l) == 0; +} + +auto WDC65816::instructionBitImmediate16() -> void { + U.l = fetch(); +L U.h = fetch(); + ZF = (U.w & A.w) == 0; +} + +auto WDC65816::instructionNoOperation() -> void { +L idleIRQ(); +} + +auto WDC65816::instructionPrefix() -> void { +L fetch(); +} + +auto WDC65816::instructionExchangeBA() -> void { + idle(); +L idle(); + A.w = A.w >> 8 | A.w << 8; + ZF = A.l == 0; + NF = A.l & 0x80; +} + +auto WDC65816::instructionBlockMove8(int adjust) -> void { + U.b = fetch(); + V.b = fetch(); + B = U.b; + W.l = read(V.b << 16 | X.w); + write(U.b << 16 | Y.w, W.l); + idle(); + X.l += adjust; + Y.l += adjust; +L idle(); + if(A.w--) PC.w -= 3; +} + +auto WDC65816::instructionBlockMove16(int adjust) -> void { + U.b = fetch(); + V.b = fetch(); + B = U.b; + W.l = read(V.b << 16 | X.w); + write(U.b << 16 | Y.w, W.l); + idle(); + X.w += adjust; + Y.w += adjust; +L idle(); + if(A.w--) PC.w -= 3; +} + +auto WDC65816::instructionInterrupt(r16 vector) -> void { + fetch(); +N push(PC.b); + push(PC.h); + push(PC.l); + push(P); + IF = 1; + DF = 0; + PC.l = read(vector.w + 0); +L PC.h = read(vector.w + 1); + PC.b = 0x00; +} + +auto WDC65816::instructionStop() -> void { + r.stp = true; + while(r.stp && !synchronizing()) { +L idle(); + } +} + +auto WDC65816::instructionWait() -> void { + r.wai = true; + while(r.wai && !synchronizing()) { +L idle(); + } + idle(); +} + +auto WDC65816::instructionExchangeCE() -> void { +L idleIRQ(); + swap(CF, EF); + if(EF) { + XF = 1; + MF = 1; + X.h = 0x00; + Y.h = 0x00; + S.h = 0x01; + } +} + +auto WDC65816::instructionSetFlag(bool& flag) -> void { +L idleIRQ(); + flag = 1; +} + +auto WDC65816::instructionClearFlag(bool& flag) -> void { +L idleIRQ(); + flag = 0; +} + +auto WDC65816::instructionResetP() -> void { + W.l = fetch(); +L idle(); + P = P & ~W.l; +E XF = 1, MF = 1; + if(XF) X.h = 0x00, Y.h = 0x00; +} + +auto WDC65816::instructionSetP() -> void { + W.l = fetch(); +L idle(); + P = P | W.l; +E XF = 1, MF = 1; + if(XF) X.h = 0x00, Y.h = 0x00; +} + +auto WDC65816::instructionTransfer8(r16 F, r16& T) -> void { +L idleIRQ(); + T.l = F.l; + ZF = T.l == 0; + NF = T.l & 0x80; +} + +auto WDC65816::instructionTransfer16(r16 F, r16& T) -> void { +L idleIRQ(); + T.w = F.w; + ZF = T.w == 0; + NF = T.w & 0x8000; +} + +auto WDC65816::instructionTransferCS() -> void { +L idleIRQ(); + S.w = A.w; +E S.h = 0x01; +} + +auto WDC65816::instructionTransferSX8() -> void { +L idleIRQ(); + X.l = S.l; + ZF = X.l == 0; + NF = X.l & 0x80; +} + +auto WDC65816::instructionTransferSX16() -> void { +L idleIRQ(); + X.w = S.w; + ZF = X.w == 0; + NF = X.w & 0x8000; +} + +auto WDC65816::instructionTransferXS() -> void { +L idleIRQ(); +E S.l = X.l; +N S.w = X.w; +} + +auto WDC65816::instructionPush8(r16 F) -> void { + idle(); +L push(F.l); +} + +auto WDC65816::instructionPush16(r16 F) -> void { + idle(); + push(F.h); +L push(F.l); +} + +auto WDC65816::instructionPushD() -> void { + idle(); + pushN(D.h); +L pushN(D.l); +E S.h = 0x01; +} + +auto WDC65816::instructionPull8(r16& T) -> void { + idle(); + idle(); +L T.l = pull(); + ZF = T.l == 0; + NF = T.l & 0x80; +} + +auto WDC65816::instructionPull16(r16& T) -> void { + idle(); + idle(); + T.l = pull(); +L T.h = pull(); + ZF = T.w == 0; + NF = T.w & 0x8000; +} + +auto WDC65816::instructionPullD() -> void { + idle(); + idle(); + D.l = pullN(); +L D.h = pullN(); + ZF = D.w == 0; + NF = D.w & 0x8000; +E S.h = 0x01; +} + +auto WDC65816::instructionPullB() -> void { + idle(); + idle(); +L B = pull(); + ZF = B == 0; + NF = B & 0x80; +} + +auto WDC65816::instructionPullP() -> void { + idle(); + idle(); +L P = pull(); +E XF = 1, MF = 1; + if(XF) X.h = 0x00, Y.h = 0x00; +} + +auto WDC65816::instructionPushEffectiveAddress() -> void { + W.l = fetch(); + W.h = fetch(); + pushN(W.h); +L pushN(W.l); +E S.h = 0x01; +} + +auto WDC65816::instructionPushEffectiveIndirectAddress() -> void { + U.l = fetch(); + idle2(); + W.l = readDirectN(U.l + 0); + W.h = readDirectN(U.l + 1); + pushN(W.h); +L pushN(W.l); +E S.h = 0x01; +} + +auto WDC65816::instructionPushEffectiveRelativeAddress() -> void { + V.l = fetch(); + V.h = fetch(); + idle(); + W.w = PC.d + (int16)V.w; + pushN(W.h); +L pushN(W.l); +E S.h = 0x01; +} diff --git a/processor/wdc65816/instructions-pc.cpp b/processor/wdc65816/instructions-pc.cpp new file mode 100755 index 0000000..beb6f7c --- /dev/null +++ b/processor/wdc65816/instructions-pc.cpp @@ -0,0 +1,142 @@ +auto WDC65816::instructionBranch(bool take) -> void { + if(!take) { +L fetch(); + } else { + U.l = fetch(); + V.w = PC.d + (int8)U.l; + idle6(V.w); +L idle(); + PC.w = V.w; + idleBranch(); + } +} + +auto WDC65816::instructionBranchLong() -> void { + U.l = fetch(); + U.h = fetch(); + V.w = PC.d + (int16)U.w; +L idle(); + PC.w = V.w; + idleBranch(); +} + +auto WDC65816::instructionJumpShort() -> void { + W.l = fetch(); +L W.h = fetch(); + PC.w = W.w; + idleJump(); +} + +auto WDC65816::instructionJumpLong() -> void { + V.l = fetch(); + V.h = fetch(); +L V.b = fetch(); + PC.d = V.d; + idleJump(); +} + +auto WDC65816::instructionJumpIndirect() -> void { + V.l = fetch(); + V.h = fetch(); + W.l = read(uint16(V.w + 0)); +L W.h = read(uint16(V.w + 1)); + PC.w = W.w; + idleJump(); +} + +auto WDC65816::instructionJumpIndexedIndirect() -> void { + V.l = fetch(); + V.h = fetch(); + idle(); + W.l = read(PC.b << 16 | uint16(V.w + X.w + 0)); +L W.h = read(PC.b << 16 | uint16(V.w + X.w + 1)); + PC.w = W.w; + idleJump(); +} + +auto WDC65816::instructionJumpIndirectLong() -> void { + U.l = fetch(); + U.h = fetch(); + V.l = read(uint16(U.w + 0)); + V.h = read(uint16(U.w + 1)); +L V.b = read(uint16(U.w + 2)); + PC.d = V.d; + idleJump(); +} + +auto WDC65816::instructionCallShort() -> void { + W.l = fetch(); + W.h = fetch(); + idle(); + PC.w--; + push(PC.h); +L push(PC.l); + PC.w = W.w; + idleJump(); +} + +auto WDC65816::instructionCallLong() -> void { + V.l = fetch(); + V.h = fetch(); + pushN(PC.b); + idle(); + V.b = fetch(); + PC.w--; + pushN(PC.h); +L pushN(PC.l); + PC.d = V.d; +E S.h = 0x01; + idleJump(); +} + +auto WDC65816::instructionCallIndexedIndirect() -> void { + V.l = fetch(); + pushN(PC.h); + pushN(PC.l); + V.h = fetch(); + idle(); + W.l = read(PC.b << 16 | uint16(V.w + X.w + 0)); +L W.h = read(PC.b << 16 | uint16(V.w + X.w + 1)); + PC.w = W.w; +E S.h = 0x01; + idleJump(); +} + +auto WDC65816::instructionReturnInterrupt() -> void { + idle(); + idle(); + P = pull(); +E XF = 1, MF = 1; + if(XF) X.h = 0x00, Y.h = 0x00; + PC.l = pull(); + if(EF) { + L PC.h = pull(); + } else { + PC.h = pull(); + L PC.b = pull(); + } + idleJump(); +} + +auto WDC65816::instructionReturnShort() -> void { + idle(); + idle(); + W.l = pull(); + W.h = pull(); +L idle(); + PC.w = W.w; + PC.w++; + idleJump(); +} + +auto WDC65816::instructionReturnLong() -> void { + idle(); + idle(); + V.l = pullN(); + V.h = pullN(); +L V.b = pullN(); + PC.d = V.d; + PC.w++; +E S.h = 0x01; + idleJump(); +} diff --git a/processor/wdc65816/instructions-read.cpp b/processor/wdc65816/instructions-read.cpp new file mode 100755 index 0000000..e364725 --- /dev/null +++ b/processor/wdc65816/instructions-read.cpp @@ -0,0 +1,209 @@ +auto WDC65816::instructionImmediateRead8(alu8 op) -> void { +L W.l = fetch(); + alu(W.l); +} + +auto WDC65816::instructionImmediateRead16(alu16 op) -> void { + W.l = fetch(); +L W.h = fetch(); + alu(W.w); +} + +auto WDC65816::instructionBankRead8(alu8 op) -> void { + V.l = fetch(); + V.h = fetch(); +L W.l = readBank(V.w + 0); + alu(W.l); +} + +auto WDC65816::instructionBankRead16(alu16 op) -> void { + V.l = fetch(); + V.h = fetch(); + W.l = readBank(V.w + 0); +L W.h = readBank(V.w + 1); + alu(W.w); +} + +auto WDC65816::instructionBankRead8(alu8 op, r16 I) -> void { + V.l = fetch(); + V.h = fetch(); + idle4(V.w, V.w + I.w); +L W.l = readBank(V.w + I.w + 0); + alu(W.l); +} + +auto WDC65816::instructionBankRead16(alu16 op, r16 I) -> void { + V.l = fetch(); + V.h = fetch(); + idle4(V.w, V.w + I.w); + W.l = readBank(V.w + I.w + 0); +L W.h = readBank(V.w + I.w + 1); + alu(W.w); +} + +auto WDC65816::instructionLongRead8(alu8 op, r16 I) -> void { + V.l = fetch(); + V.h = fetch(); + V.b = fetch(); +L W.l = readLong(V.d + I.w + 0); + alu(W.l); +} + +auto WDC65816::instructionLongRead16(alu16 op, r16 I) -> void { + V.l = fetch(); + V.h = fetch(); + V.b = fetch(); + W.l = readLong(V.d + I.w + 0); +L W.h = readLong(V.d + I.w + 1); + alu(W.w); +} + +auto WDC65816::instructionDirectRead8(alu8 op) -> void { + U.l = fetch(); + idle2(); +L W.l = readDirect(U.l + 0); + alu(W.l); +} + +auto WDC65816::instructionDirectRead16(alu16 op) -> void { + U.l = fetch(); + idle2(); + W.l = readDirect(U.l + 0); +L W.h = readDirect(U.l + 1); + alu(W.w); +} + +auto WDC65816::instructionDirectRead8(alu8 op, r16 I) -> void { + U.l = fetch(); + idle2(); + idle(); +L W.l = readDirect(U.l + I.w + 0); + alu(W.l); +} + +auto WDC65816::instructionDirectRead16(alu16 op, r16 I) -> void { + U.l = fetch(); + idle2(); + idle(); + W.l = readDirect(U.l + I.w + 0); +L W.h = readDirect(U.l + I.w + 1); + alu(W.w); +} + +auto WDC65816::instructionIndirectRead8(alu8 op) -> void { + U.l = fetch(); + idle2(); + V.l = readDirect(U.l + 0); + V.h = readDirect(U.l + 1); +L W.l = readBank(V.w + 0); + alu(W.l); +} + +auto WDC65816::instructionIndirectRead16(alu16 op) -> void { + U.l = fetch(); + idle2(); + V.l = readDirect(U.l + 0); + V.h = readDirect(U.l + 1); + W.l = readBank(V.w + 0); +L W.h = readBank(V.w + 1); + alu(W.w); +} + +auto WDC65816::instructionIndexedIndirectRead8(alu8 op) -> void { + U.l = fetch(); + idle2(); + idle(); + V.l = readDirect(U.l + X.w + 0); + V.h = readDirect(U.l + X.w + 1); +L W.l = readBank(V.w + 0); + alu(W.l); +} + +auto WDC65816::instructionIndexedIndirectRead16(alu16 op) -> void { + U.l = fetch(); + idle2(); + idle(); + V.l = readDirect(U.l + X.w + 0); + V.h = readDirect(U.l + X.w + 1); + W.l = readBank(V.w + 0); +L W.h = readBank(V.w + 1); + alu(W.w); +} + +auto WDC65816::instructionIndirectIndexedRead8(alu8 op) -> void { + U.l = fetch(); + idle2(); + V.l = readDirect(U.l + 0); + V.h = readDirect(U.l + 1); + idle4(V.w, V.w + Y.w); +L W.l = readBank(V.w + Y.w + 0); + alu(W.l); +} + +auto WDC65816::instructionIndirectIndexedRead16(alu16 op) -> void { + U.l = fetch(); + idle2(); + V.l = readDirect(U.l + 0); + V.h = readDirect(U.l + 1); + idle4(V.w, V.w + Y.w); + W.l = readBank(V.w + Y.w + 0); +L W.h = readBank(V.w + Y.w + 1); + alu(W.w); +} + +auto WDC65816::instructionIndirectLongRead8(alu8 op, r16 I) -> void { + U.l = fetch(); + idle2(); + V.l = readDirectN(U.l + 0); + V.h = readDirectN(U.l + 1); + V.b = readDirectN(U.l + 2); +L W.l = readLong(V.d + I.w + 0); + alu(W.l); +} + +auto WDC65816::instructionIndirectLongRead16(alu16 op, r16 I) -> void { + U.l = fetch(); + idle2(); + V.l = readDirectN(U.l + 0); + V.h = readDirectN(U.l + 1); + V.b = readDirectN(U.l + 2); + W.l = readLong(V.d + I.w + 0); +L W.h = readLong(V.d + I.w + 1); + alu(W.w); +} + +auto WDC65816::instructionStackRead8(alu8 op) -> void { + U.l = fetch(); + idle(); +L W.l = readStack(U.l + 0); + alu(W.l); +} + +auto WDC65816::instructionStackRead16(alu16 op) -> void { + U.l = fetch(); + idle(); + W.l = readStack(U.l + 0); +L W.h = readStack(U.l + 1); + alu(W.w); +} + +auto WDC65816::instructionIndirectStackRead8(alu8 op) -> void { + U.l = fetch(); + idle(); + V.l = readStack(U.l + 0); + V.h = readStack(U.l + 1); + idle(); +L W.l = readBank(V.w + Y.w + 0); + alu(W.l); +} + +auto WDC65816::instructionIndirectStackRead16(alu16 op) -> void { + U.l = fetch(); + idle(); + V.l = readStack(U.l + 0); + V.h = readStack(U.l + 1); + idle(); + W.l = readBank(V.w + Y.w + 0); +L W.h = readBank(V.w + Y.w + 1); + alu(W.w); +} diff --git a/processor/wdc65816/instructions-write.cpp b/processor/wdc65816/instructions-write.cpp new file mode 100755 index 0000000..f2851ed --- /dev/null +++ b/processor/wdc65816/instructions-write.cpp @@ -0,0 +1,176 @@ +auto WDC65816::instructionBankWrite8(r16 F) -> void { + V.l = fetch(); + V.h = fetch(); +L writeBank(V.w + 0, F.l); +} + +auto WDC65816::instructionBankWrite16(r16 F) -> void { + V.l = fetch(); + V.h = fetch(); + writeBank(V.w + 0, F.l); +L writeBank(V.w + 1, F.h); +} + +auto WDC65816::instructionBankWrite8(r16 F, r16 I) -> void { + V.l = fetch(); + V.h = fetch(); + idle(); +L writeBank(V.w + I.w + 0, F.l); +} + +auto WDC65816::instructionBankWrite16(r16 F, r16 I) -> void { + V.l = fetch(); + V.h = fetch(); + idle(); + writeBank(V.w + I.w + 0, F.l); +L writeBank(V.w + I.w + 1, F.h); +} + +auto WDC65816::instructionLongWrite8(r16 I) -> void { + V.l = fetch(); + V.h = fetch(); + V.b = fetch(); +L writeLong(V.d + I.w + 0, A.l); +} + +auto WDC65816::instructionLongWrite16(r16 I) -> void { + V.l = fetch(); + V.h = fetch(); + V.b = fetch(); + writeLong(V.d + I.w + 0, A.l); +L writeLong(V.d + I.w + 1, A.h); +} + +auto WDC65816::instructionDirectWrite8(r16 F) -> void { + U.l = fetch(); + idle2(); +L writeDirect(U.l + 0, F.l); +} + +auto WDC65816::instructionDirectWrite16(r16 F) -> void { + U.l = fetch(); + idle2(); + writeDirect(U.l + 0, F.l); +L writeDirect(U.l + 1, F.h); +} + +auto WDC65816::instructionDirectWrite8(r16 F, r16 I) -> void { + U.l = fetch(); + idle2(); + idle(); +L writeDirect(U.l + I.w + 0, F.l); +} + +auto WDC65816::instructionDirectWrite16(r16 F, r16 I) -> void { + U.l = fetch(); + idle2(); + idle(); + writeDirect(U.l + I.w + 0, F.l); +L writeDirect(U.l + I.w + 1, F.h); +} + +auto WDC65816::instructionIndirectWrite8() -> void { + U.l = fetch(); + idle2(); + V.l = readDirect(U.l + 0); + V.h = readDirect(U.l + 1); +L writeBank(V.w + 0, A.l); +} + +auto WDC65816::instructionIndirectWrite16() -> void { + U.l = fetch(); + idle2(); + V.l = readDirect(U.l + 0); + V.h = readDirect(U.l + 1); + writeBank(V.w + 0, A.l); +L writeBank(V.w + 1, A.h); +} + +auto WDC65816::instructionIndexedIndirectWrite8() -> void { + U.l = fetch(); + idle2(); + idle(); + V.l = readDirect(U.l + X.w + 0); + V.h = readDirect(U.l + X.w + 1); +L writeBank(V.w + 0, A.l); +} + +auto WDC65816::instructionIndexedIndirectWrite16() -> void { + U.l = fetch(); + idle2(); + idle(); + V.l = readDirect(U.l + X.w + 0); + V.h = readDirect(U.l + X.w + 1); + writeBank(V.w + 0, A.l); +L writeBank(V.w + 1, A.h); +} + +auto WDC65816::instructionIndirectIndexedWrite8() -> void { + U.l = fetch(); + idle2(); + V.l = readDirect(U.l + 0); + V.h = readDirect(U.l + 1); + idle(); +L writeBank(V.w + Y.w + 0, A.l); +} + +auto WDC65816::instructionIndirectIndexedWrite16() -> void { + U.l = fetch(); + idle2(); + V.l = readDirect(U.l + 0); + V.h = readDirect(U.l + 1); + idle(); + writeBank(V.w + Y.w + 0, A.l); +L writeBank(V.w + Y.w + 1, A.h); +} + +auto WDC65816::instructionIndirectLongWrite8(r16 I) -> void { + U.l = fetch(); + idle2(); + V.l = readDirectN(U.l + 0); + V.h = readDirectN(U.l + 1); + V.b = readDirectN(U.l + 2); +L writeLong(V.d + I.w + 0, A.l); +} + +auto WDC65816::instructionIndirectLongWrite16(r16 I) -> void { + U.l = fetch(); + idle2(); + V.l = readDirectN(U.l + 0); + V.h = readDirectN(U.l + 1); + V.b = readDirectN(U.l + 2); + writeLong(V.d + I.w + 0, A.l); +L writeLong(V.d + I.w + 1, A.h); +} + +auto WDC65816::instructionStackWrite8() -> void { + U.l = fetch(); + idle(); +L writeStack(U.l + 0, A.l); +} + +auto WDC65816::instructionStackWrite16() -> void { + U.l = fetch(); + idle(); + writeStack(U.l + 0, A.l); +L writeStack(U.l + 1, A.h); +} + +auto WDC65816::instructionIndirectStackWrite8() -> void { + U.l = fetch(); + idle(); + V.l = readStack(U.l + 0); + V.h = readStack(U.l + 1); + idle(); +L writeBank(V.w + Y.w + 0, A.l); +} + +auto WDC65816::instructionIndirectStackWrite16() -> void { + U.l = fetch(); + idle(); + V.l = readStack(U.l + 0); + V.h = readStack(U.l + 1); + idle(); + writeBank(V.w + Y.w + 0, A.l); +L writeBank(V.w + Y.w + 1, A.h); +} diff --git a/processor/wdc65816/memory.cpp b/processor/wdc65816/memory.cpp new file mode 100644 index 0000000..4f60374 --- /dev/null +++ b/processor/wdc65816/memory.cpp @@ -0,0 +1,88 @@ +//immediate, 2-cycle opcodes with idle 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. +auto WDC65816::idleIRQ() -> void { + if(interruptPending()) { + //modify I/O cycle to bus read cycle, do not increment PC + read(PC.d); + } else { + idle(); + } +} + +auto WDC65816::idle2() -> void { + if(D.l) idle(); +} + +auto WDC65816::idle4(uint16 x, uint16 y) -> void { + if(!XF || x >> 8 != y >> 8) idle(); +} + +auto WDC65816::idle6(uint16 address) -> void { + if(EF && PC.h != address >> 8) idle(); +} + +auto WDC65816::fetch() -> uint8 { + return read(PC.b << 16 | PC.w++); +} + +auto WDC65816::pull() -> uint8 { + EF ? (void)S.l++ : (void)S.w++; + return read(S.w); +} + +auto WDC65816::push(uint8 data) -> void { + write(S.w, data); + EF ? (void)S.l-- : (void)S.w--; +} + +auto WDC65816::pullN() -> uint8 { + return read(++S.w); +} + +auto WDC65816::pushN(uint8 data) -> void { + write(S.w--, data); +} + +auto WDC65816::readDirect(uint address) -> uint8 { + if(EF && !D.l) return read(D.w | address & 0xff); + return read(D.w + address & 0xffff); +} + +auto WDC65816::writeDirect(uint address, uint8 data) -> void { + if(EF && !D.l) return write(D.w | address & 0xff, data); + write(D.w + address & 0xffff, data); +} + +auto WDC65816::readDirectN(uint address) -> uint8 { + return read(D.w + address & 0xffff); +} + +auto WDC65816::readBank(uint address) -> uint8 { + return read((B << 16) + address & 0xffffff); +} + +auto WDC65816::writeBank(uint address, uint8 data) -> void { + write((B << 16) + address & 0xffffff, data); +} + +auto WDC65816::readLong(uint address) -> uint8 { + return read(address & 0xffffff); +} + +auto WDC65816::writeLong(uint address, uint8 data) -> void { + write(address & 0xffffff, data); +} + +auto WDC65816::readStack(uint address) -> uint8 { + return read(S.w + address & 0xffff); +} + +auto WDC65816::writeStack(uint address, uint8 data) -> void { + write(S.w + address & 0xffff, data); +} diff --git a/processor/wdc65816/registers.hpp b/processor/wdc65816/registers.hpp new file mode 100644 index 0000000..4b07a53 --- /dev/null +++ b/processor/wdc65816/registers.hpp @@ -0,0 +1,65 @@ +#if !defined(WDC65816_REGISTERS_HPP) + #define WDC65816_REGISTERS_HPP + + #define PC r.pc + #define A r.a + #define X r.x + #define Y r.y + #define Z r.z + #define S r.s + #define D r.d + #define B r.b + #define P r.p + + #define CF r.p.c + #define ZF r.p.z + #define IF r.p.i + #define DF r.p.d + #define XF r.p.x + #define MF r.p.m + #define VF r.p.v + #define NF r.p.n + #define EF r.e + + #define U r.u + #define V r.v + #define W r.w + + #define E if(r.e) + #define N if(!r.e) + #define L lastCycle(); + + #define alu(...) (this->*op)(__VA_ARGS__) +#else + #undef WDC65816_REGISTERS_HPP + + #undef PC + #undef A + #undef X + #undef Y + #undef Z + #undef S + #undef D + #undef B + #undef P + + #undef CF + #undef ZF + #undef IF + #undef DF + #undef XF + #undef MF + #undef VF + #undef NF + #undef EF + + #undef U + #undef V + #undef W + + #undef E + #undef N + #undef L + + #undef alu +#endif diff --git a/processor/wdc65816/serialization.cpp b/processor/wdc65816/serialization.cpp new file mode 100755 index 0000000..2b9ae93 --- /dev/null +++ b/processor/wdc65816/serialization.cpp @@ -0,0 +1,33 @@ +auto WDC65816::serialize(serializer& s) -> void { + s.integer(r.pc.d); + + s.integer(r.a.w); + s.integer(r.x.w); + s.integer(r.y.w); + s.integer(r.z.w); + s.integer(r.s.w); + s.integer(r.d.w); + s.integer(r.b); + + s.integer(r.p.c); + s.integer(r.p.z); + s.integer(r.p.i); + s.integer(r.p.d); + s.integer(r.p.x); + s.integer(r.p.m); + s.integer(r.p.v); + s.integer(r.p.n); + + s.integer(r.e); + s.integer(r.irq); + s.integer(r.wai); + s.integer(r.stp); + + s.integer(r.vector); + s.integer(r.mar); + s.integer(r.mdr); + + s.integer(r.u.d); + s.integer(r.v.d); + s.integer(r.w.d); +} diff --git a/processor/wdc65816/wdc65816.cpp b/processor/wdc65816/wdc65816.cpp new file mode 100755 index 0000000..5481693 --- /dev/null +++ b/processor/wdc65816/wdc65816.cpp @@ -0,0 +1,41 @@ +#include +#include "wdc65816.hpp" + +namespace Processor { + +#include "registers.hpp" +#include "memory.cpp" +#include "algorithms.cpp" + +#include "instructions-read.cpp" +#include "instructions-write.cpp" +#include "instructions-modify.cpp" +#include "instructions-pc.cpp" +#include "instructions-other.cpp" +#include "instruction.cpp" + +auto WDC65816::power() -> void { + r.pc.d = 0x000000; + r.a = 0x0000; + r.x = 0x0000; + r.y = 0x0000; + r.s = 0x01ff; + r.d = 0x0000; + r.b = 0x00; + r.p = 0x34; + r.e = 1; + + r.irq = 0; + r.wai = 0; + r.stp = 0; + r.mar = 0x000000; + r.mdr = 0x00; + + r.vector = 0xfffc; //reset vector address +} + +#include "registers.hpp" +#include "serialization.cpp" +#include "disassembler.cpp" + +} diff --git a/processor/wdc65816/wdc65816.hpp b/processor/wdc65816/wdc65816.hpp new file mode 100755 index 0000000..3821794 --- /dev/null +++ b/processor/wdc65816/wdc65816.hpp @@ -0,0 +1,288 @@ +//WDC 65C816 CPU core +//* Ricoh 5A22 +//* Nintendo SA-1 + +#pragma once + +namespace Processor { + +struct WDC65816 { + virtual auto idle() -> void = 0; + virtual auto idleBranch() -> void {} + virtual auto idleJump() -> void {} + virtual auto read(uint addr) -> uint8 = 0; + virtual auto write(uint addr, uint8 data) -> void = 0; + virtual auto lastCycle() -> void = 0; + virtual auto interruptPending() const -> bool = 0; + virtual auto interrupt() -> void; + virtual auto synchronizing() const -> bool = 0; + + virtual auto readDisassembler(uint addr) -> uint8 { return 0; } + + inline auto irq() const -> bool { return r.irq; } + inline auto irq(bool line) -> void { r.irq = line; } + + using r8 = uint8; + + union r16 { + inline r16() : w(0) {} + inline r16(uint data) : w(data) {} + inline auto& operator=(uint data) { w = data; return *this; } + + uint16 w; + struct { uint8 order_lsb2(l, h); }; + }; + + union r24 { + inline r24() : d(0) {} + inline r24(uint data) : d(data) {} + inline auto& operator=(uint data) { d = data; return *this; } + + uint24 d; + struct { uint16 order_lsb2(w, x); }; + struct { uint8 order_lsb4(l, h, b, y); }; + }; + + //wdc65816.cpp + auto power() -> void; + + //memory.cpp + alwaysinline auto idleIRQ() -> void; + alwaysinline auto idle2() -> void; + alwaysinline auto idle4(uint16 x, uint16 y) -> void; + alwaysinline auto idle6(uint16 address) -> void; + alwaysinline auto fetch() -> uint8; + alwaysinline auto pull() -> uint8; + auto push(uint8 data) -> void; + alwaysinline auto pullN() -> uint8; + alwaysinline auto pushN(uint8 data) -> void; + alwaysinline auto readDirect(uint address) -> uint8; + alwaysinline auto writeDirect(uint address, uint8 data) -> void; + alwaysinline auto readDirectN(uint address) -> uint8; + alwaysinline auto readBank(uint address) -> uint8; + alwaysinline auto writeBank(uint address, uint8 data) -> void; + alwaysinline auto readLong(uint address) -> uint8; + alwaysinline auto writeLong(uint address, uint8 data) -> void; + alwaysinline auto readStack(uint address) -> uint8; + alwaysinline auto writeStack(uint address, uint8 data) -> void; + + //algorithms.cpp + using alu8 = auto (WDC65816::*)( uint8) -> uint8; + using alu16 = auto (WDC65816::*)(uint16) -> uint16; + + auto algorithmADC8(uint8) -> uint8; + auto algorithmADC16(uint16) -> uint16; + auto algorithmAND8(uint8) -> uint8; + auto algorithmAND16(uint16) -> uint16; + auto algorithmASL8(uint8) -> uint8; + auto algorithmASL16(uint16) -> uint16; + auto algorithmBIT8(uint8) -> uint8; + auto algorithmBIT16(uint16) -> uint16; + auto algorithmCMP8(uint8) -> uint8; + auto algorithmCMP16(uint16) -> uint16; + auto algorithmCPX8(uint8) -> uint8; + auto algorithmCPX16(uint16) -> uint16; + auto algorithmCPY8(uint8) -> uint8; + auto algorithmCPY16(uint16) -> uint16; + auto algorithmDEC8(uint8) -> uint8; + auto algorithmDEC16(uint16) -> uint16; + auto algorithmEOR8(uint8) -> uint8; + auto algorithmEOR16(uint16) -> uint16; + auto algorithmINC8(uint8) -> uint8; + auto algorithmINC16(uint16) -> uint16; + auto algorithmLDA8(uint8) -> uint8; + auto algorithmLDA16(uint16) -> uint16; + auto algorithmLDX8(uint8) -> uint8; + auto algorithmLDX16(uint16) -> uint16; + auto algorithmLDY8(uint8) -> uint8; + auto algorithmLDY16(uint16) -> uint16; + auto algorithmLSR8(uint8) -> uint8; + auto algorithmLSR16(uint16) -> uint16; + auto algorithmORA8(uint8) -> uint8; + auto algorithmORA16(uint16) -> uint16; + auto algorithmROL8(uint8) -> uint8; + auto algorithmROL16(uint16) -> uint16; + auto algorithmROR8(uint8) -> uint8; + auto algorithmROR16(uint16) -> uint16; + auto algorithmSBC8(uint8) -> uint8; + auto algorithmSBC16(uint16) -> uint16; + auto algorithmTRB8(uint8) -> uint8; + auto algorithmTRB16(uint16) -> uint16; + auto algorithmTSB8(uint8) -> uint8; + auto algorithmTSB16(uint16) -> uint16; + + //instructions-read.cpp + auto instructionImmediateRead8(alu8) -> void; + auto instructionImmediateRead16(alu16) -> void; + auto instructionBankRead8(alu8) -> void; + auto instructionBankRead16(alu16) -> void; + auto instructionBankRead8(alu8, r16) -> void; + auto instructionBankRead16(alu16, r16) -> void; + auto instructionLongRead8(alu8, r16 = {}) -> void; + auto instructionLongRead16(alu16, r16 = {}) -> void; + auto instructionDirectRead8(alu8) -> void; + auto instructionDirectRead16(alu16) -> void; + auto instructionDirectRead8(alu8, r16) -> void; + auto instructionDirectRead16(alu16, r16) -> void; + auto instructionIndirectRead8(alu8) -> void; + auto instructionIndirectRead16(alu16) -> void; + auto instructionIndexedIndirectRead8(alu8) -> void; + auto instructionIndexedIndirectRead16(alu16) -> void; + auto instructionIndirectIndexedRead8(alu8) -> void; + auto instructionIndirectIndexedRead16(alu16) -> void; + auto instructionIndirectLongRead8(alu8, r16 = {}) -> void; + auto instructionIndirectLongRead16(alu16, r16 = {}) -> void; + auto instructionStackRead8(alu8) -> void; + auto instructionStackRead16(alu16) -> void; + auto instructionIndirectStackRead8(alu8) -> void; + auto instructionIndirectStackRead16(alu16) -> void; + + //instructions-write.cpp + auto instructionBankWrite8(r16) -> void; + auto instructionBankWrite16(r16) -> void; + auto instructionBankWrite8(r16, r16) -> void; + auto instructionBankWrite16(r16, r16) -> void; + auto instructionLongWrite8(r16 = {}) -> void; + auto instructionLongWrite16(r16 = {}) -> void; + auto instructionDirectWrite8(r16) -> void; + auto instructionDirectWrite16(r16) -> void; + auto instructionDirectWrite8(r16, r16) -> void; + auto instructionDirectWrite16(r16, r16) -> void; + auto instructionIndirectWrite8() -> void; + auto instructionIndirectWrite16() -> void; + auto instructionIndexedIndirectWrite8() -> void; + auto instructionIndexedIndirectWrite16() -> void; + auto instructionIndirectIndexedWrite8() -> void; + auto instructionIndirectIndexedWrite16() -> void; + auto instructionIndirectLongWrite8(r16 = {}) -> void; + auto instructionIndirectLongWrite16(r16 = {}) -> void; + auto instructionStackWrite8() -> void; + auto instructionStackWrite16() -> void; + auto instructionIndirectStackWrite8() -> void; + auto instructionIndirectStackWrite16() -> void; + + //instructions-modify.cpp + auto instructionImpliedModify8(alu8, r16&) -> void; + auto instructionImpliedModify16(alu16, r16&) -> void; + auto instructionBankModify8(alu8) -> void; + auto instructionBankModify16(alu16) -> void; + auto instructionBankIndexedModify8(alu8) -> void; + auto instructionBankIndexedModify16(alu16) -> void; + auto instructionDirectModify8(alu8) -> void; + auto instructionDirectModify16(alu16) -> void; + auto instructionDirectIndexedModify8(alu8) -> void; + auto instructionDirectIndexedModify16(alu16) -> void; + + //instructions-pc.cpp + auto instructionBranch(bool = 1) -> void; + auto instructionBranchLong() -> void; + auto instructionJumpShort() -> void; + auto instructionJumpLong() -> void; + auto instructionJumpIndirect() -> void; + auto instructionJumpIndexedIndirect() -> void; + auto instructionJumpIndirectLong() -> void; + auto instructionCallShort() -> void; + auto instructionCallLong() -> void; + auto instructionCallIndexedIndirect() -> void; + auto instructionReturnInterrupt() -> void; + auto instructionReturnShort() -> void; + auto instructionReturnLong() -> void; + + //instructions-misc.cpp + auto instructionBitImmediate8() -> void; + auto instructionBitImmediate16() -> void; + auto instructionNoOperation() -> void; + auto instructionPrefix() -> void; + auto instructionExchangeBA() -> void; + auto instructionBlockMove8(int) -> void; + auto instructionBlockMove16(int) -> void; + auto instructionInterrupt(r16) -> void; + auto instructionStop() -> void; + auto instructionWait() -> void; + auto instructionExchangeCE() -> void; + auto instructionSetFlag(bool&) -> void; + auto instructionClearFlag(bool&) -> void; + auto instructionResetP() -> void; + auto instructionSetP() -> void; + auto instructionTransfer8(r16, r16&) -> void; + auto instructionTransfer16(r16, r16&) -> void; + auto instructionTransferCS() -> void; + auto instructionTransferSX8() -> void; + auto instructionTransferSX16() -> void; + auto instructionTransferXS() -> void; + auto instructionPush8(r16) -> void; + auto instructionPush16(r16) -> void; + auto instructionPushD() -> void; + auto instructionPull8(r16&) -> void; + auto instructionPull16(r16&) -> void; + auto instructionPullD() -> void; + auto instructionPullB() -> void; + auto instructionPullP() -> void; + auto instructionPushEffectiveAddress() -> void; + auto instructionPushEffectiveIndirectAddress() -> void; + auto instructionPushEffectiveRelativeAddress() -> void; + + //instruction.cpp + auto instruction() -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + //disassembler.cpp + auto disassemble() -> string; + auto disassemble(uint24 addr, bool e, bool m, bool x) -> string; + + struct f8 { + bool c = 0; //carry + bool z = 0; //zero + bool i = 0; //interrupt disable + bool d = 0; //decimal mode + bool x = 0; //index register mode + bool m = 0; //accumulator mode + bool v = 0; //overflow + bool n = 0; //negative + + inline operator uint() const { + return c << 0 | z << 1 | i << 2 | d << 3 | x << 4 | m << 5 | v << 6 | n << 7; + } + + inline auto& operator=(uint data) { + c = data & 0x01; + z = data & 0x02; + i = data & 0x04; + d = data & 0x08; + x = data & 0x10; + m = data & 0x20; + v = data & 0x40; + n = data & 0x80; + return *this; + } + }; + + struct Registers { + r24 pc; + r16 a; + r16 x; + r16 y; + r16 z; + r16 s; + r16 d; + r8 b; + f8 p; + + bool e = 0; //emulation mode + bool irq = 0; //IRQ pin (0 = low, 1 = trigger) + bool wai = 0; //raised during wai, cleared after interrupt triggered + bool stp = 0; //raised during stp, never cleared + + uint16 vector; //interrupt vector address + uint24 mar; //memory address register + r8 mdr; //memory data register + + r24 u; //temporary register + r24 v; //temporary register + r24 w; //temporary register + } r; +}; + +} diff --git a/sfc/cartridge/cartridge.cpp b/sfc/cartridge/cartridge.cpp new file mode 100644 index 0000000..b39ceb6 --- /dev/null +++ b/sfc/cartridge/cartridge.cpp @@ -0,0 +1,161 @@ +#include + +namespace SuperFamicom { + +#include "load.cpp" +#include "save.cpp" +#include "serialization.cpp" +Cartridge cartridge; + +auto Cartridge::hashes() const -> vector { + vector hashes; + hashes.append(game.sha256); + if(slotGameBoy.sha256) hashes.append(slotGameBoy.sha256); + if(slotBSMemory.sha256) hashes.append(slotBSMemory.sha256); + if(slotSufamiTurboA.sha256) hashes.append(slotSufamiTurboA.sha256); + if(slotSufamiTurboB.sha256) hashes.append(slotSufamiTurboB.sha256); + return hashes; +} + +auto Cartridge::manifests() const -> vector { + vector manifests; + manifests.append(string{BML::serialize(game.document), "\n", BML::serialize(board)}); + if(slotGameBoy.document) manifests.append(BML::serialize(slotGameBoy.document)); + if(slotBSMemory.document) manifests.append(BML::serialize(slotBSMemory.document)); + if(slotSufamiTurboA.document) manifests.append(BML::serialize(slotSufamiTurboA.document)); + if(slotSufamiTurboB.document) manifests.append(BML::serialize(slotSufamiTurboB.document)); + return manifests; +} + +auto Cartridge::titles() const -> vector { + vector titles; + titles.append(game.label); + if(slotGameBoy.label) titles.append(slotGameBoy.label); + if(slotBSMemory.label) titles.append(slotBSMemory.label); + if(slotSufamiTurboA.label) titles.append(slotSufamiTurboA.label); + if(slotSufamiTurboB.label) titles.append(slotSufamiTurboB.label); + return titles; +} + +auto Cartridge::title() const -> string { + if(slotGameBoy.label) return slotGameBoy.label; + if(has.MCC && slotBSMemory.label) return slotBSMemory.label; + if(slotBSMemory.label) return {game.label, " + ", slotBSMemory.label}; + if(slotSufamiTurboA.label && slotSufamiTurboB.label) return {slotSufamiTurboA.label, " + ", slotSufamiTurboB.label}; + if(slotSufamiTurboA.label) return slotSufamiTurboA.label; + if(slotSufamiTurboB.label) return slotSufamiTurboB.label; + if(has.Cx4 || has.DSP1 || has.DSP2 || has.DSP4 || has.ST0010) return {"[HLE] ", game.label}; + return game.label; +} + +auto Cartridge::load() -> bool { + information = {}; + has = {}; + game = {}; + slotGameBoy = {}; + slotBSMemory = {}; + slotSufamiTurboA = {}; + slotSufamiTurboB = {}; + + if(auto loaded = platform->load(ID::SuperFamicom, "Super Famicom", "sfc", {"Auto", "NTSC", "PAL"})) { + information.pathID = loaded.pathID; + information.region = loaded.option; + } else return false; + + if(auto fp = platform->open(ID::SuperFamicom, "manifest.bml", File::Read, File::Required)) { + game.load(fp->reads()); + } else return false; + + loadCartridge(game.document); + + //Game Boy + if(cartridge.has.ICD) { + information.sha256 = ""; //Game Boy cartridge not loaded yet: set later via loadGameBoy() + } + + //BS Memory + else if(cartridge.has.MCC && cartridge.has.BSMemorySlot) { + information.sha256 = Hash::SHA256({bsmemory.memory.data(), bsmemory.memory.size()}).digest(); + } + + //Sufami Turbo + else if(cartridge.has.SufamiTurboSlotA || cartridge.has.SufamiTurboSlotB) { + Hash::SHA256 sha; + if(cartridge.has.SufamiTurboSlotA) sha.input(sufamiturboA.rom.data(), sufamiturboA.rom.size()); + if(cartridge.has.SufamiTurboSlotB) sha.input(sufamiturboB.rom.data(), sufamiturboB.rom.size()); + information.sha256 = sha.digest(); + } + + //Super Famicom + else { + Hash::SHA256 sha; + //hash each ROM image that exists; any with size() == 0 is ignored by sha256_chunk() + sha.input(rom.data(), rom.size()); + sha.input(mcc.rom.data(), mcc.rom.size()); + sha.input(sa1.rom.data(), sa1.rom.size()); + sha.input(superfx.rom.data(), superfx.rom.size()); + sha.input(hitachidsp.rom.data(), hitachidsp.rom.size()); + sha.input(spc7110.prom.data(), spc7110.prom.size()); + sha.input(spc7110.drom.data(), spc7110.drom.size()); + sha.input(sdd1.rom.data(), sdd1.rom.size()); + //hash all firmware that exists + vector buffer; + buffer = armdsp.firmware(); + sha.input(buffer.data(), buffer.size()); + buffer = hitachidsp.firmware(); + sha.input(buffer.data(), buffer.size()); + buffer = necdsp.firmware(); + sha.input(buffer.data(), buffer.size()); + //finalize hash + information.sha256 = sha.digest(); + } + + return true; +} + +auto Cartridge::loadBSMemory() -> bool { + if(auto fp = platform->open(bsmemory.pathID, "manifest.bml", File::Read, File::Required)) { + slotBSMemory.load(fp->reads()); + } else return false; + loadCartridgeBSMemory(slotBSMemory.document); + return true; +} + +auto Cartridge::loadSufamiTurboA() -> bool { + if(auto fp = platform->open(sufamiturboA.pathID, "manifest.bml", File::Read, File::Required)) { + slotSufamiTurboA.load(fp->reads()); + } else return false; + loadCartridgeSufamiTurboA(slotSufamiTurboA.document); + return true; +} + +auto Cartridge::loadSufamiTurboB() -> bool { + if(auto fp = platform->open(sufamiturboB.pathID, "manifest.bml", File::Read, File::Required)) { + slotSufamiTurboB.load(fp->reads()); + } else return false; + loadCartridgeSufamiTurboB(slotSufamiTurboB.document); + return true; +} + +auto Cartridge::save() -> void { + saveCartridge(game.document); + if(has.GameBoySlot) { + icd.save(); + } + if(has.BSMemorySlot) { + saveCartridgeBSMemory(slotBSMemory.document); + } + if(has.SufamiTurboSlotA) { + saveCartridgeSufamiTurboA(slotSufamiTurboA.document); + } + if(has.SufamiTurboSlotB) { + saveCartridgeSufamiTurboB(slotSufamiTurboB.document); + } +} + +auto Cartridge::unload() -> void { + rom.reset(); + ram.reset(); +} + +} diff --git a/sfc/cartridge/cartridge.hpp b/sfc/cartridge/cartridge.hpp new file mode 100644 index 0000000..b975c19 --- /dev/null +++ b/sfc/cartridge/cartridge.hpp @@ -0,0 +1,126 @@ +struct Cartridge { + auto pathID() const -> uint { return information.pathID; } + auto region() const -> string { return information.region; } + auto headerTitle() const -> string { return game.title; } + + auto hashes() const -> vector; + auto manifests() const -> vector; + auto titles() const -> vector; + auto title() const -> string; + + auto load() -> bool; + auto save() -> void; + auto unload() -> void; + + auto serialize(serializer&) -> void; + + ReadableMemory rom; + WritableMemory ram; + + struct Information { + uint pathID = 0; + string region; + string sha256; + } information; + + struct Has { + boolean ICD; + boolean MCC; + boolean DIP; + boolean Event; + boolean SA1; + boolean SuperFX; + boolean ARMDSP; + boolean HitachiDSP; + boolean NECDSP; + boolean EpsonRTC; + boolean SharpRTC; + boolean SPC7110; + boolean SDD1; + boolean OBC1; + boolean MSU1; + + boolean Cx4; + boolean DSP1; + boolean DSP2; + boolean DSP4; + boolean ST0010; + + boolean GameBoySlot; + boolean BSMemorySlot; + boolean SufamiTurboSlotA; + boolean SufamiTurboSlotB; + } has; + +private: + Emulator::Game game; + Emulator::Game slotGameBoy; + Emulator::Game slotBSMemory; + Emulator::Game slotSufamiTurboA; + Emulator::Game slotSufamiTurboB; + Markup::Node board; + + //cartridge.cpp + auto loadBSMemory() -> bool; + auto loadSufamiTurboA() -> bool; + auto loadSufamiTurboB() -> bool; + + //load.cpp + auto loadBoard(string) -> Markup::Node; + auto loadCartridge(Markup::Node) -> void; + auto loadCartridgeBSMemory(Markup::Node) -> void; + auto loadCartridgeSufamiTurboA(Markup::Node) -> void; + auto loadCartridgeSufamiTurboB(Markup::Node) -> void; + + auto loadMemory(Memory&, Markup::Node, bool required) -> void; + template auto loadMap(Markup::Node, T&) -> uint; + auto loadMap(Markup::Node, const function&, const function&) -> uint; + + auto loadROM(Markup::Node) -> void; + auto loadRAM(Markup::Node) -> void; + auto loadICD(Markup::Node) -> void; + auto loadMCC(Markup::Node) -> void; + auto loadBSMemory(Markup::Node) -> void; + auto loadSufamiTurboA(Markup::Node) -> void; + auto loadSufamiTurboB(Markup::Node) -> void; + auto loadDIP(Markup::Node) -> void; + auto loadEvent(Markup::Node) -> void; + auto loadSA1(Markup::Node) -> void; + auto loadSuperFX(Markup::Node) -> void; + auto loadARMDSP(Markup::Node) -> void; + auto loadHitachiDSP(Markup::Node, uint roms) -> void; + auto loaduPD7725(Markup::Node) -> void; + auto loaduPD96050(Markup::Node) -> void; + auto loadEpsonRTC(Markup::Node) -> void; + auto loadSharpRTC(Markup::Node) -> void; + auto loadSPC7110(Markup::Node) -> void; + auto loadSDD1(Markup::Node) -> void; + auto loadOBC1(Markup::Node) -> void; + auto loadMSU1() -> void; + + //save.cpp + auto saveCartridge(Markup::Node) -> void; + auto saveCartridgeBSMemory(Markup::Node) -> void; + auto saveCartridgeSufamiTurboA(Markup::Node) -> void; + auto saveCartridgeSufamiTurboB(Markup::Node) -> void; + + auto saveMemory(Memory&, Markup::Node) -> void; + + auto saveRAM(Markup::Node) -> void; + auto saveMCC(Markup::Node) -> void; + auto saveSA1(Markup::Node) -> void; + auto saveSuperFX(Markup::Node) -> void; + auto saveARMDSP(Markup::Node) -> void; + auto saveHitachiDSP(Markup::Node) -> void; + auto saveuPD7725(Markup::Node) -> void; + auto saveuPD96050(Markup::Node) -> void; + auto saveEpsonRTC(Markup::Node) -> void; + auto saveSharpRTC(Markup::Node) -> void; + auto saveSPC7110(Markup::Node) -> void; + auto saveOBC1(Markup::Node) -> void; + + friend class Interface; + friend class ICD; +}; + +extern Cartridge cartridge; diff --git a/sfc/cartridge/load.cpp b/sfc/cartridge/load.cpp new file mode 100644 index 0000000..21b50de --- /dev/null +++ b/sfc/cartridge/load.cpp @@ -0,0 +1,730 @@ +auto Cartridge::loadBoard(string board) -> Markup::Node { + string output; + + if(board.beginsWith("SNSP-")) board.replace("SNSP-", "SHVC-", 1L); + if(board.beginsWith("MAXI-")) board.replace("MAXI-", "SHVC-", 1L); + if(board.beginsWith("MJSC-")) board.replace("MJSC-", "SHVC-", 1L); + if(board.beginsWith("EA-" )) board.replace("EA-", "SHVC-", 1L); + if(board.beginsWith("WEI-" )) board.replace("WEI-", "SHVC-", 1L); + + if(auto fp = platform->open(ID::System, "boards.bml", File::Read, File::Required)) { + auto document = BML::unserialize(fp->reads()); + for(auto leaf : document.find("board")) { + auto id = leaf.text(); + bool matched = id == board; + if(!matched && id.match("*(*)*")) { + auto part = id.transform("()", "||").split("|"); + for(auto& revision : part(1).split(",")) { + if(string{part(0), revision, part(2)} == board) matched = true; + } + } + if(matched) return leaf; + } + } + + return {}; +} + +auto Cartridge::loadCartridge(Markup::Node node) -> void { + board = node["board"]; + if(!board) board = loadBoard(game.board); + + if(region() == "Auto") { + auto region = game.region; + if(region.endsWith("BRA") + || region.endsWith("CAN") + || region.endsWith("HKG") + || region.endsWith("JPN") + || region.endsWith("KOR") + || region.endsWith("LTN") + || region.endsWith("ROC") + || region.endsWith("USA") + || region.beginsWith("SHVC-") + || region == "NTSC") { + information.region = "NTSC"; + } else { + information.region = "PAL"; + } + } + + if(auto node = board["memory(type=ROM,content=Program)"]) loadROM(node); + if(auto node = board["memory(type=ROM,content=Expansion)"]) loadROM(node); //todo: handle this better + if(auto node = board["memory(type=RAM,content=Save)"]) loadRAM(node); + if(auto node = board["processor(identifier=ICD)"]) loadICD(node); + if(auto node = board["processor(identifier=MCC)"]) loadMCC(node); + if(auto node = board["slot(type=BSMemory)"]) loadBSMemory(node); + if(auto node = board["slot(type=SufamiTurbo)[0]"]) loadSufamiTurboA(node); + if(auto node = board["slot(type=SufamiTurbo)[1]"]) loadSufamiTurboB(node); + if(auto node = board["dip"]) loadDIP(node); + if(auto node = board["processor(architecture=uPD78214)"]) loadEvent(node); + if(auto node = board["processor(architecture=W65C816S)"]) loadSA1(node); + if(auto node = board["processor(architecture=GSU)"]) loadSuperFX(node); + if(auto node = board["processor(architecture=ARM6)"]) loadARMDSP(node); + if(auto node = board["processor(architecture=HG51BS169)"]) loadHitachiDSP(node, game.board.match("2DC*") ? 2 : 1); + if(auto node = board["processor(architecture=uPD7725)"]) loaduPD7725(node); + if(auto node = board["processor(architecture=uPD96050)"]) loaduPD96050(node); + if(auto node = board["rtc(manufacturer=Epson)"]) loadEpsonRTC(node); + if(auto node = board["rtc(manufacturer=Sharp)"]) loadSharpRTC(node); + if(auto node = board["processor(identifier=SPC7110)"]) loadSPC7110(node); + if(auto node = board["processor(identifier=SDD1)"]) loadSDD1(node); + if(auto node = board["processor(identifier=OBC1)"]) loadOBC1(node); + + if(auto fp = platform->open(pathID(), "msu1/data.rom", File::Read)) loadMSU1(); +} + +auto Cartridge::loadCartridgeBSMemory(Markup::Node node) -> void { + if(auto memory = Emulator::Game::Memory{node["game/board/memory(content=Program)"]}) { + bsmemory.ROM = memory.type == "ROM"; + bsmemory.memory.allocate(memory.size); + if(auto fp = platform->open(bsmemory.pathID, memory.name(), File::Read, File::Required)) { + fp->read(bsmemory.memory.data(), memory.size); + } + } +} + +auto Cartridge::loadCartridgeSufamiTurboA(Markup::Node node) -> void { + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=ROM,content=Program)"]}) { + sufamiturboA.rom.allocate(memory.size); + if(auto fp = platform->open(sufamiturboA.pathID, memory.name(), File::Read, File::Required)) { + fp->read(sufamiturboA.rom.data(), memory.size); + } + } + + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=RAM,content=Save)"]}) { + sufamiturboA.ram.allocate(memory.size); + if(auto fp = platform->open(sufamiturboA.pathID, memory.name(), File::Read)) { + fp->read(sufamiturboA.ram.data(), memory.size); + } + } +} + +auto Cartridge::loadCartridgeSufamiTurboB(Markup::Node node) -> void { + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=ROM,content=Program)"]}) { + sufamiturboB.rom.allocate(memory.size); + if(auto fp = platform->open(sufamiturboB.pathID, memory.name(), File::Read, File::Required)) { + fp->read(sufamiturboB.rom.data(), memory.size); + } + } + + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=RAM,content=Save)"]}) { + sufamiturboB.ram.allocate(memory.size); + if(auto fp = platform->open(sufamiturboB.pathID, memory.name(), File::Read)) { + fp->read(sufamiturboB.ram.data(), memory.size); + } + } +} + +// + +auto Cartridge::loadMemory(Memory& ram, Markup::Node node, bool required) -> void { + if(auto memory = game.memory(node)) { + ram.allocate(memory->size); + if(memory->type == "RAM" && !memory->nonVolatile) return; + if(memory->type == "RTC" && !memory->nonVolatile) return; + if(auto fp = platform->open(pathID(), memory->name(), File::Read, required)) { + fp->read(ram.data(), min(fp->size(), ram.size())); + } + } +} + +template //T = ReadableMemory, WritableMemory, ProtectableMemory +auto Cartridge::loadMap(Markup::Node map, T& memory) -> uint { + auto addr = map["address"].text(); + auto size = map["size"].natural(); + auto base = map["base"].natural(); + auto mask = map["mask"].natural(); + if(size == 0) size = memory.size(); + if(size == 0) return print("loadMap(): size=0\n"), 0; //does this ever actually occur? + return bus.map({&T::read, &memory}, {&T::write, &memory}, addr, size, base, mask); +} + +auto Cartridge::loadMap( + Markup::Node map, + const function& reader, + const function& writer +) -> uint { + auto addr = map["address"].text(); + auto size = map["size"].natural(); + auto base = map["base"].natural(); + auto mask = map["mask"].natural(); + return bus.map(reader, writer, addr, size, base, mask); +} + +//memory(type=ROM,content=Program) +auto Cartridge::loadROM(Markup::Node node) -> void { + loadMemory(rom, node, File::Required); + for(auto leaf : node.find("map")) loadMap(leaf, rom); +} + +//memory(type=RAM,content=Save) +auto Cartridge::loadRAM(Markup::Node node) -> void { + loadMemory(ram, node, File::Optional); + for(auto leaf : node.find("map")) loadMap(leaf, ram); +} + +//processor(identifier=ICD) +auto Cartridge::loadICD(Markup::Node node) -> void { + has.GameBoySlot = true; + has.ICD = true; + + icd.Revision = node["revision"].natural(); + if(auto oscillator = game.oscillator()) { + icd.Frequency = oscillator->frequency; + } else { + icd.Frequency = 0; + } + + //Game Boy core loads data through ICD interface + for(auto map : node.find("map")) { + loadMap(map, {&ICD::readIO, &icd}, {&ICD::writeIO, &icd}); + } +} + +//processor(identifier=MCC) +auto Cartridge::loadMCC(Markup::Node node) -> void { + has.MCC = true; + + for(auto map : node.find("map")) { + loadMap(map, {&MCC::read, &mcc}, {&MCC::write, &mcc}); + } + + if(auto mcu = node["mcu"]) { + for(auto map : mcu.find("map")) { + loadMap(map, {&MCC::mcuRead, &mcc}, {&MCC::mcuWrite, &mcc}); + } + if(auto memory = mcu["memory(type=ROM,content=Program)"]) { + loadMemory(mcc.rom, memory, File::Required); + } + if(auto memory = mcu["memory(type=RAM,content=Download)"]) { + loadMemory(mcc.psram, memory, File::Optional); + } + if(auto slot = mcu["slot(type=BSMemory)"]) { + loadBSMemory(slot); + } + } +} + +//slot(type=BSMemory) +auto Cartridge::loadBSMemory(Markup::Node node) -> void { + has.BSMemorySlot = true; + + if(auto loaded = platform->load(ID::BSMemory, "BS Memory", "bs")) { + bsmemory.pathID = loaded.pathID; + loadBSMemory(); + + for(auto map : node.find("map")) { + loadMap(map, bsmemory); + } + } +} + +//slot(type=SufamiTurbo)[0] +auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void { + has.SufamiTurboSlotA = true; + + if(auto loaded = platform->load(ID::SufamiTurboA, "Sufami Turbo", "st")) { + sufamiturboA.pathID = loaded.pathID; + loadSufamiTurboA(); + + for(auto map : node.find("rom/map")) { + loadMap(map, sufamiturboA.rom); + } + + for(auto map : node.find("ram/map")) { + loadMap(map, sufamiturboA.ram); + } + } +} + +//slot(type=SufamiTurbo)[1] +auto Cartridge::loadSufamiTurboB(Markup::Node node) -> void { + has.SufamiTurboSlotB = true; + + if(auto loaded = platform->load(ID::SufamiTurboB, "Sufami Turbo", "st")) { + sufamiturboB.pathID = loaded.pathID; + loadSufamiTurboB(); + + for(auto map : node.find("rom/map")) { + loadMap(map, sufamiturboB.rom); + } + + for(auto map : node.find("ram/map")) { + loadMap(map, sufamiturboB.ram); + } + } +} + +//dip +auto Cartridge::loadDIP(Markup::Node node) -> void { + has.DIP = true; + dip.value = platform->dipSettings(node); + + for(auto map : node.find("map")) { + loadMap(map, {&DIP::read, &dip}, {&DIP::write, &dip}); + } +} + +//processor(architecture=uPD78214) +auto Cartridge::loadEvent(Markup::Node node) -> void { + has.Event = true; + event.board = Event::Board::Unknown; + if(node["identifier"].text() == "Campus Challenge '92") event.board = Event::Board::CampusChallenge92; + if(node["identifier"].text() == "PowerFest '94") event.board = Event::Board::PowerFest94; + + for(auto map : node.find("map")) { + loadMap(map, {&Event::read, &event}, {&Event::write, &event}); + } + + if(auto mcu = node["mcu"]) { + for(auto map : mcu.find("map")) { + loadMap(map, {&Event::mcuRead, &event}, {&Event::mcuWrite, &event}); + } + if(auto memory = mcu["memory(type=ROM,content=Program)"]) { + loadMemory(event.rom[0], memory, File::Required); + } + if(auto memory = mcu["memory(type=ROM,content=Level-1)"]) { + loadMemory(event.rom[1], memory, File::Required); + } + if(auto memory = mcu["memory(type=ROM,content=Level-2)"]) { + loadMemory(event.rom[2], memory, File::Required); + } + if(auto memory = mcu["memory(type=ROM,content=Level-3)"]) { + loadMemory(event.rom[3], memory, File::Required); + } + } +} + +//processor(architecture=W65C816S) +auto Cartridge::loadSA1(Markup::Node node) -> void { + has.SA1 = true; + + for(auto map : node.find("map")) { + loadMap(map, {&SA1::readIOCPU, &sa1}, {&SA1::writeIOCPU, &sa1}); + } + + if(auto mcu = node["mcu"]) { + for(auto map : mcu.find("map")) { + loadMap(map, {&SA1::ROM::readCPU, &sa1.rom}, {&SA1::ROM::writeCPU, &sa1.rom}); + } + if(auto memory = mcu["memory(type=ROM,content=Program)"]) { + loadMemory(sa1.rom, memory, File::Required); + } + if(auto slot = mcu["slot(type=BSMemory)"]) { + loadBSMemory(slot); + } + } + + if(auto memory = node["memory(type=RAM,content=Save)"]) { + loadMemory(sa1.bwram, memory, File::Optional); + for(auto map : memory.find("map")) { + loadMap(map, {&SA1::BWRAM::readCPU, &sa1.bwram}, {&SA1::BWRAM::writeCPU, &sa1.bwram}); + } + } + + if(auto memory = node["memory(type=RAM,content=Internal)"]) { + loadMemory(sa1.iram, memory, File::Optional); + for(auto map : memory.find("map")) { + loadMap(map, {&SA1::IRAM::readCPU, &sa1.iram}, {&SA1::IRAM::writeCPU, &sa1.iram}); + } + } +} + +//processor(architecture=GSU) +auto Cartridge::loadSuperFX(Markup::Node node) -> void { + has.SuperFX = true; + + if(auto oscillator = game.oscillator()) { + superfx.Frequency = oscillator->frequency; //GSU-1, GSU-2 + } else { + superfx.Frequency = system.cpuFrequency(); //MARIO CHIP 1 + } + + for(auto map : node.find("map")) { + loadMap(map, {&SuperFX::readIO, &superfx}, {&SuperFX::writeIO, &superfx}); + } + + if(auto memory = node["memory(type=ROM,content=Program)"]) { + loadMemory(superfx.rom, memory, File::Required); + for(auto map : memory.find("map")) { + loadMap(map, superfx.cpurom); + } + } + + if(auto memory = node["memory(type=RAM,content=Save)"]) { + loadMemory(superfx.ram, memory, File::Optional); + for(auto map : memory.find("map")) { + loadMap(map, superfx.cpuram); + } + } +} + +//processor(architecture=ARM6) +auto Cartridge::loadARMDSP(Markup::Node node) -> void { + has.ARMDSP = true; + + for(auto& word : armdsp.programROM) word = 0x00; + for(auto& word : armdsp.dataROM) word = 0x00; + for(auto& word : armdsp.programRAM) word = 0x00; + + if(auto oscillator = game.oscillator()) { + armdsp.Frequency = oscillator->frequency; + } else { + armdsp.Frequency = 21'440'000; + } + + for(auto map : node.find("map")) { + loadMap(map, {&ArmDSP::read, &armdsp}, {&ArmDSP::write, &armdsp}); + } + + if(auto memory = node["memory(type=ROM,content=Program,architecture=ARM6)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) { + for(auto n : range(128 * 1024)) armdsp.programROM[n] = fp->read(); + } + } + } + + if(auto memory = node["memory(type=ROM,content=Data,architecture=ARM6)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) { + for(auto n : range(32 * 1024)) armdsp.dataROM[n] = fp->read(); + } + } + } + + if(auto memory = node["memory(type=RAM,content=Data,architecture=ARM6)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + for(auto n : range(16 * 1024)) armdsp.programRAM[n] = fp->read(); + } + } + } +} + +//processor(architecture=HG51BS169) +auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void { + for(auto& word : hitachidsp.dataROM) word = 0x000000; + for(auto& word : hitachidsp.dataRAM) word = 0x00; + + if(auto oscillator = game.oscillator()) { + hitachidsp.Frequency = oscillator->frequency; + } else { + hitachidsp.Frequency = 20'000'000; + } + hitachidsp.Roms = roms; //1 or 2 + hitachidsp.Mapping = 0; //0 or 1 + + if(auto memory = node["memory(type=ROM,content=Program)"]) { + loadMemory(hitachidsp.rom, memory, File::Required); + for(auto map : memory.find("map")) { + loadMap(map, {&HitachiDSP::readROM, &hitachidsp}, {&HitachiDSP::writeROM, &hitachidsp}); + } + } + + if(auto memory = node["memory(type=RAM,content=Save)"]) { + loadMemory(hitachidsp.ram, memory, File::Optional); + for(auto map : memory.find("map")) { + loadMap(map, {&HitachiDSP::readRAM, &hitachidsp}, {&HitachiDSP::writeRAM, &hitachidsp}); + } + } + + if(configuration.hacks.coprocessor.preferHLE) { + has.Cx4 = true; + for(auto map : node.find("map")) { + loadMap(map, {&Cx4::read, &cx4}, {&Cx4::write, &cx4}); + } + if(auto memory = node["memory(type=RAM,content=Data,architecture=HG51BS169)"]) { + for(auto map : memory.find("map")) { + loadMap(map, {&Cx4::read, &cx4}, {&Cx4::write, &cx4}); + } + } + return; + } + + if(auto memory = node["memory(type=ROM,content=Data,architecture=HG51BS169)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + for(auto n : range(1 * 1024)) hitachidsp.dataROM[n] = fp->readl(3); + } else { + for(auto n : range(1 * 1024)) { + hitachidsp.dataROM[n] = hitachidsp.staticDataROM[n * 3 + 0] << 0; + hitachidsp.dataROM[n] |= hitachidsp.staticDataROM[n * 3 + 1] << 8; + hitachidsp.dataROM[n] |= hitachidsp.staticDataROM[n * 3 + 2] << 16; + } + } + } + } + + if(auto memory = node["memory(type=RAM,content=Data,architecture=HG51BS169)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + for(auto n : range(3 * 1024)) hitachidsp.dataRAM[n] = fp->readl(1); + } + } + for(auto map : memory.find("map")) { + loadMap(map, {&HitachiDSP::readDRAM, &hitachidsp}, {&HitachiDSP::writeDRAM, &hitachidsp}); + } + } + + has.HitachiDSP = true; + + for(auto map : node.find("map")) { + loadMap(map, {&HitachiDSP::readIO, &hitachidsp}, {&HitachiDSP::writeIO, &hitachidsp}); + } +} + +//processor(architecture=uPD7725) +auto Cartridge::loaduPD7725(Markup::Node node) -> void { + for(auto& word : necdsp.programROM) word = 0x000000; + for(auto& word : necdsp.dataROM) word = 0x0000; + for(auto& word : necdsp.dataRAM) word = 0x0000; + + if(auto oscillator = game.oscillator()) { + necdsp.Frequency = oscillator->frequency; + } else { + necdsp.Frequency = 7'600'000; + } + + bool failed = false; + + if(auto memory = node["memory(type=ROM,content=Program,architecture=uPD7725)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + for(auto n : range(2048)) necdsp.programROM[n] = fp->readl(3); + } else failed = true; + } + } + + if(auto memory = node["memory(type=ROM,content=Data,architecture=uPD7725)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + for(auto n : range(1024)) necdsp.dataROM[n] = fp->readl(2); + } else failed = true; + } + } + + if(failed || configuration.hacks.coprocessor.preferHLE) { + auto manifest = BML::serialize(game.document); + if(manifest.find("identifier: DSP1")) { //also matches DSP1B + has.DSP1 = true; + for(auto map : node.find("map")) { + loadMap(map, {&DSP1::read, &dsp1}, {&DSP1::write, &dsp1}); + } + return; + } + if(manifest.find("identifier: DSP2")) { + has.DSP2 = true; + for(auto map : node.find("map")) { + loadMap(map, {&DSP2::read, &dsp2}, {&DSP2::write, &dsp2}); + } + return; + } + if(manifest.find("identifier: DSP4")) { + has.DSP4 = true; + for(auto map : node.find("map")) { + loadMap(map, {&DSP4::read, &dsp4}, {&DSP4::write, &dsp4}); + } + return; + } + } + + if(failed) { + //throw an error to the user + platform->open(ID::SuperFamicom, "DSP3", File::Read, File::Required); + return; + } + + if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD7725)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + for(auto n : range(256)) necdsp.dataRAM[n] = fp->readl(2); + } + } + for(auto map : memory.find("map")) { + loadMap(map, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp}); + } + } + + has.NECDSP = true; + necdsp.revision = NECDSP::Revision::uPD7725; + + for(auto map : node.find("map")) { + loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp}); + } +} + +//processor(architecture=uPD96050) +auto Cartridge::loaduPD96050(Markup::Node node) -> void { + for(auto& word : necdsp.programROM) word = 0x000000; + for(auto& word : necdsp.dataROM) word = 0x0000; + for(auto& word : necdsp.dataRAM) word = 0x0000; + + if(auto oscillator = game.oscillator()) { + necdsp.Frequency = oscillator->frequency; + } else { + necdsp.Frequency = 11'000'000; + } + + bool failed = false; + + if(auto memory = node["memory(type=ROM,content=Program,architecture=uPD96050)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + for(auto n : range(16384)) necdsp.programROM[n] = fp->readl(3); + } else failed = true; + } + } + + if(auto memory = node["memory(type=ROM,content=Data,architecture=uPD96050)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + for(auto n : range(2048)) necdsp.dataROM[n] = fp->readl(2); + } else failed = true; + } + } + + if(failed || configuration.hacks.coprocessor.preferHLE) { + auto manifest = BML::serialize(game.document); + if(manifest.find("identifier: ST010")) { + has.ST0010 = true; + if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD96050)"]) { + for(auto map : memory.find("map")) { + loadMap(map, {&ST0010::read, &st0010}, {&ST0010::write, &st0010}); + } + } + return; + } + } + + if(failed) { + //throw an error to the user + platform->open(ID::SuperFamicom, "ST011", File::Read, File::Required); + return; + } + + if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD96050)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + for(auto n : range(2048)) necdsp.dataRAM[n] = fp->readl(2); + } + } + for(auto map : memory.find("map")) { + loadMap(map, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp}); + } + } + + has.NECDSP = true; + necdsp.revision = NECDSP::Revision::uPD96050; + + for(auto map : node.find("map")) { + loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp}); + } +} + +//rtc(manufacturer=Epson) +auto Cartridge::loadEpsonRTC(Markup::Node node) -> void { + has.EpsonRTC = true; + + epsonrtc.initialize(); + + for(auto map : node.find("map")) { + loadMap(map, {&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc}); + } + + if(auto memory = node["memory(type=RTC,content=Time,manufacturer=Epson)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + uint8 data[16] = {0}; + for(auto& byte : data) byte = fp->read(); + epsonrtc.load(data); + } + } + } +} + +//rtc(manufacturer=Sharp) +auto Cartridge::loadSharpRTC(Markup::Node node) -> void { + has.SharpRTC = true; + + sharprtc.initialize(); + + for(auto map : node.find("map")) { + loadMap(map, {&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc}); + } + + if(auto memory = node["memory(type=RTC,content=Time,manufacturer=Sharp)"]) { + if(auto file = game.memory(memory)) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { + uint8 data[16] = {0}; + for(auto& byte : data) byte = fp->read(); + sharprtc.load(data); + } + } + } +} + +//processor(identifier=SPC7110) +auto Cartridge::loadSPC7110(Markup::Node node) -> void { + has.SPC7110 = true; + + for(auto map : node.find("map")) { + loadMap(map, {&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110}); + } + + if(auto mcu = node["mcu"]) { + for(auto map : mcu.find("map")) { + loadMap(map, {&SPC7110::mcuromRead, &spc7110}, {&SPC7110::mcuromWrite, &spc7110}); + } + if(auto memory = mcu["memory(type=ROM,content=Program)"]) { + loadMemory(spc7110.prom, memory, File::Required); + } + if(auto memory = mcu["memory(type=ROM,content=Data)"]) { + loadMemory(spc7110.drom, memory, File::Required); + } + } + + if(auto memory = node["memory(type=RAM,content=Save)"]) { + loadMemory(spc7110.ram, memory, File::Optional); + for(auto map : memory.find("map")) { + loadMap(map, {&SPC7110::mcuramRead, &spc7110}, {&SPC7110::mcuramWrite, &spc7110}); + } + } +} + +//processor(identifier=SDD1) +auto Cartridge::loadSDD1(Markup::Node node) -> void { + has.SDD1 = true; + + for(auto map : node.find("map")) { + loadMap(map, {&SDD1::ioRead, &sdd1}, {&SDD1::ioWrite, &sdd1}); + } + + if(auto mcu = node["mcu"]) { + for(auto map : mcu.find("map")) { + loadMap(map, {&SDD1::mcuRead, &sdd1}, {&SDD1::mcuWrite, &sdd1}); + } + if(auto memory = mcu["memory(type=ROM,content=Program)"]) { + loadMemory(sdd1.rom, memory, File::Required); + } + } +} + +//processor(identifier=OBC1) +auto Cartridge::loadOBC1(Markup::Node node) -> void { + has.OBC1 = true; + + for(auto map : node.find("map")) { + loadMap(map, {&OBC1::read, &obc1}, {&OBC1::write, &obc1}); + } + + if(auto memory = node["memory(type=RAM,content=Save)"]) { + loadMemory(obc1.ram, memory, File::Optional); + } +} + +//file::exists("msu1/data.rom") +auto Cartridge::loadMSU1() -> void { + has.MSU1 = true; + + bus.map({&MSU1::readIO, &msu1}, {&MSU1::writeIO, &msu1}, "00-3f,80-bf:2000-2007"); +} diff --git a/sfc/cartridge/save.cpp b/sfc/cartridge/save.cpp new file mode 100644 index 0000000..4c5b9fa --- /dev/null +++ b/sfc/cartridge/save.cpp @@ -0,0 +1,190 @@ +auto Cartridge::saveCartridge(Markup::Node node) -> void { + if(auto node = board["memory(type=RAM,content=Save)"]) saveRAM(node); + if(auto node = board["processor(identifier=MCC)"]) saveMCC(node); + if(auto node = board["processor(architecture=W65C816S)"]) saveSA1(node); + if(auto node = board["processor(architecture=GSU)"]) saveSuperFX(node); + if(auto node = board["processor(architecture=ARM6)"]) saveARMDSP(node); + if(auto node = board["processor(architecture=HG51BS169)"]) saveHitachiDSP(node); + if(auto node = board["processor(architecture=uPD7725)"]) saveuPD7725(node); + if(auto node = board["processor(architecture=uPD96050)"]) saveuPD96050(node); + if(auto node = board["rtc(manufacturer=Epson)"]) saveEpsonRTC(node); + if(auto node = board["rtc(manufacturer=Sharp)"]) saveSharpRTC(node); + if(auto node = board["processor(identifier=SPC7110)"]) saveSPC7110(node); + if(auto node = board["processor(identifier=OBC1)"]) saveOBC1(node); +} + +auto Cartridge::saveCartridgeBSMemory(Markup::Node node) -> void { + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=Flash,content=Program)"]}) { + if(auto fp = platform->open(bsmemory.pathID, memory.name(), File::Write)) { + if (bsmemory.memory.data() != nullptr) { + fp->write(bsmemory.memory.data(), memory.size); + } + } + } +} + +auto Cartridge::saveCartridgeSufamiTurboA(Markup::Node node) -> void { + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=RAM,content=Save)"]}) { + if(memory.nonVolatile) { + if(auto fp = platform->open(sufamiturboA.pathID, memory.name(), File::Write)) { + fp->write(sufamiturboA.ram.data(), memory.size); + } + } + } +} + +auto Cartridge::saveCartridgeSufamiTurboB(Markup::Node node) -> void { + if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=RAM,content=Save)"]}) { + if(memory.nonVolatile) { + if(auto fp = platform->open(sufamiturboB.pathID, memory.name(), File::Write)) { + fp->write(sufamiturboB.ram.data(), memory.size); + } + } + } +} + +// + +auto Cartridge::saveMemory(Memory& ram, Markup::Node node) -> void { + if(auto memory = game.memory(node)) { + if(memory->type == "RAM" && !memory->nonVolatile) return; + if(memory->type == "RTC" && !memory->nonVolatile) return; + if(auto fp = platform->open(pathID(), memory->name(), File::Write)) { + fp->write(ram.data(), ram.size()); + } + } +} + +//memory(type=RAM,content=Save) +auto Cartridge::saveRAM(Markup::Node node) -> void { + saveMemory(ram, node); +} + +//processor(identifier=MCC) +auto Cartridge::saveMCC(Markup::Node node) -> void { + if(auto mcu = node["mcu"]) { + if(auto memory = mcu["memory(type=RAM,content=Download)"]) { + saveMemory(mcc.psram, memory); + } + } +} + +//processor(architecture=W65C816S) +auto Cartridge::saveSA1(Markup::Node node) -> void { + if(auto memory = node["memory(type=RAM,content=Save)"]) { + saveMemory(sa1.bwram, memory); + } + + if(auto memory = node["memory(type=RAM,content=Internal)"]) { + saveMemory(sa1.iram, memory); + } +} + +//processor(architecture=GSU) +auto Cartridge::saveSuperFX(Markup::Node node) -> void { + if(auto memory = node["memory(type=RAM,content=Save)"]) { + saveMemory(superfx.ram, memory); + } +} + +//processor(architecture=ARM6) +auto Cartridge::saveARMDSP(Markup::Node node) -> void { + if(auto memory = node["memory(type=RAM,content=Data,architecture=ARM6)"]) { + if(auto file = game.memory(memory)) { + if(file->nonVolatile) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Write)) { + for(auto n : range(16 * 1024)) fp->write(armdsp.programRAM[n]); + } + } + } + } +} + +//processor(architecture=HG51BS169) +auto Cartridge::saveHitachiDSP(Markup::Node node) -> void { + saveMemory(hitachidsp.ram, node["ram"]); + + if(auto memory = node["memory(type=RAM,content=Save)"]) { + saveMemory(hitachidsp.ram, memory); + } + + if(auto memory = node["memory(type=RAM,content=Data,architecture=HG51BS169)"]) { + if(auto file = game.memory(memory)) { + if(file->nonVolatile) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Write)) { + for(auto n : range(3 * 1024)) fp->write(hitachidsp.dataRAM[n]); + } + } + } + } +} + +//processor(architecture=uPD7725) +auto Cartridge::saveuPD7725(Markup::Node node) -> void { + if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD7725)"]) { + if(auto file = game.memory(memory)) { + if(file->nonVolatile) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Write)) { + for(auto n : range(256)) fp->writel(necdsp.dataRAM[n], 2); + } + } + } + } +} + +//processor(architecture=uPD96050) +auto Cartridge::saveuPD96050(Markup::Node node) -> void { + if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD96050)"]) { + if(auto file = game.memory(memory)) { + if(file->nonVolatile) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Write)) { + for(auto n : range(2 * 1024)) fp->writel(necdsp.dataRAM[n], 2); + } + } + } + } +} + +//rtc(manufacturer=Epson) +auto Cartridge::saveEpsonRTC(Markup::Node node) -> void { + if(auto memory = node["memory(type=RTC,content=Time,manufacturer=Epson)"]) { + if(auto file = game.memory(memory)) { + if(file->nonVolatile) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Write)) { + uint8 data[16] = {0}; + epsonrtc.save(data); + fp->write(data, 16); + } + } + } + } +} + +//rtc(manufacturer=Sharp) +auto Cartridge::saveSharpRTC(Markup::Node node) -> void { + if(auto memory = node["memory(type=RTC,content=Time,manufacturer=Sharp)"]) { + if(auto file = game.memory(memory)) { + if(file->nonVolatile) { + if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Write)) { + uint8 data[16] = {0}; + sharprtc.save(data); + fp->write(data, 16); + } + } + } + } +} + +//processor(identifier=SPC7110) +auto Cartridge::saveSPC7110(Markup::Node node) -> void { + if(auto memory = node["memory(type=RAM,content=Save)"]) { + saveMemory(spc7110.ram, memory); + } +} + +//processor(identifier=OBC1) +auto Cartridge::saveOBC1(Markup::Node node) -> void { + if(auto memory = node["memory(type=RAM,content=Save)"]) { + saveMemory(obc1.ram, memory); + } +} diff --git a/sfc/cartridge/serialization.cpp b/sfc/cartridge/serialization.cpp new file mode 100644 index 0000000..1509ab4 --- /dev/null +++ b/sfc/cartridge/serialization.cpp @@ -0,0 +1,3 @@ +auto Cartridge::serialize(serializer& s) -> void { + s.array(ram.data(), ram.size()); +} diff --git a/sfc/controller/controller.cpp b/sfc/controller/controller.cpp new file mode 100644 index 0000000..a68a037 --- /dev/null +++ b/sfc/controller/controller.cpp @@ -0,0 +1,63 @@ +#include + +namespace SuperFamicom { + +ControllerPort controllerPort1; +ControllerPort controllerPort2; +#include "gamepad/gamepad.cpp" +#include "mouse/mouse.cpp" +#include "super-multitap/super-multitap.cpp" +#include "super-scope/super-scope.cpp" +#include "justifier/justifier.cpp" + +Controller::Controller(uint port) : port(port) { +} + +Controller::~Controller() { +} + +auto Controller::iobit() -> bool { + switch(port) { + case ID::Port::Controller1: return cpu.pio() & 0x40; + case ID::Port::Controller2: return cpu.pio() & 0x80; + } + unreachable; +} + +auto Controller::iobit(bool data) -> void { + switch(port) { + case ID::Port::Controller1: bus.write(0x4201, (cpu.pio() & ~0x40) | (data << 6)); break; + case ID::Port::Controller2: bus.write(0x4201, (cpu.pio() & ~0x80) | (data << 7)); break; + } +} + +// + +auto ControllerPort::connect(uint deviceID) -> void { + if(!system.loaded()) return; + delete device; + + switch(deviceID) { default: + case ID::Device::None: device = new Controller(port); break; + case ID::Device::Gamepad: device = new Gamepad(port); break; + case ID::Device::Mouse: device = new Mouse(port); break; + case ID::Device::SuperMultitap: device = new SuperMultitap(port); break; + case ID::Device::SuperScope: device = new SuperScope(port); break; + case ID::Device::Justifier: device = new Justifier(port, false); break; + case ID::Device::Justifiers: device = new Justifier(port, true); break; + } +} + +auto ControllerPort::power(uint port) -> void { + this->port = port; +} + +auto ControllerPort::unload() -> void { + delete device; + device = nullptr; +} + +auto ControllerPort::serialize(serializer& s) -> void { +} + +} diff --git a/sfc/controller/controller.hpp b/sfc/controller/controller.hpp new file mode 100644 index 0000000..96bc7c2 --- /dev/null +++ b/sfc/controller/controller.hpp @@ -0,0 +1,46 @@ +// 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 { + Controller(uint port); + virtual ~Controller(); + + auto iobit() -> bool; + auto iobit(bool data) -> void; + virtual auto data() -> uint2 { return 0; } + virtual auto latch(bool data) -> void {} + virtual auto latch() -> void {} //light guns + virtual auto draw(uint16_t* output, uint pitch, uint width, uint height) -> void {} //light guns + + const uint port; +}; + +struct ControllerPort { + auto connect(uint deviceID) -> void; + + auto power(uint port) -> void; + auto unload() -> void; + auto serialize(serializer&) -> void; + + uint port; + Controller* device = nullptr; +}; + +extern ControllerPort controllerPort1; +extern ControllerPort controllerPort2; + +#include "gamepad/gamepad.hpp" +#include "mouse/mouse.hpp" +#include "super-multitap/super-multitap.hpp" +#include "super-scope/super-scope.hpp" +#include "justifier/justifier.hpp" diff --git a/sfc/controller/gamepad/gamepad.cpp b/sfc/controller/gamepad/gamepad.cpp new file mode 100644 index 0000000..bdef37e --- /dev/null +++ b/sfc/controller/gamepad/gamepad.cpp @@ -0,0 +1,48 @@ +Gamepad::Gamepad(uint port) : Controller(port) { + latched = 0; + counter = 0; +} + +auto Gamepad::data() -> uint2 { + if(counter >= 16) return 1; + if(latched == 1) return platform->inputPoll(port, ID::Device::Gamepad, B); + + //note: D-pad physically prevents up+down and left+right from being pressed at the same time + switch(counter++) { + case 0: return b; + case 1: return y; + case 2: return select; + case 3: return start; + case 4: return up & !down; + case 5: return down & !up; + case 6: return left & !right; + case 7: return right & !left; + case 8: return a; + case 9: return x; + case 10: return l; + case 11: return r; + } + + return 0; //12-15: signature +} + +auto Gamepad::latch(bool data) -> void { + if(latched == data) return; + latched = data; + counter = 0; + + if(latched == 0) { + b = platform->inputPoll(port, ID::Device::Gamepad, B); + y = platform->inputPoll(port, ID::Device::Gamepad, Y); + select = platform->inputPoll(port, ID::Device::Gamepad, Select); + start = platform->inputPoll(port, ID::Device::Gamepad, Start); + up = platform->inputPoll(port, ID::Device::Gamepad, Up); + down = platform->inputPoll(port, ID::Device::Gamepad, Down); + left = platform->inputPoll(port, ID::Device::Gamepad, Left); + right = platform->inputPoll(port, ID::Device::Gamepad, Right); + a = platform->inputPoll(port, ID::Device::Gamepad, A); + x = platform->inputPoll(port, ID::Device::Gamepad, X); + l = platform->inputPoll(port, ID::Device::Gamepad, L); + r = platform->inputPoll(port, ID::Device::Gamepad, R); + } +} diff --git a/sfc/controller/gamepad/gamepad.hpp b/sfc/controller/gamepad/gamepad.hpp new file mode 100644 index 0000000..b28c7ba --- /dev/null +++ b/sfc/controller/gamepad/gamepad.hpp @@ -0,0 +1,18 @@ +struct Gamepad : Controller { + enum : uint { + Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start, + }; + + Gamepad(uint port); + + auto data() -> uint2; + auto latch(bool data) -> void; + +private: + bool latched; + uint counter; + + boolean b, y, select, start; + boolean up, down, left, right; + boolean a, x, l, r; +}; diff --git a/sfc/controller/justifier/justifier.cpp b/sfc/controller/justifier/justifier.cpp new file mode 100644 index 0000000..b735c2d --- /dev/null +++ b/sfc/controller/justifier/justifier.cpp @@ -0,0 +1,162 @@ +Justifier::Justifier(uint port, bool chained): +Controller(port), +chained(chained), +device(!chained ? ID::Device::Justifier : ID::Device::Justifiers) +{ + latched = 0; + counter = 0; + active = 0; + prev = 0; + + player1.x = 256 / 2; + player1.y = 240 / 2; + player1.trigger = false; + player2.start = false; + + player2.x = 256 / 2; + player2.y = 240 / 2; + player2.trigger = false; + player2.start = false; + + if(chained == false) { + player2.x = -1; + player2.y = -1; + } else { + player1.x -= 16; + player2.x += 16; + } +} + +auto Justifier::data() -> uint2 { + if(counter >= 32) return 1; + + if(counter == 0) { + player1.trigger = platform->inputPoll(port, device, 0 + Trigger); + player1.start = platform->inputPoll(port, device, 0 + Start); + } + + if(counter == 0 && chained) { + player2.trigger = platform->inputPoll(port, device, 4 + Trigger); + player2.start = platform->inputPoll(port, device, 4 + 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 player1.trigger; + case 25: return player2.trigger; + case 26: return player1.start; + case 27: return player2.start; + case 28: return active; + + case 29: return 0; + case 30: return 0; + case 31: return 0; + } + + unreachable; +} + +auto Justifier::latch(bool data) -> void { + if(latched == data) return; + latched = data; + counter = 0; + if(latched == 0) active = !active; //toggle between both controllers, even when unchained +} + +auto Justifier::latch() -> void { + /* active value is inverted here ... */ + + if(active != 0) { + int nx = platform->inputPoll(port, device, 0 + X); + int ny = platform->inputPoll(port, device, 0 + Y); + player1.x = max(-16, min(256 + 16, nx + player1.x)); + player1.y = max(-16, min((int)ppu.vdisp() + 16, ny + player1.y)); + bool offscreen = (player1.x < 0 || player1.y < 0 || player1.x >= 256 || player1.y >= (int)ppu.vdisp()); + if(!offscreen) ppu.latchCounters(player1.x, player1.y); + } + + if(active != 1) { + int nx = platform->inputPoll(port, device, 4 + X); + int ny = platform->inputPoll(port, device, 4 + Y); + player2.x = max(-16, min(256 + 16, nx + player2.x)); + player2.y = max(-16, min((int)ppu.vdisp() + 16, ny + player2.y)); + bool offscreen = (player2.x < 0 || player2.y < 0 || player2.x >= 256 || player2.y >= (int)ppu.vdisp()); + if(!offscreen) ppu.latchCounters(player2.x, player2.y); + } +} + +auto Justifier::draw(uint16_t* data, uint pitch, uint width, uint height) -> void { + pitch >>= 1; + float scaleX = (float)width / 256.0; + float scaleY = (float)height / (float)ppu.vdisp(); + int length = (float)width / 256.0 * 4.0; + + auto plot = [&](int x, int y, uint16_t color) -> void { + if(x >= 0 && y >= 0 && x < (int)width && y < (int)height) { + data[y * pitch + x] = color; + } + }; + + { int x = player1.x * scaleX; + int y = player1.y * scaleY; + + uint16_t color = 0x03e0; + uint16_t black = 0x0000; + + for(int px = x - length - 1; px <= x + length + 1; px++) plot(px, y - 1, black); + for(int px = x - length - 1; px <= x + length + 1; px++) plot(px, y + 1, black); + for(int py = y - length - 1; py <= y + length + 1; py++) plot(x - 1, py, black); + for(int py = y - length - 1; py <= y + length + 1; py++) plot(x + 1, py, black); + plot(x - length - 1, y, black); + plot(x + length + 1, y, black); + plot(x, y - length - 1, black); + plot(x, y + length + 1, black); + for(int px = x - length; px <= x + length; px++) plot(px, y, color); + for(int py = y - length; py <= y + length; py++) plot(x, py, color); + } + + if(chained) + { int x = player2.x * scaleX; + int y = player2.y * scaleY; + + uint16_t color = 0x7c00; + uint16_t black = 0x0000; + + for(int px = x - length - 1; px <= x + length + 1; px++) plot(px, y - 1, black); + for(int px = x - length - 1; px <= x + length + 1; px++) plot(px, y + 1, black); + for(int py = y - length - 1; py <= y + length + 1; py++) plot(x - 1, py, black); + for(int py = y - length - 1; py <= y + length + 1; py++) plot(x + 1, py, black); + plot(x - length - 1, y, black); + plot(x + length + 1, y, black); + plot(x, y - length - 1, black); + plot(x, y + length + 1, black); + for(int px = x - length; px <= x + length; px++) plot(px, y, color); + for(int py = y - length; py <= y + length; py++) plot(x, py, color); + } +} diff --git a/sfc/controller/justifier/justifier.hpp b/sfc/controller/justifier/justifier.hpp new file mode 100644 index 0000000..b5923b7 --- /dev/null +++ b/sfc/controller/justifier/justifier.hpp @@ -0,0 +1,27 @@ +struct Justifier : Controller { + enum : uint { + X, Y, Trigger, Start, + }; + + Justifier(uint port, bool chained); + + auto data() -> uint2; + auto latch(bool data) -> void; + auto latch() -> void override; + auto draw(uint16_t* data, uint pitch, uint width, uint height) -> void override; + +//private: + const bool chained; //true if the second justifier is attached to the first + const uint device; + bool latched; + uint counter; + uint prev; + + bool active; + struct Player { + int x; + int y; + bool trigger; + bool start; + } player1, player2; +}; diff --git a/sfc/controller/mouse/mouse.cpp b/sfc/controller/mouse/mouse.cpp new file mode 100644 index 0000000..88e450c --- /dev/null +++ b/sfc/controller/mouse/mouse.cpp @@ -0,0 +1,86 @@ +Mouse::Mouse(uint port) : Controller(port) { + latched = 0; + counter = 0; + + speed = 0; + x = 0; + y = 0; + dx = 0; + dy = 0; + l = 0; + r = 0; +} + +auto Mouse::data() -> uint2 { + if(latched == 1) { + speed = (speed + 1) % 3; + return 0; + } + + if(counter >= 32) return 1; + + 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 r; + case 9: return l; + case 10: return (speed >> 1) & 1; + case 11: return (speed >> 0) & 1; + + case 12: return 0; //signature + case 13: return 0; // || + case 14: return 0; // || + case 15: return 1; // || + + case 16: return dy; + case 17: return (y >> 6) & 1; + case 18: return (y >> 5) & 1; + case 19: return (y >> 4) & 1; + case 20: return (y >> 3) & 1; + case 21: return (y >> 2) & 1; + case 22: return (y >> 1) & 1; + case 23: return (y >> 0) & 1; + + case 24: return dx; + case 25: return (x >> 6) & 1; + case 26: return (x >> 5) & 1; + case 27: return (x >> 4) & 1; + case 28: return (x >> 3) & 1; + case 29: return (x >> 2) & 1; + case 30: return (x >> 1) & 1; + case 31: return (x >> 0) & 1; + } +} + +auto Mouse::latch(bool data) -> void { + if(latched == data) return; + latched = data; + counter = 0; + + x = platform->inputPoll(port, ID::Device::Mouse, X); //-n = left, 0 = center, +n = right + y = platform->inputPoll(port, ID::Device::Mouse, Y); //-n = up, 0 = center, +n = down + l = platform->inputPoll(port, ID::Device::Mouse, Left); + r = platform->inputPoll(port, ID::Device::Mouse, Right); + + dx = x < 0; //0 = right, 1 = left + dy = y < 0; //0 = down, 1 = up + + if(x < 0) x = -x; //abs(position_x) + if(y < 0) y = -y; //abs(position_y) + + double multiplier = 1.0; + if(speed == 1) multiplier = 1.5; + if(speed == 2) multiplier = 2.0; + x = (double)x * multiplier; + y = (double)y * multiplier; + + x = min(127, x); + y = min(127, y); +} diff --git a/sfc/controller/mouse/mouse.hpp b/sfc/controller/mouse/mouse.hpp new file mode 100644 index 0000000..a094d23 --- /dev/null +++ b/sfc/controller/mouse/mouse.hpp @@ -0,0 +1,22 @@ +struct Mouse : Controller { + enum : uint { + X, Y, Left, Right, + }; + + Mouse(uint port); + + auto data() -> uint2; + auto latch(bool data) -> void; + +private: + bool latched; + uint counter; + + uint speed; //0 = slow, 1 = normal, 2 = fast + int x; //x-coordinate + int y; //y-coordinate + bool dx; //x-direction + bool dy; //y-direction + bool l; //left button + bool r; //right button +}; diff --git a/sfc/controller/super-multitap/super-multitap.cpp b/sfc/controller/super-multitap/super-multitap.cpp new file mode 100644 index 0000000..7ef141b --- /dev/null +++ b/sfc/controller/super-multitap/super-multitap.cpp @@ -0,0 +1,70 @@ +SuperMultitap::SuperMultitap(uint port) : Controller(port) { + latched = 0; + counter1 = 0; + counter2 = 0; +} + +auto SuperMultitap::data() -> uint2 { + if(latched) return 2; //device detection + uint counter, a, b; + + if(iobit()) { + counter = counter1; + if(counter >= 16) return 3; + counter1++; + if(counter >= 12) return 0; + a = 0; //controller 2 + b = 1; //controller 3 + } else { + counter = counter2; + if(counter >= 16) return 3; + counter2++; + if(counter >= 12) return 0; + a = 2; //controller 4 + b = 3; //controller 5 + } + + auto& A = gamepads[a]; + auto& B = gamepads[b]; + + switch(counter) { + case 0: return A.b << 0 | B.b << 1; + case 1: return A.y << 0 | B.y << 1; + case 2: return A.select << 0 | B.select << 1; + case 3: return A.start << 0 | B.start << 1; + case 4: return (A.up & !A.down) << 0 | (B.up & !B.down) << 1; + case 5: return (A.down & !A.up) << 0 | (B.down & !B.up) << 1; + case 6: return (A.left & !A.right) << 0 | (B.left & !B.right) << 1; + case 7: return (A.right & !A.left) << 0 | (B.right & !B.left) << 1; + case 8: return A.a << 0 | B.a << 1; + case 9: return A.x << 0 | B.x << 1; + case 10: return A.l << 0 | B.l << 1; + case 11: return A.r << 0 | B.r << 1; + } + unreachable; +} + +auto SuperMultitap::latch(bool data) -> void { + if(latched == data) return; + latched = data; + counter1 = 0; + counter2 = 0; + + if(latched == 0) { + for(uint id : range(4)) { + auto& gamepad = gamepads[id]; + gamepad.b = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + B); + gamepad.y = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Y); + gamepad.select = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Select); + gamepad.start = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Start); + gamepad.up = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Up); + gamepad.down = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Down); + gamepad.left = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Left); + gamepad.right = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Right); + gamepad.a = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + A); + gamepad.x = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + X); + gamepad.l = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + L); + gamepad.r = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + R); + } + } +} diff --git a/sfc/controller/super-multitap/super-multitap.hpp b/sfc/controller/super-multitap/super-multitap.hpp new file mode 100644 index 0000000..7ab2127 --- /dev/null +++ b/sfc/controller/super-multitap/super-multitap.hpp @@ -0,0 +1,21 @@ +struct SuperMultitap : Controller { + enum : uint { + Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start, + }; + + SuperMultitap(uint port); + + auto data() -> uint2; + auto latch(bool data) -> void; + +private: + bool latched; + uint counter1; + uint counter2; + + struct Gamepad { + boolean b, y, select, start; + boolean up, down, left, right; + boolean a, x, l, r; + } gamepads[4]; +}; diff --git a/sfc/controller/super-scope/super-scope.cpp b/sfc/controller/super-scope/super-scope.cpp new file mode 100644 index 0000000..4247dbe --- /dev/null +++ b/sfc/controller/super-scope/super-scope.cpp @@ -0,0 +1,133 @@ +//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. + +SuperScope::SuperScope(uint port) : Controller(port) { + latched = 0; + counter = 0; + + //center cursor onscreen + x = 256 / 2; + y = 240 / 2; + + trigger = false; + cursor = false; + turbo = false; + pause = false; + offscreen = false; + + oldturbo = false; + triggerlock = false; + pauselock = false; + + prev = 0; +} + +auto SuperScope::data() -> uint2 { + if(counter >= 8) return 1; + + if(counter == 0) { + //turbo is a switch; toggle is edge sensitive + bool newturbo = platform->inputPoll(port, ID::Device::SuperScope, Turbo); + if(newturbo && !oldturbo) { + turbo = !turbo; //toggle state + } + oldturbo = newturbo; + + //trigger is a button + //if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive + trigger = false; + bool newtrigger = platform->inputPoll(port, ID::Device::SuperScope, Trigger); + if(newtrigger && (turbo || !triggerlock)) { + trigger = true; + triggerlock = true; + } else if(!newtrigger) { + triggerlock = false; + } + + //cursor is a button; it is always level sensitive + cursor = platform->inputPoll(port, ID::Device::SuperScope, Cursor); + + //pause is a button; it is always edge sensitive + pause = false; + bool newpause = platform->inputPoll(port, ID::Device::SuperScope, Pause); + if(newpause && !pauselock) { + pause = true; + pauselock = true; + } else if(!newpause) { + pauselock = false; + } + + // Changes were made here because some games need their coords offset JOLLYGOOD + offscreen = (x < -16 || y < -16 || x >= 512 || y >= 480); + } + + 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) + } + + unreachable; +} + +auto SuperScope::latch(bool data) -> void { + if(latched == data) return; + latched = data; + counter = 0; +} + +auto SuperScope::latch() -> void { + /*int nx = platform->inputPoll(port, ID::Device::SuperScope, X); + int ny = platform->inputPoll(port, ID::Device::SuperScope, Y); + x = max(-16, min(256 + 16, nx + x)); + y = max(-16, min((int)ppu.vdisp() + 16, ny + y));*/ + // Changes were made here so that simple coords can be used JOLLYGOOD + x = platform->inputPoll(port, ID::Device::SuperScope, X); + y = platform->inputPoll(port, ID::Device::SuperScope, Y); + offscreen = (x < 0 || y < 0 || x >= 512 || y >= 480); + if(!offscreen) ppu.latchCounters(x, y); +} + +auto SuperScope::draw(uint16_t* data, uint pitch, uint width, uint height) -> void { + /*pitch >>= 1; + float scaleX = (float)width / 256.0; + float scaleY = (float)height / (float)ppu.vdisp(); + int length = (float)width / 256.0 * 4.0; + + int x = this->x * scaleX; + int y = this->y * scaleY; + + auto plot = [&](int x, int y, uint16_t color) -> void { + if(x >= 0 && y >= 0 && x < (int)width && y < (int)height) { + data[y * pitch + x] = color; + } + }; + + uint16_t color = turbo ? 0x7c00 : 0x03e0; + uint16_t black = 0x0000; + + for(int px = x - length - 1; px <= x + length + 1; px++) plot(px, y - 1, black); + for(int px = x - length - 1; px <= x + length + 1; px++) plot(px, y + 1, black); + for(int py = y - length - 1; py <= y + length + 1; py++) plot(x - 1, py, black); + for(int py = y - length - 1; py <= y + length + 1; py++) plot(x + 1, py, black); + plot(x - length - 1, y, black); + plot(x + length + 1, y, black); + plot(x, y - length - 1, black); + plot(x, y + length + 1, black); + for(int px = x - length; px <= x + length; px++) plot(px, y, color); + for(int py = y - length; py <= y + length; py++) plot(x, py, color);*/ +} diff --git a/sfc/controller/super-scope/super-scope.hpp b/sfc/controller/super-scope/super-scope.hpp new file mode 100644 index 0000000..ffa475f --- /dev/null +++ b/sfc/controller/super-scope/super-scope.hpp @@ -0,0 +1,31 @@ +struct SuperScope : Controller { + enum : uint { + X, Y, Trigger, Cursor, Turbo, Pause, + }; + + SuperScope(uint port); + + auto data() -> uint2; + auto latch(bool data) -> void; + auto latch() -> void override; + auto draw(uint16_t* data, uint pitch, uint width, uint height) -> void override; + +private: + bool latched; + uint counter; + + int x; + int y; + + bool trigger; + bool cursor; + bool turbo; + bool pause; + bool offscreen; + + bool oldturbo; + bool triggerlock; + bool pauselock; + + uint prev; +}; diff --git a/sfc/coprocessor/armdsp/armdsp.cpp b/sfc/coprocessor/armdsp/armdsp.cpp new file mode 100644 index 0000000..8a7d08d --- /dev/null +++ b/sfc/coprocessor/armdsp/armdsp.cpp @@ -0,0 +1,109 @@ +#include + +namespace SuperFamicom { + +#include "memory.cpp" +#include "serialization.cpp" +ArmDSP armdsp; + +auto ArmDSP::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto ArmDSP::Enter() -> void { + armdsp.boot(); + while(true) { + scheduler.synchronize(); + armdsp.main(); + } +} + +auto ArmDSP::boot() -> void { + //reset hold delay + while(bridge.reset) { + step(1); + continue; + } + + //reset sequence delay + if(bridge.ready == false) { + step(65'536); + bridge.ready = true; + } +} + +auto ArmDSP::main() -> void { + processor.cpsr.t = 0; //force ARM mode + instruction(); +} + +auto ArmDSP::step(uint clocks) -> void { + if(bridge.timer && --bridge.timer == 0); + clock += clocks * (uint64_t)cpu.frequency; + synchronizeCPU(); +} + +//MMIO: 00-3f,80-bf:3800-38ff +//3800-3807 mirrored throughout +//a0 ignored + +auto ArmDSP::read(uint addr, uint8) -> uint8 { + cpu.synchronizeCoprocessors(); + + uint8 data = 0x00; + addr &= 0xff06; + + if(addr == 0x3800) { + if(bridge.armtocpu.ready) { + bridge.armtocpu.ready = false; + data = bridge.armtocpu.data; + } + } + + if(addr == 0x3802) { + bridge.signal = false; + } + + if(addr == 0x3804) { + data = bridge.status(); + } + + return data; +} + +auto ArmDSP::write(uint addr, uint8 data) -> void { + cpu.synchronizeCoprocessors(); + + addr &= 0xff06; + + if(addr == 0x3802) { + bridge.cputoarm.ready = true; + bridge.cputoarm.data = data; + } + + if(addr == 0x3804) { + data &= 1; + if(!bridge.reset && data) reset(); + bridge.reset = data; + } +} + +auto ArmDSP::power() -> void { + random.array((uint8*)programRAM, sizeof(programRAM)); + bridge.reset = false; + reset(); +} + +auto ArmDSP::reset() -> void { + ARM7TDMI::power(); + create(ArmDSP::Enter, Frequency); + + bridge.ready = false; + bridge.signal = false; + bridge.timer = 0; + bridge.timerlatch = 0; + bridge.cputoarm.ready = false; + bridge.armtocpu.ready = false; +} + +} diff --git a/sfc/coprocessor/armdsp/armdsp.hpp b/sfc/coprocessor/armdsp/armdsp.hpp new file mode 100644 index 0000000..732ee89 --- /dev/null +++ b/sfc/coprocessor/armdsp/armdsp.hpp @@ -0,0 +1,36 @@ +//ARMv3 (ARM60) + +//note: this coprocessor uses the ARMv4 (ARM7TDMI) core as its base +//instruction execution forces ARM mode to remove ARMv4 THUMB access +//there is a possibility the ARMv3 supports 26-bit mode; but cannot be verified + +struct ArmDSP : Processor::ARM7TDMI, Thread { + #include "registers.hpp" + + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto boot() -> void; + auto main() -> void; + + auto step(uint clocks) -> void override; + auto sleep() -> void override; + auto get(uint mode, uint32 addr) -> uint32 override; + auto set(uint mode, uint32 addr, uint32 word) -> void override; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto power() -> void; + auto reset() -> void; //soft reset + + auto firmware() const -> nall::vector; + auto serialize(serializer&) -> void; + + uint Frequency; + + uint8 programROM[128 * 1024]; + uint8 dataROM[32 * 1024]; + uint8 programRAM[16 * 1024]; +}; + +extern ArmDSP armdsp; diff --git a/sfc/coprocessor/armdsp/memory.cpp b/sfc/coprocessor/armdsp/memory.cpp new file mode 100644 index 0000000..c672d52 --- /dev/null +++ b/sfc/coprocessor/armdsp/memory.cpp @@ -0,0 +1,91 @@ +//note: timings are completely unverified +//due to the ST018 chip design (on-die ROM), testing is nearly impossible + +auto ArmDSP::sleep() -> void { + step(1); +} + +auto ArmDSP::get(uint mode, uint32 addr) -> uint32 { + step(1); + + static auto memory = [&](const uint8* memory, uint mode, uint32 addr) -> uint32 { + if(mode & Word) { + memory += addr & ~3; + return memory[0] << 0 | memory[1] << 8 | memory[2] << 16 | memory[3] << 24; + } else if(mode & Byte) { + return memory[addr]; + } else { + return 0; //should never occur + } + }; + + switch(addr & 0xe000'0000) { + case 0x0000'0000: return memory(programROM, mode, addr & 0x1ffff); + case 0x2000'0000: return pipeline.fetch.instruction; + case 0x4000'0000: break; + case 0x6000'0000: return 0x40404001; + case 0x8000'0000: return pipeline.fetch.instruction; + case 0xa000'0000: return memory(dataROM, mode, addr & 0x7fff); + case 0xc000'0000: return pipeline.fetch.instruction; + case 0xe000'0000: return memory(programRAM, mode, addr & 0x3fff); + } + + addr &= 0xe000'003f; + + if(addr == 0x4000'0010) { + if(bridge.cputoarm.ready) { + bridge.cputoarm.ready = false; + return bridge.cputoarm.data; + } + } + + if(addr == 0x4000'0020) { + return bridge.status(); + } + + return 0; +} + +auto ArmDSP::set(uint mode, uint32 addr, uint32 word) -> void { + step(1); + + static auto memory = [](uint8* memory, uint mode, uint32 addr, uint32 word) { + if(mode & Word) { + memory += addr & ~3; + *memory++ = word >> 0; + *memory++ = word >> 8; + *memory++ = word >> 16; + *memory++ = word >> 24; + } else if(mode & Byte) { + memory += addr; + *memory++ = word >> 0; + } + }; + + switch(addr & 0xe000'0000) { + case 0x0000'0000: return; + case 0x2000'0000: return; + case 0x4000'0000: break; + case 0x6000'0000: return; + case 0x8000'0000: return; + case 0xa000'0000: return; + case 0xc000'0000: return; + case 0xe000'0000: return memory(programRAM, mode, addr & 0x3fff, word); + } + + addr &= 0xe000'003f; + word &= 0x0000'00ff; + + if(addr == 0x4000'0000) { + bridge.armtocpu.ready = true; + bridge.armtocpu.data = word; + } + + if(addr == 0x4000'0010) bridge.signal = true; + + if(addr == 0x4000'0020) bridge.timerlatch = bridge.timerlatch & 0xffff00 | word << 0; + if(addr == 0x4000'0024) bridge.timerlatch = bridge.timerlatch & 0xff00ff | word << 8; + if(addr == 0x4000'0028) bridge.timerlatch = bridge.timerlatch & 0x00ffff | word << 16; + + if(addr == 0x4000'002c) bridge.timer = bridge.timerlatch; +} diff --git a/sfc/coprocessor/armdsp/registers.hpp b/sfc/coprocessor/armdsp/registers.hpp new file mode 100644 index 0000000..c05a097 --- /dev/null +++ b/sfc/coprocessor/armdsp/registers.hpp @@ -0,0 +1,22 @@ +struct Bridge { + struct Buffer { + bool ready; + uint8 data; + }; + Buffer cputoarm; + Buffer armtocpu; + uint32 timer; + uint32 timerlatch; + bool reset; + bool ready; + bool signal; + + auto status() const -> uint8 { + return ( + armtocpu.ready << 0 + | signal << 2 + | cputoarm.ready << 3 + | ready << 7 + ); + } +} bridge; diff --git a/sfc/coprocessor/armdsp/serialization.cpp b/sfc/coprocessor/armdsp/serialization.cpp new file mode 100644 index 0000000..143f3a6 --- /dev/null +++ b/sfc/coprocessor/armdsp/serialization.cpp @@ -0,0 +1,25 @@ +auto ArmDSP::firmware() const -> nall::vector { + nall::vector buffer; + if(!cartridge.has.ARMDSP) return buffer; + buffer.reserve(128 * 1024 + 32 * 1024); + for(auto n : range(128 * 1024)) buffer.append(programROM[n]); + for(auto n : range( 32 * 1024)) buffer.append(dataROM[n]); + return buffer; +} + +auto ArmDSP::serialize(serializer& s) -> void { + ARM7TDMI::serialize(s); + Thread::serialize(s); + + s.array(programRAM, 16 * 1024); + + s.integer(bridge.cputoarm.ready); + s.integer(bridge.cputoarm.data); + s.integer(bridge.armtocpu.ready); + s.integer(bridge.armtocpu.data); + s.integer(bridge.timer); + s.integer(bridge.timerlatch); + s.integer(bridge.reset); + s.integer(bridge.ready); + s.integer(bridge.signal); +} diff --git a/sfc/coprocessor/coprocessor.cpp b/sfc/coprocessor/coprocessor.cpp new file mode 100644 index 0000000..8fe8ec4 --- /dev/null +++ b/sfc/coprocessor/coprocessor.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include diff --git a/sfc/coprocessor/coprocessor.hpp b/sfc/coprocessor/coprocessor.hpp new file mode 100644 index 0000000..f01516a --- /dev/null +++ b/sfc/coprocessor/coprocessor.hpp @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include diff --git a/sfc/coprocessor/cx4/cx4.cpp b/sfc/coprocessor/cx4/cx4.cpp new file mode 100644 index 0000000..5b6c86e --- /dev/null +++ b/sfc/coprocessor/cx4/cx4.cpp @@ -0,0 +1,191 @@ +#include + +namespace SuperFamicom { + +Cx4 cx4; +#define CX4_CPP +#include "data.cpp" +#include "functions.cpp" +#include "oam.cpp" +#include "opcodes.cpp" +#include "serialization.cpp" + +auto Cx4::power() -> void { + memset(ram, 0, 0x0c00); + memset(reg, 0, 0x0100); +} + +uint32 Cx4::ldr(uint8 r) { + uint16 addr = 0x0080 + (r * 3); + return (reg[addr + 0] << 0) + | (reg[addr + 1] << 8) + | (reg[addr + 2] << 16); +} + +void Cx4::str(uint8 r, uint32 data) { + uint16 addr = 0x0080 + (r * 3); + reg[addr + 0] = (data >> 0); + reg[addr + 1] = (data >> 8); + reg[addr + 2] = (data >> 16); +} + +void Cx4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) { + int64 rx = x & 0xffffff; + int64 ry = y & 0xffffff; + if(rx & 0x800000)rx |= ~0x7fffff; + if(ry & 0x800000)ry |= ~0x7fffff; + + rx *= ry; + + rl = (rx) & 0xffffff; + rh = (rx >> 24) & 0xffffff; +} + +uint32 Cx4::sin(uint32 rx) { + r0 = rx & 0x1ff; + if(r0 & 0x100)r0 ^= 0x1ff; + if(r0 & 0x080)r0 ^= 0x0ff; + if(rx & 0x100) { + return sin_table[r0 + 0x80]; + } else { + return sin_table[r0]; + } +} + +uint32 Cx4::cos(uint32 rx) { + return sin(rx + 0x080); +} + +void Cx4::immediate_reg(uint32 start) { + r0 = ldr(0); + for(uint32 i = start; i < 48; i++) { + if((r0 & 0x0fff) < 0x0c00) { + ram[r0 & 0x0fff] = immediate_data[i]; + } + r0++; + } + str(0, r0); +} + +void Cx4::transfer_data() { + uint32 src; + uint16 dest, count; + + src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16); + count = (reg[0x43]) | (reg[0x44] << 8); + dest = (reg[0x45]) | (reg[0x46] << 8); + + for(uint32 i=0;i> 2; + return; + } + + switch(data) { + case 0x00: op00(); break; + case 0x01: op01(); break; + case 0x05: op05(); break; + case 0x0d: op0d(); break; + case 0x10: op10(); break; + case 0x13: op13(); break; + case 0x15: op15(); break; + case 0x1f: op1f(); break; + case 0x22: op22(); break; + case 0x25: op25(); break; + case 0x2d: op2d(); break; + case 0x40: op40(); break; + case 0x54: op54(); break; + case 0x5c: op5c(); break; + case 0x5e: op5e(); break; + case 0x60: op60(); break; + case 0x62: op62(); break; + case 0x64: op64(); break; + case 0x66: op66(); break; + case 0x68: op68(); break; + case 0x6a: op6a(); break; + case 0x6c: op6c(); break; + case 0x6e: op6e(); break; + case 0x70: op70(); break; + case 0x72: op72(); break; + case 0x74: op74(); break; + case 0x76: op76(); break; + case 0x78: op78(); break; + case 0x7a: op7a(); break; + case 0x7c: op7c(); break; + case 0x89: op89(); break; + } + } +} + +void Cx4::writeb(uint16 addr, uint8 data) { + write(addr, data); +} + +void Cx4::writew(uint16 addr, uint16 data) { + write(addr + 0, data >> 0); + write(addr + 1, data >> 8); +} + +void Cx4::writel(uint16 addr, uint32 data) { + write(addr + 0, data >> 0); + write(addr + 1, data >> 8); + write(addr + 2, data >> 16); +} + +uint8 Cx4::read(uint addr, uint8 data) { + addr &= 0x1fff; + + if(addr < 0x0c00) { + return ram[addr]; + } + + if(addr >= 0x1f00) { + return reg[addr & 0xff]; + } + + return cpu.r.mdr; +} + +uint8 Cx4::readb(uint16 addr) { + return read(addr); +} + +uint16 Cx4::readw(uint16 addr) { + return read(addr) | (read(addr + 1) << 8); +} + +uint32 Cx4::readl(uint16 addr) { + return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16); +} + +} diff --git a/sfc/coprocessor/cx4/cx4.hpp b/sfc/coprocessor/cx4/cx4.hpp new file mode 100644 index 0000000..94b5264 --- /dev/null +++ b/sfc/coprocessor/cx4/cx4.hpp @@ -0,0 +1,90 @@ +struct Cx4 { + auto power() -> void; + + auto read(uint addr, uint8 data = 0) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; + + uint8 ram[0x0c00]; + uint8 reg[0x0100]; + uint32 r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15; + + static const uint8 immediate_data[48]; + static const uint16 wave_data[40]; + static const uint32 sin_table[256]; + + static const int16 SinTable[512]; + static const int16 CosTable[512]; + + int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale; + int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal; + + void C4TransfWireFrame(); + void C4TransfWireFrame2(); + void C4CalcWireFrame(); + void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color); + void C4DrawWireFrame(); + void C4DoScaleRotate(int row_padding); + +public: + uint32 ldr(uint8 r); + void str(uint8 r, uint32 data); + void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh); + uint32 sin(uint32 rx); + uint32 cos(uint32 rx); + + void transfer_data(); + void immediate_reg(uint32 num); + + void op00_00(); + void op00_03(); + void op00_05(); + void op00_07(); + void op00_08(); + void op00_0b(); + void op00_0c(); + + void op00(); + void op01(); + void op05(); + void op0d(); + void op10(); + void op13(); + void op15(); + void op1f(); + void op22(); + void op25(); + void op2d(); + void op40(); + void op54(); + void op5c(); + void op5e(); + void op60(); + void op62(); + void op64(); + void op66(); + void op68(); + void op6a(); + void op6c(); + void op6e(); + void op70(); + void op72(); + void op74(); + void op76(); + void op78(); + void op7a(); + void op7c(); + void op89(); + + uint8 readb(uint16 addr); + uint16 readw(uint16 addr); + uint32 readl(uint16 addr); + + void writeb(uint16 addr, uint8 data); + void writew(uint16 addr, uint16 data); + void writel(uint16 addr, uint32 data); +}; + +extern Cx4 cx4; diff --git a/sfc/coprocessor/cx4/data.cpp b/sfc/coprocessor/cx4/data.cpp new file mode 100644 index 0000000..8538f60 --- /dev/null +++ b/sfc/coprocessor/cx4/data.cpp @@ -0,0 +1,187 @@ +#ifdef CX4_CPP + +const uint8 Cx4::immediate_data[48] = { + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, + 0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, + 0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00 +}; + +const uint16 Cx4::wave_data[40] = { + 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e, + 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e, + 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e, + 0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e, + 0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e +}; + +const uint32 Cx4::sin_table[256] = { + 0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6, + 0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb, + 0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d, + 0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e, + 0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5, + 0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a, + 0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6, + 0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8, + 0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2, + 0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318, + 0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046, + 0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b, + 0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b, + 0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73, + 0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70, + 0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb, + 0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09, + 0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124, + 0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2, + 0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1, + 0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a, + 0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465, + 0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009, + 0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37, + 0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e, + 0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7, + 0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9, + 0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4, + 0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4, + 0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d, + 0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f, + 0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004 +}; + +const int16 Cx4::SinTable[512] = { + 0, 402, 804, 1206, 1607, 2009, 2410, 2811, + 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, + 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, + 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, + 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, + 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, + 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, + 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, + 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, + 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, + 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, + 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, + 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, + 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, + 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, + 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765, + 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, + 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, + 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, + 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, + 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, + 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, + 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, + 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, + 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, + 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, + 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, + 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, + 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, + 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, + 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, + 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, + 0, -402, -804, -1206, -1607, -2009, -2410, -2811, + -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, + -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, + -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, + -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, + -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, + -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, + -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, + -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, + -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, + -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, + -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, + -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, + -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, + -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, + -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, + -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, + -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, + -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, + -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, + -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, + -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, + -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, + -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, + -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, + -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, + -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, + -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, + -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, + -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, + -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, + -3211, -2811, -2410, -2009, -1607, -1206, -804, -402 +}; + +const int16 Cx4::CosTable[512] = { + 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, + 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, + 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, + 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, + 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, + 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, + 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, + 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, + 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, + 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, + 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, + 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, + 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, + 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, + 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, + 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, + 0, -402, -804, -1206, -1607, -2009, -2410, -2811, + -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, + -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, + -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, + -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, + -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, + -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, + -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, + -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, + -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, + -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, + -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, + -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, + -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, + -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, + -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, + -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, + -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, + -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, + -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, + -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, + -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, + -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, + -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, + -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, + -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, + -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, + -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, + -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, + -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, + -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, + -3211, -2811, -2410, -2009, -1607, -1206, -804, -402, + 0, 402, 804, 1206, 1607, 2009, 2410, 2811, + 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, + 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, + 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, + 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, + 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, + 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, + 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, + 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, + 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, + 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, + 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, + 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, + 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, + 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, + 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765 +}; + +#endif diff --git a/sfc/coprocessor/cx4/functions.cpp b/sfc/coprocessor/cx4/functions.cpp new file mode 100644 index 0000000..b4684dd --- /dev/null +++ b/sfc/coprocessor/cx4/functions.cpp @@ -0,0 +1,251 @@ +#ifdef CX4_CPP + +#include +#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000) +#define sar(b, n) ((b) >> (n)) +#ifdef PI +#undef PI +#endif +#define PI 3.1415926535897932384626433832795 + +//Wireframe Helpers +void Cx4::C4TransfWireFrame() { + double c4x = (double)C4WFXVal; + double c4y = (double)C4WFYVal; + double c4z = (double)C4WFZVal - 0x95; + double tanval, c4x2, c4y2, c4z2; + + //Rotate X + tanval = -(double)C4WFX2Val * PI * 2 / 128; + c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval); + c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval); + + //Rotate Y + tanval = -(double)C4WFY2Val * PI * 2 / 128; + c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval); + c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval); + + //Rotate Z + tanval = -(double)C4WFDist * PI * 2 / 128; + c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval); + c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval); + + //Scale + C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95); + C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95); +} + +void Cx4::C4CalcWireFrame() { + C4WFXVal = C4WFX2Val - C4WFXVal; + C4WFYVal = C4WFY2Val - C4WFYVal; + + if(abs(C4WFXVal) > abs(C4WFYVal)) { + C4WFDist = abs(C4WFXVal) + 1; + C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal); + C4WFXVal = (C4WFXVal < 0) ? -256 : 256; + } else if(C4WFYVal != 0) { + C4WFDist = abs(C4WFYVal) + 1; + C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal); + C4WFYVal = (C4WFYVal < 0) ? -256 : 256; + } else { + C4WFDist = 0; + } +} + +void Cx4::C4TransfWireFrame2() { + double c4x = (double)C4WFXVal; + double c4y = (double)C4WFYVal; + double c4z = (double)C4WFZVal; + double tanval, c4x2, c4y2, c4z2; + + //Rotate X + tanval = -(double)C4WFX2Val * PI * 2 / 128; + c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval); + c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval); + + //Rotate Y + tanval = -(double)C4WFY2Val * PI * 2 / 128; + c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval); + c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval); + + //Rotate Z + tanval = -(double)C4WFDist * PI * 2 / 128; + c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval); + c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval); + + //Scale + C4WFXVal = (int16)(c4x * C4WFScale / 0x100); + C4WFYVal = (int16)(c4y * C4WFScale / 0x100); +} + +void Cx4::C4DrawWireFrame() { + uint32 line = readl(0x1f80); + uint32 point1, point2; + int16 X1, Y1, Z1; + int16 X2, Y2, Z2; + uint8 Color; + + for(int32 i = ram[0x0295]; i > 0; i--, line += 5) { + if(bus.read(line) == 0xff && bus.read(line + 1) == 0xff) { + int32 tmp = line - 5; + while(bus.read(tmp + 2) == 0xff && bus.read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; } + point1 = (read(0x1f82) << 16) | (bus.read(tmp + 2) << 8) | bus.read(tmp + 3); + } else { + point1 = (read(0x1f82) << 16) | (bus.read(line) << 8) | bus.read(line + 1); + } + point2 = (read(0x1f82) << 16) | (bus.read(line + 2) << 8) | bus.read(line + 3); + + X1=(bus.read(point1 + 0) << 8) | bus.read(point1 + 1); + Y1=(bus.read(point1 + 2) << 8) | bus.read(point1 + 3); + Z1=(bus.read(point1 + 4) << 8) | bus.read(point1 + 5); + X2=(bus.read(point2 + 0) << 8) | bus.read(point2 + 1); + Y2=(bus.read(point2 + 2) << 8) | bus.read(point2 + 3); + Z2=(bus.read(point2 + 4) << 8) | bus.read(point2 + 5); + Color = bus.read(line + 4); + C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color); + } +} + +void Cx4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) { + //Transform coordinates + C4WFXVal = (int16)X1; + C4WFYVal = (int16)Y1; + C4WFZVal = Z1; + C4WFScale = read(0x1f90); + C4WFX2Val = read(0x1f86); + C4WFY2Val = read(0x1f87); + C4WFDist = read(0x1f88); + C4TransfWireFrame2(); + X1 = (C4WFXVal + 48) << 8; + Y1 = (C4WFYVal + 48) << 8; + + C4WFXVal = (int16)X2; + C4WFYVal = (int16)Y2; + C4WFZVal = Z2; + C4TransfWireFrame2(); + X2 = (C4WFXVal + 48) << 8; + Y2 = (C4WFYVal + 48) << 8; + + //Get line info + C4WFXVal = (int16)(X1 >> 8); + C4WFYVal = (int16)(Y1 >> 8); + C4WFX2Val = (int16)(X2 >> 8); + C4WFY2Val = (int16)(Y2 >> 8); + C4CalcWireFrame(); + X2 = (int16)C4WFXVal; + Y2 = (int16)C4WFYVal; + + //Render line + for(int32 i = C4WFDist ? C4WFDist : (int16)1; i > 0; i--) { + if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) { + uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2; + uint8 bit = 0x80 >> ((X1 >> 8) & 7); + ram[addr + 0x300] &= ~bit; + ram[addr + 0x301] &= ~bit; + if(Color & 1) ram[addr + 0x300] |= bit; + if(Color & 2) ram[addr + 0x301] |= bit; + } + X1 += X2; + Y1 += Y2; + } +} + +void Cx4::C4DoScaleRotate(int row_padding) { + int16 A, B, C, D; + + //Calculate matrix + int32 XScale = readw(0x1f8f); + int32 YScale = readw(0x1f92); + + if(XScale & 0x8000)XScale = 0x7fff; + if(YScale & 0x8000)YScale = 0x7fff; + + if(readw(0x1f80) == 0) { //no rotation + A = (int16)XScale; + B = 0; + C = 0; + D = (int16)YScale; + } else if(readw(0x1f80) == 128) { //90 degree rotation + A = 0; + B = (int16)(-YScale); + C = (int16)XScale; + D = 0; + } else if(readw(0x1f80) == 256) { //180 degree rotation + A = (int16)(-XScale); + B = 0; + C = 0; + D = (int16)(-YScale); + } else if(readw(0x1f80) == 384) { //270 degree rotation + A = 0; + B = (int16)YScale; + C = (int16)(-XScale); + D = 0; + } else { + A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15); + B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15)); + C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15); + D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15); + } + + //Calculate Pixel Resolution + uint8 w = read(0x1f89) & ~7; + uint8 h = read(0x1f8c) & ~7; + + //Clear the output RAM + memset(ram, 0, (w + row_padding / 4) * h / 2); + + int32 Cx = (int16)readw(0x1f83); + int32 Cy = (int16)readw(0x1f86); + + //Calculate start position (i.e. (Ox, Oy) = (0, 0)) + //The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in + //the function. We do Cx*A etc normally because the matrix parameters + //already have the fractional parts. + int32 LineX = (Cx << 12) - Cx * A - Cx * B; + int32 LineY = (Cy << 12) - Cy * C - Cy * D; + + //Start loop + uint32 X, Y; + uint8 byte; + int32 outidx = 0; + uint8 bit = 0x80; + + for(int32 y = 0; y < h; y++) { + X = LineX; + Y = LineY; + for(int32 x = 0; x < w; x++) { + if((X >> 12) >= w || (Y >> 12) >= h) { + byte = 0; + } else { + uint32 addr = (Y >> 12) * w + (X >> 12); + byte = read(0x600 + (addr >> 1)); + if(addr & 1) { byte >>= 4; } + } + + //De-bitplanify + if(byte & 1) ram[outidx ] |= bit; + if(byte & 2) ram[outidx + 1] |= bit; + if(byte & 4) ram[outidx + 16] |= bit; + if(byte & 8) ram[outidx + 17] |= bit; + + bit >>= 1; + if(!bit) { + bit = 0x80; + outidx += 32; + } + + X += A; //Add 1 to output x => add an A and a C + Y += C; + } + outidx += 2 + row_padding; + if(outidx & 0x10) { + outidx &= ~0x10; + } else { + outidx -= w * 4 + row_padding; + } + LineX += B; //Add 1 to output y => add a B and a D + LineY += D; + } +} + +#endif diff --git a/sfc/coprocessor/cx4/oam.cpp b/sfc/coprocessor/cx4/oam.cpp new file mode 100644 index 0000000..af958b5 --- /dev/null +++ b/sfc/coprocessor/cx4/oam.cpp @@ -0,0 +1,228 @@ +#ifdef CX4_CPP + +//Build OAM +void Cx4::op00_00() { + uint32 oamptr = ram[0x626] << 2; + for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) { + //clear oam-to-be + if(i >= 0) ram[i] = 0xe0; + } + + uint16 globalx, globaly; + uint32 oamptr2; + int16 sprx, spry; + uint8 sprname, sprattr; + uint8 sprcount; + + globalx = readw(0x621); + globaly = readw(0x623); + oamptr2 = 0x200 + (ram[0x626] >> 2); + + if(!ram[0x620]) return; + + sprcount = 128 - ram[0x626]; + uint8 offset = (ram[0x626] & 3) * 2; + uint32 srcptr = 0x220; + + for(int i = ram[0x620]; i > 0 && sprcount > 0; i--, srcptr += 16) { + sprx = readw(srcptr) - globalx; + spry = readw(srcptr + 2) - globaly; + sprname = ram[srcptr + 5]; + sprattr = ram[srcptr + 4] | ram[srcptr + 6]; + + uint32 spraddr = readl(srcptr + 7); + if(bus.read(spraddr)) { + int16 x, y; + for(int sprcnt = bus.read(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4) { + x = (int8)bus.read(spraddr + 1); + if(sprattr & 0x40) { + x = -x - ((bus.read(spraddr) & 0x20) ? 16 : 8); + } + x += sprx; + if(x >= -16 && x <= 272) { + y = (int8)bus.read(spraddr + 2); + if(sprattr & 0x80) { + y = -y - ((bus.read(spraddr) & 0x20) ? 16 : 8); + } + y += spry; + if(y >= -16 && y <= 224) { + ram[oamptr ] = (uint8)x; + ram[oamptr + 1] = (uint8)y; + ram[oamptr + 2] = sprname + bus.read(spraddr + 3); + ram[oamptr + 3] = sprattr ^ (bus.read(spraddr) & 0xc0); + ram[oamptr2] &= ~(3 << offset); + if(x & 0x100) ram[oamptr2] |= 1 << offset; + if(bus.read(spraddr) & 0x20) ram[oamptr2] |= 2 << offset; + oamptr += 4; + sprcount--; + offset = (offset + 2) & 6; + if(!offset)oamptr2++; + } + } + } + } else if(sprcount > 0) { + ram[oamptr ] = (uint8)sprx; + ram[oamptr + 1] = (uint8)spry; + ram[oamptr + 2] = sprname; + ram[oamptr + 3] = sprattr; + ram[oamptr2] &= ~(3 << offset); + if(sprx & 0x100) ram[oamptr2] |= 3 << offset; + else ram[oamptr2] |= 2 << offset; + oamptr += 4; + sprcount--; + offset = (offset + 2) & 6; + if(!offset) oamptr2++; + } + } +} + +//Scale and Rotate +void Cx4::op00_03() { + C4DoScaleRotate(0); +} + +//Transform Lines +void Cx4::op00_05() { + C4WFX2Val = read(0x1f83); + C4WFY2Val = read(0x1f86); + C4WFDist = read(0x1f89); + C4WFScale = read(0x1f8c); + +//Transform Vertices +uint32 ptr = 0; + for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) { + C4WFXVal = readw(ptr + 1); + C4WFYVal = readw(ptr + 5); + C4WFZVal = readw(ptr + 9); + C4TransfWireFrame(); + + //Displace + writew(ptr + 1, C4WFXVal + 0x80); + writew(ptr + 5, C4WFYVal + 0x50); + } + + writew(0x600, 23); + writew(0x602, 0x60); + writew(0x605, 0x40); + writew(0x600 + 8, 23); + writew(0x602 + 8, 0x60); + writew(0x605 + 8, 0x40); + + ptr = 0xb02; + uint32 ptr2 = 0; + + for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) { + C4WFXVal = readw((read(ptr + 0) << 4) + 1); + C4WFYVal = readw((read(ptr + 0) << 4) + 5); + C4WFX2Val = readw((read(ptr + 1) << 4) + 1); + C4WFY2Val = readw((read(ptr + 1) << 4) + 5); + C4CalcWireFrame(); + writew(ptr2 + 0x600, C4WFDist ? C4WFDist : (int16)1); + writew(ptr2 + 0x602, C4WFXVal); + writew(ptr2 + 0x605, C4WFYVal); + } +} + +//Scale and Rotate +void Cx4::op00_07() { + C4DoScaleRotate(64); +} + +//Draw Wireframe +void Cx4::op00_08() { + C4DrawWireFrame(); +} + +//Disintegrate +void Cx4::op00_0b() { + uint8 width, height; + uint32 startx, starty; + uint32 srcptr; + uint32 x, y; + int32 scalex, scaley; + int32 cx, cy; + int32 i, j; + + width = read(0x1f89); + height = read(0x1f8c); + cx = readw(0x1f80); + cy = readw(0x1f83); + + scalex = (int16)readw(0x1f86); + scaley = (int16)readw(0x1f8f); + startx = -cx * scalex + (cx << 8); + starty = -cy * scaley + (cy << 8); + srcptr = 0x600; + + for(i = 0; i < (width * height) >> 1; i++) { + write(i, 0); + } + + for(y = starty, i = 0;i < height; i++, y += scaley) { + for(x = startx, j = 0;j < width; j++, x += scalex) { + if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) { + uint8 pixel = (j & 1) ? (uint8)(ram[srcptr] >> 4) : (ram[srcptr]); + int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2; + uint8 mask = 0x80 >> ((x >> 8) & 7); + + if(pixel & 1) ram[index ] |= mask; + if(pixel & 2) ram[index + 1] |= mask; + if(pixel & 4) ram[index + 16] |= mask; + if(pixel & 8) ram[index + 17] |= mask; + } + if(j & 1) srcptr++; + } + } +} + +//Bitplane Wave +void Cx4::op00_0c() { + uint32 destptr = 0; + uint32 waveptr = read(0x1f83); + uint16 mask1 = 0xc0c0; + uint16 mask2 = 0x3f3f; + + for(int j = 0; j < 0x10; j++) { + do { + int16 height = -((int8)read(waveptr + 0xb00)) - 16; + for(int i = 0; i < 40; i++) { + uint16 temp = readw(destptr + wave_data[i]) & mask2; + if(height >= 0) { + if(height < 8) { + temp |= mask1 & readw(0xa00 + height * 2); + } else { + temp |= mask1 & 0xff00; + } + } + writew(destptr + wave_data[i], temp); + height++; + } + waveptr = (waveptr + 1) & 0x7f; + mask1 = (mask1 >> 2) | (mask1 << 6); + mask2 = (mask2 >> 2) | (mask2 << 6); + } while(mask1 != 0xc0c0); + destptr += 16; + + do { + int16 height = -((int8)read(waveptr + 0xb00)) - 16; + for(int i = 0; i < 40; i++) { + uint16 temp = readw(destptr + wave_data[i]) & mask2; + if(height >= 0) { + if(height < 8) { + temp |= mask1 & readw(0xa10 + height * 2); + } else { + temp |= mask1 & 0xff00; + } + } + writew(destptr + wave_data[i], temp); + height++; + } + waveptr = (waveptr + 1) & 0x7f; + mask1 = (mask1 >> 2) | (mask1 << 6); + mask2 = (mask2 >> 2) | (mask2 << 6); + } while(mask1 != 0xc0c0); + destptr += 16; + } +} + +#endif diff --git a/sfc/coprocessor/cx4/opcodes.cpp b/sfc/coprocessor/cx4/opcodes.cpp new file mode 100644 index 0000000..639097b --- /dev/null +++ b/sfc/coprocessor/cx4/opcodes.cpp @@ -0,0 +1,228 @@ +#ifdef CX4_CPP + +//Sprite Functions +void Cx4::op00() { + switch(reg[0x4d]) { + case 0x00: op00_00(); break; + case 0x03: op00_03(); break; + case 0x05: op00_05(); break; + case 0x07: op00_07(); break; + case 0x08: op00_08(); break; + case 0x0b: op00_0b(); break; + case 0x0c: op00_0c(); break; + } +} + +//Draw Wireframe +void Cx4::op01() { + memset(ram + 0x300, 0, 2304); + C4DrawWireFrame(); +} + +//Propulsion +void Cx4::op05() { + int32 temp = 0x10000; + if(readw(0x1f83)) { + temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8); + } + writew(0x1f80, temp); +} + +//Set Vector length +void Cx4::op0d() { + C41FXVal = readw(0x1f80); + C41FYVal = readw(0x1f83); + C41FDistVal = readw(0x1f86); + double tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal)); + tanval = (double)C41FDistVal / tanval; + C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99); + C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98); + writew(0x1f89, C41FXVal); + writew(0x1f8c, C41FYVal); +} + +//Triangle +void Cx4::op10() { + r0 = ldr(0); + r1 = ldr(1); + + r4 = r0 & 0x1ff; + if(r1 & 0x8000)r1 |= ~0x7fff; + else r1 &= 0x7fff; + + mul(cos(r4), r1, r5, r2); + r5 = (r5 >> 16) & 0xff; + r2 = (r2 << 8) + r5; + + mul(sin(r4), r1, r5, r3); + r5 = (r5 >> 16) & 0xff; + r3 = (r3 << 8) + r5; + + str(0, r0); + str(1, r1); + str(2, r2); + str(3, r3); + str(4, r4); + str(5, r5); +} + +//Triangle +void Cx4::op13() { + r0 = ldr(0); + r1 = ldr(1); + + r4 = r0 & 0x1ff; + + mul(cos(r4), r1, r5, r2); + r5 = (r5 >> 8) & 0xffff; + r2 = (r2 << 16) + r5; + + mul(sin(r4), r1, r5, r3); + r5 = (r5 >> 8) & 0xffff; + r3 = (r3 << 16) + r5; + + str(0, r0); + str(1, r1); + str(2, r2); + str(3, r3); + str(4, r4); + str(5, r5); +} + +//Pythagorean +void Cx4::op15() { + C41FXVal = readw(0x1f80); + C41FYVal = readw(0x1f83); + C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal); + writew(0x1f80, C41FDist); +} + +//Calculate distance +void Cx4::op1f() { + C41FXVal = readw(0x1f80); + C41FYVal = readw(0x1f83); + if(!C41FXVal) { + C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180; + } else { + double tanval = ((double)C41FYVal) / ((double)C41FXVal); + C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512); + C41FAngleRes = C41FAngleRes; + if(C41FXVal < 0) { + C41FAngleRes += 0x100; + } + C41FAngleRes &= 0x1ff; + } + writew(0x1f86, C41FAngleRes); +} + +//Trapezoid +void Cx4::op22() { + int16 angle1 = readw(0x1f8c) & 0x1ff; + int16 angle2 = readw(0x1f8f) & 0x1ff; + int32 tan1 = Tan(angle1); + int32 tan2 = Tan(angle2); + int16 y = readw(0x1f83) - readw(0x1f89); + int16 left, right; + + for(int32 j = 0; j < 225; j++, y++) { + if(y >= 0) { + left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86); + right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93); + + if(left < 0 && right < 0) { + left = 1; + right = 0; + } else if(left < 0) { + left = 0; + } else if(right < 0) { + right = 0; + } + + if(left > 255 && right > 255) { + left = 255; + right = 254; + } else if(left > 255) { + left = 255; + } else if(right > 255) { + right = 255; + } + } else { + left = 1; + right = 0; + } + ram[j + 0x800] = (uint8)left; + ram[j + 0x900] = (uint8)right; + } +} + +//Multiply +void Cx4::op25() { + r0 = ldr(0); + r1 = ldr(1); + mul(r0, r1, r0, r1); + str(0, r0); + str(1, r1); +} + +//Transform Coords +void Cx4::op2d() { + C4WFXVal = readw(0x1f81); + C4WFYVal = readw(0x1f84); + C4WFZVal = readw(0x1f87); + C4WFX2Val = read (0x1f89); + C4WFY2Val = read (0x1f8a); + C4WFDist = read (0x1f8b); + C4WFScale = readw(0x1f90); + C4TransfWireFrame2(); + writew(0x1f80, C4WFXVal); + writew(0x1f83, C4WFYVal); +} + +//Sum +void Cx4::op40() { + r0 = 0; + for(uint32 i=0;i<0x800;i++) { + r0 += ram[i]; + } + str(0, r0); +} + +//Square +void Cx4::op54() { + r0 = ldr(0); + mul(r0, r0, r1, r2); + str(1, r1); + str(2, r2); +} + +//Immediate Register +void Cx4::op5c() { + str(0, 0x000000); + immediate_reg(0); +} + +//Immediate Register (Multiple) +void Cx4::op5e() { immediate_reg( 0); } +void Cx4::op60() { immediate_reg( 3); } +void Cx4::op62() { immediate_reg( 6); } +void Cx4::op64() { immediate_reg( 9); } +void Cx4::op66() { immediate_reg(12); } +void Cx4::op68() { immediate_reg(15); } +void Cx4::op6a() { immediate_reg(18); } +void Cx4::op6c() { immediate_reg(21); } +void Cx4::op6e() { immediate_reg(24); } +void Cx4::op70() { immediate_reg(27); } +void Cx4::op72() { immediate_reg(30); } +void Cx4::op74() { immediate_reg(33); } +void Cx4::op76() { immediate_reg(36); } +void Cx4::op78() { immediate_reg(39); } +void Cx4::op7a() { immediate_reg(42); } +void Cx4::op7c() { immediate_reg(45); } + +//Immediate ROM +void Cx4::op89() { + str(0, 0x054336); + str(1, 0xffffff); +} + +#endif diff --git a/sfc/coprocessor/cx4/serialization.cpp b/sfc/coprocessor/cx4/serialization.cpp new file mode 100644 index 0000000..55cac82 --- /dev/null +++ b/sfc/coprocessor/cx4/serialization.cpp @@ -0,0 +1,35 @@ +auto Cx4::serialize(serializer& s) -> void { + s.array(ram); + s.array(reg); + + s.integer(r0); + s.integer(r1); + s.integer(r2); + s.integer(r3); + s.integer(r4); + s.integer(r5); + s.integer(r6); + s.integer(r7); + s.integer(r8); + s.integer(r9); + s.integer(r10); + s.integer(r11); + s.integer(r12); + s.integer(r13); + s.integer(r14); + s.integer(r15); + + s.integer(C4WFXVal); + s.integer(C4WFYVal); + s.integer(C4WFZVal); + s.integer(C4WFX2Val); + s.integer(C4WFY2Val); + s.integer(C4WFDist); + s.integer(C4WFScale); + + s.integer(C41FXVal); + s.integer(C41FYVal); + s.integer(C41FAngleRes); + s.integer(C41FDist); + s.integer(C41FDistVal); +} diff --git a/sfc/coprocessor/dip/dip.cpp b/sfc/coprocessor/dip/dip.cpp new file mode 100644 index 0000000..a894571 --- /dev/null +++ b/sfc/coprocessor/dip/dip.cpp @@ -0,0 +1,21 @@ +//DIP switch +//used for Nintendo Super System emulation + +#include + +namespace SuperFamicom { + +#include "serialization.cpp" +DIP dip; + +auto DIP::power() -> void { +} + +auto DIP::read(uint, uint8) -> uint8 { + return value; +} + +auto DIP::write(uint, uint8) -> void { +} + +} diff --git a/sfc/coprocessor/dip/dip.hpp b/sfc/coprocessor/dip/dip.hpp new file mode 100644 index 0000000..7004d3d --- /dev/null +++ b/sfc/coprocessor/dip/dip.hpp @@ -0,0 +1,14 @@ +struct DIP { + //dip.cpp + auto power() -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + uint8 value = 0x00; +}; + +extern DIP dip; diff --git a/sfc/coprocessor/dip/serialization.cpp b/sfc/coprocessor/dip/serialization.cpp new file mode 100644 index 0000000..ed645e3 --- /dev/null +++ b/sfc/coprocessor/dip/serialization.cpp @@ -0,0 +1,3 @@ +auto DIP::serialize(serializer& s) -> void { + s.integer(value); +} diff --git a/sfc/coprocessor/dsp1/dsp1.cpp b/sfc/coprocessor/dsp1/dsp1.cpp new file mode 100644 index 0000000..b2424b4 --- /dev/null +++ b/sfc/coprocessor/dsp1/dsp1.cpp @@ -0,0 +1,48 @@ +#include + +namespace SuperFamicom { + +#define int8 int8_t +#define int16 int16_t +#define int32 int32_t +#define int64 int64_t +#define uint8 uint8_t +#define uint16 uint16_t +#define uint32 uint32_t +#define uint64 uint64_t +#define DSP1_CPP +#include "dsp1emu.hpp" +#include "dsp1emu.cpp" +Dsp1 dsp1emu; +#undef int8 +#undef int16 +#undef int32 +#undef int64 +#undef uint8 +#undef uint16 +#undef uint32 +#undef uint64 + +DSP1 dsp1; +#include "serialization.cpp" + +auto DSP1::power() -> void { + dsp1emu.reset(); +} + +auto DSP1::read(uint addr, uint8 data) -> uint8 { + if(addr & 1) { + return dsp1emu.getSr(); + } else { + return dsp1emu.getDr(); + } +} + +auto DSP1::write(uint addr, uint8 data) -> void { + if(addr & 1) { + } else { + return dsp1emu.setDr(data); + } +} + +} diff --git a/sfc/coprocessor/dsp1/dsp1.hpp b/sfc/coprocessor/dsp1/dsp1.hpp new file mode 100644 index 0000000..146c108 --- /dev/null +++ b/sfc/coprocessor/dsp1/dsp1.hpp @@ -0,0 +1,10 @@ +struct DSP1 { + auto power() -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; +}; + +extern DSP1 dsp1; diff --git a/sfc/coprocessor/dsp1/dsp1emu.cpp b/sfc/coprocessor/dsp1/dsp1emu.cpp new file mode 100644 index 0000000..c0ed19d --- /dev/null +++ b/sfc/coprocessor/dsp1/dsp1emu.cpp @@ -0,0 +1,1626 @@ +#ifdef DSP1_CPP + +// DSP-1's emulation code +// +// Based on research by Overload, The Dumper, Neviksti and Andreas Naive +// Date: June 2006 + +////////////////////////////////////////////////////////////////// + +Dsp1::Dsp1() +{ + reset(); +} + +////////////////////////////////////////////////////////////////// + +uint8 Dsp1::getSr() +{ + mSrLowByteAccess = ~mSrLowByteAccess; + if (mSrLowByteAccess) + return 0; + else + return mSr; +} + +////////////////////////////////////////////////////////////////// + +uint8 Dsp1::getDr() +{ + uint8 oDr; + + fsmStep(true, oDr); + return oDr; +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::setDr(uint8 iDr) +{ + fsmStep(false, iDr); +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::reset() +{ + mSr = DRC|RQM; + mSrLowByteAccess = false; + mDr = 0x0080; // Only a supposition. Is this correct? + mFreeze = false; + mFsmMajorState = WAIT_COMMAND; + memset(&shared, 0, sizeof(SharedData)); // another supposition +} + +////////////////////////////////////////////////////////////////// + +// Though the DSP-1 is unaware of the type of operation (read or write) +// we need to know what is being done by the program, as the class +// is responsible for maintaining the binding between the +// "external" and "internal" representations of the DR (data register). + +void Dsp1::fsmStep(bool read, uint8 &data) +{ + if (0 == (mSr&RQM)) return; + // Now RQM would be cleared; however, as this code is not to be used in + // a multithread environment, we will simply fake RQM operation. + // (The only exception would be Op1A's freeze.) + + // binding + if (read) + { + if (mSr&DRS) + data = static_cast(mDr>>8); + else + data = static_cast(mDr); + } + else + { + if (mSr&DRS) + { + mDr &= 0x00ff; + mDr |= data<<8; + } + else + { + mDr &= 0xff00; + mDr |= data; + } + } + + + switch (mFsmMajorState) + { + case WAIT_COMMAND: + mCommand = static_cast(mDr); + if (!(mCommand & 0xc0)) // valid command? + { + switch(mCommand) + { + // freeze cases + case 0x1a: + case 0x2a: + case 0x3a: + mFreeze = true; + break; + // normal cases + default: + mDataCounter=0; + mFsmMajorState = READ_DATA; + mSr &= ~DRC; + break; + } + } + break; + case READ_DATA: + mSr ^= DRS; + if (!(mSr&DRS)) + { + mReadBuffer[mDataCounter++] = static_cast(mDr); + if (mDataCounter >= mCommandTable[mCommand].reads) + { + (this->*mCommandTable[mCommand].callback)(mReadBuffer, mWriteBuffer); + if (0 != mCommandTable[mCommand].writes) // any output? + { + mDataCounter = 0; + mDr = static_cast(mWriteBuffer[mDataCounter]); + mFsmMajorState = WRITE_DATA; + } + else + { + mDr = 0x0080; // valid command completion + mFsmMajorState = WAIT_COMMAND; + mSr |= DRC; + } + } + } + break; + case WRITE_DATA: + mSr ^= DRS; + if (!(mSr&DRS)) + { + ++mDataCounter; + if (mDataCounter >= mCommandTable[mCommand].writes) + { + if ((mCommand == 0x0a)&&(mDr != 0x8000)) + { + // works in continuous mode + mReadBuffer[0]++; // next raster line + (this->*mCommandTable[mCommand].callback)(mReadBuffer, mWriteBuffer); + mDataCounter = 0; + mDr = static_cast(mWriteBuffer[mDataCounter]); + } + else + { + mDr = 0x0080; // valid command completion + mFsmMajorState = WAIT_COMMAND; + mSr |= DRC; + } + } + else + { + mDr = static_cast(mWriteBuffer[mDataCounter]); + } + } + break; + } + + + + // Now RQM would be set (except when executing Op1A -command equals 0x1a, 0x2a or 0x3a-). + if (mFreeze) + mSr &= ~RQM; +} + +////////////////////////////////////////////////////////////////// + +// The info on this table follows Overload's docs. + +const Dsp1::Command Dsp1::mCommandTable[0x40] = { + {&Dsp1::multiply, 2, 1}, //0x00 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveA, 3, 3}, //0x03 + {&Dsp1::triangle, 2, 2}, //0x04 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memoryTest, 1, 1}, //0x0f + {&Dsp1::radius, 3, 2}, //0x08 + {&Dsp1::objectiveA, 3, 3}, //0x0d + {&Dsp1::raster, 1, 4}, // 0x0a. This will normally work in continuous mode + {&Dsp1::scalarA, 3, 1}, //0x0b + {&Dsp1::rotate, 3, 2}, //0x0c + {&Dsp1::objectiveA, 3, 3}, //0x0d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memoryTest, 1, 1}, //0x0f + + {&Dsp1::inverse, 2, 2}, //0x10 + {&Dsp1::attitudeB, 4, 0}, //0x11 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveB, 3, 3}, //0x13 + {&Dsp1::gyrate, 6, 3}, //0x14 + {&Dsp1::attitudeB, 4, 0}, //0x11 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memoryDump, 1, 1024}, //0x1f + {&Dsp1::range, 4, 1}, //0x18 + {&Dsp1::objectiveB, 3, 3}, //0x1d + {0, 0, 0}, // 0x1a; the chip freezes + {&Dsp1::scalarB, 3, 1}, //0x1b + {&Dsp1::polar, 6, 3}, //0x1c + {&Dsp1::objectiveB, 3, 3}, //0x1d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memoryDump, 1, 1024}, //0x1f + + {&Dsp1::multiply2, 2, 1}, //0x20 + {&Dsp1::attitudeC, 4, 0}, //0x21 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveC, 3, 3}, //0x23 + {&Dsp1::triangle, 2, 2}, //0x04 + {&Dsp1::attitudeC, 4, 0}, //0x21 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memorySize, 1, 1}, //0x2f + {&Dsp1::distance, 3, 1}, //0x28 + {&Dsp1::objectiveC, 3, 3}, //0x2d + {0, 0, 0}, // 0x1a; the chip freezes + {&Dsp1::scalarC, 3, 1}, //0x2b + {&Dsp1::rotate, 3, 2}, //0x0c + {&Dsp1::objectiveC, 3, 3}, //0x2d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memorySize, 1, 1}, //0x2f + + {&Dsp1::inverse, 2, 2}, //0x10 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::parameter, 7, 4}, //0x02 + {&Dsp1::subjectiveA, 3, 3}, //0x03 + {&Dsp1::gyrate, 6, 3}, //0x14 + {&Dsp1::attitudeA, 4, 0}, //0x01 + {&Dsp1::project, 3, 3}, //0x06 + {&Dsp1::memoryDump, 1, 1024}, //0x1f + {&Dsp1::range2, 4, 1}, //0x38 + {&Dsp1::objectiveA, 3, 3}, //0x0d + {0, 0, 0}, // 0x1a; the chip freezes + {&Dsp1::scalarA, 3, 1}, //0x0b + {&Dsp1::polar, 6, 3}, //0x1c + {&Dsp1::objectiveA, 3, 3}, //0x0d + {&Dsp1::target, 2, 2}, //0x0e + {&Dsp1::memoryDump, 1, 1024}, //0x1f +}; + +////////////////////////////////////////////////////////////////// + +void Dsp1::memoryTest(int16 *input, int16 *output) +{ + int16& Size = input[0]; + int16& Result = output[0]; + + Result = 0x0000; +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::memoryDump(int16 *input, int16 *output) +{ + memcpy(output, DataRom, 1024); +} + +////////////////////////////////////////////////////////////////// + +void Dsp1::memorySize(int16 *input, int16 *output) +{ + int16& Size = output[0]; + + Size = 0x0100; +} + +////////////////////////////////////////////////////////////////// + +// 16-bit multiplication + +void Dsp1::multiply(int16 *input, int16 *output) +{ + int16& Multiplicand = input[0]; + int16& Multiplier = input[1]; + int16& Product = output[0]; + + Product = Multiplicand * Multiplier >> 15; +} + +////////////////////////////////////////////////////////////////// + +// 16-bit multiplication. 'Alternative' method. Can anyone check this carefully? + +void Dsp1::multiply2(int16 *input, int16 *output) +{ + int16& Multiplicand = input[0]; + int16& Multiplier = input[1]; + int16& Product = output[0]; + + Product = (Multiplicand * Multiplier >> 15)+1; +} + +////////////////////////////////////////////////////////////////// + +// This command determines the inverse of a floating point decimal number. + +void Dsp1::inverse(int16 *input, int16 *output) +{ + int16& Coefficient = input[0]; + int16& Exponent = input[1]; + int16& iCoefficient = output[0]; + int16& iExponent = output[1]; + + inverse(Coefficient, Exponent, iCoefficient, iExponent); +} + +////////////////////////////////////////////////////////////////// + +// Vector component calculation. Determines the X and Y components for a +// two-dimensional vector whose size and direction is known. +// Y = Radius * sin(Angle) +// X = Radius * cos(Angle) + +void Dsp1::triangle(int16 *input, int16 *output) +{ + int16& Angle = input[0]; + int16& Radius = input[1]; + int16& Y = output[0]; + int16& X = output[1]; + + Y = sin(Angle) * Radius >> 15; + X = cos(Angle) * Radius >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Determines the squared norm of a vector (X,Y,Z) +// The output is Radius = X^2+Y^2+Z^2 (double integer) + +void Dsp1::radius(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& RadiusLow = output[0]; + int16& RadiusHigh = output[1]; + + int32 Radius; + + Radius = (X * X + Y * Y + Z * Z) << 1; + RadiusLow = static_cast(Radius); + RadiusHigh = static_cast(Radius>>16); +} + +////////////////////////////////////////////////////////////////// + +// Vector size comparison. This command compares the size of the vector (X,Y,Z) and the distance (R) +// from a particular point, and so may be used to determine if a point is within the sphere or radius R. +// The output is D = X^2+Y^2+Z^2-R^2 + +void Dsp1::range(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& Radius = input[3]; + int16& Range = output[0]; + + Range = (X * X + Y * Y + Z * Z - Radius * Radius) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Vector size comparison. 'Alternative' method. + +void Dsp1::range2(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& Radius = input[3]; + int16& Range = output[0]; + + Range = ((X * X + Y * Y + Z * Z - Radius * Radius) >> 15) + 1; +} + +////////////////////////////////////////////////////////////////// + +// This command calculates the norm of a (X,Y,Z) vector, or the distance from +// the point (X,Y,Z) to (0,0,0), as you prefer to see it. +// Distance = sqrt(X^2+Y^2+Z^2) +// The square root of a number 'a' is calculated by doing this: you +// write 'a' as b*2^2n, with 'b' between 1/4 and 1; then, you calculate +// c=sqrt(b) by using lineal interpolation between points of a +// look-up table and, finally, you output the result as c*2^n. + +void Dsp1::distance(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& Distance = output[0]; + + int32 Radius = X * X + Y * Y + Z * Z; + + if (Radius == 0) Distance = 0; + else + { + int16 C, E; + normalizeDouble(Radius, C, E); + if (E & 1) C = C * 0x4000 >> 15; + + int16 Pos = C * 0x0040 >> 15; + + int16 Node1 = DataRom[0x00d5 + Pos]; + int16 Node2 = DataRom[0x00d6 + Pos]; + + Distance = ((Node2 - Node1) * (C & 0x1ff) >> 9) + Node1; + +#if DSP1_VERSION < 0x0102 + if (Pos & 1) Distance -= (Node2 - Node1); +#endif + Distance >>= (E >> 1); + } +} + +////////////////////////////////////////////////////////////////// + +// Determines the (X2, Y2) coordinates obtained by rotating (X1, Y1) +// clockwise for an angle 'Angle'. The official documentation says +// 'counterclockwise', but it's obviously wrong (surprise! :P) +// +// In matrix notation: +// |X2| |cos(Angle) sin(Angle)| |X1| +// | | = | | | | +// |Y2| |-sin(Angle cos(Angle)| |Y1| + +void Dsp1::rotate(int16 *input, int16 *output) +{ + int16& Angle = input[0]; + int16& X1 = input[1]; + int16& Y1 = input[2]; + int16& X2 = output[0]; + int16& Y2 = output[1]; + + X2 = (Y1 * sin(Angle) >> 15) + (X1 * cos(Angle) >> 15); + Y2 = (Y1 * cos(Angle) >> 15) - (X1 * sin(Angle) >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Calculate the coordinates (X2, Y2, Z2) obtained when rotating (X1, Y1, Z1) +// three-dimensionally. Rotation is done in the order of Az around the Z axis, +// Ay around the Y axis and Ax around the X axis. As occur with the "attitude" commands +// (see comments in the "gyrate" command), this doesn't match what explained in +// the official documentation, but it's coherent with what it is done in the "attitude" +// command (but not with the "gyrate" command). +// +// In matrix notation: +// |X2| |1 0 0 | |cosRy 0 -sinRy| | cosRz sinRz 0| |X1| +// |Y2| = |0 cosRx sinRx| | 0 1 0 | |-sinRz cosRz 0| |Y1| +// |Z2| |0 -sinRx cosRx| |sinRy 0 cosRy| | 0 0 1| |Z1| + +void Dsp1::polar(int16 *input, int16 *output) +{ + int16& Az = input[0]; + int16& Ay = input[1]; + int16& Ax = input[2]; + int16& X1 = input[3]; + int16& Y1 = input[4]; + int16& Z1 = input[5]; + int16& X2 = output[0]; + int16& Y2 = output[1]; + int16& Z2 = output[2]; + + int16 X, Y, Z; + + // Rotate Around Z + X = (Y1 * sin(Az) >> 15) + (X1 * cos(Az) >> 15); + Y = (Y1 * cos(Az) >> 15) - (X1 * sin(Az) >> 15); + X1 = X; Y1 = Y; + + // Rotate Around Y + Z = (X1 * sin(Ay) >> 15) + (Z1 * cos(Ay) >> 15); + X = (X1 * cos(Ay) >> 15) - (Z1 * sin(Ay) >> 15); + X2 = X; Z1 = Z; + + // Rotate Around X + Y = (Z1 * sin(Ax) >> 15) + (Y1 * cos(Ax) >> 15); + Z = (Z1 * cos(Ax) >> 15) - (Y1 * sin(Ax) >> 15); + Y2 = Y; Z2 = Z; +} + +////////////////////////////////////////////////////////////////// + +// Set up the elements of an "attitude matrix" (there are other ones): +// S | cosRz sinRz 0| |cosRy 0 -sinRy| |1 0 0 | +// MatrixA = - |-sinRz cosRz 0| | 0 1 0 | |0 cosRx sinRx| +// 2 | 0 0 1| |sinRy 0 cosRy| |0 -sinRx cosRx| +// This matrix is thought to be used within the following framework: +// let's suppose we define positive rotations around a system of orthogonal axes in this manner: +// a rotation of +90 degrees around axis3 converts axis2 into axis1 +// a rotation of +90 degrees around axis2 converts axis1 into axis3 +// a rotation of +90 degrees around axis1 converts axis3 into axis2 +// and let's suppose that we have defined a new orthonormal axes system (FLU) +// by doing the following operations about the standard one (XYZ): +// first rotating the XYZ system around Z by an angle Rz (obtaining X'Y'Z'), +// then rotating the resulting system around Y by an angle Ry (obtaining X''Y''Z'') +// and, finally, rotating the resulting system around X by an angle Rx (obtaining FLU) +// This FLU (forward/left/up) system represents an "attitude" and, then, the matrix here defined +// is the change of coordinates matrix that transform coordinates in the FLU +// system (the "object coordinates") into the standard XYZ system (the "global coordinates"), +// multiplied by a scale factor S/2, that is: +// |x| S |f| +// |y| * - = MatrixA * |l| +// |z| 2 |u| +// In a similar way, if we use the transpose of the matrix, we can transform global coordinates +// into object coordinates: +// |f| S |x| +// |l| * - = MatrixA_transposed * |y| +// |u| 2 |z| +// +// input[0]: S +// input[1]: Rz +// input[2]: Ry +// input[3]: Rx + +void Dsp1::attitudeA(int16 *input, int16 *output) +{ + int16& S = input[0]; + int16& Rz = input[1]; + int16& Ry = input[2]; + int16& Rx = input[3]; + + int16 SinRz = sin(Rz); + int16 CosRz = cos(Rz); + int16 SinRy = sin(Ry); + int16 CosRy = cos(Ry); + int16 SinRx = sin(Rx); + int16 CosRx = cos(Rx); + + S >>= 1; + + shared.MatrixA[0][0] = (S * CosRz >> 15) * CosRy >> 15; + shared.MatrixA[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixA[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixA[1][0] = -((S * SinRz >> 15) * CosRy >> 15); + shared.MatrixA[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixA[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixA[2][0] = S * SinRy >> 15; + shared.MatrixA[2][1] = -((S * SinRx >> 15) * CosRy >> 15); + shared.MatrixA[2][2] = (S * CosRx >> 15) * CosRy >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'attitudeA', but with a difference attitude matrix (matrixB) + +void Dsp1::attitudeB(int16 *input, int16 *output) +{ + int16& S = input[0]; + int16& Rz = input[1]; + int16& Ry = input[2]; + int16& Rx = input[3]; + + int16 SinRz = sin(Rz); + int16 CosRz = cos(Rz); + int16 SinRy = sin(Ry); + int16 CosRy = cos(Ry); + int16 SinRx = sin(Rx); + int16 CosRx = cos(Rx); + + S >>= 1; + + shared.MatrixB[0][0] = (S * CosRz >> 15) * CosRy >> 15; + shared.MatrixB[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixB[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixB[1][0] = -((S * SinRz >> 15) * CosRy >> 15); + shared.MatrixB[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixB[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixB[2][0] = S * SinRy >> 15; + shared.MatrixB[2][1] = -((S * SinRx >> 15) * CosRy >> 15); + shared.MatrixB[2][2] = (S * CosRx >> 15) * CosRy >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'attitudeA', but with a difference attitude matrix (matrixC) + +void Dsp1::attitudeC(int16 *input, int16 *output) +{ + int16& S = input[0]; + int16& Rz = input[1]; + int16& Ry = input[2]; + int16& Rx = input[3]; + + int16 SinRz = sin(Rz); + int16 CosRz = cos(Rz); + int16 SinRy = sin(Ry); + int16 CosRy = cos(Ry); + int16 SinRx = sin(Rx); + int16 CosRx = cos(Rx); + + S >>= 1; + + shared.MatrixC[0][0] = (S * CosRz >> 15) * CosRy >> 15; + shared.MatrixC[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixC[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixC[1][0] = -((S * SinRz >> 15) * CosRy >> 15); + shared.MatrixC[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15); + shared.MatrixC[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15); + + shared.MatrixC[2][0] = S * SinRy >> 15; + shared.MatrixC[2][1] = -((S * SinRx >> 15) * CosRy >> 15); + shared.MatrixC[2][2] = (S * CosRx >> 15) * CosRy >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Convert global coordinates (X,Y,Z) to object coordinates (F,L,U) +// See the comment in "attitudeA" for a explanation about the calculation. +// +// input[0]: X ; input[1]: Y ; input[2]: Z +// output[0]: F ; output[1]: L ; output[2]: U + +void Dsp1::objectiveA(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& F = output[0]; + int16& L = output[1]; + int16& U = output[2]; + + F = (shared.MatrixA[0][0] * X >> 15) + (shared.MatrixA[1][0] * Y >> 15) + (shared.MatrixA[2][0] * Z >> 15); + L = (shared.MatrixA[0][1] * X >> 15) + (shared.MatrixA[1][1] * Y >> 15) + (shared.MatrixA[2][1] * Z >> 15); + U = (shared.MatrixA[0][2] * X >> 15) + (shared.MatrixA[1][2] * Y >> 15) + (shared.MatrixA[2][2] * Z >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'objectiveA', but for the 'B' attitude + +void Dsp1::objectiveB(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& F = output[0]; + int16& L = output[1]; + int16& U = output[2]; + + F = (shared.MatrixB[0][0] * X >> 15) + (shared.MatrixB[1][0] * Y >> 15) + (shared.MatrixB[2][0] * Z >> 15); + L = (shared.MatrixB[0][1] * X >> 15) + (shared.MatrixB[1][1] * Y >> 15) + (shared.MatrixB[2][1] * Z >> 15); + U = (shared.MatrixB[0][2] * X >> 15) + (shared.MatrixB[1][2] * Y >> 15) + (shared.MatrixB[2][2] * Z >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'objectiveA', but for the 'C' attitude + +void Dsp1::objectiveC(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& F = output[0]; + int16& L = output[1]; + int16& U = output[2]; + + F = (shared.MatrixC[0][0] * X >> 15) + (shared.MatrixC[1][0] * Y >> 15) + (shared.MatrixC[2][0] * Z >> 15); + L = (shared.MatrixC[0][1] * X >> 15) + (shared.MatrixC[1][1] * Y >> 15) + (shared.MatrixC[2][1] * Z >> 15); + U = (shared.MatrixC[0][2] * X >> 15) + (shared.MatrixC[1][2] * Y >> 15) + (shared.MatrixC[2][2] * Z >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Convert object coordinates (F,L,U) to object coordinates (X,Y,Z) +// See the comment in "attitudeA" for a explanation about the calculation. +// +// input[0]: F ; input[1]: L ; input[2]: U +// output[0]: X ; output[1]: Y ; output[2]: Z + +void Dsp1::subjectiveA(int16 *input, int16 *output) +{ + int16& F = input[0]; + int16& L = input[1]; + int16& U = input[2]; + int16& X = output[0]; + int16& Y = output[1]; + int16& Z = output[2]; + + X = (shared.MatrixA[0][0] * F >> 15) + (shared.MatrixA[0][1] * L >> 15) + (shared.MatrixA[0][2] * U >> 15); + Y = (shared.MatrixA[1][0] * F >> 15) + (shared.MatrixA[1][1] * L >> 15) + (shared.MatrixA[1][2] * U >> 15); + Z = (shared.MatrixA[2][0] * F >> 15) + (shared.MatrixA[2][1] * L >> 15) + (shared.MatrixA[2][2] * U >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'subjectiveA', but for the 'B' attitude + +void Dsp1::subjectiveB(int16 *input, int16 *output) +{ + int16& F = input[0]; + int16& L = input[1]; + int16& U = input[2]; + int16& X = output[0]; + int16& Y = output[1]; + int16& Z = output[2]; + + X = (shared.MatrixB[0][0] * F >> 15) + (shared.MatrixB[0][1] * L >> 15) + (shared.MatrixB[0][2] * U >> 15); + Y = (shared.MatrixB[1][0] * F >> 15) + (shared.MatrixB[1][1] * L >> 15) + (shared.MatrixB[1][2] * U >> 15); + Z = (shared.MatrixB[2][0] * F >> 15) + (shared.MatrixB[2][1] * L >> 15) + (shared.MatrixB[2][2] * U >> 15); +} + +////////////////////////////////////////////////////////////////// + +// Same than 'subjectiveA', but for the 'C' attitude + +void Dsp1::subjectiveC(int16 *input, int16 *output) +{ + int16& F = input[0]; + int16& L = input[1]; + int16& U = input[2]; + int16& X = output[0]; + int16& Y = output[1]; + int16& Z = output[2]; + + X = (shared.MatrixC[0][0] * F >> 15) + (shared.MatrixC[0][1] * L >> 15) + (shared.MatrixC[0][2] * U >> 15); + Y = (shared.MatrixC[1][0] * F >> 15) + (shared.MatrixC[1][1] * L >> 15) + (shared.MatrixC[1][2] * U >> 15); + Z = (shared.MatrixC[2][0] * F >> 15) + (shared.MatrixC[2][1] * L >> 15) + (shared.MatrixC[2][2] * U >> 15); +} + +////////////////////////////////////////////////////////////////// + +// This command calculates the inner product (S) of a vector (X,Y,Z) and +// the first column of MatrixA. It should be noted that that first column +// represent the global coordinates of an unity vector in the forward +// direction in the object coordinate system (coordinates (1,0,0) in the FLU +// axes system). +// +// input[0]: X ; input[1]: Y ; input[2]: Z +// output[0]: S + +void Dsp1::scalarA(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& S = output[0]; + + S = (X * shared.MatrixA[0][0] + Y * shared.MatrixA[1][0] + Z * shared.MatrixA[2][0]) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'scalarA', but for the 'B' attitude + +void Dsp1::scalarB(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& S = output[0]; + + S = (X * shared.MatrixB[0][0] + Y * shared.MatrixB[1][0] + Z * shared.MatrixB[2][0]) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'scalarA', but for the 'C' attitude + +void Dsp1::scalarC(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& S = output[0]; + + S = (X * shared.MatrixC[0][0] + Y * shared.MatrixC[1][0] + Z * shared.MatrixC[2][0]) >> 15; +} + +////////////////////////////////////////////////////////////////// + +// This command determines the final attitude angles after the body with attitude angles (Ax, Ay, Az) with +// respect to the global coordinates is rotated by the minor angular displacements (DeltaF, DeltaL, DeltaU). +// It means that the XYZ axes are rotated by (Ax, Ay, Az) to obtain the FLU axes and, then, these +// are rotated by (DeltaF, DeltaL, DeltaU). The command calculates and return the new FLU angles respect to the +// XYZ system (Rx, Ry, Rz) +// The formulae are: +// Rx = Ax + (DeltaU*sin(Ay)+DeltaF*cos(Ay)) +// Ry = Ay + DeltaL - tan(Ax)*(DeltaU*cos(Ay)+DeltaF*sin(Ay)) +// Rz = Az + sec(Ax)*(DeltaU*cos(Ay)-DeltaF*sin(Ay)) +// +// Now the discussion: according to the official documentation, as described in various commands, you pass from +// XYZ to FLU by doing the rotations in the order Y, X, Z. In this command, the formulae are coherent with the +// fact that Y is the first axis to do a rotation around it. However, in the "attitude" command, while the official +// document describe it that way, we have discovered, when reverse engineering the command, that the calculated +// matrix do the rotation around Y in the second place. This incoherent behaviour of various commands is, in my +// opinion, a pretty severe implementation error. However, if you only use small "minor displacements", the error term +// introduced by that incoherence should be almost negligible. + +void Dsp1::gyrate(int16 *input, int16 *output) +{ + int16& Az = input[0]; + int16& Ax = input[1]; + int16& Ay = input[2]; + int16& U = input[3]; + int16& F = input[4]; + int16& L = input[5]; + int16& Rz = output[0]; + int16& Rx = output[1]; + int16& Ry = output[2]; + + int16 CSec, ESec, CSin, C, E; + int16 SinAy = sin(Ay); + int16 CosAy = cos(Ay); + + inverse(cos(Ax), 0, CSec, ESec); + + // Rotation Around Z + normalizeDouble(U * CosAy - F * SinAy, C, E); + + E = ESec - E; + + normalize(C * CSec >> 15, C, E); + + Rz = Az + denormalizeAndClip(C, E); + + // Rotation Around X + Rx = Ax + (U * SinAy >> 15) + (F * CosAy >> 15); + + // Rotation Around Y + normalizeDouble(U * CosAy + F * SinAy, C, E); + + E = ESec - E; + + normalize(sin(Ax), CSin, E); + + normalize(-(C * (CSec * CSin >> 15) >> 15), C, E); + + Ry = Ay + denormalizeAndClip(C, E) + L; +} + +////////////////////////////////////////////////////////////////// + +const int16 Dsp1::MaxAZS_Exp[16] = { + 0x38b4, 0x38b7, 0x38ba, 0x38be, 0x38c0, 0x38c4, 0x38c7, 0x38ca, + 0x38ce, 0x38d0, 0x38d4, 0x38d7, 0x38da, 0x38dd, 0x38e0, 0x38e4 +}; + +////////////////////////////////////////////////////////////////// + + +// Set-up the projection framework. Besides returning some values, it store in RAM some values that +// will be used by the other three projection commands (raster, target an project) +// Input: +// (Fx, Fy, Fz)-> coordinates of base point (global coordinates) +// Lfe-> distance between the base point and the viewpoint (center of projection) +// Les-> distance between the base point and the screen +// Aas-> azimuth angle (0 degrees is east; 90 degrees is north) +// Azs-> zenith angle (0 degrees is zenith) +// Output: +// Vof-> raster line of imaginary center (whatever it means ;) ) +// Vva-> raster line representing the horizon line +// (Cx, Cy)-> coordinates of the projection of the center of the screen over the ground (ground coordinates) + +void Dsp1::parameter(int16 *input, int16 *output) +{ + int16& Fx = input[0]; + int16& Fy = input[1]; + int16& Fz = input[2]; + int16& Lfe = input[3]; + int16& Les = input[4]; + int16& Aas = input[5]; + int16& Azs = input[6]; + int16& Vof = output[0]; + int16& Vva = output[1]; + int16& Cx = output[2]; + int16& Cy = output[3]; + + int16 CSec, C, E; + int16 LfeNx, LfeNy, LfeNz; + int16 LesNx, LesNy, LesNz; + + // Copy Zenith angle for clipping + int16 AZS = Azs; + + // Store Les and his coefficient and exponent when normalized + shared.Les = Les; + shared.E_Les=0; + normalize(Les, shared.C_Les, shared.E_Les); + + // Store Sine and Cosine of Azimuth and Zenith angle + shared.SinAas = sin(Aas); + shared.CosAas = cos(Aas); + shared.SinAzs = sin(Azs); + shared.CosAzs = cos(Azs); + + // normal vector to the screen (norm 1, points toward the center of projection) + shared.Nx = shared.SinAzs * -shared.SinAas >> 15; + shared.Ny = shared.SinAzs * shared.CosAas >> 15; + shared.Nz = shared.CosAzs * 0x7fff >> 15; + + // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen) + shared.Hx = shared.CosAas*0x7fff>>15; + shared.Hy = shared.SinAas*0x7fff>>15; + + // vertical vector of the screen (norm 1, points toward the top of the screen) + shared.Vx = shared.CosAzs*-shared.SinAas>>15; + shared.Vy = shared.CosAzs*shared.CosAas>>15; + shared.Vz = -shared.SinAzs*0x7fff>>15; + + LfeNx = Lfe*shared.Nx>>15; + LfeNy = Lfe*shared.Ny>>15; + LfeNz = Lfe*shared.Nz>>15; + + // Center of Projection + shared.CentreX = Fx+LfeNx; + shared.CentreY = Fy+LfeNy; + shared.CentreZ = Fz+LfeNz; + + LesNx = Les*shared.Nx>>15; + LesNy = Les*shared.Ny>>15; + LesNz = Les*shared.Nz>>15; + + // center of the screen (global coordinates) + shared.Gx=shared.CentreX-LesNx; + shared.Gy=shared.CentreY-LesNy; + shared.Gz=shared.CentreZ-LesNz; + + + E = 0; + normalize(shared.CentreZ, C, E); + + shared.CentreZ_C = C; + shared.CentreZ_E = E; + + // Determine clip boundary and clip Zenith angle if necessary + // (Why to clip? Maybe to avoid the screen can only show sky with no ground? Only a guess...) + int16 MaxAZS = MaxAZS_Exp[-E]; + + if (AZS < 0) { + MaxAZS = -MaxAZS; + if (AZS < MaxAZS + 1) AZS = MaxAZS + 1; + } else { + if (AZS > MaxAZS) AZS = MaxAZS; + } + + // Store Sine and Cosine of clipped Zenith angle + shared.SinAZS = sin(AZS); + shared.CosAZS = cos(AZS); + + // calculate the separation of (cx, cy) from the projection of + // the 'centre of projection' over the ground... (CentreZ*tg(AZS)) + inverse(shared.CosAZS, 0, shared.SecAZS_C1, shared.SecAZS_E1); + normalize(C * shared.SecAZS_C1 >> 15, C, E); + E += shared.SecAZS_E1; + C = denormalizeAndClip(C, E) * shared.SinAZS >> 15; + + // ... and then take into account the position of the centre of + // projection and the azimuth angle + shared.CentreX += C * shared.SinAas >> 15; + shared.CentreY -= C * shared.CosAas >> 15; + + Cx = shared.CentreX; + Cy = shared.CentreY; + + // Raster number of imaginary center and horizontal line + Vof = 0; + + if ((Azs != AZS) || (Azs == MaxAZS)) + { + // correct vof and vva when Azs is outside the 'non-clipping interval' + // we have only some few Taylor coefficients, so we cannot guess which ones + // are the approximated functions and, what is worse, we don't know why + // the own clipping stuff (and, particularly, this correction) is done + if (Azs == -32768) Azs = -32767; + + C = Azs - MaxAZS; + if (C >= 0) C--; + int16 Aux = ~(C << 2); + + // Vof += x+(1/3)*x^3, where x ranges from 0 to PI/4 when Azs-MaxAZS goes from 0 to 0x2000 + C = Aux * DataRom[0x0328] >> 15; + C = (C * Aux >> 15) + DataRom[0x0327]; + Vof -= (C * Aux >> 15) * Les >> 15; + + // CosAZS *= 1+(1/2)*x^2+(5/24)*x^24, where x ranges from 0 to PI/4 when Azs-MaxAZS goes from 0 to 0x2000 + C = Aux * Aux >> 15; + Aux = (C * DataRom[0x0324] >> 15) + DataRom[0x0325]; + shared.CosAZS += (C * Aux >> 15) * shared.CosAZS >> 15; + } + + // vertical offset of the screen with regard to the horizontal plane + // containing the centre of projection + shared.VOffset = Les * shared.CosAZS >> 15; + + // The horizon line (the line in the screen that is crossed by the horizon plane + // -the horizontal plane containing the 'centre of projection'-), + // will be at distance Les*cotg(AZS) from the centre of the screen. This is difficult + // to explain but easily seen in a graph. To better see it, consider it in this way: + // Les*tg(AZS-90), draw some lines and apply basic trigonometry. ;) + inverse(shared.SinAZS, 0, CSec, E); + normalize(shared.VOffset, C, E); + normalize(C * CSec >> 15, C, E); + + if (C == -32768) { C >>= 1; E++; } + + Vva = denormalizeAndClip(-C, E); + + // Store Secant of clipped Zenith angle + inverse(shared.CosAZS, 0, shared.SecAZS_C2, shared.SecAZS_E2); +} + +////////////////////////////////////////////////////////////////// + +// Calculates the matrix which transform an object situated on a raster line (Vs) into +// his projection over the ground. The modified SecAZS is used here, so +// i don't understand the fine details, but, basically, it's done +// this way: The vertical offset between the point of projection and the +// raster line is calculated (Vs*SinAzs>>15)+VOffset, then the height of +// the center of projection is measured in that units (*CentreZ_C). If, now +// you consider the "reference case" (center of projection at an unit of height), +// the projection of a thin strip containing the raster line will have the same +// width (as the raster line would be on the ground in this case, but will suffer a +// change of scale in height (as the ground and the vertical axis would form an angle of 180-Azs degrees). +// This scale factor, when the angle 'center of screen-center of projection-raster line' is small, +// can be aproximated by the one of the center of the screen, 1/cos(Azs).(**) (Here is when it's used +// SecAZS). By last, you have to consider the effect of the azimuth angle Aas, and you are done. +// +// Using matrix notation: +// |A B| Centre_ZS | cos(Aas) -sin(Aas)| |1 0| +// ProjectionMatrix = | | = ----------- * | | * | | +// |C D| Vs*sin(Azs) |sin(Aas) cos(Aas)| |0 sec(Azs)| +// +// (**) +// If Les=1, the vertical offset between the center +// of projection and the center of the screen is Cos(Azs); then, if the vertical +// offset is 1, the ratio of the projection over the ground respect to the +// line on the screen is 1/cos(Azs). + +void Dsp1::raster(int16 *input, int16 *output) +{ + int16& Vs = input[0]; + int16& An = output[0]; + int16& Bn = output[1]; + int16& Cn = output[2]; + int16& Dn = output[3]; + + int16 C, E, C1, E1; + + inverse((Vs * shared.SinAzs >> 15) + shared.VOffset, 7, C, E); + + E += shared.CentreZ_E; + C1 = C * shared.CentreZ_C >> 15; + + E1 = E + shared.SecAZS_E2; + + normalize(C1, C, E); + C = denormalizeAndClip(C, E); + + An = C * shared.CosAas >> 15; + Cn = C * shared.SinAas >> 15; + + normalize(C1 * shared.SecAZS_C2 >> 15, C, E1); + C = denormalizeAndClip(C, E1); + + Bn = C * -shared.SinAas >> 15; + Dn = C * shared.CosAas >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Calculate the projection over the ground of a selected point of screen +// It simply apply the projection matrix described in the "Raster" command +// to the vector (H,V) transposed, and add the result to the position of +// the centre of projection. +// The only special point to take into account is the directions on the screen: +// H is positive rightward, but V is positive downward; this is why +// the signs take that configuration + +void Dsp1::target(int16 *input, int16 *output) +{ + int16& H = input[0]; + int16& V = input[1]; + int16& X = output[0]; + int16& Y = output[1]; + + int16 C, E, C1, E1; + + inverse((V * shared.SinAzs >> 15) + shared.VOffset, 8, C, E); + + E += shared.CentreZ_E; + C1 = C * shared.CentreZ_C >> 15; + + E1 = E + shared.SecAZS_E1; + + H <<= 8; + normalize(C1, C, E); + C = denormalizeAndClip(C, E) * H >> 15; + + X = shared.CentreX + (C * shared.CosAas >> 15); + Y = shared.CentreY - (C * shared.SinAas >> 15); + + V <<= 8; + normalize(C1 * shared.SecAZS_C1 >> 15, C, E1); + C = denormalizeAndClip(C, E1) * V >> 15; + + X += C * -shared.SinAas >> 15; + Y += C * shared.CosAas >> 15; +} + +////////////////////////////////////////////////////////////////// + +// Calculation of the projection over the screen (H,V) of an object (X,Y,Z) and his +// 'enlargement ratio' (M). The positive directions on the screen are as described +// in the targe command. M is scaled down by 2^-7, that is, M==0x0100 means ratio 1:1 + + void Dsp1::project(int16 *input, int16 *output) +{ + int16& X = input[0]; + int16& Y = input[1]; + int16& Z = input[2]; + int16& H = output[0]; + int16& V = output[1]; + int16& M = output[2]; + + int32 aux, aux4; + int16 E, E2, E3, E4, E5, refE, E6, E7; + int16 C2, C4, C6, C8, C9, C10, C11, C12, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26; + int16 Px, Py, Pz; + + E4=E3=E2=E=E5=0; + + normalizeDouble(int32(X)-shared.Gx, Px, E4); + normalizeDouble(int32(Y)-shared.Gy, Py, E); + normalizeDouble(int32(Z)-shared.Gz, Pz, E3); + Px>>=1; E4--; // to avoid overflows when calculating the scalar products + Py>>=1; E--; + Pz>>=1; E3--; + + refE = (E>15); + C8=- (Py*shared.Ny>>15); + C9=- (Pz*shared.Nz>>15); + C12=C11+C8+C9; // this cannot overflow! + + aux4=C12; // de-normalization with 32-bits arithmetic + refE = 16-refE; // refE can be up to 3 + if (refE>=0) + aux4 <<=(refE); + else + aux4 >>=-(refE); + if (aux4==-1) aux4 = 0; // why? + aux4>>=1; + + aux = static_cast(shared.Les) + aux4; // Les - the scalar product of P with the normal vector of the screen + normalizeDouble(aux, C10, E2); + E2 = 15-E2; + + inverse(C10, 0, C4, E4); + C2=C4*shared.C_Les>>15; // scale factor + + + // H + E7=0; + C16= (Px*shared.Hx>>15); + C20= (Py*shared.Hy>>15); + C17=C16+C20; // scalar product of P with the normalized horizontal vector of the screen... + + C18=C17*C2>>15; // ... multiplied by the scale factor + normalize(C18, C19, E7); + H=denormalizeAndClip(C19, shared.E_Les-E2+refE+E7); + + // V + E6=0; + C21 = Px*shared.Vx>>15; + C22 = Py*shared.Vy>>15; + C23 = Pz*shared.Vz>>15; + C24=C21+C22+C23; // scalar product of P with the normalized vertical vector of the screen... + + C26=C24*C2>>15; // ... multiplied by the scale factor + normalize(C26, C25, E6); + V=denormalizeAndClip(C25, shared.E_Les-E2+refE+E6); + + // M + normalize(C2, C6, E4); + M=denormalizeAndClip(C6, E4+shared.E_Les-E2-7); // M is the scale factor divided by 2^7 +} + +////////////////////////////////////////////////////////////////// + +// Calculate the sine of the input parameter +// this is done by linear interpolation between +// the points of a look-up table + +int16 Dsp1::sin(int16 Angle) +{ + if (Angle < 0) { + if (Angle == -32768) return 0; + return -sin(-Angle); + } + int32 S = SinTable[Angle >> 8] + (MulTable[Angle & 0xff] * SinTable[0x40 + (Angle >> 8)] >> 15); + if (S > 32767) S = 32767; + return (int16) S; +} + +////////////////////////////////////////////////////////////////// + +// Calculate the cosine of the input parameter. +// It's used the same method than in sin(int16) + +int16 Dsp1::cos(int16 Angle) +{ + if (Angle < 0) { + if (Angle == -32768) return -32768; + Angle = -Angle; + } + int32 S = SinTable[0x40 + (Angle >> 8)] - (MulTable[Angle & 0xff] * SinTable[Angle >> 8] >> 15); + if (S < -32768) S = -32767; + return (int16) S; +} + +////////////////////////////////////////////////////////////////// + +// Determines the inverse of a floating point decimal number +// iCoefficient*2^iExponent = 1/(Coefficient*2^Exponent), with the output +// normalized (iCoefficient represents a number whose absolute value is between 1/2 and 1) +// To invert 'Coefficient' a first initial guess is taken from a look-up table +// and, then, two iterations of the Newton method (applied to the function +// f(x)=1/(2*x)-Coefficient) are done. This results in a close approximation (iCoefficient) to a number 'y' +// that verify Coefficient*y=1/2. This is why you have to correct the exponent by one +// unit at the end. + +void Dsp1::inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent) +{ + // Step One: Division by Zero + if (Coefficient == 0x0000) + { + iCoefficient = 0x7fff; + iExponent = 0x002f; + } + else + { + int16 Sign = 1; + + // Step Two: Remove Sign + if (Coefficient < 0) + { + if (Coefficient < -32767) Coefficient = -32767; + Coefficient = -Coefficient; + Sign = -1; + } + + // Step Three: Normalize + while (Coefficient < 0x4000) + { + Coefficient <<= 1; + Exponent--; + } + + // Step Four: Special Case + if (Coefficient == 0x4000) + if (Sign == 1) iCoefficient = 0x7fff; + else { + iCoefficient = -0x4000; + Exponent--; + } + else { + // Step Five: Initial Guess + int16 i = DataRom[((Coefficient - 0x4000) >> 7) + 0x0065]; + + // Step Six: Iterate Newton's Method + i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; + i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; + + iCoefficient = i * Sign; + } + + iExponent = 1 - Exponent; + } +} + +////////////////////////////////////////////////////////////////// + +int16 Dsp1::denormalizeAndClip(int16 C, int16 E) +{ + if (E > 0) { + if (C > 0) return 32767; else if (C < 0) return -32767; + } else { + if (E < 0) return C * DataRom[0x0031 + E] >> 15; + } + return C; +} + +////////////////////////////////////////////////////////////////// + +// Normalize the input number (m), understood as ranging from -1 to 1, +// to the form: Coefficient*2^Exponent, +// where the absolute value of Coefficient is >= 1/2 +// (Coefficient>=0x4000 or Coefficient <= (int16)0xc001) + +void Dsp1::normalize(int16 m, int16 &Coefficient, int16 &Exponent) +{ + int16 i = 0x4000; + int16 e = 0; + + if (m < 0) + while ((m & i) && i) + { + i >>= 1; + e++; + } + else + while (!(m & i) && i) + { + i >>= 1; + e++; + } + + if (e > 0) + Coefficient = m * DataRom[0x21 + e] << 1; + else + Coefficient = m; + + Exponent -= e; +} + +////////////////////////////////////////////////////////////////// + +// Same than 'normalize' but with an int32 input + +void Dsp1::normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent) +{ + int16 n = Product & 0x7fff; + int16 m = Product >> 15; + int16 i = 0x4000; + int16 e = 0; + + if (m < 0) + while ((m & i) && i) + { + i >>= 1; + e++; + } + else + while (!(m & i) && i) + { + i >>= 1; + e++; + } + + if (e > 0) + { + Coefficient = m * DataRom[0x0021 + e] << 1; + + if (e < 15) + Coefficient += n * DataRom[0x0040 - e] >> 15; + else + { + i = 0x4000; + + if (m < 0) + while ((n & i) && i) + { + i >>= 1; + e++; + } + else + while (!(n & i) && i) + { + i >>= 1; + e++; + } + + if (e > 15) + Coefficient = n * DataRom[0x0012 + e] << 1; + else + Coefficient += n; + } + } + else + Coefficient = m; + + Exponent = e; +} + +////////////////////////////////////////////////////////////////// + +// Shift to the right + +int16 Dsp1::shiftR(int16 C, int16 E) +{ + return (C * DataRom[0x0031 + E] >> 15); +} + +////////////////////////////////////////////////////////////////// + +// this is, indeed, only part of the Data ROM +const int16 Dsp1::SinTable[256] = { + 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, + 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, + 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, + 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, + 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, + 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, + 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, + 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, + 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, + 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, + 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, + 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, + 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, + 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, + 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, + 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, + -0x0000, -0x0324, -0x0647, -0x096a, -0x0c8b, -0x0fab, -0x12c8, -0x15e2, + -0x18f8, -0x1c0b, -0x1f19, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11, + -0x30fb, -0x33de, -0x36ba, -0x398c, -0x3c56, -0x3f17, -0x41ce, -0x447a, + -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842, + -0x5a82, -0x5cb4, -0x5ed7, -0x60ec, -0x62f2, -0x64e8, -0x66cf, -0x68a6, + -0x6a6d, -0x6c24, -0x6dca, -0x6f5f, -0x70e2, -0x7255, -0x73b5, -0x7504, + -0x7641, -0x776c, -0x7884, -0x798a, -0x7a7d, -0x7b5d, -0x7c29, -0x7ce3, + -0x7d8a, -0x7e1d, -0x7e9d, -0x7f09, -0x7f62, -0x7fa7, -0x7fd8, -0x7ff6, + -0x7fff, -0x7ff6, -0x7fd8, -0x7fa7, -0x7f62, -0x7f09, -0x7e9d, -0x7e1d, + -0x7d8a, -0x7ce3, -0x7c29, -0x7b5d, -0x7a7d, -0x798a, -0x7884, -0x776c, + -0x7641, -0x7504, -0x73b5, -0x7255, -0x70e2, -0x6f5f, -0x6dca, -0x6c24, + -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f2, -0x60ec, -0x5ed7, -0x5cb4, + -0x5a82, -0x5842, -0x55f5, -0x539b, -0x5133, -0x4ebf, -0x4c3f, -0x49b4, + -0x471c, -0x447a, -0x41ce, -0x3f17, -0x3c56, -0x398c, -0x36ba, -0x33de, + -0x30fb, -0x2e11, -0x2b1f, -0x2826, -0x2528, -0x2223, -0x1f19, -0x1c0b, + -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324}; + + ////////////////////////////////////////////////////////////////// + +// Optimised for Performance + const int16 Dsp1::MulTable[256] = { + 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015, + 0x0019, 0x001c, 0x001f, 0x0022, 0x0025, 0x0028, 0x002b, 0x002f, + 0x0032, 0x0035, 0x0038, 0x003b, 0x003e, 0x0041, 0x0045, 0x0048, + 0x004b, 0x004e, 0x0051, 0x0054, 0x0057, 0x005b, 0x005e, 0x0061, + 0x0064, 0x0067, 0x006a, 0x006d, 0x0071, 0x0074, 0x0077, 0x007a, + 0x007d, 0x0080, 0x0083, 0x0087, 0x008a, 0x008d, 0x0090, 0x0093, + 0x0096, 0x0099, 0x009d, 0x00a0, 0x00a3, 0x00a6, 0x00a9, 0x00ac, + 0x00af, 0x00b3, 0x00b6, 0x00b9, 0x00bc, 0x00bf, 0x00c2, 0x00c5, + 0x00c9, 0x00cc, 0x00cf, 0x00d2, 0x00d5, 0x00d8, 0x00db, 0x00df, + 0x00e2, 0x00e5, 0x00e8, 0x00eb, 0x00ee, 0x00f1, 0x00f5, 0x00f8, + 0x00fb, 0x00fe, 0x0101, 0x0104, 0x0107, 0x010b, 0x010e, 0x0111, + 0x0114, 0x0117, 0x011a, 0x011d, 0x0121, 0x0124, 0x0127, 0x012a, + 0x012d, 0x0130, 0x0133, 0x0137, 0x013a, 0x013d, 0x0140, 0x0143, + 0x0146, 0x0149, 0x014d, 0x0150, 0x0153, 0x0156, 0x0159, 0x015c, + 0x015f, 0x0163, 0x0166, 0x0169, 0x016c, 0x016f, 0x0172, 0x0175, + 0x0178, 0x017c, 0x017f, 0x0182, 0x0185, 0x0188, 0x018b, 0x018e, + 0x0192, 0x0195, 0x0198, 0x019b, 0x019e, 0x01a1, 0x01a4, 0x01a8, + 0x01ab, 0x01ae, 0x01b1, 0x01b4, 0x01b7, 0x01ba, 0x01be, 0x01c1, + 0x01c4, 0x01c7, 0x01ca, 0x01cd, 0x01d0, 0x01d4, 0x01d7, 0x01da, + 0x01dd, 0x01e0, 0x01e3, 0x01e6, 0x01ea, 0x01ed, 0x01f0, 0x01f3, + 0x01f6, 0x01f9, 0x01fc, 0x0200, 0x0203, 0x0206, 0x0209, 0x020c, + 0x020f, 0x0212, 0x0216, 0x0219, 0x021c, 0x021f, 0x0222, 0x0225, + 0x0228, 0x022c, 0x022f, 0x0232, 0x0235, 0x0238, 0x023b, 0x023e, + 0x0242, 0x0245, 0x0248, 0x024b, 0x024e, 0x0251, 0x0254, 0x0258, + 0x025b, 0x025e, 0x0261, 0x0264, 0x0267, 0x026a, 0x026e, 0x0271, + 0x0274, 0x0277, 0x027a, 0x027d, 0x0280, 0x0284, 0x0287, 0x028a, + 0x028d, 0x0290, 0x0293, 0x0296, 0x029a, 0x029d, 0x02a0, 0x02a3, + 0x02a6, 0x02a9, 0x02ac, 0x02b0, 0x02b3, 0x02b6, 0x02b9, 0x02bc, + 0x02bf, 0x02c2, 0x02c6, 0x02c9, 0x02cc, 0x02cf, 0x02d2, 0x02d5, + 0x02d8, 0x02db, 0x02df, 0x02e2, 0x02e5, 0x02e8, 0x02eb, 0x02ee, + 0x02f1, 0x02f5, 0x02f8, 0x02fb, 0x02fe, 0x0301, 0x0304, 0x0307, + 0x030b, 0x030e, 0x0311, 0x0314, 0x0317, 0x031a, 0x031d, 0x0321}; + +////////////////////////////////////////////////////////////////// + +// Data ROM, as logged from a DSP-1B with the 0x1f command; +// it contains the tables and constants used by the commands. +// The tables used are: two shift tables (0x022-0x031 and 0x031-0x040 -this last one +// with an error in 0x03c which has survived to all the DSP-1 revisions-); a inverse +// table (used as initial guess) at 0x065-0x0e4; a square root table (used also +// as initial guess) at 0x0e5-0x115; two sin and cos tables (used as nodes to construct +// a interpolation curve) at, respectively, 0x116-0x197 and 0x196-0x215. +// As a curiosity, in the positions 0x21c-0x31c it's contained a +// 257-points arccos table that, apparently, have been not used anywhere +// (maybe for the MaxAZS_Exp table?). +// byuu note: the error at DataRom[0x3c] has been corrected from 0x0001 to 0x0010 + const uint16 Dsp1::DataRom[1024] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, + 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, + 0x4000, 0x7fff, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, + 0x0100, 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8000, 0xffe5, 0x0100, 0x7fff, 0x7f02, 0x7e08, + 0x7d12, 0x7c1f, 0x7b30, 0x7a45, 0x795d, 0x7878, 0x7797, 0x76ba, + 0x75df, 0x7507, 0x7433, 0x7361, 0x7293, 0x71c7, 0x70fe, 0x7038, + 0x6f75, 0x6eb4, 0x6df6, 0x6d3a, 0x6c81, 0x6bca, 0x6b16, 0x6a64, + 0x69b4, 0x6907, 0x685b, 0x67b2, 0x670b, 0x6666, 0x65c4, 0x6523, + 0x6484, 0x63e7, 0x634c, 0x62b3, 0x621c, 0x6186, 0x60f2, 0x6060, + 0x5fd0, 0x5f41, 0x5eb5, 0x5e29, 0x5d9f, 0x5d17, 0x5c91, 0x5c0c, + 0x5b88, 0x5b06, 0x5a85, 0x5a06, 0x5988, 0x590b, 0x5890, 0x5816, + 0x579d, 0x5726, 0x56b0, 0x563b, 0x55c8, 0x5555, 0x54e4, 0x5474, + 0x5405, 0x5398, 0x532b, 0x52bf, 0x5255, 0x51ec, 0x5183, 0x511c, + 0x50b6, 0x5050, 0x4fec, 0x4f89, 0x4f26, 0x4ec5, 0x4e64, 0x4e05, + 0x4da6, 0x4d48, 0x4cec, 0x4c90, 0x4c34, 0x4bda, 0x4b81, 0x4b28, + 0x4ad0, 0x4a79, 0x4a23, 0x49cd, 0x4979, 0x4925, 0x48d1, 0x487f, + 0x482d, 0x47dc, 0x478c, 0x473c, 0x46ed, 0x469f, 0x4651, 0x4604, + 0x45b8, 0x456c, 0x4521, 0x44d7, 0x448d, 0x4444, 0x43fc, 0x43b4, + 0x436d, 0x4326, 0x42e0, 0x429a, 0x4255, 0x4211, 0x41cd, 0x4189, + 0x4146, 0x4104, 0x40c2, 0x4081, 0x4040, 0x3fff, 0x41f7, 0x43e1, + 0x45bd, 0x478d, 0x4951, 0x4b0b, 0x4cbb, 0x4e61, 0x4fff, 0x5194, + 0x5322, 0x54a9, 0x5628, 0x57a2, 0x5914, 0x5a81, 0x5be9, 0x5d4a, + 0x5ea7, 0x5fff, 0x6152, 0x62a0, 0x63ea, 0x6530, 0x6672, 0x67b0, + 0x68ea, 0x6a20, 0x6b53, 0x6c83, 0x6daf, 0x6ed9, 0x6fff, 0x7122, + 0x7242, 0x735f, 0x747a, 0x7592, 0x76a7, 0x77ba, 0x78cb, 0x79d9, + 0x7ae5, 0x7bee, 0x7cf5, 0x7dfa, 0x7efe, 0x7fff, 0x0000, 0x0324, + 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 0x18f8, 0x1c0b, + 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33de, + 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4, + 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb4, + 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c24, + 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 0x7641, 0x776c, + 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 0x7d8a, 0x7e1d, + 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 0x7fff, 0x7ff6, + 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, + 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, + 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, + 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, + 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, + 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, + 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, + 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x7fff, 0x7ff6, + 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, + 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, + 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, + 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, + 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, + 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, + 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, + 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x0000, 0xfcdc, + 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e, 0xe708, 0xe3f5, + 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef, 0xcf05, 0xcc22, + 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86, 0xb8e4, 0xb64c, + 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be, 0xa57e, 0xa34c, + 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a, 0x9593, 0x93dc, + 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc, 0x89bf, 0x8894, + 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d, 0x8276, 0x81e3, + 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a, 0x6488, 0x0080, + 0x03ff, 0x0116, 0x0002, 0x0080, 0x4000, 0x3fd7, 0x3faf, 0x3f86, + 0x3f5d, 0x3f34, 0x3f0c, 0x3ee3, 0x3eba, 0x3e91, 0x3e68, 0x3e40, + 0x3e17, 0x3dee, 0x3dc5, 0x3d9c, 0x3d74, 0x3d4b, 0x3d22, 0x3cf9, + 0x3cd0, 0x3ca7, 0x3c7f, 0x3c56, 0x3c2d, 0x3c04, 0x3bdb, 0x3bb2, + 0x3b89, 0x3b60, 0x3b37, 0x3b0e, 0x3ae5, 0x3abc, 0x3a93, 0x3a69, + 0x3a40, 0x3a17, 0x39ee, 0x39c5, 0x399c, 0x3972, 0x3949, 0x3920, + 0x38f6, 0x38cd, 0x38a4, 0x387a, 0x3851, 0x3827, 0x37fe, 0x37d4, + 0x37aa, 0x3781, 0x3757, 0x372d, 0x3704, 0x36da, 0x36b0, 0x3686, + 0x365c, 0x3632, 0x3609, 0x35df, 0x35b4, 0x358a, 0x3560, 0x3536, + 0x350c, 0x34e1, 0x34b7, 0x348d, 0x3462, 0x3438, 0x340d, 0x33e3, + 0x33b8, 0x338d, 0x3363, 0x3338, 0x330d, 0x32e2, 0x32b7, 0x328c, + 0x3261, 0x3236, 0x320b, 0x31df, 0x31b4, 0x3188, 0x315d, 0x3131, + 0x3106, 0x30da, 0x30ae, 0x3083, 0x3057, 0x302b, 0x2fff, 0x2fd2, + 0x2fa6, 0x2f7a, 0x2f4d, 0x2f21, 0x2ef4, 0x2ec8, 0x2e9b, 0x2e6e, + 0x2e41, 0x2e14, 0x2de7, 0x2dba, 0x2d8d, 0x2d60, 0x2d32, 0x2d05, + 0x2cd7, 0x2ca9, 0x2c7b, 0x2c4d, 0x2c1f, 0x2bf1, 0x2bc3, 0x2b94, + 0x2b66, 0x2b37, 0x2b09, 0x2ada, 0x2aab, 0x2a7c, 0x2a4c, 0x2a1d, + 0x29ed, 0x29be, 0x298e, 0x295e, 0x292e, 0x28fe, 0x28ce, 0x289d, + 0x286d, 0x283c, 0x280b, 0x27da, 0x27a9, 0x2777, 0x2746, 0x2714, + 0x26e2, 0x26b0, 0x267e, 0x264c, 0x2619, 0x25e7, 0x25b4, 0x2581, + 0x254d, 0x251a, 0x24e6, 0x24b2, 0x247e, 0x244a, 0x2415, 0x23e1, + 0x23ac, 0x2376, 0x2341, 0x230b, 0x22d6, 0x229f, 0x2269, 0x2232, + 0x21fc, 0x21c4, 0x218d, 0x2155, 0x211d, 0x20e5, 0x20ad, 0x2074, + 0x203b, 0x2001, 0x1fc7, 0x1f8d, 0x1f53, 0x1f18, 0x1edd, 0x1ea1, + 0x1e66, 0x1e29, 0x1ded, 0x1db0, 0x1d72, 0x1d35, 0x1cf6, 0x1cb8, + 0x1c79, 0x1c39, 0x1bf9, 0x1bb8, 0x1b77, 0x1b36, 0x1af4, 0x1ab1, + 0x1a6e, 0x1a2a, 0x19e6, 0x19a1, 0x195c, 0x1915, 0x18ce, 0x1887, + 0x183f, 0x17f5, 0x17ac, 0x1761, 0x1715, 0x16c9, 0x167c, 0x162e, + 0x15df, 0x158e, 0x153d, 0x14eb, 0x1497, 0x1442, 0x13ec, 0x1395, + 0x133c, 0x12e2, 0x1286, 0x1228, 0x11c9, 0x1167, 0x1104, 0x109e, + 0x1036, 0x0fcc, 0x0f5f, 0x0eef, 0x0e7b, 0x0e04, 0x0d89, 0x0d0a, + 0x0c86, 0x0bfd, 0x0b6d, 0x0ad6, 0x0a36, 0x098d, 0x08d7, 0x0811, + 0x0736, 0x063e, 0x0519, 0x039a, 0x0000, 0x7fff, 0x0100, 0x0080, + 0x021d, 0x00c8, 0x00ce, 0x0048, 0x0a26, 0x277a, 0x00ce, 0x6488, + 0x14ac, 0x0001, 0x00f9, 0x00fc, 0x00ff, 0x00fc, 0x00f9, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; + +////////////////////////////////////////////////////////////////// + +#endif diff --git a/sfc/coprocessor/dsp1/dsp1emu.hpp b/sfc/coprocessor/dsp1/dsp1emu.hpp new file mode 100644 index 0000000..9ae313a --- /dev/null +++ b/sfc/coprocessor/dsp1/dsp1emu.hpp @@ -0,0 +1,129 @@ +// DSP-1's emulation code +// +// Based on research by Overload, The Dumper, Neviksti and Andreas Naive +// Date: June 2006 + +#ifndef __DSP1EMUL_H +#define __DSP1EMUL_H + +#define DSP1_VERSION 0x0102 + +class Dsp1 +{ + public: + // The DSP-1 status register has 16 bits, but only + // the upper 8 bits can be accessed from an external device, so all these + // positions are referred to the upper byte (bits D8 to D15) + enum SrFlags {DRC=0x04, DRS=0x10, RQM=0x80}; + + // According to Overload's docs, these are the meanings of the flags: + // DRC: The Data Register Control (DRC) bit specifies the data transfer length to and from the host CPU. + // 0: Data transfer to and from the DSP-1 is 16 bits. + // 1: Data transfer to and from the DSP-1 is 8 bits. + // DRS: The Data Register Status (DRS) bit indicates the data transfer status in the case of transfering 16-bit data. + // 0: Data transfer has terminated. + // 1: Data transfer in progress. + // RQM: The Request for Master (RQM) indicates that the DSP1 is requesting host CPU for data read/write. + // 0: Internal Data Register Transfer. + // 1: External Data Register Transfer. + + Dsp1(); + uint8 getSr(); // return the status register's high byte + uint8 getDr(); + void setDr(uint8 iDr); + void reset(); + + void serialize(serializer&); + + private: + enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA}; + enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024}; + + struct Command { + void (Dsp1::*callback)(int16 *, int16 *); + unsigned int reads; + unsigned int writes; + }; + + static const Command mCommandTable[]; + static const int16 MaxAZS_Exp[16]; + static const int16 SinTable[]; + static const int16 MulTable[]; + static const uint16 DataRom[]; + + struct SharedData { // some RAM variables shared between commands + int16 MatrixA[3][3]; // attitude matrix A + int16 MatrixB[3][3]; + int16 MatrixC[3][3]; + int16 CentreX, CentreY, CentreZ; // center of projection + int16 CentreZ_C, CentreZ_E; + int16 VOffset; // vertical offset of the screen with regard to the centre of projection + int16 Les, C_Les, E_Les; + int16 SinAas, CosAas; + int16 SinAzs, CosAzs; + int16 SinAZS, CosAZS; + int16 SecAZS_C1, SecAZS_E1; + int16 SecAZS_C2, SecAZS_E2; + int16 Nx, Ny, Nz; // normal vector to the screen (norm 1, points toward the center of projection) + int16 Gx, Gy, Gz; // center of the screen (global coordinates) + int16 Hx, Hy; // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen) + int16 Vx, Vy, Vz; // vertical vector of the screen (norm 1, points toward the top of the screen) + + } shared; + + uint8 mSr; // status register + int mSrLowByteAccess; + uint16 mDr; // "internal" representation of the data register + unsigned mFsmMajorState; // current major state of the FSM + uint8 mCommand; // current command processed by the FSM + uint8 mDataCounter; // #uint16 read/writes counter used by the FSM + int16 mReadBuffer[MAX_READS]; + int16 mWriteBuffer[MAX_WRITES]; + bool mFreeze; // need explanation? ;) + + void fsmStep(bool read, uint8 &data); // FSM logic + + // commands + void memoryTest(int16 *input, int16 *output); + void memoryDump(int16 *input, int16 *output); + void memorySize(int16 *input, int16 *output); + void multiply(int16* input, int16* output); + void multiply2(int16* input, int16* output); + void inverse(int16 *input, int16 *output); + void triangle(int16 *input, int16 *output); + void radius(int16 *input, int16 *output); + void range(int16 *input, int16 *output); + void range2(int16 *input, int16 *output); + void distance(int16 *input, int16 *output); + void rotate(int16 *input, int16 *output); + void polar(int16 *input, int16 *output); + void attitudeA(int16 *input, int16 *output); + void attitudeB(int16 *input, int16 *output); + void attitudeC(int16 *input, int16 *output); + void objectiveA(int16 *input, int16 *output); + void objectiveB(int16 *input, int16 *output); + void objectiveC(int16 *input, int16 *output); + void subjectiveA(int16 *input, int16 *output); + void subjectiveB(int16 *input, int16 *output); + void subjectiveC(int16 *input, int16 *output); + void scalarA(int16 *input, int16 *output); + void scalarB(int16 *input, int16 *output); + void scalarC(int16 *input, int16 *output); + void gyrate(int16 *input, int16 *output); + void parameter(int16 *input, int16 *output); + void raster(int16 *input, int16 *output); + void target(int16 *input, int16 *output); + void project(int16 *input, int16 *output); + + // auxiliar functions + int16 sin(int16 Angle); + int16 cos(int16 Angle); + void inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent); + int16 denormalizeAndClip(int16 C, int16 E); + void normalize(int16 m, int16 &Coefficient, int16 &Exponent); + void normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent); + int16 shiftR(int16 C, int16 E); +}; + +#endif + diff --git a/sfc/coprocessor/dsp1/serialization.cpp b/sfc/coprocessor/dsp1/serialization.cpp new file mode 100644 index 0000000..a3781f0 --- /dev/null +++ b/sfc/coprocessor/dsp1/serialization.cpp @@ -0,0 +1,52 @@ +auto DSP1::serialize(serializer& s) -> void { + dsp1emu.serialize(s); +} + +auto Dsp1::serialize(serializer &s) -> void { + for(unsigned i = 0; i < 3; i++) { + s.array(shared.MatrixA[i]); + s.array(shared.MatrixB[i]); + s.array(shared.MatrixC[i]); + } + + s.integer(shared.CentreX); + s.integer(shared.CentreY); + s.integer(shared.CentreZ); + s.integer(shared.CentreZ_C); + s.integer(shared.CentreZ_E); + s.integer(shared.VOffset); + s.integer(shared.Les); + s.integer(shared.C_Les); + s.integer(shared.E_Les); + s.integer(shared.SinAas); + s.integer(shared.CosAas); + s.integer(shared.SinAzs); + s.integer(shared.CosAzs); + s.integer(shared.SinAZS); + s.integer(shared.CosAZS); + s.integer(shared.SecAZS_C1); + s.integer(shared.SecAZS_E1); + s.integer(shared.SecAZS_C2); + s.integer(shared.SecAZS_E2); + s.integer(shared.Nx); + s.integer(shared.Ny); + s.integer(shared.Nz); + s.integer(shared.Gx); + s.integer(shared.Gy); + s.integer(shared.Gz); + s.integer(shared.Hx); + s.integer(shared.Hy); + s.integer(shared.Vx); + s.integer(shared.Vy); + s.integer(shared.Vz); + + s.integer(mSr); + s.integer(mSrLowByteAccess); + s.integer(mDr); + s.integer(mFsmMajorState); + s.integer(mCommand); + s.integer(mDataCounter); + s.array(mReadBuffer); + s.array(mWriteBuffer); + s.integer(mFreeze); +} diff --git a/sfc/coprocessor/dsp2/dsp2.cpp b/sfc/coprocessor/dsp2/dsp2.cpp new file mode 100644 index 0000000..ffb16d8 --- /dev/null +++ b/sfc/coprocessor/dsp2/dsp2.cpp @@ -0,0 +1,136 @@ +#include + +namespace SuperFamicom { + +#define DSP2_CPP +#include "opcodes.cpp" + +DSP2 dsp2; +#include "serialization.cpp" + +auto DSP2::power() -> void { + status.waiting_for_command = true; + status.in_count = 0; + status.in_index = 0; + status.out_count = 0; + status.out_index = 0; + + status.op05transparent = 0; + status.op05haslen = false; + status.op05len = 0; + status.op06haslen = false; + status.op06len = 0; + status.op09word1 = 0; + status.op09word2 = 0; + status.op0dhaslen = false; + status.op0doutlen = 0; + status.op0dinlen = 0; +} + +auto DSP2::read(uint addr, uint8 data) -> uint8 { + if(addr & 1) return 0x00; + + uint8 r = 0xff; + if(status.out_count) { + r = status.output[status.out_index++]; + status.out_index &= 511; + if(status.out_count == status.out_index) { + status.out_count = 0; + } + } + return r; +} + +auto DSP2::write(uint addr, uint8 data) -> void { + if(addr & 1) return; + + if(status.waiting_for_command) { + status.command = data; + status.in_index = 0; + status.waiting_for_command = false; + + switch(data) { + case 0x01: status.in_count = 32; break; + case 0x03: status.in_count = 1; break; + case 0x05: status.in_count = 1; break; + case 0x06: status.in_count = 1; break; + case 0x07: break; + case 0x08: break; + case 0x09: status.in_count = 4; break; + case 0x0d: status.in_count = 2; break; + case 0x0f: status.in_count = 0; break; + } + } else { + status.parameters[status.in_index++] = data; + status.in_index &= 511; + } + + if(status.in_count == status.in_index) { + status.waiting_for_command = true; + status.out_index = 0; + switch(status.command) { + case 0x01: { + status.out_count = 32; + op01(); + } break; + + case 0x03: { + op03(); + } break; + + case 0x05: { + if(status.op05haslen) { + status.op05haslen = false; + status.out_count = status.op05len; + op05(); + } else { + status.op05len = status.parameters[0]; + status.in_index = 0; + status.in_count = status.op05len * 2; + status.op05haslen = true; + if(data)status.waiting_for_command = false; + } + } break; + + case 0x06: { + if(status.op06haslen) { + status.op06haslen = false; + status.out_count = status.op06len; + op06(); + } else { + status.op06len = status.parameters[0]; + status.in_index = 0; + status.in_count = status.op06len; + status.op06haslen = true; + if(data)status.waiting_for_command = false; + } + } break; + + case 0x07: break; + case 0x08: break; + + case 0x09: { + op09(); + } break; + + case 0x0d: { + if(status.op0dhaslen) { + status.op0dhaslen = false; + status.out_count = status.op0doutlen; + op0d(); + } else { + status.op0dinlen = status.parameters[0]; + status.op0doutlen = status.parameters[1]; + status.in_index = 0; + status.in_count = (status.op0dinlen + 1) >> 1; + status.op0dhaslen = true; + if(data)status.waiting_for_command = false; + } + } break; + + case 0x0f: break; + } + } +} + +} diff --git a/sfc/coprocessor/dsp2/dsp2.hpp b/sfc/coprocessor/dsp2/dsp2.hpp new file mode 100644 index 0000000..3dc1c83 --- /dev/null +++ b/sfc/coprocessor/dsp2/dsp2.hpp @@ -0,0 +1,38 @@ +struct DSP2 { + auto power() -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; + + struct { + bool waiting_for_command; + unsigned command; + unsigned in_count, in_index; + unsigned out_count, out_index; + + uint8_t parameters[512]; + uint8_t output[512]; + + uint8 op05transparent; + bool op05haslen; + int op05len; + bool op06haslen; + int op06len; + uint16 op09word1; + uint16 op09word2; + bool op0dhaslen; + int op0doutlen; + int op0dinlen; + } status; + + void op01(); + void op03(); + void op05(); + void op06(); + void op09(); + void op0d(); +}; + +extern DSP2 dsp2; diff --git a/sfc/coprocessor/dsp2/opcodes.cpp b/sfc/coprocessor/dsp2/opcodes.cpp new file mode 100644 index 0000000..f015ac3 --- /dev/null +++ b/sfc/coprocessor/dsp2/opcodes.cpp @@ -0,0 +1,177 @@ +#ifdef DSP2_CPP + +//convert bitmap to bitplane tile +void DSP2::op01() { +//op01 size is always 32 bytes input and output +//the hardware does strange things if you vary the size + +unsigned char c0, c1, c2, c3; +unsigned char *p1 = status.parameters; +unsigned char *p2a = status.output; +unsigned char *p2b = status.output + 16; //halfway + +//process 8 blocks of 4 bytes each + for(int j = 0; j < 8; j++) { + c0 = *p1++; + c1 = *p1++; + c2 = *p1++; + c3 = *p1++; + + *p2a++ = (c0 & 0x10) << 3 | + (c0 & 0x01) << 6 | + (c1 & 0x10) << 1 | + (c1 & 0x01) << 4 | + (c2 & 0x10) >> 1 | + (c2 & 0x01) << 2 | + (c3 & 0x10) >> 3 | + (c3 & 0x01); + + *p2a++ = (c0 & 0x20) << 2 | + (c0 & 0x02) << 5 | + (c1 & 0x20) | + (c1 & 0x02) << 3 | + (c2 & 0x20) >> 2 | + (c2 & 0x02) << 1 | + (c3 & 0x20) >> 4 | + (c3 & 0x02) >> 1; + + *p2b++ = (c0 & 0x40) << 1 | + (c0 & 0x04) << 4 | + (c1 & 0x40) >> 1 | + (c1 & 0x04) << 2 | + (c2 & 0x40) >> 3 | + (c2 & 0x04) | + (c3 & 0x40) >> 5 | + (c3 & 0x04) >> 2; + + *p2b++ = (c0 & 0x80) | + (c0 & 0x08) << 3 | + (c1 & 0x80) >> 2 | + (c1 & 0x08) << 1 | + (c2 & 0x80) >> 4 | + (c2 & 0x08) >> 1 | + (c3 & 0x80) >> 6 | + (c3 & 0x08) >> 3; + } +} + +//set transparent color +void DSP2::op03() { + status.op05transparent = status.parameters[0]; +} + +//replace bitmap using transparent color +void DSP2::op05() { +uint8 color; +// Overlay bitmap with transparency. +// Input: +// +// Bitmap 1: i[0] <=> i[size-1] +// Bitmap 2: i[size] <=> i[2*size-1] +// +// Output: +// +// Bitmap 3: o[0] <=> o[size-1] +// +// Processing: +// +// Process all 4-bit pixels (nibbles) in the bitmap +// +// if ( BM2_pixel == transparent_color ) +// pixelout = BM1_pixel +// else +// pixelout = BM2_pixel + +// The max size bitmap is limited to 255 because the size parameter is a byte +// I think size=0 is an error. The behavior of the chip on size=0 is to +// return the last value written to DR if you read DR on Op05 with +// size = 0. I don't think it's worth implementing this quirk unless it's +// proven necessary. + +unsigned char c1, c2; +unsigned char *p1 = status.parameters; +unsigned char *p2 = status.parameters + status.op05len; +unsigned char *p3 = status.output; + + color = status.op05transparent & 0x0f; + + for(int n = 0; n < status.op05len; n++) { + c1 = *p1++; + c2 = *p2++; + *p3++ = ( ((c2 >> 4) == color ) ? c1 & 0xf0 : c2 & 0xf0 ) | + ( ((c2 & 0x0f) == color ) ? c1 & 0x0f : c2 & 0x0f ); + } +} + +//reverse bitmap +void DSP2::op06() { +// Input: +// size +// bitmap + +int i, j; + for(i = 0, j = status.op06len - 1; i < status.op06len; i++, j--) { + status.output[j] = (status.parameters[i] << 4) | (status.parameters[i] >> 4); + } +} + +//multiply +void DSP2::op09() { + status.out_count = 4; + + status.op09word1 = status.parameters[0] | (status.parameters[1] << 8); + status.op09word2 = status.parameters[2] | (status.parameters[3] << 8); + +uint32 r; + r = status.op09word1 * status.op09word2; + status.output[0] = r; + status.output[1] = r >> 8; + status.output[2] = r >> 16; + status.output[3] = r >> 24; +} + +//scale bitmap +void DSP2::op0d() { +// Bit accurate hardware algorithm - uses fixed point math +// This should match the DSP2 Op0D output exactly +// I wouldn't recommend using this unless you're doing hardware debug. +// In some situations it has small visual artifacts that +// are not readily apparent on a TV screen but show up clearly +// on a monitor. Use Overload's scaling instead. +// This is for hardware verification testing. +// +// One note: the HW can do odd byte scaling but since we divide +// by two to get the count of bytes this won't work well for +// odd byte scaling (in any of the current algorithm implementations). +// So far I haven't seen Dungeon Master use it. +// If it does we can adjust the parameters and code to work with it + +uint32 multiplier; // Any size int >= 32-bits +uint32 pixloc; // match size of multiplier +int i, j; +uint8 pixelarray[512]; + if(status.op0dinlen <= status.op0doutlen) { + multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1 + } else { + multiplier = (status.op0dinlen << 17) / ((status.op0doutlen << 1) + 1); + } + + pixloc = 0; + for(i = 0; i < status.op0doutlen * 2; i++) { + j = pixloc >> 16; + + if(j & 1) { + pixelarray[i] = (status.parameters[j >> 1] & 0x0f); + } else { + pixelarray[i] = (status.parameters[j >> 1] & 0xf0) >> 4; + } + + pixloc += multiplier; + } + + for(i = 0; i < status.op0doutlen; i++) { + status.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1]; + } +} + +#endif diff --git a/sfc/coprocessor/dsp2/serialization.cpp b/sfc/coprocessor/dsp2/serialization.cpp new file mode 100644 index 0000000..b219361 --- /dev/null +++ b/sfc/coprocessor/dsp2/serialization.cpp @@ -0,0 +1,22 @@ +auto DSP2::serialize(serializer& s) -> void { + s.integer(status.waiting_for_command); + s.integer(status.command); + s.integer(status.in_count); + s.integer(status.in_index); + s.integer(status.out_count); + s.integer(status.out_index); + + s.array(status.parameters); + s.array(status.output); + + s.integer(status.op05transparent); + s.integer(status.op05haslen); + s.integer(status.op05len); + s.integer(status.op06haslen); + s.integer(status.op06len); + s.integer(status.op09word1); + s.integer(status.op09word2); + s.integer(status.op0dhaslen); + s.integer(status.op0doutlen); + s.integer(status.op0dinlen); +} diff --git a/sfc/coprocessor/dsp4/dsp4.cpp b/sfc/coprocessor/dsp4/dsp4.cpp new file mode 100644 index 0000000..8c4830f --- /dev/null +++ b/sfc/coprocessor/dsp4/dsp4.cpp @@ -0,0 +1,62 @@ +#include + +namespace SuperFamicom { + +namespace DSP4i { + #define bool8 uint8_t + #define int8 int8_t + #define int16 int16_t + #define int32 int32_t + #define int64 int64_t + #define uint8 uint8_t + #define uint16 uint16_t + #define uint32 uint32_t + #define uint64 uint64_t + #define DSP4_CPP + inline uint16 READ_WORD(uint8 *addr) { + return (addr[0]) + (addr[1] << 8); + } + inline uint32 READ_DWORD(uint8 *addr) { + return (addr[0]) + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24); + } + inline void WRITE_WORD(uint8 *addr, uint16 data) { + addr[0] = data; + addr[1] = data >> 8; + } + #include "dsp4emu.h" + #include "dsp4emu.c" + #undef bool8 + #undef int8 + #undef int16 + #undef int32 + #undef int64 + #undef uint8 + #undef uint16 + #undef uint32 + #undef uint64 +} + +DSP4 dsp4; +#include "serialization.cpp" + +auto DSP4::power() -> void { + DSP4i::InitDSP4(); +} + +auto DSP4::read(uint addr, uint8 data) -> uint8 { + if(addr & 1) return 0x80; + + DSP4i::dsp4_address = addr; + DSP4i::DSP4GetByte(); + return DSP4i::dsp4_byte; +} + +auto DSP4::write(uint addr, uint8 data) -> void { + if(addr & 1) return; + + DSP4i::dsp4_address = addr; + DSP4i::dsp4_byte = data; + DSP4i::DSP4SetByte(); +} + +} diff --git a/sfc/coprocessor/dsp4/dsp4.hpp b/sfc/coprocessor/dsp4/dsp4.hpp new file mode 100644 index 0000000..38c7893 --- /dev/null +++ b/sfc/coprocessor/dsp4/dsp4.hpp @@ -0,0 +1,10 @@ +struct DSP4 { + auto power() -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; +}; + +extern DSP4 dsp4; diff --git a/sfc/coprocessor/dsp4/dsp4emu.c b/sfc/coprocessor/dsp4/dsp4emu.c new file mode 100644 index 0000000..73c1ec3 --- /dev/null +++ b/sfc/coprocessor/dsp4/dsp4emu.c @@ -0,0 +1,2150 @@ +#ifdef DSP4_CPP + +//DSP-4 emulator code +//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden + +/* +Due recognition and credit are given on Overload's DSP website. +Thank those contributors for their hard work on this chip. + + +Fixed-point math reminder: + +[sign, integer, fraction] +1.15.00 * 1.15.00 = 2.30.00 -> 1.30.00 (DSP) -> 1.31.00 (LSB is '0') +1.15.00 * 1.00.15 = 2.15.15 -> 1.15.15 (DSP) -> 1.15.16 (LSB is '0') +*/ + +#include "dsp4emu.h" + +struct DSP4_t DSP4; +struct DSP4_vars_t DSP4_vars; + +////////////////////////////////////////////////////////////// + +// input protocol + +static int16 DSP4_READ_WORD() +{ + int16 out; + + out = READ_WORD(DSP4.parameters + DSP4.in_index); + DSP4.in_index += 2; + + return out; +} + +static int32 DSP4_READ_DWORD() +{ + int32 out; + + out = READ_DWORD(DSP4.parameters + DSP4.in_index); + DSP4.in_index += 4; + + return out; +} + + +////////////////////////////////////////////////////////////// + +// output protocol + +#define DSP4_CLEAR_OUT() \ +{ DSP4.out_count = 0; DSP4.out_index = 0; } + +#define DSP4_WRITE_BYTE( d ) \ +{ WRITE_WORD( DSP4.output + DSP4.out_count, ( d ) ); DSP4.out_count++; } + +#define DSP4_WRITE_WORD( d ) \ +{ WRITE_WORD( DSP4.output + DSP4.out_count, ( d ) ); DSP4.out_count += 2; } + +#ifndef MSB_FIRST +#define DSP4_WRITE_16_WORD( d ) \ +{ memcpy(DSP4.output + DSP4.out_count, ( d ), 32); DSP4.out_count += 32; } +#else +#define DSP4_WRITE_16_WORD( d ) \ +{ int16 *p = ( d ), *end = ( d )+16; \ + for (; p != end; p++) \ + { \ + WRITE_WORD( DSP4.output + DSP4.out_count, *p ); \ + } \ + DSP4.out_count += 32; \ +} +#endif + +#ifdef PRINT_OP +#define DSP4_WRITE_DEBUG( x, d ) \ + WRITE_WORD( nop + x, d ); +#endif + +#ifdef DEBUG_DSP +#define DSP4_WRITE_DEBUG( x, d ) \ + WRITE_WORD( nop + x, d ); +#endif + +////////////////////////////////////////////////////////////// + +// used to wait for dsp i/o + +#define DSP4_WAIT( x ) \ + DSP4.in_index = 0; DSP4_vars.DSP4_Logic = x; return; + +////////////////////////////////////////////////////////////// + +// 1.7.8 -> 1.15.16 +#define SEX78( a ) ( ( (int32) ( (int16) (a) ) ) << 8 ) + +// 1.15.0 -> 1.15.16 +#define SEX16( a ) ( ( (int32) ( (int16) (a) ) ) << 16 ) + +#ifdef PRINT_OP +#define U16( a ) ( (uint16) ( a ) ) +#endif + +#ifdef DEBUG_DSP +#define U16( a ) ( (uint16) ( a ) ) +#endif + +////////////////////////////////////////////////////////////// + +// Attention: This lookup table is not verified +static const uint16 div_lut[64] = { 0x0000, 0x8000, 0x4000, 0x2aaa, 0x2000, 0x1999, 0x1555, 0x1249, 0x1000, 0x0e38, + 0x0ccc, 0x0ba2, 0x0aaa, 0x09d8, 0x0924, 0x0888, 0x0800, 0x0787, 0x071c, 0x06bc, + 0x0666, 0x0618, 0x05d1, 0x0590, 0x0555, 0x051e, 0x04ec, 0x04bd, 0x0492, 0x0469, + 0x0444, 0x0421, 0x0400, 0x03e0, 0x03c3, 0x03a8, 0x038e, 0x0375, 0x035e, 0x0348, + 0x0333, 0x031f, 0x030c, 0x02fa, 0x02e8, 0x02d8, 0x02c8, 0x02b9, 0x02aa, 0x029c, + 0x028f, 0x0282, 0x0276, 0x026a, 0x025e, 0x0253, 0x0249, 0x023e, 0x0234, 0x022b, + 0x0222, 0x0219, 0x0210, 0x0208, }; +int16 DSP4_Inverse(int16 value) +{ + // saturate bounds + if (value < 0) + { + value = 0; + } + if (value > 63) + { + value = 63; + } + + return div_lut[value]; +} + +////////////////////////////////////////////////////////////// + +// Prototype +void DSP4_OP0B(bool8 *draw, int16 sp_x, int16 sp_y, int16 sp_attr, bool8 size, bool8 stop); + +////////////////////////////////////////////////////////////// + +// OP00 +void DSP4_Multiply(int16 Multiplicand, int16 Multiplier, int32 *Product) +{ + *Product = (Multiplicand * Multiplier << 1) >> 1; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP01() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + case 3: + goto resume3; break; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // sort inputs + DSP4_vars.world_y = DSP4_READ_DWORD(); + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + DSP4_vars.world_x = DSP4_READ_DWORD(); + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.world_yofs = DSP4_READ_WORD(); + DSP4_vars.world_dy = DSP4_READ_DWORD(); + DSP4_vars.world_dx = DSP4_READ_DWORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.world_xenv = DSP4_READ_DWORD(); + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting DSP4_vars.raster line + DSP4_vars.view_x1 = (int16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16); + DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16); + DSP4_vars.view_xofs1 = (int16)(DSP4_vars.world_x >> 16); + DSP4_vars.view_yofs1 = DSP4_vars.world_yofs; + DSP4_vars.view_turnoff_x = 0; + DSP4_vars.view_turnoff_dx = 0; + + // first DSP4_vars.raster line + DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0]; + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // perspective projection of world (x,y,scroll) points + // based on the current projection lines + DSP4_vars.view_x2 = (int16)(( ( ( DSP4_vars.world_x + DSP4_vars.world_xenv ) >> 16 ) * DSP4_vars.distance >> 15 ) + ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 )); + DSP4_vars.view_y2 = (int16)((DSP4_vars.world_y >> 16) * DSP4_vars.distance >> 15); + DSP4_vars.view_xofs2 = DSP4_vars.view_x2; + DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2; + + + // 1. World x-location before transformation + // 2. Viewer x-position at the next + // 3. World y-location before perspective projection + // 4. Viewer y-position below the horizon + // 5. Number of DSP4_vars.raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((uint16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_x2); + DSP4_WRITE_WORD((uint16)(DSP4_vars.world_y >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of DSP4_vars.raster lines used + DSP4_vars.segments = DSP4_vars.poly_raster[0][0] - DSP4_vars.view_y2; + + // prevent overdraw + if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0]) + DSP4_vars.segments = 0; + else + DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2; + + // don't draw outside the window + if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0]) + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(DSP4_vars.segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + + // starting step values + x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1); + y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs); + + // SR = 0x80 + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + // 1. HDMA memory pointer (bg1) + // 2. vertical scroll offset ($210E) + // 3. horizontal scroll offset ($210D) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]); + DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16)); + DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16)); + + + // update memory address + DSP4_vars.poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + //////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn + DSP4_vars.view_x1 = DSP4_vars.view_x2; + DSP4_vars.view_y1 = DSP4_vars.view_y2; + DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2; + DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2; + + // add deltas for projection lines + DSP4_vars.world_dx += SEX78(DSP4_vars.world_ddx); + DSP4_vars.world_dy += SEX78(DSP4_vars.world_ddy); + + // update projection lines + DSP4_vars.world_x += (DSP4_vars.world_dx + DSP4_vars.world_xenv); + DSP4_vars.world_y += DSP4_vars.world_dy; + + // update road turnoff position + DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // check for termination + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + break; + + // road turnoff + if( (uint16) DSP4_vars.distance == 0x8001 ) + { + DSP4.in_count = 6; + DSP4_WAIT(2) resume2: + + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_vars.view_turnoff_x = DSP4_READ_WORD(); + DSP4_vars.view_turnoff_dx = DSP4_READ_WORD(); + + // factor in new changes + DSP4_vars.view_x1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 ); + DSP4_vars.view_xofs1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 ); + + // update stepping values + DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx; + + DSP4.in_count = 2; + DSP4_WAIT(1) + } + + // already have 2 bytes read + DSP4.in_count = 6; + DSP4_WAIT(3) resume3 : + + // inspect inputs + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // no envelope here + DSP4_vars.world_xenv = 0; + } + while (1); + + // terminate op + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP03() +{ + DSP4_vars.OAM_RowMax = 33; + memset(DSP4_vars.OAM_Row, 0, 64); +} + + +////////////////////////////////////////////////////////////// + + +void DSP4_OP05() +{ + DSP4_vars.OAM_index = 0; + DSP4_vars.OAM_bits = 0; + memset(DSP4_vars.OAM_attr, 0, 32); + DSP4_vars.sprite_count = 0; +} + + +////////////////////////////////////////////////////////////// + +void DSP4_OP06() +{ + DSP4_CLEAR_OUT(); + DSP4_WRITE_16_WORD(DSP4_vars.OAM_attr); +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP07() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + } + + //////////////////////////////////////////////////// + // sort inputs + + DSP4_vars.world_y = DSP4_READ_DWORD(); + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + DSP4_vars.world_x = DSP4_READ_DWORD(); + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.world_yofs = DSP4_READ_WORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_vars.view_y2 = DSP4_READ_WORD(); + DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_x2 = DSP4_READ_WORD(); + DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting DSP4_vars.raster line + DSP4_vars.view_x1 = (int16)(DSP4_vars.world_x >> 16); + DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16); + DSP4_vars.view_xofs1 = DSP4_vars.view_x1; + DSP4_vars.view_yofs1 = DSP4_vars.world_yofs; + + // first DSP4_vars.raster line + DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0]; + + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // add shaping + DSP4_vars.view_x2 += DSP4_vars.view_dx; + DSP4_vars.view_y2 += DSP4_vars.view_dy; + + // vertical scroll calculation + DSP4_vars.view_xofs2 = DSP4_vars.view_x2; + DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2; + + // 1. Viewer x-position at the next + // 2. Viewer y-position below the horizon + // 3. Number of DSP4_vars.raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(DSP4_vars.view_x2); + DSP4_WRITE_WORD(DSP4_vars.view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of DSP4_vars.raster lines used + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.view_y2; + + // prevent overdraw + if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0]) + DSP4_vars.segments = 0; + else + DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2; + + // don't draw outside the window + if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0]) + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(DSP4_vars.segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + + // starting step values + x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1); + y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs); + + // SR = 0x80 + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + // 1. HDMA memory pointer (bg2) + // 2. vertical scroll offset ($2110) + // 3. horizontal scroll offset ($210F) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]); + DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16)); + DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16)); + + // update memory address + DSP4_vars.poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + ///////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn + DSP4_vars.view_x1 = DSP4_vars.view_x2; + DSP4_vars.view_y1 = DSP4_vars.view_y2; + DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2; + DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // check for opcode termination + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 10; + DSP4_WAIT(2) resume2 : + + // inspect inputs + DSP4_vars.view_y2 = DSP4_READ_WORD(); + DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_x2 = DSP4_READ_WORD(); + DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + } + while (1); + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP08() +{ + int16 win_left, win_right; + int16 view_x[2], view_y[2]; + int16 envelope[2][2]; + + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + } + + //////////////////////////////////////////////////// + // process initial inputs for two polygons + + // clip values + DSP4_vars.poly_clipRt[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_clipRt[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_clipRt[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_clipRt[1][1] = DSP4_READ_WORD(); + + DSP4_vars.poly_clipLf[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_clipLf[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_clipLf[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_clipLf[1][1] = DSP4_READ_WORD(); + + // unknown (constant) (ex. 1P/2P = $00A6, $00A6, $00A6, $00A6) + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + + // unknown (constant) (ex. 1P/2P = $00A5, $00A5, $00A7, $00A7) + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + + // polygon centering (left,right) + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][1] = DSP4_READ_WORD(); + + // HDMA pointer locations + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[1][1] = DSP4_READ_WORD(); + + // starting DSP4_vars.raster line below the horizon + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_bottom[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_bottom[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_bottom[1][1] = DSP4_READ_WORD(); + + // top boundary line to clip + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_top[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[1][1] = DSP4_READ_WORD(); + + // unknown + // (ex. 1P = $2FC8, $0034, $FF5C, $0035) + // + // (ex. 2P = $3178, $0034, $FFCC, $0035) + // (ex. 2P = $2FC8, $0034, $FFCC, $0035) + + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + + // look at guidelines for both polygon shapes + DSP4_vars.distance = DSP4_READ_WORD(); + view_x[0] = DSP4_READ_WORD(); + view_y[0] = DSP4_READ_WORD(); + view_x[1] = DSP4_READ_WORD(); + view_y[1] = DSP4_READ_WORD(); + + // envelope shaping guidelines (one frame only) + envelope[0][0] = DSP4_READ_WORD(); + envelope[0][1] = DSP4_READ_WORD(); + envelope[1][0] = DSP4_READ_WORD(); + envelope[1][1] = DSP4_READ_WORD(); + + // starting base values to project from + DSP4_vars.poly_start[0] = view_x[0]; + DSP4_vars.poly_start[1] = view_x[1]; + + // starting DSP4_vars.raster lines to begin drawing + DSP4_vars.poly_raster[0][0] = view_y[0]; + DSP4_vars.poly_raster[0][1] = view_y[0]; + DSP4_vars.poly_raster[1][0] = view_y[1]; + DSP4_vars.poly_raster[1][1] = view_y[1]; + + // starting distances + DSP4_vars.poly_plane[0] = DSP4_vars.distance; + DSP4_vars.poly_plane[1] = DSP4_vars.distance; + + // SR = 0x00 + + // re-center coordinates + win_left = DSP4_vars.poly_cx[0][0] - view_x[0] + envelope[0][0]; + win_right = DSP4_vars.poly_cx[0][1] - view_x[0] + envelope[0][1]; + + // saturate offscreen data for polygon #1 + if (win_left < DSP4_vars.poly_clipLf[0][0]) + { + win_left = DSP4_vars.poly_clipLf[0][0]; + } + if (win_left > DSP4_vars.poly_clipRt[0][0]) + { + win_left = DSP4_vars.poly_clipRt[0][0]; + } + if (win_right < DSP4_vars.poly_clipLf[0][1]) + { + win_right = DSP4_vars.poly_clipLf[0][1]; + } + if (win_right > DSP4_vars.poly_clipRt[0][1]) + { + win_right = DSP4_vars.poly_clipRt[0][1]; + } + + // SR = 0x80 + + // initial output for polygon #1 + DSP4_CLEAR_OUT(); + DSP4_WRITE_BYTE(win_left & 0xff); + DSP4_WRITE_BYTE(win_right & 0xff); + + + do + { + int16 polygon; + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // terminate op + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 16; + + DSP4_WAIT(2) resume2 : + + // look at guidelines for both polygon shapes + view_x[0] = DSP4_READ_WORD(); + view_y[0] = DSP4_READ_WORD(); + view_x[1] = DSP4_READ_WORD(); + view_y[1] = DSP4_READ_WORD(); + + // envelope shaping guidelines (one frame only) + envelope[0][0] = DSP4_READ_WORD(); + envelope[0][1] = DSP4_READ_WORD(); + envelope[1][0] = DSP4_READ_WORD(); + envelope[1][1] = DSP4_READ_WORD(); + + //////////////////////////////////////////////////// + // projection begins + + // init + DSP4_CLEAR_OUT(); + + + ////////////////////////////////////////////// + // solid polygon renderer - 2 shapes + + for (polygon = 0; polygon < 2; polygon++) + { + int32 left_inc, right_inc; + int16 x1_final, x2_final; + int16 env[2][2]; + int16 poly; + + // SR = 0x00 + + // # DSP4_vars.raster lines to draw + DSP4_vars.segments = DSP4_vars.poly_raster[polygon][0] - view_y[polygon]; + + // prevent overdraw + if (DSP4_vars.segments > 0) + { + // bump drawing cursor + DSP4_vars.poly_raster[polygon][0] = view_y[polygon]; + DSP4_vars.poly_raster[polygon][1] = view_y[polygon]; + } + else + DSP4_vars.segments = 0; + + // don't draw outside the window + if (view_y[polygon] < DSP4_vars.poly_top[polygon][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (view_y[polygon] >= DSP4_vars.poly_top[polygon][0]) + DSP4_vars.segments = view_y[polygon] - DSP4_vars.poly_top[polygon][0]; + } + + // SR = 0x80 + + // tell user how many DSP4_vars.raster structures to read in + DSP4_WRITE_WORD(DSP4_vars.segments); + + // normal parameters + poly = polygon; + + ///////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 win_left, win_right; + + // road turnoff selection + if( (uint16) envelope[ polygon ][ 0 ] == (uint16) 0xc001 ) + poly = 1; + else if( envelope[ polygon ][ 1 ] == 0x3fff ) + poly = 1; + + /////////////////////////////////////////////// + // left side of polygon + + // perspective correction on additional shaping parameters + env[0][0] = envelope[polygon][0] * DSP4_vars.poly_plane[poly] >> 15; + env[0][1] = envelope[polygon][0] * DSP4_vars.distance >> 15; + + // project new shapes (left side) + x1_final = view_x[poly] + env[0][0]; + x2_final = DSP4_vars.poly_start[poly] + env[0][1]; + + // interpolate between projected points with shaping + left_inc = (x2_final - x1_final) * DSP4_Inverse(DSP4_vars.segments) << 1; + if (DSP4_vars.segments == 1) + left_inc = -left_inc; + + /////////////////////////////////////////////// + // right side of polygon + + // perspective correction on additional shaping parameters + env[1][0] = envelope[polygon][1] * DSP4_vars.poly_plane[poly] >> 15;; + env[1][1] = envelope[polygon][1] * DSP4_vars.distance >> 15; + + // project new shapes (right side) + x1_final = view_x[poly] + env[1][0]; + x2_final = DSP4_vars.poly_start[poly] + env[1][1]; + + + // interpolate between projected points with shaping + right_inc = (x2_final - x1_final) * DSP4_Inverse(DSP4_vars.segments) << 1; + if (DSP4_vars.segments == 1) + right_inc = -right_inc; + + /////////////////////////////////////////////// + // update each point on the line + + win_left = SEX16(DSP4_vars.poly_cx[polygon][0] - DSP4_vars.poly_start[poly] + env[0][0]); + win_right = SEX16(DSP4_vars.poly_cx[polygon][1] - DSP4_vars.poly_start[poly] + env[1][0]); + + // update DSP4_vars.distance drawn into world + DSP4_vars.poly_plane[polygon] = DSP4_vars.distance; + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + int16 x_left, x_right; + + // project new coordinates + win_left += left_inc; + win_right += right_inc; + + // grab integer portion, drop fraction (no rounding) + x_left = (int16)(win_left >> 16); + x_right = (int16)(win_right >> 16); + + // saturate offscreen data + if (x_left < DSP4_vars.poly_clipLf[polygon][0]) + x_left = DSP4_vars.poly_clipLf[polygon][0]; + if (x_left > DSP4_vars.poly_clipRt[polygon][0]) + x_left = DSP4_vars.poly_clipRt[polygon][0]; + if (x_right < DSP4_vars.poly_clipLf[polygon][1]) + x_right = DSP4_vars.poly_clipLf[polygon][1]; + if (x_right > DSP4_vars.poly_clipRt[polygon][1]) + x_right = DSP4_vars.poly_clipRt[polygon][1]; + + // 1. HDMA memory pointer + // 2. Left window position ($2126/$2128) + // 3. Right window position ($2127/$2129) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[polygon][0]); + DSP4_WRITE_BYTE(x_left & 0xff); + DSP4_WRITE_BYTE(x_right & 0xff); + + + // update memory pointers + DSP4_vars.poly_ptr[polygon][0] -= 4; + DSP4_vars.poly_ptr[polygon][1] -= 4; + } // end rasterize line + } + + //////////////////////////////////////////////// + // Post-update + + // new projection spot to continue rasterizing from + DSP4_vars.poly_start[polygon] = view_x[poly]; + } // end polygon rasterizer + } + while (1); + + // unknown output + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(0); + + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP09() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + case 3: + goto resume3; break; + case 4: + goto resume4; break; + case 5: + goto resume5; break; + case 6: + goto resume6; break; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // grab screen information + DSP4_vars.viewport_cx = DSP4_READ_WORD(); + DSP4_vars.viewport_cy = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.viewport_left = DSP4_READ_WORD(); + DSP4_vars.viewport_right = DSP4_READ_WORD(); + DSP4_vars.viewport_top = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + + // starting DSP4_vars.raster line below the horizon + DSP4_vars.poly_bottom[0][0] = DSP4_vars.viewport_bottom - DSP4_vars.viewport_cy; + DSP4_vars.poly_raster[0][0] = 0x100; + + do + { + //////////////////////////////////////////////////// + // check for new sprites + + DSP4.in_count = 4; + DSP4_WAIT(1) resume1 : + + //////////////////////////////////////////////// + // DSP4_vars.raster overdraw check + + DSP4_vars.raster = DSP4_READ_WORD(); + + // continue updating the DSP4_vars.raster line where overdraw begins + if (DSP4_vars.raster < DSP4_vars.poly_raster[0][0]) + { + DSP4_vars.sprite_clipy = DSP4_vars.viewport_bottom - (DSP4_vars.poly_bottom[0][0] - DSP4_vars.raster); + DSP4_vars.poly_raster[0][0] = DSP4_vars.raster; + } + + ///////////////////////////////////////////////// + // identify sprite + + // op termination + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + goto terminate; + + + // no sprite + if (DSP4_vars.distance == 0x0000) + { + continue; + } + + //////////////////////////////////////////////////// + // process projection information + + // vehicle sprite + if ((uint16) DSP4_vars.distance == 0x9000) + { + int16 car_left, car_right, car_back; + int16 impact_left, impact_back; + int16 world_spx, world_spy; + int16 view_spx, view_spy; + uint16 energy; + + // we already have 4 bytes we want + DSP4.in_count = 14; + DSP4_WAIT(2) resume2 : + + // filter inputs + energy = DSP4_READ_WORD(); + impact_back = DSP4_READ_WORD(); + car_back = DSP4_READ_WORD(); + impact_left = DSP4_READ_WORD(); + car_left = DSP4_READ_WORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + car_right = DSP4_READ_WORD(); + + // calculate car's world (x,y) values + world_spx = car_right - car_left; + world_spy = car_back; + + // add in collision vector [needs bit-twiddling] + world_spx -= energy * (impact_left - car_left) >> 16; + world_spy -= energy * (car_back - impact_back) >> 16; + + // perspective correction for world (x,y) + view_spx = world_spx * DSP4_vars.distance >> 15; + view_spy = world_spy * DSP4_vars.distance >> 15; + + // convert to screen values + DSP4_vars.sprite_x = DSP4_vars.viewport_cx + view_spx; + DSP4_vars.sprite_y = DSP4_vars.viewport_bottom - (DSP4_vars.poly_bottom[0][0] - view_spy); + + // make the car's (x)-coordinate available + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(world_spx); + + // grab a few remaining vehicle values + DSP4.in_count = 4; + DSP4_WAIT(3) resume3 : + + // add vertical lift factor + DSP4_vars.sprite_y += DSP4_READ_WORD(); + } + // terrain sprite + else + { + int16 world_spx, world_spy; + int16 view_spx, view_spy; + + // we already have 4 bytes we want + DSP4.in_count = 10; + DSP4_WAIT(4) resume4 : + + // sort loop inputs + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_raster[0][1] = DSP4_READ_WORD(); + world_spx = DSP4_READ_WORD(); + world_spy = DSP4_READ_WORD(); + + // compute base DSP4_vars.raster line from the bottom + DSP4_vars.segments = DSP4_vars.poly_bottom[0][0] - DSP4_vars.raster; + + // perspective correction for world (x,y) + view_spx = world_spx * DSP4_vars.distance >> 15; + view_spy = world_spy * DSP4_vars.distance >> 15; + + // convert to screen values + DSP4_vars.sprite_x = DSP4_vars.viewport_cx + view_spx - DSP4_vars.poly_cx[0][0]; + DSP4_vars.sprite_y = DSP4_vars.viewport_bottom - DSP4_vars.segments + view_spy; + } + + // default sprite size: 16x16 + DSP4_vars.sprite_size = 1; + DSP4_vars.sprite_attr = DSP4_READ_WORD(); + + //////////////////////////////////////////////////// + // convert tile data to SNES OAM format + + do + { + uint16 header; + + int16 sp_x, sp_y, sp_attr, sp_dattr; + int16 sp_dx, sp_dy; + int16 pixels; + + bool8 draw; + + DSP4.in_count = 2; + DSP4_WAIT(5) resume5 : + + draw = TRUE; + + // opcode termination + DSP4_vars.raster = DSP4_READ_WORD(); + if (DSP4_vars.raster == -0x8000) + goto terminate; + + // stop code + if (DSP4_vars.raster == 0x0000 && !DSP4_vars.sprite_size) + break; + + // toggle sprite size + if (DSP4_vars.raster == 0x0000) + { + DSP4_vars.sprite_size = !DSP4_vars.sprite_size; + continue; + } + + // check for valid sprite header + header = DSP4_vars.raster; + header >>= 8; + if (header != 0x20 && + header != 0x2e && //This is for attractor sprite + header != 0x40 && + header != 0x60 && + header != 0xa0 && + header != 0xc0 && + header != 0xe0) + break; + + // read in rest of sprite data + DSP4.in_count = 4; + DSP4_WAIT(6) resume6 : + + draw = TRUE; + + ///////////////////////////////////// + // process tile data + + // sprite deltas + sp_dattr = DSP4_vars.raster; + sp_dy = DSP4_READ_WORD(); + sp_dx = DSP4_READ_WORD(); + + // update coordinates to screen space + sp_x = DSP4_vars.sprite_x + sp_dx; + sp_y = DSP4_vars.sprite_y + sp_dy; + + // update sprite nametable/attribute information + sp_attr = DSP4_vars.sprite_attr + sp_dattr; + + // allow partially visibile tiles + pixels = DSP4_vars.sprite_size ? 15 : 7; + + DSP4_CLEAR_OUT(); + + // transparent tile to clip off parts of a sprite (overdraw) + if (DSP4_vars.sprite_clipy - pixels <= sp_y && + sp_y <= DSP4_vars.sprite_clipy && + sp_x >= DSP4_vars.viewport_left - pixels && + sp_x <= DSP4_vars.viewport_right && + DSP4_vars.sprite_clipy >= DSP4_vars.viewport_top - pixels && + DSP4_vars.sprite_clipy <= DSP4_vars.viewport_bottom) + { + DSP4_OP0B(&draw, sp_x, DSP4_vars.sprite_clipy, 0x00EE, DSP4_vars.sprite_size, 0); + } + + + // normal sprite tile + if (sp_x >= DSP4_vars.viewport_left - pixels && + sp_x <= DSP4_vars.viewport_right && + sp_y >= DSP4_vars.viewport_top - pixels && + sp_y <= DSP4_vars.viewport_bottom && + sp_y <= DSP4_vars.sprite_clipy) + { + DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, DSP4_vars.sprite_size, 0); + } + + + // no following OAM data + DSP4_OP0B(&draw, 0, 0x0100, 0, 0, 1); + } + while (1); + } + while (1); + + terminate : DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +const uint16 OP0A_Values[16] = { 0x0000, 0x0030, 0x0060, 0x0090, 0x00c0, 0x00f0, 0x0120, 0x0150, 0xfe80, + 0xfeb0, 0xfee0, 0xff10, 0xff40, 0xff70, 0xffa0, 0xffd0 }; + +void DSP4_OP0A(int16 n2, int16 *o1, int16 *o2, int16 *o3, int16 *o4) +{ + *o4 = OP0A_Values[(n2 & 0x000f)]; + *o3 = OP0A_Values[(n2 & 0x00f0) >> 4]; + *o2 = OP0A_Values[(n2 & 0x0f00) >> 8]; + *o1 = OP0A_Values[(n2 & 0xf000) >> 12]; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP0B(bool8 *draw, int16 sp_x, int16 sp_y, int16 sp_attr, bool8 size, bool8 stop) +{ + int16 Row1, Row2; + + // SR = 0x00 + + // align to nearest 8-pixel row + Row1 = (sp_y >> 3) & 0x1f; + Row2 = (Row1 + 1) & 0x1f; + + // check boundaries + if (!((sp_y < 0) || ((sp_y & 0x01ff) < 0x00eb))) + { + *draw = 0; + } + if (size) + { + if (DSP4_vars.OAM_Row[Row1] + 1 >= DSP4_vars.OAM_RowMax) + *draw = 0; + if (DSP4_vars.OAM_Row[Row2] + 1 >= DSP4_vars.OAM_RowMax) + *draw = 0; + } + else + { + if (DSP4_vars.OAM_Row[Row1] >= DSP4_vars.OAM_RowMax) + { + *draw = 0; + } + } + + // emulator fail-safe (unknown if this really exists) + if (DSP4_vars.sprite_count >= 128) + { + *draw = 0; + } + + // SR = 0x80 + + if (*draw) + { + // Row tiles + if (size) + { + DSP4_vars.OAM_Row[Row1] += 2; + DSP4_vars.OAM_Row[Row2] += 2; + } + else + { + DSP4_vars.OAM_Row[Row1]++; + } + + // yield OAM output + DSP4_WRITE_WORD(1); + + // pack OAM data: x,y,name,attr + DSP4_WRITE_BYTE(sp_x & 0xff); + DSP4_WRITE_BYTE(sp_y & 0xff); + DSP4_WRITE_WORD(sp_attr); + + DSP4_vars.sprite_count++; + + // OAM: size,msb data + // save post-oam table data for future retrieval + DSP4_vars.OAM_attr[DSP4_vars.OAM_index] |= ((sp_x <0 || sp_x> 255) << DSP4_vars.OAM_bits); + DSP4_vars.OAM_bits++; + + DSP4_vars.OAM_attr[DSP4_vars.OAM_index] |= (size << DSP4_vars.OAM_bits); + DSP4_vars.OAM_bits++; + + // move to next byte in buffer + if (DSP4_vars.OAM_bits == 16) + { + DSP4_vars.OAM_bits = 0; + DSP4_vars.OAM_index++; + } + } + else if (stop) + { + // yield no OAM output + DSP4_WRITE_WORD(0); + } +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP0D() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // sort inputs + DSP4_vars.world_y = DSP4_READ_DWORD(); + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + DSP4_vars.world_x = DSP4_READ_DWORD(); + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.world_yofs = DSP4_READ_WORD(); + DSP4_vars.world_dy = DSP4_READ_DWORD(); + DSP4_vars.world_dx = DSP4_READ_DWORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.world_xenv = SEX78(DSP4_READ_WORD()); + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting DSP4_vars.raster line + DSP4_vars.view_x1 = (int16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16); + DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16); + DSP4_vars.view_xofs1 = (int16)(DSP4_vars.world_x >> 16); + DSP4_vars.view_yofs1 = DSP4_vars.world_yofs; + + // first DSP4_vars.raster line + DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0]; + + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // perspective projection of world (x,y,scroll) points + // based on the current projection lines + DSP4_vars.view_x2 = (int16)(( ( ( DSP4_vars.world_x + DSP4_vars.world_xenv ) >> 16 ) * DSP4_vars.distance >> 15 ) + ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 )); + DSP4_vars.view_y2 = (int16)((DSP4_vars.world_y >> 16) * DSP4_vars.distance >> 15); + DSP4_vars.view_xofs2 = DSP4_vars.view_x2; + DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2; + + // 1. World x-location before transformation + // 2. Viewer x-position at the current + // 3. World y-location before perspective projection + // 4. Viewer y-position below the horizon + // 5. Number of DSP4_vars.raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((uint16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_x2); + DSP4_WRITE_WORD((uint16)(DSP4_vars.world_y >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_y2); + + ////////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of DSP4_vars.raster lines used + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.view_y2; + + // prevent overdraw + if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0]) + DSP4_vars.segments = 0; + else + DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2; + + // don't draw outside the window + if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0]) + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(DSP4_vars.segments); + + ////////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + + // starting step values + x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1); + y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs); + + // SR = 0x80 + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + // 1. HDMA memory pointer (bg1) + // 2. vertical scroll offset ($210E) + // 3. horizontal scroll offset ($210D) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]); + DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16)); + DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16)); + + + // update memory address + DSP4_vars.poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + ///////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn + DSP4_vars.view_x1 = DSP4_vars.view_x2; + DSP4_vars.view_y1 = DSP4_vars.view_y2; + DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2; + DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2; + + // add deltas for projection lines + DSP4_vars.world_dx += SEX78(DSP4_vars.world_ddx); + DSP4_vars.world_dy += SEX78(DSP4_vars.world_ddy); + + // update projection lines + DSP4_vars.world_x += (DSP4_vars.world_dx + DSP4_vars.world_xenv); + DSP4_vars.world_y += DSP4_vars.world_dy; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // inspect input + DSP4_vars.distance = DSP4_READ_WORD(); + + // terminate op + if (DSP4_vars.distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 6; + DSP4_WAIT(2) resume2: + + // inspect inputs + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // no envelope here + DSP4_vars.world_xenv = 0; + } + while (1); + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP0E() +{ + DSP4_vars.OAM_RowMax = 16; + memset(DSP4_vars.OAM_Row, 0, 64); +} + + +////////////////////////////////////////////////////////////// + +void DSP4_OP0F() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + case 3: + goto resume3; break; + case 4: + goto resume4; break; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // sort inputs + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.world_y = DSP4_READ_DWORD(); + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + DSP4_vars.world_x = DSP4_READ_DWORD(); + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.world_yofs = DSP4_READ_WORD(); + DSP4_vars.world_dy = DSP4_READ_DWORD(); + DSP4_vars.world_dx = DSP4_READ_DWORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.world_xenv = DSP4_READ_DWORD(); + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting DSP4_vars.raster line + DSP4_vars.view_x1 = (int16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16); + DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16); + DSP4_vars.view_xofs1 = (int16)(DSP4_vars.world_x >> 16); + DSP4_vars.view_yofs1 = DSP4_vars.world_yofs; + DSP4_vars.view_turnoff_x = 0; + DSP4_vars.view_turnoff_dx = 0; + + // first DSP4_vars.raster line + DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0]; + + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // perspective projection of world (x,y,scroll) points + // based on the current projection lines + DSP4_vars.view_x2 = (int16)(((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16) * DSP4_vars.distance >> 15); + DSP4_vars.view_y2 = (int16)((DSP4_vars.world_y >> 16) * DSP4_vars.distance >> 15); + DSP4_vars.view_xofs2 = DSP4_vars.view_x2; + DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2; + + // 1. World x-location before transformation + // 2. Viewer x-position at the next + // 3. World y-location before perspective projection + // 4. Viewer y-position below the horizon + // 5. Number of DSP4_vars.raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((uint16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_x2); + DSP4_WRITE_WORD((uint16)(DSP4_vars.world_y >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of DSP4_vars.raster lines used + DSP4_vars.segments = DSP4_vars.poly_raster[0][0] - DSP4_vars.view_y2; + + // prevent overdraw + if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0]) + DSP4_vars.segments = 0; + else + DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2; + + // don't draw outside the window + if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0]) + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(DSP4_vars.segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < 4; DSP4_vars.lcv++) + { + // grab inputs + DSP4.in_count = 4; + DSP4_WAIT(1); + resume1 : + for (;;) + { + int16 distance; + int16 color, red, green, blue; + + distance = DSP4_READ_WORD(); + color = DSP4_READ_WORD(); + + // U1+B5+G5+R5 + red = color & 0x1f; + green = (color >> 5) & 0x1f; + blue = (color >> 10) & 0x1f; + + // dynamic lighting + red = (red * distance >> 15) & 0x1f; + green = (green * distance >> 15) & 0x1f; + blue = (blue * distance >> 15) & 0x1f; + color = red | (green << 5) | (blue << 10); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(color); + break; + } + } + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + + + // starting step values + x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1); + y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs); + + // SR = 0x80 + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + // 1. HDMA memory pointer + // 2. vertical scroll offset ($210E) + // 3. horizontal scroll offset ($210D) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]); + DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16)); + DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16)); + + // update memory address + DSP4_vars.poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + //////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn + DSP4_vars.view_x1 = DSP4_vars.view_x2; + DSP4_vars.view_y1 = DSP4_vars.view_y2; + DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2; + DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2; + + // add deltas for projection lines + DSP4_vars.world_dx += SEX78(DSP4_vars.world_ddx); + DSP4_vars.world_dy += SEX78(DSP4_vars.world_ddy); + + // update projection lines + DSP4_vars.world_x += (DSP4_vars.world_dx + DSP4_vars.world_xenv); + DSP4_vars.world_y += DSP4_vars.world_dy; + + // update road turnoff position + DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(2) resume2: + + // check for termination + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + break; + + // road splice + if( (uint16) DSP4_vars.distance == 0x8001 ) + { + DSP4.in_count = 6; + DSP4_WAIT(3) resume3: + + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_vars.view_turnoff_x = DSP4_READ_WORD(); + DSP4_vars.view_turnoff_dx = DSP4_READ_WORD(); + + // factor in new changes + DSP4_vars.view_x1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 ); + DSP4_vars.view_xofs1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 ); + + // update stepping values + DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx; + + DSP4.in_count = 2; + DSP4_WAIT(2) + } + + // already have 2 bytes in queue + DSP4.in_count = 6; + DSP4_WAIT(4) resume4 : + + // inspect inputs + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // no envelope here + DSP4_vars.world_xenv = 0; + } + while (1); + + // terminate op + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP10() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + case 3: + goto resume3; break; + } + + //////////////////////////////////////////////////// + // sort inputs + + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.world_y = DSP4_READ_DWORD(); + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + DSP4_vars.world_x = DSP4_READ_DWORD(); + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.world_yofs = DSP4_READ_WORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_vars.view_y2 = DSP4_READ_WORD(); + DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_x2 = DSP4_READ_WORD(); + DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting DSP4_vars.raster line + DSP4_vars.view_x1 = (int16)(DSP4_vars.world_x >> 16); + DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16); + DSP4_vars.view_xofs1 = DSP4_vars.view_x1; + DSP4_vars.view_yofs1 = DSP4_vars.world_yofs; + + // first DSP4_vars.raster line + DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0]; + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // add shaping + DSP4_vars.view_x2 += DSP4_vars.view_dx; + DSP4_vars.view_y2 += DSP4_vars.view_dy; + + // vertical scroll calculation + DSP4_vars.view_xofs2 = DSP4_vars.view_x2; + DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2; + + // 1. Viewer x-position at the next + // 2. Viewer y-position below the horizon + // 3. Number of DSP4_vars.raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(DSP4_vars.view_x2); + DSP4_WRITE_WORD(DSP4_vars.view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of DSP4_vars.raster lines used + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.view_y2; + + // prevent overdraw + if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0]) + DSP4_vars.segments = 0; + else + DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2; + + // don't draw outside the window + if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0]) + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(DSP4_vars.segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < 4; DSP4_vars.lcv++) + { + // grab inputs + DSP4.in_count = 4; + DSP4_WAIT(1); + resume1 : + for (;;) + { + int16 distance; + int16 color, red, green, blue; + + distance = DSP4_READ_WORD(); + color = DSP4_READ_WORD(); + + // U1+B5+G5+R5 + red = color & 0x1f; + green = (color >> 5) & 0x1f; + blue = (color >> 10) & 0x1f; + + // dynamic lighting + red = (red * distance >> 15) & 0x1f; + green = (green * distance >> 15) & 0x1f; + blue = (blue * distance >> 15) & 0x1f; + color = red | (green << 5) | (blue << 10); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(color); + break; + } + } + } + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + + // starting step values + x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1); + y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs); + + // SR = 0x80 + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + // 1. HDMA memory pointer (bg2) + // 2. vertical scroll offset ($2110) + // 3. horizontal scroll offset ($210F) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]); + DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16)); + DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16)); + + // update memory address + DSP4_vars.poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + ///////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn + DSP4_vars.view_x1 = DSP4_vars.view_x2; + DSP4_vars.view_y1 = DSP4_vars.view_y2; + DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2; + DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(2) resume2 : + + // check for opcode termination + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 10; + DSP4_WAIT(3) resume3 : + + + // inspect inputs + DSP4_vars.view_y2 = DSP4_READ_WORD(); + DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_x2 = DSP4_READ_WORD(); + DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + } + while (1); + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP11(int16 A, int16 B, int16 C, int16 D, int16 *M) +{ + // 0x155 = 341 = Horizontal Width of the Screen + *M = ((A * 0x0155 >> 2) & 0xf000) | + ((B * 0x0155 >> 6) & 0x0f00) | + ((C * 0x0155 >> 10) & 0x00f0) | + ((D * 0x0155 >> 14) & 0x000f); +} + + + + + +///////////////////////////////////////////////////////////// +//Processing Code +///////////////////////////////////////////////////////////// +uint8 dsp4_byte; +uint16 dsp4_address; + +void InitDSP4() +{ + memset(&DSP4, 0, sizeof(DSP4)); + DSP4.waiting4command = TRUE; +} + +void DSP4SetByte() +{ + // clear pending read + if (DSP4.out_index < DSP4.out_count) + { + DSP4.out_index++; + return; + } + + if (DSP4.waiting4command) + { + if (DSP4.half_command) + { + DSP4.command |= (dsp4_byte << 8); + DSP4.in_index = 0; + DSP4.waiting4command = FALSE; + DSP4.half_command = FALSE; + DSP4.out_count = 0; + DSP4.out_index = 0; + + DSP4_vars.DSP4_Logic = 0; + + + switch (DSP4.command) + { + case 0x0000: + DSP4.in_count = 4; break; + case 0x0001: + DSP4.in_count = 44; break; + case 0x0003: + DSP4.in_count = 0; break; + case 0x0005: + DSP4.in_count = 0; break; + case 0x0006: + DSP4.in_count = 0; break; + case 0x0007: + DSP4.in_count = 34; break; + case 0x0008: + DSP4.in_count = 90; break; + case 0x0009: + DSP4.in_count = 14; break; + case 0x000a: + DSP4.in_count = 6; break; + case 0x000b: + DSP4.in_count = 6; break; + case 0x000d: + DSP4.in_count = 42; break; + case 0x000e: + DSP4.in_count = 0; break; + case 0x000f: + DSP4.in_count = 46; break; + case 0x0010: + DSP4.in_count = 36; break; + case 0x0011: + DSP4.in_count = 8; break; + default: + DSP4.waiting4command = TRUE; + break; + } + } + else + { + DSP4.command = dsp4_byte; + DSP4.half_command = TRUE; + } + } + else + { + DSP4.parameters[DSP4.in_index] = dsp4_byte; + DSP4.in_index++; + } + + if (!DSP4.waiting4command && DSP4.in_count == DSP4.in_index) + { + // Actually execute the command + DSP4.waiting4command = TRUE; + DSP4.out_index = 0; + DSP4.in_index = 0; + + switch (DSP4.command) + { + // 16-bit multiplication + case 0x0000: + { + int16 multiplier, multiplicand; + int32 product; + + multiplier = DSP4_READ_WORD(); + multiplicand = DSP4_READ_WORD(); + + DSP4_Multiply(multiplicand, multiplier, &product); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((uint16)(product)); + DSP4_WRITE_WORD((uint16)(product >> 16)); + } + break; + + // single-player track projection + case 0x0001: + DSP4_OP01(); break; + + // single-player selection + case 0x0003: + DSP4_OP03(); break; + + // clear OAM + case 0x0005: + DSP4_OP05(); break; + + // transfer OAM + case 0x0006: + DSP4_OP06(); break; + + // single-player track turnoff projection + case 0x0007: + DSP4_OP07(); break; + + // solid polygon projection + case 0x0008: + DSP4_OP08(); break; + + // sprite projection + case 0x0009: + DSP4_OP09(); break; + + // unknown + case 0x000A: + { + int16 in1a = DSP4_READ_WORD(); + int16 in2a = DSP4_READ_WORD(); + int16 in3a = DSP4_READ_WORD(); + int16 out1a, out2a, out3a, out4a; + + DSP4_OP0A(in2a, &out2a, &out1a, &out4a, &out3a); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(out1a); + DSP4_WRITE_WORD(out2a); + DSP4_WRITE_WORD(out3a); + DSP4_WRITE_WORD(out4a); + } + break; + + // set OAM + case 0x000B: + { + int16 sp_x = DSP4_READ_WORD(); + int16 sp_y = DSP4_READ_WORD(); + int16 sp_attr = DSP4_READ_WORD(); + bool8 draw = 1; + + DSP4_CLEAR_OUT(); + + DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, 0, 1); + } + break; + + // multi-player track projection + case 0x000D: + DSP4_OP0D(); break; + + // multi-player selection + case 0x000E: + DSP4_OP0E(); break; + + // single-player track projection with lighting + case 0x000F: + DSP4_OP0F(); break; + + // single-player track turnoff projection with lighting + case 0x0010: + DSP4_OP10(); break; + + // unknown: horizontal mapping command + case 0x0011: + { + int16 a, b, c, d, m; + + + d = DSP4_READ_WORD(); + c = DSP4_READ_WORD(); + b = DSP4_READ_WORD(); + a = DSP4_READ_WORD(); + + DSP4_OP11(a, b, c, d, &m); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(m); + + break; + } + + default: + break; + } + } +} + +void DSP4GetByte() +{ + if (DSP4.out_count) + { + dsp4_byte = (uint8) DSP4.output[DSP4.out_index&0x1FF]; + DSP4.out_index++; + if (DSP4.out_count == DSP4.out_index) + DSP4.out_count = 0; + } + else + { + dsp4_byte = 0xff; + } +} + +#endif diff --git a/sfc/coprocessor/dsp4/dsp4emu.h b/sfc/coprocessor/dsp4/dsp4emu.h new file mode 100644 index 0000000..834b33d --- /dev/null +++ b/sfc/coprocessor/dsp4/dsp4emu.h @@ -0,0 +1,108 @@ +//DSP-4 emulator code +//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden + +#ifndef DSP4EMU_H +#define DSP4EMU_H + +#undef TRUE +#undef FALSE +#define TRUE true +#define FALSE false + +struct DSP4_t +{ + bool8 waiting4command; + bool8 half_command; + uint16 command; + uint32 in_count; + uint32 in_index; + uint32 out_count; + uint32 out_index; + uint8 parameters[512]; + uint8 output[512]; +}; + +extern struct DSP4_t DSP4; + +struct DSP4_vars_t +{ + // op control + int8 DSP4_Logic; // controls op flow + + + // projection format + int16 lcv; // loop-control variable + int16 distance; // z-position into virtual world + int16 raster; // current raster line + int16 segments; // number of raster lines drawn + + // 1.15.16 or 1.15.0 [sign, integer, fraction] + int32 world_x; // line of x-projection in world + int32 world_y; // line of y-projection in world + int32 world_dx; // projection line x-delta + int32 world_dy; // projection line y-delta + int16 world_ddx; // x-delta increment + int16 world_ddy; // y-delta increment + int32 world_xenv; // world x-shaping factor + int16 world_yofs; // world y-vertical scroll + + int16 view_x1; // current viewer-x + int16 view_y1; // current viewer-y + int16 view_x2; // future viewer-x + int16 view_y2; // future viewer-y + int16 view_dx; // view x-delta factor + int16 view_dy; // view y-delta factor + int16 view_xofs1; // current viewer x-vertical scroll + int16 view_yofs1; // current viewer y-vertical scroll + int16 view_xofs2; // future viewer x-vertical scroll + int16 view_yofs2; // future viewer y-vertical scroll + int16 view_yofsenv; // y-scroll shaping factor + int16 view_turnoff_x; // road turnoff data + int16 view_turnoff_dx; // road turnoff delta factor + + + // drawing area + + int16 viewport_cx; // x-center of viewport window + int16 viewport_cy; // y-center of render window + int16 viewport_left; // x-left of viewport + int16 viewport_right; // x-right of viewport + int16 viewport_top; // y-top of viewport + int16 viewport_bottom; // y-bottom of viewport + + + // sprite structure + + int16 sprite_x; // projected x-pos of sprite + int16 sprite_y; // projected y-pos of sprite + int16 sprite_attr; // obj attributes + bool8 sprite_size; // sprite size: 8x8 or 16x16 + int16 sprite_clipy; // visible line to clip pixels off + int16 sprite_count; + + // generic projection variables designed for + // two solid polygons + two polygon sides + + int16 poly_clipLf[2][2]; // left clip boundary + int16 poly_clipRt[2][2]; // right clip boundary + int16 poly_ptr[2][2]; // HDMA structure pointers + int16 poly_raster[2][2]; // current raster line below horizon + int16 poly_top[2][2]; // top clip boundary + int16 poly_bottom[2][2]; // bottom clip boundary + int16 poly_cx[2][2]; // center for left/right points + int16 poly_start[2]; // current projection points + int16 poly_plane[2]; // previous z-plane distance + + + // OAM + int16 OAM_attr[16]; // OAM (size,MSB) data + int16 OAM_index; // index into OAM table + int16 OAM_bits; // offset into OAM table + + int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row) + int16 OAM_Row[32]; // current number of tiles per row +}; + +extern struct DSP4_vars_t DSP4_vars; + +#endif diff --git a/sfc/coprocessor/dsp4/serialization.cpp b/sfc/coprocessor/dsp4/serialization.cpp new file mode 100644 index 0000000..a7f0647 --- /dev/null +++ b/sfc/coprocessor/dsp4/serialization.cpp @@ -0,0 +1,72 @@ +auto DSP4::serialize(serializer& s) -> void { + s.integer(DSP4i::DSP4.waiting4command); + s.integer(DSP4i::DSP4.half_command); + s.integer(DSP4i::DSP4.command); + s.integer(DSP4i::DSP4.in_count); + s.integer(DSP4i::DSP4.in_index); + s.integer(DSP4i::DSP4.out_count); + s.integer(DSP4i::DSP4.out_index); + s.array(DSP4i::DSP4.parameters); + s.array(DSP4i::DSP4.output); + + s.integer(DSP4i::DSP4_vars.DSP4_Logic); + s.integer(DSP4i::DSP4_vars.lcv); + s.integer(DSP4i::DSP4_vars.distance); + s.integer(DSP4i::DSP4_vars.raster); + s.integer(DSP4i::DSP4_vars.segments); + s.integer(DSP4i::DSP4_vars.world_x); + s.integer(DSP4i::DSP4_vars.world_y); + s.integer(DSP4i::DSP4_vars.world_dx); + s.integer(DSP4i::DSP4_vars.world_dy); + s.integer(DSP4i::DSP4_vars.world_ddx); + s.integer(DSP4i::DSP4_vars.world_ddy); + s.integer(DSP4i::DSP4_vars.world_xenv); + s.integer(DSP4i::DSP4_vars.world_yofs); + s.integer(DSP4i::DSP4_vars.view_x1); + s.integer(DSP4i::DSP4_vars.view_y1); + s.integer(DSP4i::DSP4_vars.view_x2); + s.integer(DSP4i::DSP4_vars.view_y2); + s.integer(DSP4i::DSP4_vars.view_dx); + s.integer(DSP4i::DSP4_vars.view_dy); + s.integer(DSP4i::DSP4_vars.view_xofs1); + s.integer(DSP4i::DSP4_vars.view_yofs1); + s.integer(DSP4i::DSP4_vars.view_xofs2); + s.integer(DSP4i::DSP4_vars.view_yofs2); + s.integer(DSP4i::DSP4_vars.view_yofsenv); + s.integer(DSP4i::DSP4_vars.view_turnoff_x); + s.integer(DSP4i::DSP4_vars.view_turnoff_dx); + s.integer(DSP4i::DSP4_vars.viewport_cx); + s.integer(DSP4i::DSP4_vars.viewport_cy); + s.integer(DSP4i::DSP4_vars.viewport_left); + s.integer(DSP4i::DSP4_vars.viewport_right); + s.integer(DSP4i::DSP4_vars.viewport_top); + s.integer(DSP4i::DSP4_vars.viewport_bottom); + s.integer(DSP4i::DSP4_vars.sprite_x); + s.integer(DSP4i::DSP4_vars.sprite_y); + s.integer(DSP4i::DSP4_vars.sprite_attr); + s.integer(DSP4i::DSP4_vars.sprite_size); + s.integer(DSP4i::DSP4_vars.sprite_clipy); + s.integer(DSP4i::DSP4_vars.sprite_count); + + s.array(DSP4i::DSP4_vars.poly_clipLf[0]); + s.array(DSP4i::DSP4_vars.poly_clipLf[1]); + s.array(DSP4i::DSP4_vars.poly_clipRt[0]); + s.array(DSP4i::DSP4_vars.poly_clipRt[1]); + s.array(DSP4i::DSP4_vars.poly_ptr[0]); + s.array(DSP4i::DSP4_vars.poly_ptr[1]); + s.array(DSP4i::DSP4_vars.poly_raster[0]); + s.array(DSP4i::DSP4_vars.poly_raster[1]); + s.array(DSP4i::DSP4_vars.poly_top[0]); + s.array(DSP4i::DSP4_vars.poly_top[1]); + s.array(DSP4i::DSP4_vars.poly_bottom[0]); + s.array(DSP4i::DSP4_vars.poly_bottom[1]); + s.array(DSP4i::DSP4_vars.poly_cx[0]); + s.array(DSP4i::DSP4_vars.poly_cx[1]); + s.array(DSP4i::DSP4_vars.poly_start); + s.array(DSP4i::DSP4_vars.poly_plane); + s.array(DSP4i::DSP4_vars.OAM_attr); + s.integer(DSP4i::DSP4_vars.OAM_index); + s.integer(DSP4i::DSP4_vars.OAM_bits); + s.integer(DSP4i::DSP4_vars.OAM_RowMax); + s.array(DSP4i::DSP4_vars.OAM_Row); +} diff --git a/sfc/coprocessor/epsonrtc/epsonrtc.cpp b/sfc/coprocessor/epsonrtc/epsonrtc.cpp new file mode 100644 index 0000000..74e0c2f --- /dev/null +++ b/sfc/coprocessor/epsonrtc/epsonrtc.cpp @@ -0,0 +1,205 @@ +#include + +namespace SuperFamicom { + +#include "memory.cpp" +#include "time.cpp" +#include "serialization.cpp" +EpsonRTC epsonrtc; + +auto EpsonRTC::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto EpsonRTC::Enter() -> void { + while(true) { + scheduler.synchronize(); + epsonrtc.main(); + } +} + +auto EpsonRTC::main() -> void { + if(wait) { if(--wait == 0) ready = 1; } + + clocks++; + if((clocks & ~0x00ff) == 0) roundSeconds(); //125 microseconds + if((clocks & ~0x3fff) == 0) duty(); //1/128th second + if((clocks & ~0x7fff) == 0) irq(0); //1/64th second + if(clocks == 0) { //1 second + seconds++; + irq(1); + if(seconds % 60 == 0) irq(2); //1 minute + if(seconds % 1440 == 0) irq(3), seconds = 0; //1 hour + tick(); + } + + step(1); + synchronizeCPU(); +} + +auto EpsonRTC::step(uint clocks) -> void { + clock += clocks * (uint64_t)cpu.frequency; +} + +auto EpsonRTC::initialize() -> void { + secondlo = 0; + secondhi = 0; + batteryfailure = 1; + + minutelo = 0; + minutehi = 0; + resync = 0; + + hourlo = 0; + hourhi = 0; + meridian = 0; + + daylo = 0; + dayhi = 0; + dayram = 0; + + monthlo = 0; + monthhi = 0; + monthram = 0; + + yearlo = 0; + yearhi = 0; + + weekday = 0; + + hold = 0; + calendar = 0; + irqflag = 0; + roundseconds = 0; + + irqmask = 0; + irqduty = 0; + irqperiod = 0; + + pause = 0; + stop = 0; + atime = 0; + test = 0; +} + +auto EpsonRTC::power() -> void { + create(EpsonRTC::Enter, 32'768 * 64); + + clocks = 0; + seconds = 0; + + chipselect = 0; + state = State::Mode; + offset = 0; + wait = 0; + ready = 0; + holdtick = 0; +} + +auto EpsonRTC::synchronize(uint64 timestamp) -> void { + time_t systime = timestamp; + tm* timeinfo = localtime(&systime); + + uint second = min(59, timeinfo->tm_sec); + secondlo = second % 10; + secondhi = second / 10; + + uint minute = timeinfo->tm_min; + minutelo = minute % 10; + minutehi = minute / 10; + + uint hour = timeinfo->tm_hour; + if(atime) { + hourlo = hour % 10; + hourhi = hour / 10; + } else { + meridian = hour >= 12; + hour %= 12; + if(hour == 0) hour = 12; + hourlo = hour % 10; + hourhi = hour / 10; + } + + uint day = timeinfo->tm_mday; + daylo = day % 10; + dayhi = day / 10; + + uint month = 1 + timeinfo->tm_mon; + monthlo = month % 10; + monthhi = month / 10; + + uint year = timeinfo->tm_year % 100; + yearlo = year % 10; + yearhi = year / 10; + + weekday = timeinfo->tm_wday; + + resync = true; //alert program that time has changed +} + +auto EpsonRTC::read(uint addr, uint8 data) -> uint8 { + cpu.synchronizeCoprocessors(); + addr &= 3; + + if(addr == 0) { + return chipselect; + } + + if(addr == 1) { + if(chipselect != 1) return 0; + if(ready == 0) return 0; + if(state == State::Write) return mdr; + if(state != State::Read) return 0; + ready = 0; + wait = 8; + return rtcRead(offset++); + } + + if(addr == 2) { + return ready << 7; + } + + return data; +} + +auto EpsonRTC::write(uint addr, uint8 data) -> void { + cpu.synchronizeCoprocessors(); + addr &= 3, data &= 15; + + if(addr == 0) { + chipselect = data; + if(chipselect != 1) rtcReset(); + ready = 1; + } + + if(addr == 1) { + if(chipselect != 1) return; + if(ready == 0) return; + + if(state == State::Mode) { + if(data != 0x03 && data != 0x0c) return; + state = State::Seek; + ready = 0; + wait = 8; + mdr = data; + } + + else if(state == State::Seek) { + if(mdr == 0x03) state = State::Write; + if(mdr == 0x0c) state = State::Read; + offset = data; + ready = 0; + wait = 8; + mdr = data; + } + + else if(state == State::Write) { + rtcWrite(offset++, data); + ready = 0; + wait = 8; + mdr = data; + } + } +} + +} diff --git a/sfc/coprocessor/epsonrtc/epsonrtc.hpp b/sfc/coprocessor/epsonrtc/epsonrtc.hpp new file mode 100644 index 0000000..62ff70e --- /dev/null +++ b/sfc/coprocessor/epsonrtc/epsonrtc.hpp @@ -0,0 +1,90 @@ +//Epson RTC-4513 Real-Time Clock + +struct EpsonRTC : Thread { + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + + auto initialize() -> void; + auto power() -> void; + auto synchronize(uint64 timestamp) -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; + + uint21 clocks; + uint seconds; + + uint2 chipselect; + enum class State : uint { Mode, Seek, Read, Write } state; + uint4 mdr; + uint4 offset; + uint wait; + uint1 ready; + uint1 holdtick; + + uint4 secondlo; + uint3 secondhi; + uint1 batteryfailure; + + uint4 minutelo; + uint3 minutehi; + uint1 resync; + + uint4 hourlo; + uint2 hourhi; + uint1 meridian; + + uint4 daylo; + uint2 dayhi; + uint1 dayram; + + uint4 monthlo; + uint1 monthhi; + uint2 monthram; + + uint4 yearlo; + uint4 yearhi; + + uint3 weekday; + + uint1 hold; + uint1 calendar; + uint1 irqflag; + uint1 roundseconds; + + uint1 irqmask; + uint1 irqduty; + uint2 irqperiod; + + uint1 pause; + uint1 stop; + uint1 atime; //astronomical time (24-hour mode) + uint1 test; + + //memory.cpp + auto rtcReset() -> void; + auto rtcRead(uint4 addr) -> uint4; + auto rtcWrite(uint4 addr, uint4 data) -> void; + + auto load(const uint8* data) -> void; + auto save(uint8* data) -> void; + + //time.cpp + auto irq(uint2 period) -> void; + auto duty() -> void; + auto roundSeconds() -> void; + auto tick() -> void; + + auto tickSecond() -> void; + auto tickMinute() -> void; + auto tickHour() -> void; + auto tickDay() -> void; + auto tickMonth() -> void; + auto tickYear() -> void; +}; + +extern EpsonRTC epsonrtc; diff --git a/sfc/coprocessor/epsonrtc/memory.cpp b/sfc/coprocessor/epsonrtc/memory.cpp new file mode 100644 index 0000000..f3ab59e --- /dev/null +++ b/sfc/coprocessor/epsonrtc/memory.cpp @@ -0,0 +1,180 @@ +auto EpsonRTC::rtcReset() -> void { + state = State::Mode; + offset = 0; + + resync = 0; + pause = 0; + test = 0; +} + +auto EpsonRTC::rtcRead(uint4 addr) -> uint4 { + switch(addr) { default: + case 0: return secondlo; + case 1: return secondhi | batteryfailure << 3; + case 2: return minutelo; + case 3: return minutehi | resync << 3; + case 4: return hourlo; + case 5: return hourhi | meridian << 2 | resync << 3; + case 6: return daylo; + case 7: return dayhi | dayram << 2 | resync << 3; + case 8: return monthlo; + case 9: return monthhi | monthram << 1 | resync << 3; + case 10: return yearlo; + case 11: return yearhi; + case 12: return weekday | resync << 3; + case 13: { + uint1 readflag = irqflag & !irqmask; + irqflag = 0; + return hold | calendar << 1 | readflag << 2 | roundseconds << 3; + } + case 14: return irqmask | irqduty << 1 | irqperiod << 2; + case 15: return pause | stop << 1 | atime << 2 | test << 3; + } +} + +auto EpsonRTC::rtcWrite(uint4 addr, uint4 data) -> void { + switch(addr) { + case 0: + secondlo = data; + break; + case 1: + secondhi = data; + batteryfailure = data >> 3; + break; + case 2: + minutelo = data; + break; + case 3: + minutehi = data; + break; + case 4: + hourlo = data; + break; + case 5: + hourhi = data; + meridian = data >> 2; + if(atime == 1) meridian = 0; + if(atime == 0) hourhi &= 1; + break; + case 6: + daylo = data; + break; + case 7: + dayhi = data; + dayram = data >> 2; + break; + case 8: + monthlo = data; + break; + case 9: + monthhi = data; + monthram = data >> 1; + break; + case 10: + yearlo = data; + break; + case 11: + yearhi = data; + break; + case 12: + weekday = data; + break; + case 13: { + bool held = hold; + hold = data; + calendar = data >> 1; + roundseconds = data >> 3; + if(held == 1 && hold == 0 && holdtick == 1) { + //if a second has passed during hold, increment one second upon resuming + holdtick = 0; + tickSecond(); + } + } break; + case 14: + irqmask = data; + irqduty = data >> 1; + irqperiod = data >> 2; + break; + case 15: + pause = data; + stop = data >> 1; + atime = data >> 2; + test = data >> 3; + if(atime == 1) meridian = 0; + if(atime == 0) hourhi &= 1; + if(pause) { + secondlo = 0; + secondhi = 0; + } + break; + } +} + +auto EpsonRTC::load(const uint8* data) -> void { + secondlo = data[0] >> 0; + secondhi = data[0] >> 4; + batteryfailure = data[0] >> 7; + + minutelo = data[1] >> 0; + minutehi = data[1] >> 4; + resync = data[1] >> 7; + + hourlo = data[2] >> 0; + hourhi = data[2] >> 4; + meridian = data[2] >> 6; + + daylo = data[3] >> 0; + dayhi = data[3] >> 4; + dayram = data[3] >> 6; + + monthlo = data[4] >> 0; + monthhi = data[4] >> 4; + monthram = data[4] >> 5; + + yearlo = data[5] >> 0; + yearhi = data[5] >> 4; + + weekday = data[6] >> 0; + + hold = data[6] >> 4; + calendar = data[6] >> 5; + irqflag = data[6] >> 6; + roundseconds = data[6] >> 7; + + irqmask = data[7] >> 0; + irqduty = data[7] >> 1; + irqperiod = data[7] >> 2; + + pause = data[7] >> 4; + stop = data[7] >> 5; + atime = data[7] >> 6; + test = data[7] >> 7; + + uint64 timestamp = 0; + for(auto byte : range(8)) { + timestamp |= data[8 + byte] << (byte * 8); + } + + uint64 diff = (uint64)time(0) - timestamp; + while(diff >= 60 * 60 * 24) { tickDay(); diff -= 60 * 60 * 24; } + while(diff >= 60 * 60) { tickHour(); diff -= 60 * 60; } + while(diff >= 60) { tickMinute(); diff -= 60; } + while(diff--) tickSecond(); +} + +auto EpsonRTC::save(uint8* data) -> void { + data[0] = secondlo << 0 | secondhi << 4 | batteryfailure << 7; + data[1] = minutelo << 0 | minutehi << 4 | resync << 7; + data[2] = hourlo << 0 | hourhi << 4 | meridian << 6 | resync << 7; + data[3] = daylo << 0 | dayhi << 4 | dayram << 6 | resync << 7; + data[4] = monthlo << 0 | monthhi << 4 | monthram << 5 | resync << 7; + data[5] = yearlo << 0 | yearhi << 4; + data[6] = weekday << 0 | resync << 3 | hold << 4 | calendar << 5 | irqflag << 6 | roundseconds << 7; + data[7] = irqmask << 0 | irqduty << 1 | irqperiod << 2 | pause << 4 | stop << 5 | atime << 6 | test << 7; + + uint64 timestamp = (uint64)time(0); + for(auto byte : range(8)) { + data[8 + byte] = timestamp; + timestamp >>= 8; + } +} diff --git a/sfc/coprocessor/epsonrtc/serialization.cpp b/sfc/coprocessor/epsonrtc/serialization.cpp new file mode 100644 index 0000000..0b75af6 --- /dev/null +++ b/sfc/coprocessor/epsonrtc/serialization.cpp @@ -0,0 +1,53 @@ +auto EpsonRTC::serialize(serializer& s) -> void { + Thread::serialize(s); + + s.integer(clocks); + s.integer(seconds); + + s.integer(chipselect); + s.integer((uint&)state); + s.integer(mdr); + s.integer(offset); + s.integer(wait); + s.integer(ready); + s.integer(holdtick); + + s.integer(secondlo); + s.integer(secondhi); + s.integer(batteryfailure); + + s.integer(minutelo); + s.integer(minutehi); + s.integer(resync); + + s.integer(hourlo); + s.integer(hourhi); + s.integer(meridian); + + s.integer(daylo); + s.integer(dayhi); + s.integer(dayram); + + s.integer(monthlo); + s.integer(monthhi); + s.integer(monthram); + + s.integer(yearlo); + s.integer(yearhi); + + s.integer(weekday); + + s.integer(hold); + s.integer(calendar); + s.integer(irqflag); + s.integer(roundseconds); + + s.integer(irqmask); + s.integer(irqduty); + s.integer(irqperiod); + + s.integer(pause); + s.integer(stop); + s.integer(atime); + s.integer(test); +} diff --git a/sfc/coprocessor/epsonrtc/time.cpp b/sfc/coprocessor/epsonrtc/time.cpp new file mode 100644 index 0000000..08c13a4 --- /dev/null +++ b/sfc/coprocessor/epsonrtc/time.cpp @@ -0,0 +1,182 @@ +auto EpsonRTC::irq(uint2 period) -> void { + if(stop || pause) return; + + if(period == irqperiod) irqflag = 1; +} + +auto EpsonRTC::duty() -> void { + if(irqduty) irqflag = 0; +} + +auto EpsonRTC::roundSeconds() -> void { + if(roundseconds == 0) return; + roundseconds = 0; + + if(secondhi >= 3) tickMinute(); + secondlo = 0; + secondhi = 0; +} + +auto EpsonRTC::tick() -> void { + if(stop || pause) return; + + if(hold) { + holdtick = 1; + return; + } + + resync = 1; + tickSecond(); +} + +//below code provides bit-perfect emulation of invalid BCD values on the RTC-4513 +//code makes extensive use of variable-length integers (see epsonrtc.hpp for sizes) + +auto EpsonRTC::tickSecond() -> void { + if(secondlo <= 8 || secondlo == 12) { + secondlo++; + } else { + secondlo = 0; + if(secondhi < 5) { + secondhi++; + } else { + secondhi = 0; + tickMinute(); + } + } +} + +auto EpsonRTC::tickMinute() -> void { + if(minutelo <= 8 || minutelo == 12) { + minutelo++; + } else { + minutelo = 0; + if(minutehi < 5) { + minutehi++; + } else { + minutehi = 0; + tickHour(); + } + } +} + +auto EpsonRTC::tickHour() -> void { + if(atime) { + if(hourhi < 2) { + if(hourlo <= 8 || hourlo == 12) { + hourlo++; + } else { + hourlo = !(hourlo & 1); + hourhi++; + } + } else { + if(hourlo != 3 && !(hourlo & 4)) { + if(hourlo <= 8 || hourlo >= 12) { + hourlo++; + } else { + hourlo = !(hourlo & 1); + hourhi++; + } + } else { + hourlo = !(hourlo & 1); + hourhi = 0; + tickDay(); + } + } + } else { + if(hourhi == 0) { + if(hourlo <= 8 || hourlo == 12) { + hourlo++; + } else { + hourlo = !(hourlo & 1); + hourhi ^= 1; + } + } else { + if(hourlo & 1) meridian ^= 1; + if(hourlo < 2 || hourlo == 4 || hourlo == 5 || hourlo == 8 || hourlo == 12) { + hourlo++; + } else { + hourlo = !(hourlo & 1); + hourhi ^= 1; + } + if(meridian == 0 && !(hourlo & 1)) tickDay(); + } + } +} + +auto EpsonRTC::tickDay() -> void { + if(calendar == 0) return; + weekday = (weekday + 1) + (weekday == 6); + + //January - December = 0x01 - 0x09; 0x10 - 0x12 + static const uint daysinmonth[32] = { + 30, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30, 31, 30, + 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, + }; + + uint days = daysinmonth[monthhi << 4 | monthlo]; + if(days == 28) { + //add one day for leap years + if((yearhi & 1) == 0 && ((yearlo - 0) & 3) == 0) days++; + if((yearhi & 1) == 1 && ((yearlo - 2) & 3) == 0) days++; + } + + if(days == 28 && (dayhi == 3 || (dayhi == 2 && daylo >= 8))) { + daylo = 1; + dayhi = 0; + return tickMonth(); + } + + if(days == 29 && (dayhi == 3 || (dayhi == 2 && (daylo > 8 && daylo != 12)))) { + daylo = 1; + dayhi = 0; + return tickMonth(); + } + + if(days == 30 && (dayhi == 3 || (dayhi == 2 && (daylo == 10 || daylo == 14)))) { + daylo = 1; + dayhi = 0; + return tickMonth(); + } + + if(days == 31 && (dayhi == 3 && (daylo & 3))) { + daylo = 1; + dayhi = 0; + return tickMonth(); + } + + if(daylo <= 8 || daylo == 12) { + daylo++; + } else { + daylo = !(daylo & 1); + dayhi++; + } +} + +auto EpsonRTC::tickMonth() -> void { + if(monthhi == 0 || !(monthlo & 2)) { + if(monthlo <= 8 || monthlo == 12) { + monthlo++; + } else { + monthlo = !(monthlo & 1); + monthhi ^= 1; + } + } else { + monthlo = !(monthlo & 1); + monthhi = 0; + tickYear(); + } +} + +auto EpsonRTC::tickYear() -> void { + if(yearlo <= 8 || yearlo == 12) { + yearlo++; + } else { + yearlo = !(yearlo & 1); + if(yearhi <= 8 || yearhi == 12) { + yearhi++; + } else { + yearhi = !(yearhi & 1); + } + } +} diff --git a/sfc/coprocessor/event/event.cpp b/sfc/coprocessor/event/event.cpp new file mode 100644 index 0000000..08c053a --- /dev/null +++ b/sfc/coprocessor/event/event.cpp @@ -0,0 +1,122 @@ +#include + +namespace SuperFamicom { + +#include "serialization.cpp" +Event event; + +auto Event::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto Event::Enter() -> void { + while(true) { + scheduler.synchronize(); + event.main(); + } +} + +auto Event::main() -> void { + if(scoreActive && scoreSecondsRemaining) { + if(--scoreSecondsRemaining == 0) { + scoreActive = false; + } + } + + if(timerActive && timerSecondsRemaining) { + if(--timerSecondsRemaining == 0) { + timerActive = false; + status |= 0x02; //time over + scoreActive = true; + scoreSecondsRemaining = 5; + } + } + + step(1); + synchronizeCPU(); +} + +auto Event::step(uint clocks) -> void { + clock += clocks * (uint64_t)cpu.frequency; +} + +auto Event::unload() -> void { + rom[0].reset(); + rom[1].reset(); + rom[2].reset(); + rom[3].reset(); +} + +auto Event::power() -> void { + create(Event::Enter, 1); + + //DIP switches 0-3 control the time: 3 minutes + 0-15 extra minutes + timer = (3 + (dip.value & 15)) * 60; //in seconds + //DIP switches 4-5 serve an unknown purpose + //DIP switches 6-7 are not connected + + status = 0x00; + select = 0x00; + timerActive = false; + scoreActive = false; + timerSecondsRemaining = 0; + scoreSecondsRemaining = 0; +} + +auto Event::mcuRead(uint addr, uint8 data) -> uint8 { + if(board == Board::CampusChallenge92) { + uint id = 0; + if(select == 0x09) id = 1; + if(select == 0x05) id = 2; + if(select == 0x03) id = 3; + if((addr & 0x808000) == 0x808000) id = 0; + + if(addr & 0x008000) { + addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff); + return rom[id].read(bus.mirror(addr, rom[id].size()), data); + } + } + + if(board == Board::PowerFest94) { + uint id = 0; + if(select == 0x09) id = 1; + if(select == 0x0c) id = 2; + if(select == 0x0a) id = 3; + if((addr & 0x208000) == 0x208000) id = 0; + + if(addr & 0x400000) { + addr &= 0x3fffff; + return rom[id].read(bus.mirror(addr, rom[id].size()), data); + } + + if(addr & 0x008000) { + addr &= 0x1fffff; + if(id != 2) addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff); + return rom[id].read(bus.mirror(addr, rom[id].size()), data); + } + } + + return data; +} + +auto Event::mcuWrite(uint addr, uint8 data) -> void { +} + +auto Event::read(uint addr, uint8 data) -> uint8 { + if(addr == 0x106000 || addr == 0xc00000) { + return status; + } + return data; +} + +auto Event::write(uint addr, uint8 data) -> void { + if(addr == 0x206000 || addr == 0xe00000) { + select = data; + if(timer && data == 0x09) { + timerActive = true; + timerSecondsRemaining = timer; + } + } +} + +} diff --git a/sfc/coprocessor/event/event.hpp b/sfc/coprocessor/event/event.hpp new file mode 100644 index 0000000..b2f0de4 --- /dev/null +++ b/sfc/coprocessor/event/event.hpp @@ -0,0 +1,51 @@ +//HLE of the NEC uPD78P214GC processor found on SNES-EVENT PCBs, used by: +//* Campus Challenge '92 +//* PowerFest '94 + +//The NEC uPD78214 family are 8-bit microprocessors containing: +//* UART/CSI serial interface +//* ALU (MUL, DIV, BCD) +//* interrupts (12 internal; 7 external; 2 priority levels) +//* 16384 x 8-bit ROM +//* 512 x 8-bit RAM +//* 4 x timer/counters + +//None of the SNES-EVENT games have had their uPD78214 firmware dumped. +//As such, our only option is very basic high-level emulation, provided here. + +struct Event : Thread { + //event.cpp + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + auto unload() -> void; + auto power() -> void; + + auto mcuRead(uint addr, uint8) -> uint8; + auto mcuWrite(uint addr, uint8) -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + +public: + ReadableMemory rom[4]; + + enum class Board : uint { Unknown, CampusChallenge92, PowerFest94 } board; + uint timer; + +private: + uint8 status; + uint8 select; + + bool timerActive; + bool scoreActive; + + uint timerSecondsRemaining; + uint scoreSecondsRemaining; +}; + +extern Event event; diff --git a/sfc/coprocessor/event/serialization.cpp b/sfc/coprocessor/event/serialization.cpp new file mode 100644 index 0000000..b315cdc --- /dev/null +++ b/sfc/coprocessor/event/serialization.cpp @@ -0,0 +1,9 @@ +auto Event::serialize(serializer& s) -> void { + Thread::serialize(s); + s.integer(status); + s.integer(select); + s.integer(timerActive); + s.integer(scoreActive); + s.integer(timerSecondsRemaining); + s.integer(scoreSecondsRemaining); +} diff --git a/sfc/coprocessor/hitachidsp/data-rom.cpp b/sfc/coprocessor/hitachidsp/data-rom.cpp new file mode 100644 index 0000000..6d1d0e3 --- /dev/null +++ b/sfc/coprocessor/hitachidsp/data-rom.cpp @@ -0,0 +1,100 @@ +/* note: this is not copyrightable, as it is purely math tables such as sin and cos */ + +const uint8_t HitachiDSP::staticDataROM[3072] = { + 255,255,255,0,0,128,0,0,64,170,170,42,0,0,32,153,153,25,85,85,21,36,73,18,0,0,16,227,56,14,204,204, + 12,232,162,11,170,170,10,157,216,9,146,36,9,136,136,8,0,0,8,135,135,7,113,28,7,161,188,6,102,102,6,97, + 24,6,116,209,5,178,144,5,85,85,5,184,30,5,78,236,4,161,189,4,73,146,4,238,105,4,68,68,4,8,33,4, + 0,0,4,248,224,3,195,195,3,58,168,3,56,142,3,159,117,3,80,94,3,52,72,3,51,51,3,56,31,3,48,12, + 3,11,250,2,186,232,2,45,216,2,89,200,2,49,185,2,170,170,2,188,156,2,92,143,2,130,130,2,39,118,2,67, + 106,2,208,94,2,200,83,2,36,73,2,224,62,2,247,52,2,99,43,2,34,34,2,46,25,2,132,16,2,32,8,2, + 0,0,2,31,248,1,124,240,1,19,233,1,225,225,1,230,218,1,29,212,1,133,205,1,28,199,1,224,192,1,207,186, + 1,232,180,1,40,175,1,142,169,1,26,164,1,200,158,1,153,153,1,139,148,1,156,143,1,203,138,1,24,134,1,129, + 129,1,5,125,1,164,120,1,93,116,1,46,112,1,22,108,1,22,104,1,44,100,1,88,96,1,152,92,1,237,88,1, + 85,85,1,208,81,1,94,78,1,253,74,1,174,71,1,111,68,1,65,65,1,34,62,1,19,59,1,19,56,1,33,53, + 1,62,50,1,104,47,1,159,44,1,228,41,1,53,39,1,146,36,1,251,33,1,112,31,1,240,28,1,123,26,1,17, + 24,1,177,21,1,92,19,1,17,17,1,207,14,1,151,12,1,104,10,1,66,8,1,36,6,1,16,4,1,4,2,1, + 0,0,1,3,254,0,15,252,0,35,250,0,62,248,0,96,246,0,137,244,0,185,242,0,240,240,0,46,239,0,115,237, + 0,189,235,0,14,234,0,101,232,0,194,230,0,37,229,0,142,227,0,252,225,0,112,224,0,233,222,0,103,221,0,235, + 219,0,116,218,0,1,217,0,148,215,0,43,214,0,199,212,0,104,211,0,13,210,0,182,208,0,100,207,0,22,206,0, + 204,204,0,135,203,0,69,202,0,7,201,0,206,199,0,152,198,0,101,197,0,55,196,0,12,195,0,228,193,0,192,192, + 0,160,191,0,130,190,0,105,189,0,82,188,0,62,187,0,46,186,0,33,185,0,23,184,0,15,183,0,11,182,0,9, + 181,0,11,180,0,15,179,0,22,178,0,31,177,0,44,176,0,58,175,0,76,174,0,96,173,0,118,172,0,143,171,0, + 170,170,0,200,169,0,232,168,0,10,168,0,47,167,0,85,166,0,126,165,0,169,164,0,215,163,0,6,163,0,55,162, + 0,107,161,0,160,160,0,216,159,0,17,159,0,76,158,0,137,157,0,200,156,0,9,156,0,76,155,0,144,154,0,215, + 153,0,31,153,0,104,152,0,180,151,0,1,151,0,79,150,0,160,149,0,242,148,0,69,148,0,154,147,0,241,146,0, + 73,146,0,162,145,0,253,144,0,90,144,0,184,143,0,23,143,0,120,142,0,218,141,0,61,141,0,162,140,0,8,140, + 0,112,139,0,216,138,0,66,138,0,174,137,0,26,137,0,136,136,0,247,135,0,103,135,0,217,134,0,75,134,0,191, + 133,0,52,133,0,169,132,0,33,132,0,153,131,0,18,131,0,140,130,0,8,130,0,132,129,0,2,129,0,128,128,0, + 0,0,0,0,0,16,158,160,22,122,182,27,0,0,32,239,198,35,28,49,39,255,84,42,60,65,45,0,0,48,176,152, + 50,229,16,53,245,108,55,86,176,57,212,221,59,189,247,61,0,0,64,61,248,65,219,225,67,12,190,69,222,141,71,58, + 82,73,241,11,75,185,187,76,56,98,78,0,0,80,149,149,81,112,35,83,254,169,84,162,41,86,183,162,87,144,21,89, + 121,130,90,186,233,91,148,75,93,67,168,94,0,0,96,254,82,97,112,161,98,131,235,99,96,49,101,50,115,102,29,177, + 103,68,235,104,202,33,106,205,84,107,108,132,108,194,176,109,235,217,110,0,0,112,24,35,113,74,67,114,173,96,115,84, + 123,116,84,147,117,191,168,118,168,187,119,31,204,120,52,218,121,249,229,122,122,239,123,200,246,124,239,251,125,253,254,126, + 0,0,128,1,255,128,15,252,129,52,247,130,123,240,131,238,231,132,152,221,133,130,209,134,182,195,135,61,180,136,31,163, + 137,102,144,138,25,124,139,65,102,140,228,78,141,11,54,142,188,27,143,0,0,144,219,226,144,86,196,145,117,164,146,65, + 131,147,189,96,148,241,60,149,226,23,150,150,241,150,17,202,151,89,161,152,115,119,153,100,76,154,49,32,155,222,242,155, + 112,196,156,235,148,157,84,100,158,175,50,159,0,0,160,74,204,160,146,151,161,220,97,162,42,43,163,130,243,163,230,186, + 164,90,129,165,225,70,166,126,11,167,53,207,167,9,146,168,253,83,169,19,21,170,80,213,170,180,148,171,69,83,172,3, + 17,173,242,205,173,21,138,174,110,69,175,0,0,176,204,185,176,214,114,177,32,43,178,172,226,178,124,153,179,147,79,180, + 243,4,181,157,185,181,149,109,182,220,32,183,117,211,183,96,133,184,160,54,185,56,231,185,40,151,186,115,70,187,26,245, + 187,32,163,188,134,80,189,78,253,189,121,169,190,9,85,191,0,0,192,95,170,192,40,84,193,92,253,193,253,165,194,13, + 78,195,140,245,195,125,156,196,225,66,197,184,232,197,5,142,198,201,50,199,6,215,199,187,122,200,235,29,201,152,192,201, + 193,98,202,105,4,203,145,165,203,58,70,204,100,230,204,18,134,205,68,37,206,252,195,206,58,98,207,0,0,208,78,157, + 208,38,58,209,137,214,209,119,114,210,243,13,211,252,168,211,148,67,212,188,221,212,116,119,213,190,16,214,155,169,214,11, + 66,215,15,218,215,169,113,216,216,8,217,159,159,217,254,53,218,245,203,218,133,97,219,176,246,219,118,139,220,216,31,221, + 215,179,221,115,71,222,173,218,222,134,109,223,0,0,224,25,146,224,212,35,225,48,181,225,48,70,226,210,214,226,25,103, + 227,4,247,227,148,134,228,203,21,229,168,164,229,45,51,230,90,193,230,47,79,231,173,220,231,214,105,232,169,246,232,38, + 131,233,80,15,234,38,155,234,168,38,235,217,177,235,183,60,236,67,199,236,127,81,237,106,219,237,6,101,238,82,238,238, + 80,119,239,0,0,240,97,136,240,118,16,241,62,152,241,186,31,242,234,166,242,207,45,243,105,180,243,185,58,244,192,192, + 244,125,70,245,242,203,245,30,81,246,2,214,246,159,90,247,245,222,247,5,99,248,206,230,248,82,106,249,144,237,249,138, + 112,250,63,243,250,177,117,251,223,247,251,202,121,252,114,251,252,216,124,253,251,253,253,222,126,254,127,255,254,223,127,255, + 0,0,0,58,36,3,85,72,6,50,108,9,178,143,12,183,178,15,32,213,18,208,246,21,166,23,25,133,55,28,78,86, + 31,225,115,34,32,144,37,237,170,40,40,196,43,179,219,46,112,241,49,64,5,53,4,23,56,159,38,59,242,51,62,224, + 62,65,73,71,68,16,77,71,24,80,74,67,80,77,114,77,80,137,71,83,105,62,86,247,49,89,20,34,92,164,14,95, + 138,247,97,169,220,100,229,189,103,32,155,106,64,116,109,39,73,112,186,25,115,221,229,117,116,173,120,101,112,123,147,46, + 126,228,231,128,60,156,131,130,75,134,154,245,136,107,154,139,217,57,142,204,211,144,42,104,147,217,246,149,191,127,152,197, + 2,155,209,127,157,202,246,159,153,103,162,36,210,164,85,54,167,20,148,169,73,235,171,221,59,174,186,133,176,201,200,178, + 243,4,181,34,58,183,65,104,185,58,143,187,249,174,189,103,199,191,112,216,193,0,226,195,3,228,197,101,222,199,18,209, + 201,247,187,203,2,159,205,31,122,207,61,77,209,72,24,211,49,219,212,228,149,214,82,72,216,105,242,217,26,148,219,83, + 45,221,5,190,222,33,70,224,151,197,225,89,60,227,89,170,228,135,15,230,215,107,231,59,191,232,166,9,234,11,75,235, + 94,131,236,147,178,237,157,216,238,115,245,239,8,9,241,82,19,242,71,20,243,221,11,244,10,250,244,198,222,245,7,186, + 246,197,139,247,247,83,248,151,18,249,157,199,249,1,115,250,190,20,251,205,172,251,39,59,252,201,191,252,171,58,253,203, + 171,253,35,19,254,175,112,254,109,196,254,87,14,255,109,78,255,171,132,255,15,177,255,151,211,255,67,236,255,16,251,255, + 0,0,0,249,162,0,246,69,1,248,232,1,1,140,2,20,47,3,52,210,3,100,117,4,165,24,5,251,187,5,104,95, + 6,239,2,7,146,166,7,84,74,8,56,238,8,64,146,9,110,54,10,199,218,10,76,127,11,1,36,12,231,200,12,2, + 110,13,85,19,14,227,184,14,174,94,15,185,4,16,8,171,16,158,81,17,125,248,17,169,159,18,37,71,19,244,238,19, + 25,151,20,153,63,21,117,232,21,178,145,22,83,59,23,92,229,23,209,143,24,180,58,25,10,230,25,216,145,26,32,62, + 27,231,234,27,49,152,28,2,70,29,95,244,29,76,163,30,206,82,31,234,2,32,163,179,32,0,101,33,5,23,34,184, + 201,34,30,125,35,60,49,36,24,230,36,185,155,37,36,82,38,95,9,39,113,193,39,97,122,40,54,52,41,246,238,41, + 170,170,42,89,103,43,10,37,44,199,227,44,152,163,45,133,100,46,153,38,47,220,233,47,89,174,48,27,116,49,44,59, + 50,152,3,51,107,205,51,177,152,52,120,101,53,206,51,54,193,3,55,96,213,55,187,168,56,228,125,57,236,84,58,230, + 45,59,230,8,60,1,230,60,77,197,61,227,166,62,220,138,63,82,113,64,98,90,65,44,70,66,208,52,67,113,38,68, + 55,27,69,74,19,70,214,14,71,12,14,72,32,17,73,76,24,74,205,35,75,234,51,76,236,72,77,39,99,78,249,130, + 79,201,168,80,10,213,81,63,8,83,252,66,84,234,133,85,204,209,86,130,39,88,21,136,89,188,244,90,237,110,92,108, + 248,93,105,147,95,163,66,97,165,9,99,30,237,100,129,243,102,23,38,105,34,147,107,165,82,110,124,147,113,180,206,117, + 0,0,0,36,3,0,72,6,0,109,9,0,147,12,0,186,15,0,226,18,0,11,22,0,54,25,0,99,28,0,147,31, + 0,196,34,0,249,37,0,48,41,0,107,44,0,169,47,0,235,50,0,50,54,0,124,57,0,203,60,0,31,64,0,121, + 67,0,216,70,0,61,74,0,168,77,0,25,81,0,146,84,0,17,88,0,153,91,0,40,95,0,192,98,0,96,102,0, + 9,106,0,188,109,0,122,113,0,65,117,0,20,121,0,242,124,0,220,128,0,210,132,0,213,136,0,230,140,0,5,145, + 0,51,149,0,112,153,0,190,157,0,28,162,0,139,166,0,13,171,0,162,175,0,75,180,0,9,185,0,220,189,0,198, + 194,0,200,199,0,227,204,0,24,210,0,103,215,0,211,220,0,93,226,0,6,232,0,207,237,0,187,243,0,202,249,0, + 0,0,1,92,6,1,226,12,1,148,19,1,115,26,1,131,33,1,198,40,1,62,48,1,239,55,1,220,63,1,8,72, + 1,119,80,1,45,89,1,45,98,1,125,107,1,34,117,1,33,127,1,128,137,1,68,148,1,118,159,1,28,171,1,62, + 183,1,231,195,1,31,209,1,241,222,1,105,237,1,149,252,1,131,12,2,68,29,2,233,46,2,134,65,2,51,85,2, + 9,106,2,37,128,2,167,151,2,181,176,2,120,203,2,35,232,2,236,6,3,21,40,3,235,75,3,198,114,3,16,157, + 3,71,203,3,2,254,3,247,53,4,5,116,4,63,185,4,255,6,5,249,94,5,93,195,5,9,55,6,207,189,6,230, + 92,7,151,27,8,109,4,9,54,39,10,198,156,11,129,142,13,233,70,16,255,90,20,113,38,27,72,188,40,181,123,81, + 255,255,255,16,251,255,67,236,255,151,211,255,15,177,255,171,132,255,109,78,255,87,14,255,109,196,254,175,112,254,35,19, + 254,203,171,253,171,58,253,201,191,252,39,59,252,205,172,251,190,20,251,1,115,250,157,199,249,151,18,249,247,83,248,197, + 139,247,7,186,246,198,222,245,10,250,244,221,11,244,71,20,243,82,19,242,8,9,241,115,245,239,157,216,238,147,178,237, + 94,131,236,11,75,235,166,9,234,59,191,232,215,107,231,135,15,230,89,170,228,89,60,227,151,197,225,33,70,224,5,190, + 222,83,45,221,26,148,219,105,242,217,82,72,216,228,149,214,49,219,212,72,24,211,61,77,209,31,122,207,2,159,205,247, + 187,203,18,209,201,101,222,199,3,228,197,0,226,195,112,216,193,103,199,191,249,174,189,58,143,187,65,104,185,34,58,183, + 243,4,181,201,200,178,186,133,176,221,59,174,73,235,171,20,148,169,85,54,167,36,210,164,153,103,162,202,246,159,209,127, + 157,197,2,155,191,127,152,217,246,149,42,104,147,204,211,144,217,57,142,107,154,139,154,245,136,130,75,134,60,156,131,228, + 231,128,147,46,126,101,112,123,116,173,120,221,229,117,186,25,115,39,73,112,64,116,109,32,155,106,229,189,103,169,220,100, + 138,247,97,164,14,95,20,34,92,247,49,89,105,62,86,137,71,83,114,77,80,67,80,77,24,80,74,16,77,71,73,71, + 68,224,62,65,242,51,62,159,38,59,4,23,56,64,5,53,112,241,49,179,219,46,40,196,43,237,170,40,32,144,37,225, + 115,34,78,86,31,133,55,28,166,23,25,208,246,21,32,213,18,183,178,15,178,143,12,50,108,9,85,72,6,58,36,3, +}; diff --git a/sfc/coprocessor/hitachidsp/hitachidsp.cpp b/sfc/coprocessor/hitachidsp/hitachidsp.cpp new file mode 100644 index 0000000..c4d2a51 --- /dev/null +++ b/sfc/coprocessor/hitachidsp/hitachidsp.cpp @@ -0,0 +1,43 @@ +#include +#include + +namespace SuperFamicom { + +#include "memory.cpp" +#include "serialization.cpp" +#include "data-rom.cpp" +HitachiDSP hitachidsp; + +auto HitachiDSP::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto HitachiDSP::Enter() -> void { + while(true) { + scheduler.synchronize(); + hitachidsp.main(); + } +} + +auto HitachiDSP::step(uint clocks) -> void { + HG51B::step(clocks); + clock += clocks * (uint64_t)cpu.frequency; + synchronizeCPU(); +} + +auto HitachiDSP::halt() -> void { + HG51B::halt(); + if(io.irq == 0) cpu.irq(r.i = 1); +} + +auto HitachiDSP::unload() -> void { + rom.reset(); + ram.reset(); +} + +auto HitachiDSP::power() -> void { + HG51B::power(); + create(HitachiDSP::Enter, Frequency); +} + +} diff --git a/sfc/coprocessor/hitachidsp/hitachidsp.hpp b/sfc/coprocessor/hitachidsp/hitachidsp.hpp new file mode 100644 index 0000000..632aca3 --- /dev/null +++ b/sfc/coprocessor/hitachidsp/hitachidsp.hpp @@ -0,0 +1,52 @@ +struct HitachiDSP : Processor::HG51B, Thread { + ReadableMemory rom; + WritableMemory ram; + + //hitachidsp.cpp + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto step(uint clocks) -> void override; + auto halt() -> void override; + + auto unload() -> void; + auto power() -> void; + + auto isROM(uint address) -> bool override; + auto isRAM(uint address) -> bool override; + + //HG51B read/write + auto read(uint address) -> uint8 override; + auto write(uint address, uint8 data) -> void override; + + //CPU ROM read/write + auto addressROM(uint address) const -> maybe; + auto readROM(uint address, uint8 data = 0) -> uint8; + auto writeROM(uint address, uint8 data) -> void; + + //CPU RAM read/write + auto addressRAM(uint address) const -> maybe; + auto readRAM(uint address, uint8 data = 0) -> uint8; + auto writeRAM(uint address, uint8 data) -> void; + + //HG51B data RAM read/write + auto addressDRAM(uint address) const -> maybe; + auto readDRAM(uint address, uint8 data = 0) -> uint8; + auto writeDRAM(uint address, uint8 data) -> void; + + //CPU IO read/write + auto addressIO(uint address) const -> maybe; + auto readIO(uint address, uint8 data = 0) -> uint8; + auto writeIO(uint address, uint8 data) -> void; + + auto firmware() const -> vector; + auto serialize(serializer&) -> void; + + uint Frequency; + uint Roms; + bool Mapping; + + //data-rom.cpp + static const uint8_t staticDataROM[3072]; +}; + +extern HitachiDSP hitachidsp; diff --git a/sfc/coprocessor/hitachidsp/memory.cpp b/sfc/coprocessor/hitachidsp/memory.cpp new file mode 100644 index 0000000..c7663c2 --- /dev/null +++ b/sfc/coprocessor/hitachidsp/memory.cpp @@ -0,0 +1,273 @@ +auto HitachiDSP::isROM(uint address) -> bool { + return (bool)addressROM(address); +} + +auto HitachiDSP::isRAM(uint address) -> bool { + return (bool)addressRAM(address); +} + +auto HitachiDSP::read(uint address) -> uint8 { + if(auto linear = addressROM (address)) return readROM (*linear); + if(auto linear = addressRAM (address)) return readRAM (*linear); + if(auto linear = addressDRAM(address)) return readDRAM(*linear); + if(auto linear = addressIO (address)) return readIO (*linear); + return 0x00; +} + +auto HitachiDSP::write(uint address, uint8 data) -> void { + if(auto linear = addressROM (address)) return writeROM (*linear, data); + if(auto linear = addressRAM (address)) return writeRAM (*linear, data); + if(auto linear = addressDRAM(address)) return writeDRAM(*linear, data); + if(auto linear = addressIO (address)) return writeIO (*linear, data); +} + +// + +auto HitachiDSP::addressROM(uint address) const -> maybe { + if(Mapping == 0) { + //00-3f,80-bf:8000-ffff; c0-ff:0000-ffff + if((address & 0x408000) == 0x008000 || (address & 0xc00000) == 0xc00000) { + address = (address & 0x3f0000) >> 1 | (address & 0x7fff); + return {address & 0x1fffff}; + } + } else { + //00-3f,80-bf:8000-ffff; c0-ff:0000-ffff + if((address & 0x408000) == 0x008000 || (address & 0xc00000) == 0xc00000) { + return {address & 0x3fffff}; + } + } + return {}; +} + +auto HitachiDSP::readROM(uint address, uint8 data) -> uint8 { + if(hitachidsp.active() || !busy()) { + address = bus.mirror(address, rom.size()); + //if(Roms == 2 && mmio.r1f52 == 1 && address >= (bit::round(rom.size()) >> 1)) return 0x00; + return rom.read(address, data); + } + //DSP has the bus acquired: CPU reads from 00:ffc0-ffff return IO registers (including reset vector overrides) + if(Mapping == 0 && (address & 0xbfffc0) == 0x007fc0) return readIO(0x7f40 | address & 0x3f); + if(Mapping == 1 && (address & 0xbfffc0) == 0x00ffc0) return readIO(0x7f40 | address & 0x3f); + return data; +} + +auto HitachiDSP::writeROM(uint address, uint8 data) -> void { +} + +// + +auto HitachiDSP::addressRAM(uint address) const -> maybe { + if(Mapping == 0) { + //70-77:0000-7fff + if((address & 0xf88000) == 0x700000) { + address = (address & 0x070000) >> 1 | (address & 0x7fff); + return {address & 0x03ffff}; + } + } else { + //30-3f,b0-bf:6000-7fff + if((address & 0x70e000) == 0x306000) { + address = (address & 0x0f0000) >> 3 | (address & 0x1fff); + return {address & 0x01ffff}; + } + } + return {}; +} + +auto HitachiDSP::readRAM(uint address, uint8 data) -> uint8 { + if(ram.size() == 0) return 0x00; //not open bus + return ram.read(bus.mirror(address, ram.size()), data); +} + +auto HitachiDSP::writeRAM(uint address, uint8 data) -> void { + if(ram.size() == 0) return; + return ram.write(bus.mirror(address, ram.size()), data); +} + +// + +auto HitachiDSP::addressDRAM(uint address) const -> maybe { + if(Mapping == 0) { + //00-3f,80-bf:6000-6bff,7000-7bff + if((address & 0x40e000) == 0x006000 && (address & 0x0c00) != 0x0c00) { + return {address & 0x0fff}; + } + } else { + //00-2f,80-af:6000-6bff,7000-7bff + if((address & 0x40e000) == 0x006000 && (address & 0x0c00) != 0x0c00 && (address & 0x300000) != 0x300000) { + return {address & 0x0fff}; + } + } + return {}; +} + +auto HitachiDSP::readDRAM(uint address, uint8 data) -> uint8 { + address &= 0xfff; + if(address >= 0xc00) return data; + return dataRAM[address]; +} + +auto HitachiDSP::writeDRAM(uint address, uint8 data) -> void { + address &= 0xfff; + if(address >= 0xc00) return; + dataRAM[address] = data; +} + +// + +auto HitachiDSP::addressIO(uint address) const -> maybe { + if(Mapping == 0) { + //00-3f,80-bf:6c00-6fff,7c00-7fff + if((address & 0x40ec00) == 0x006c00) { + return {address & 0x03ff}; + } + } else { + //00-2f,80-af:6c00-6fff,7c00-7fff + if((address & 0x40ec00) == 0x006c00 && (address & 0x300000) != 0x300000) { + return {address & 0x03ff}; + } + } + return {}; +} + +auto HitachiDSP::readIO(uint address, uint8 data) -> uint8 { + address = 0x7c00 | (address & 0x03ff); + + //IO + switch(address) { + case 0x7f40: return io.dma.source >> 0; + case 0x7f41: return io.dma.source >> 8; + case 0x7f42: return io.dma.source >> 16; + case 0x7f43: return io.dma.length >> 0; + case 0x7f44: return io.dma.length >> 8; + case 0x7f45: return io.dma.target >> 0; + case 0x7f46: return io.dma.target >> 8; + case 0x7f47: return io.dma.target >> 16; + case 0x7f48: return io.cache.page; + case 0x7f49: return io.cache.base >> 0; + case 0x7f4a: return io.cache.base >> 8; + case 0x7f4b: return io.cache.base >> 16; + case 0x7f4c: return io.cache.lock[0] << 0 | io.cache.lock[1] << 1; + case 0x7f4d: return io.cache.pb >> 0; + case 0x7f4e: return io.cache.pb >> 8; + case 0x7f4f: return io.cache.pc; + case 0x7f50: return io.wait.ram << 0 | io.wait.rom << 4; + case 0x7f51: return io.irq; + case 0x7f52: return io.rom; + case 0x7f53: case 0x7f54: case 0x7f55: case 0x7f56: case 0x7f57: + case 0x7f59: case 0x7f5b: case 0x7f5c: case 0x7f5d: case 0x7f5e: + case 0x7f5f: return io.suspend.enable << 0 | r.i << 1 | running() << 6 | busy() << 7; + } + + //vectors + if(address >= 0x7f60 && address <= 0x7f7f) { + return io.vector[address & 0x1f]; + } + + //registers + if((address >= 0x7f80 && address <= 0x7faf) || (address >= 0x7fc0 && address <= 0x7fef)) { + address &= 0x3f; + switch(address % 3) { + case 0: return r.gpr[address / 3] >> 0; + case 1: return r.gpr[address / 3] >> 8; + case 2: return r.gpr[address / 3] >> 16; + } + } + + return 0x00; +} + +auto HitachiDSP::writeIO(uint address, uint8 data) -> void { + address = 0x7c00 | (address & 0x03ff); + + //IO + switch(address) { + case 0x7f40: io.dma.source = io.dma.source & 0xffff00 | data << 0; return; + case 0x7f41: io.dma.source = io.dma.source & 0xff00ff | data << 8; return; + case 0x7f42: io.dma.source = io.dma.source & 0x00ffff | data << 16; return; + + case 0x7f43: io.dma.length = io.dma.length & 0xff00 | data << 0; return; + case 0x7f44: io.dma.length = io.dma.length & 0x00ff | data << 8; return; + + case 0x7f45: io.dma.target = io.dma.target & 0xffff00 | data << 0; return; + case 0x7f46: io.dma.target = io.dma.target & 0xff00ff | data << 8; return; + case 0x7f47: io.dma.target = io.dma.target & 0x00ffff | data << 16; + if(io.halt) io.dma.enable = 1; + return; + + case 0x7f48: + io.cache.page = data & 1; + if(io.halt) io.cache.enable = 1; + return; + + case 0x7f49: io.cache.base = io.cache.base & 0xffff00 | data << 0; return; + case 0x7f4a: io.cache.base = io.cache.base & 0xff00ff | data << 8; return; + case 0x7f4b: io.cache.base = io.cache.base & 0x00ffff | data << 16; return; + + case 0x7f4c: + io.cache.lock[0] = bool(data & 1); + io.cache.lock[1] = bool(data & 2); + return; + + case 0x7f4d: io.cache.pb = io.cache.pb & 0xff00 | data << 0; return; + case 0x7f4e: io.cache.pb = io.cache.pb & 0x00ff | data << 8; return; + + case 0x7f4f: + io.cache.pc = data; + if(io.halt) { + io.halt = 0; + r.pb = io.cache.pb; + r.pc = io.cache.pc; + } + return; + + case 0x7f50: + io.wait.ram = data >> 0 & 7; + io.wait.rom = data >> 4 & 7; + return; + + case 0x7f51: + io.irq = data & 1; + if(io.irq == 1) cpu.irq(r.i = 0); + return; + + case 0x7f52: + io.rom = data & 1; + return; + + case 0x7f53: + io.lock = 0; + io.halt = 1; + return; + + case 0x7f55: io.suspend.enable = 1; io.suspend.duration = 0; return; //indefinite + case 0x7f56: io.suspend.enable = 1; io.suspend.duration = 32; return; + case 0x7f57: io.suspend.enable = 1; io.suspend.duration = 64; return; + case 0x7f58: io.suspend.enable = 1; io.suspend.duration = 96; return; + case 0x7f59: io.suspend.enable = 1; io.suspend.duration = 128; return; + case 0x7f5a: io.suspend.enable = 1; io.suspend.duration = 160; return; + case 0x7f5b: io.suspend.enable = 1; io.suspend.duration = 192; return; + case 0x7f5c: io.suspend.enable = 1; io.suspend.duration = 224; return; + case 0x7f5d: io.suspend.enable = 0; return; //resume + + case 0x7f5e: + r.i = 0; //does not deassert CPU IRQ line + return; + } + + //vectors + if(address >= 0x7f60 && address <= 0x7f7f) { + io.vector[address & 0x1f] = data; + return; + } + + //registers + if((address >= 0x7f80 && address <= 0x7faf) || (address >= 0x7fc0 && address <= 0x7fef)) { + address &= 0x3f; + switch(address % 3) { + case 0: r.gpr[address / 3] = r.gpr[address / 3] & 0xffff00 | data << 0; break; + case 1: r.gpr[address / 3] = r.gpr[address / 3] & 0xff00ff | data << 8; break; + case 2: r.gpr[address / 3] = r.gpr[address / 3] & 0x00ffff | data << 16; break; + } + return; + } +} diff --git a/sfc/coprocessor/hitachidsp/serialization.cpp b/sfc/coprocessor/hitachidsp/serialization.cpp new file mode 100644 index 0000000..b4b8521 --- /dev/null +++ b/sfc/coprocessor/hitachidsp/serialization.cpp @@ -0,0 +1,16 @@ +auto HitachiDSP::firmware() const -> vector { + vector buffer; + if(!cartridge.has.HitachiDSP) return buffer; + buffer.reserve(1024 * 3); + for(auto n : range(1024)) { + buffer.append(dataROM[n] >> 0); + buffer.append(dataROM[n] >> 8); + buffer.append(dataROM[n] >> 16); + } + return buffer; +} + +auto HitachiDSP::serialize(serializer& s) -> void { + HG51B::serialize(s); + Thread::serialize(s); +} diff --git a/sfc/coprocessor/icd/boot-roms.cpp b/sfc/coprocessor/icd/boot-roms.cpp new file mode 100644 index 0000000..1794c58 --- /dev/null +++ b/sfc/coprocessor/icd/boot-roms.cpp @@ -0,0 +1,21 @@ +const uint8_t ICD::SGB1BootROM[256] = { + 49,254,255,62,48,224,0,175,33,255,159,50,203,124,32,251,33,38,255,14,17,62,128,50,226,12,62,243,226,50,62,119, + 119,62,252,224,71,33,95,192,14,8,175,50,13,32,252,17,79,1,62,251,14,6,245,6,0,26,27,50,128,71,13,32, + 248,50,241,50,14,14,214,2,254,239,32,234,17,4,1,33,16,128,26,205,211,0,205,212,0,19,123,254,52,32,243,17, + 230,0,6,8,26,19,34,35,5,32,249,62,25,234,16,153,33,47,153,14,12,61,40,8,50,13,32,249,46,15,24,243, + 62,145,224,64,33,0,192,14,0,62,0,226,62,48,226,6,16,30,8,42,87,203,66,62,16,32,2,62,32,226,62,48, + 226,203,26,29,32,239,5,32,232,62,32,226,62,48,226,205,194,0,125,254,96,32,210,14,19,62,193,226,12,62,7,226, + 24,58,22,4,240,68,254,144,32,250,30,0,29,32,253,21,32,242,201,79,6,4,197,203,17,23,193,203,17,23,5,32, + 245,34,35,34,35,201,60,66,185,165,185,165,66,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,1,224,80, +}; + +const uint8_t ICD::SGB2BootROM[256] = { + 49,254,255,62,48,224,0,175,33,255,159,50,203,124,32,251,33,38,255,14,17,62,128,50,226,12,62,243,226,50,62,119, + 119,62,252,224,71,33,95,192,14,8,175,50,13,32,252,17,79,1,62,251,14,6,245,6,0,26,27,50,128,71,13,32, + 248,50,241,50,14,14,214,2,254,239,32,234,17,4,1,33,16,128,26,205,211,0,205,212,0,19,123,254,52,32,243,17, + 230,0,6,8,26,19,34,35,5,32,249,62,25,234,16,153,33,47,153,14,12,61,40,8,50,13,32,249,46,15,24,243, + 62,145,224,64,33,0,192,14,0,62,0,226,62,48,226,6,16,30,8,42,87,203,66,62,16,32,2,62,32,226,62,48, + 226,203,26,29,32,239,5,32,232,62,32,226,62,48,226,205,194,0,125,254,96,32,210,14,19,62,193,226,12,62,7,226, + 24,58,22,4,240,68,254,144,32,250,30,0,29,32,253,21,32,242,201,79,6,4,197,203,17,23,193,203,17,23,5,32, + 245,34,35,34,35,201,60,66,185,165,185,165,66,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,255,224,80, +}; diff --git a/sfc/coprocessor/icd/icd.cpp b/sfc/coprocessor/icd/icd.cpp new file mode 100644 index 0000000..1b5199c --- /dev/null +++ b/sfc/coprocessor/icd/icd.cpp @@ -0,0 +1,181 @@ +#include + +namespace SuperFamicom { + +ICD icd; +#include "interface.cpp" +#include "io.cpp" +#include "boot-roms.cpp" +#include "serialization.cpp" + +namespace SameBoy { + static auto hreset(GB_gameboy_t*) -> void { + icd.ppuHreset(); + } + + static auto vreset(GB_gameboy_t*) -> void { + icd.ppuVreset(); + } + + static auto icd_pixel(GB_gameboy_t*, uint8_t pixel) -> void { + icd.ppuWrite(pixel); + } + + static auto joyp_write(GB_gameboy_t*, uint8_t value) -> void { + bool p14 = value & 0x10; + bool p15 = value & 0x20; + icd.joypWrite(p14, p15); + } + + static auto read_memory(GB_gameboy_t*, uint16_t addr, uint8_t data) -> uint8_t { + if(auto replace = icd.cheats.find(addr, data)) return replace(); + return data; + } + + static auto rgb_encode(GB_gameboy_t*, uint8_t r, uint8_t g, uint8_t b) -> uint32_t { + return r << 16 | g << 8 | b << 0; + } + + static auto sample(GB_gameboy_t*, GB_sample_t* sample) -> void { + float left = sample->left / 32768.0f; + float right = sample->right / 32768.0f; + icd.apuWrite(left, right); + } + + static auto vblank(GB_gameboy_t*) -> void { + } +} + +auto ICD::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto ICD::Enter() -> void { + while(true) { + scheduler.synchronize(); + icd.main(); + } +} + +auto ICD::main() -> void { + if(r6003 & 0x80) { + auto clocks = GB_run(&sameboy); + step(clocks >> 1); + } else { //DMG halted + apuWrite(0.0, 0.0); + step(128); + } + synchronizeCPU(); +} + +auto ICD::step(uint clocks) -> void { + clock += clocks * (uint64_t)cpu.frequency; +} + +//SGB1 uses the CPU oscillator (~2.4% faster than a real Game Boy) +//SGB2 uses a dedicated oscillator (same speed as a real Game Boy) +auto ICD::clockFrequency() const -> uint { + return Frequency ? Frequency : system.cpuFrequency(); +} + +auto ICD::load() -> bool { + information = {}; + + GB_random_set_enabled(configuration.hacks.entropy != "None"); + if(Frequency == 0) { + GB_init(&sameboy, GB_MODEL_SGB_NO_SFC); + GB_load_boot_rom_from_buffer(&sameboy, (const unsigned char*)&SGB1BootROM[0], 256); + } else { + GB_init(&sameboy, GB_MODEL_SGB2_NO_SFC); + GB_load_boot_rom_from_buffer(&sameboy, (const unsigned char*)&SGB2BootROM[0], 256); + } + GB_set_sample_rate_by_clocks(&sameboy, 256); + GB_set_highpass_filter_mode(&sameboy, GB_HIGHPASS_ACCURATE); + GB_set_icd_hreset_callback(&sameboy, &SameBoy::hreset); + GB_set_icd_vreset_callback(&sameboy, &SameBoy::vreset); + GB_set_icd_pixel_callback(&sameboy, &SameBoy::icd_pixel); + GB_set_joyp_write_callback(&sameboy, &SameBoy::joyp_write); + GB_set_read_memory_callback(&sameboy, &SameBoy::read_memory); + GB_set_rgb_encode_callback(&sameboy, &SameBoy::rgb_encode); + GB_apu_set_sample_callback(&sameboy, &SameBoy::sample); + GB_set_vblank_callback(&sameboy, &SameBoy::vblank); + GB_set_pixels_output(&sameboy, &bitmap[0]); + if(auto loaded = platform->load(ID::GameBoy, "Game Boy", "gb")) { + information.pathID = loaded.pathID; + } else return unload(), false; + if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) { + auto manifest = fp->reads(); + cartridge.slotGameBoy.load(manifest); + } else return unload(), false; + if(auto fp = platform->open(pathID(), "program.rom", File::Read, File::Required)) { + auto size = fp->size(); + auto data = (uint8_t*)malloc(size); + cartridge.information.sha256 = Hash::SHA256({data, (uint64_t)size}).digest(); + fp->read(data, size); + GB_load_rom_from_buffer(&sameboy, data, size); + free(data); + } else return unload(), false; + if(auto fp = platform->open(pathID(), "save.ram", File::Read)) { + auto size = fp->size(); + auto data = (uint8_t*)malloc(size); + fp->read(data, size); + GB_load_battery_from_buffer(&sameboy, data, size); + free(data); + } + return true; +} + +auto ICD::save() -> void { + if(auto size = GB_save_battery_size(&sameboy)) { + auto data = (uint8_t*)malloc(size); + GB_save_battery_to_buffer(&sameboy, data, size); + if(auto fp = platform->open(pathID(), "save.ram", File::Write)) { + fp->write(data, size); + } + free(data); + } +} + +auto ICD::unload() -> void { + save(); + GB_free(&sameboy); +} + +auto ICD::power(bool reset) -> void { + auto frequency = clockFrequency() / 5; + create(ICD::Enter, frequency); + if(!reset) stream = Emulator::audio.createStream(2, frequency / 128); + + for(auto& packet : this->packet) packet = {}; + packetSize = 0; + + joypID = 0; + joypLock = 1; + pulseLock = 1; + strobeLock = 0; + packetLock = 0; + joypPacket = {}; + packetOffset = 0; + bitData = 0; + bitOffset = 0; + + for(auto& n : output) n = 0xff; + readBank = 0; + readAddress = 0; + writeBank = 0; + + r6003 = 0x00; + r6004 = 0xff; + r6005 = 0xff; + r6006 = 0xff; + r6007 = 0xff; + for(auto& r : r7000) r = 0x00; + mltReq = 0; + + hcounter = 0; + vcounter = 0; + + GB_reset(&sameboy); +} + +} diff --git a/sfc/coprocessor/icd/icd.hpp b/sfc/coprocessor/icd/icd.hpp new file mode 100644 index 0000000..baef0ec --- /dev/null +++ b/sfc/coprocessor/icd/icd.hpp @@ -0,0 +1,85 @@ +struct ICD : Emulator::Platform, Thread { + shared_pointer stream; + Emulator::Cheat cheats; + + inline auto pathID() const -> uint { return information.pathID; } + + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + auto clockFrequency() const -> uint; + + auto load() -> bool; + auto save() -> void; + auto unload() -> void; + auto power(bool reset = false) -> void; + + //interface.cpp + auto ppuHreset() -> void; + auto ppuVreset() -> void; + auto ppuWrite(uint2 color) -> void; + auto apuWrite(float left, float right) -> void; + auto joypWrite(bool p14, bool p15) -> void; + + //io.cpp + auto readIO(uint addr, uint8 data) -> uint8; + auto writeIO(uint addr, uint8 data) -> void; + + //boot-roms.cpp + static const uint8_t SGB1BootROM[256]; + static const uint8_t SGB2BootROM[256]; + + //serialization.cpp + auto serialize(serializer&) -> void; + + uint Revision = 0; + uint Frequency = 0; + +private: + struct Packet { + auto operator[](uint4 address) -> uint8& { return data[address]; } + uint8 data[16]; + }; + Packet packet[64]; + uint7 packetSize; + + uint2 joypID; + uint1 joypLock; + uint1 pulseLock; + uint1 strobeLock; + uint1 packetLock; + Packet joypPacket; + uint4 packetOffset; + uint8 bitData; + uint3 bitOffset; + + uint8 output[4 * 512]; + uint2 readBank; + uint9 readAddress; + uint2 writeBank; + + 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 + uint8 mltReq; //number of active joypads + + uint8 hcounter; + uint8 vcounter; + + struct Information { + uint pathID = 0; + } information; + +public: + //warning: the size of this object will be too large due to C++ size rules differing from C rules. + //in practice, this won't pose a problem so long as the struct is never accessed from C++ code, + //as the offsets of all member variables will be wrong compared to what the C SameBoy code expects. + GB_gameboy_t sameboy; + uint32_t bitmap[160 * 144]; +}; + +extern ICD icd; diff --git a/sfc/coprocessor/icd/interface.cpp b/sfc/coprocessor/icd/interface.cpp new file mode 100644 index 0000000..c80d90a --- /dev/null +++ b/sfc/coprocessor/icd/interface.cpp @@ -0,0 +1,105 @@ +auto ICD::ppuHreset() -> void { + hcounter = 0; + vcounter++; + if((uint3)vcounter == 0) writeBank++; +} + +auto ICD::ppuVreset() -> void { + hcounter = 0; + vcounter = 0; +} + +auto ICD::ppuWrite(uint2 color) -> void { + auto x = (uint8)hcounter++; + auto y = (uint3)vcounter; + if(x >= 160) return; //unverified behavior + + uint11 address = writeBank * 512 + y * 2 + x / 8 * 16; + output[address + 0] = (output[address + 0] << 1) | !!(color & 1); + output[address + 1] = (output[address + 1] << 1) | !!(color & 2); +} + +auto ICD::apuWrite(float left, float right) -> void { + double samples[] = {left, right}; + if(!system.runAhead) stream->write(samples); +} + +auto ICD::joypWrite(bool p14, bool p15) -> void { + //joypad handling + if(p14 == 1 && p15 == 1) { + if(joypLock == 0) { + joypLock = 1; + joypID++; + if(mltReq == 0) joypID &= 0; //1-player mode + if(mltReq == 1) joypID &= 1; //2-player mode + if(mltReq == 2) joypID &= 3; //4-player mode (unverified; but the most likely behavior) + if(mltReq == 3) joypID &= 3; //4-player mode + } + } + + uint8 joypad; + if(joypID == 0) joypad = r6004; + if(joypID == 1) joypad = r6005; + if(joypID == 2) joypad = r6006; + if(joypID == 3) joypad = r6007; + + uint4 input = 0xf; + if(p14 == 1 && p15 == 1) input = 0xf - joypID; + if(p14 == 0) input &= (joypad >> 0 & 15); //d-pad + if(p15 == 0) input &= (joypad >> 4 & 15); //buttons + + GB_icd_set_joyp(&sameboy, input); + + if(p14 == 0 && p15 == 1); + if(p14 == 1 && p15 == 0) joypLock ^= 1; + + //packet handling + if(p14 == 0 && p15 == 0) { //pulse + pulseLock = 0; + packetOffset = 0; + bitOffset = 0; + strobeLock = 1; + packetLock = 0; + return; + } + + if(pulseLock == 1) return; + + if(p14 == 1 && p15 == 1) { + strobeLock = 0; + return; + } + + if(strobeLock == 1) { + if(p14 == 1 || p15 == 1) { //malformed packet + packetLock = 0; + pulseLock = 1; + bitOffset = 0; + packetOffset = 0; + } else { + return; + } + } + + //p14:0, p15:1 = 0 + //p14:1, p15:0 = 1 + bool bit = p15 == 0; + strobeLock = 1; + + if(packetLock == 1) { + if(p14 == 0 && p15 == 1) { + if(packetSize < 64) packet[packetSize++] = joypPacket; + packetLock = 0; + pulseLock = 1; + } + return; + } + + bitData = bit << 7 | bitData >> 1; + if(++bitOffset) return; + + joypPacket[packetOffset] = bitData; + if(++packetOffset) return; + + packetLock = 1; +} diff --git a/sfc/coprocessor/icd/io.cpp b/sfc/coprocessor/icd/io.cpp new file mode 100644 index 0000000..1f32b2a --- /dev/null +++ b/sfc/coprocessor/icd/io.cpp @@ -0,0 +1,81 @@ +auto ICD::readIO(uint addr, uint8 data) -> uint8 { + addr &= 0x40ffff; + + //LY counter + if(addr == 0x6000) { + return vcounter & ~7 | writeBank; + } + + //command ready port + if(addr == 0x6002) { + data = packetSize > 0; + if(data) { + for(auto n : range(16)) r7000[n] = packet[0][n]; + packetSize--; + for(auto n : range(packetSize)) packet[n] = packet[n + 1]; + } + return data; + } + + //ICD2 revision + if(addr == 0x600f) { + return 0x21; + } + + //command port + if((addr & 0x40fff0) == 0x7000) { + return r7000[addr & 15]; + } + + //VRAM port + if(addr == 0x7800) { + data = output[readBank * 512 + readAddress]; + readAddress = (readAddress + 1) & 511; + return data; + } + + return 0x00; +} + +auto ICD::writeIO(uint addr, uint8 data) -> void { + addr &= 0xffff; + + //VRAM port + if(addr == 0x6001) { + readBank = data & 3; + readAddress = 0; + 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) { + power(true); //soft reset + } + + mltReq = data >> 4 & 3; + if(mltReq == 0) joypID &= ~0; //1-player mode + if(mltReq == 1) joypID &= ~1; //2-player mode + if(mltReq == 2) joypID &= ~3; //4-player mode (unverified; but the most likely behavior) + if(mltReq == 3) joypID &= ~3; //4-player mode + + auto frequency = clockFrequency(); + switch(data & 3) { + case 0: this->frequency = frequency / 4; break; //fast (glitchy, even on real hardware) + case 1: this->frequency = frequency / 5; break; //normal + case 2: this->frequency = frequency / 7; break; //slow + case 3: this->frequency = frequency / 9; break; //very slow + } + stream->setFrequency(this->frequency / 128); + 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 +} diff --git a/sfc/coprocessor/icd/serialization.cpp b/sfc/coprocessor/icd/serialization.cpp new file mode 100644 index 0000000..fd0259c --- /dev/null +++ b/sfc/coprocessor/icd/serialization.cpp @@ -0,0 +1,43 @@ +auto ICD::serialize(serializer& s) -> void { + Thread::serialize(s); + + auto size = GB_get_save_state_size(&sameboy); + auto data = new uint8_t[size]; + if(s.mode() == serializer::Save) { + GB_save_state_to_buffer(&sameboy, data); + } + s.array(data, size); + if(s.mode() == serializer::Load) { + GB_load_state_from_buffer(&sameboy, data, size); + } + delete[] data; + + for(auto n : range(64)) s.array(packet[n].data); + s.integer(packetSize); + + s.integer(joypID); + s.integer(joypLock); + s.integer(pulseLock); + s.integer(strobeLock); + s.integer(packetLock); + s.array(joypPacket.data); + s.integer(packetOffset); + s.integer(bitData); + s.integer(bitOffset); + + s.array(output); + s.integer(readBank); + s.integer(readAddress); + s.integer(writeBank); + + s.integer(r6003); + s.integer(r6004); + s.integer(r6005); + s.integer(r6006); + s.integer(r6007); + s.array(r7000); + s.integer(mltReq); + + s.integer(hcounter); + s.integer(vcounter); +} diff --git a/sfc/coprocessor/mcc/mcc.cpp b/sfc/coprocessor/mcc/mcc.cpp new file mode 100644 index 0000000..1713627 --- /dev/null +++ b/sfc/coprocessor/mcc/mcc.cpp @@ -0,0 +1,257 @@ +#include + +namespace SuperFamicom { + +#include "serialization.cpp" +MCC mcc; + +auto MCC::unload() -> void { + rom.reset(); + psram.reset(); +} + +auto MCC::power() -> void { + irq.flag = 0; + irq.enable = 0; + w.mapping = 1; + w.psramEnableLo = 1; + w.psramEnableHi = 0; + w.psramMapping = 3; + w.romEnableLo = 1; + w.romEnableHi = 1; + w.exEnableLo = 1; + w.exEnableHi = 0; + w.exMapping = 1; + w.internallyWritable = 0; + w.externallyWritable = 0; + commit(); +} + +auto MCC::commit() -> void { + r = w; + bsmemory.writable(r.externallyWritable); +} + +auto MCC::read(uint address, uint8 data) -> uint8 { + if((address & 0xf0f000) == 0x005000) { //$00-0f:5000-5fff + switch(address >> 16 & 15) { + case 0: return irq.flag << 7; + case 1: return irq.enable << 7; + case 2: return r.mapping << 7; + case 3: return r.psramEnableLo << 7; + case 4: return r.psramEnableHi << 7; + case 5: return (r.psramMapping >> 0 & 1) << 7; + case 6: return (r.psramMapping >> 1 & 1) << 7; + case 7: return r.romEnableLo << 7; + case 8: return r.romEnableHi << 7; + case 9: return r.exEnableLo << 7; + case 10: return r.exEnableHi << 7; + case 11: return r.exMapping << 7; + case 12: return r.internallyWritable << 7; + case 13: return r.externallyWritable << 7; + case 14: return 0; //commit (always zero) + case 15: return 0; //unknown (always zero) + } + } + + return data; +} + +auto MCC::write(uint address, uint8 data) -> void { + if((address & 0xf0f000) == 0x005000) { //$00-0f:5000-5fff + switch(address >> 16 & 15) { + case 1: irq.enable = data >> 7; break; + case 2: w.mapping = data >> 7; break; + case 3: w.psramEnableLo = data >> 7; break; + case 4: w.psramEnableHi = data >> 7; break; + case 5: w.psramMapping = w.psramMapping & 2 | data >> 7 << 0; break; + case 6: w.psramMapping = w.psramMapping & 1 | data >> 7 << 1; break; + case 7: w.romEnableLo = data >> 7; break; + case 8: w.romEnableHi = data >> 7; break; + case 9: w.exEnableLo = data >> 7; break; + case 10: w.exEnableHi = data >> 7; break; + case 11: w.exMapping = data >> 7; break; + case 12: w.internallyWritable = data >> 7; break; + case 13: w.externallyWritable = data >> 7; break; + case 14: if(data >> 7) commit(); break; + } + } +} + +auto MCC::mcuRead(uint address, uint8 data) -> uint8 { + return mcuAccess(0, address, data); +} + +auto MCC::mcuWrite(uint address, uint8 data) -> void { + return mcuAccess(1, address, data), void(); +} + +auto MCC::mcuAccess(bool mode, uint address, uint8 data) -> uint8 { + //[[ROM]] + + if(r.romEnableLo) { + if((address & 0xc08000) == 0x008000) { //00-3f:8000-ffff + return romAccess(mode, (address & 0x3f0000) >> 1 | (address & 0x7fff), data); + } + } + + if(r.romEnableHi) { + if((address & 0xc08000) == 0x808000) { //80-bf:8000-ffff + return romAccess(mode, (address & 0x3f0000) >> 1 | (address & 0x7fff), data); + } + } + + //[[PSRAM]] + + if(r.psramEnableLo && r.mapping == 0) { + if(((address & 0xf08000) == 0x008000 && r.psramMapping == 0) //00-0f:8000-ffff + || ((address & 0xf08000) == 0x208000 && r.psramMapping == 1) //20-2f:8000-ffff + || ((address & 0xf00000) == 0x400000 && r.psramMapping == 2) //40-4f:0000-ffff + || ((address & 0xf00000) == 0x600000 && r.psramMapping == 3) //60-6f:0000-ffff + ) { + return psramAccess(mode, (address & 0x0f0000) >> 1 | (address & 0x7fff), data); + } + + if((address & 0xf08000) == 0x700000) { //70-7d:0000-7fff + return psramAccess(mode, (address & 0x0f0000) >> 1 | (address & 0x7fff), data); + } + } + + if(r.psramEnableHi && r.mapping == 0) { + if(((address & 0xf08000) == 0x808000 && r.psramMapping == 0) //80-8f:8000-ffff + || ((address & 0xf08000) == 0xa08000 && r.psramMapping == 1) //a0-af:8000-ffff + || ((address & 0xf00000) == 0xc00000 && r.psramMapping == 2) //c0-cf:0000-ffff + || ((address & 0xf00000) == 0xe00000 && r.psramMapping == 3) //e0-ef:0000-ffff + ) { + return psramAccess(mode, (address & 0x0f0000) >> 1 | (address & 0x7fff), data); + } + + if((address & 0xf08000) == 0xf00000) { //f0-ff:0000-7fff + return psramAccess(mode, (address & 0x0f0000) >> 1 | (address & 0x7fff), data); + } + } + + if(r.psramEnableLo && r.mapping == 1) { + if(((address & 0xf88000) == 0x008000 && r.psramMapping == 0) //00-07:8000-ffff + || ((address & 0xf88000) == 0x108000 && r.psramMapping == 1) //10-17:8000-ffff + || ((address & 0xf88000) == 0x208000 && r.psramMapping == 2) //20-27:8000-ffff + || ((address & 0xf88000) == 0x308000 && r.psramMapping == 3) //30-37:8000-ffff + || ((address & 0xf80000) == 0x400000 && r.psramMapping == 0) //40-47:0000-ffff + || ((address & 0xf80000) == 0x500000 && r.psramMapping == 1) //50-57:0000-ffff + || ((address & 0xf80000) == 0x600000 && r.psramMapping == 2) //60-67:0000-ffff + || ((address & 0xf80000) == 0x700000 && r.psramMapping == 3) //70-77:0000-ffff + ) { + return psramAccess(mode, address & 0x07ffff, data); + } + + if((address & 0xe0e000) == 0x206000) { //20-3f:6000-7fff + return psramAccess(mode, (address & 0x3f0000) >> 3 | (address & 0x1fff), data); + } + } + + if(r.psramEnableHi && r.mapping == 1) { + if(((address & 0xf88000) == 0x808000 && r.psramMapping == 0) //80-87:8000-ffff + || ((address & 0xf88000) == 0x908000 && r.psramMapping == 1) //90-97:8000-ffff + || ((address & 0xf88000) == 0xa08000 && r.psramMapping == 2) //a0-a7:8000-ffff + || ((address & 0xf88000) == 0xb08000 && r.psramMapping == 3) //b0-b7:8000-ffff + || ((address & 0xf80000) == 0xc00000 && r.psramMapping == 0) //c0-c7:0000-ffff + || ((address & 0xf80000) == 0xd00000 && r.psramMapping == 1) //d0-d7:0000-ffff + || ((address & 0xf80000) == 0xe00000 && r.psramMapping == 2) //e0-e7:0000-ffff + || ((address & 0xf80000) == 0xf00000 && r.psramMapping == 3) //f0-f7:0000-ffff + ) { + return psramAccess(mode, address & 0x07ffff, data); + } + + if((address & 0xe0e000) == 0xa06000) { //a0-bf:6000-7fff + return psramAccess(mode, (address & 0x3f0000) >> 3 | (address & 0x1fff), data); + } + } + + //[[EXMEMORY]] + + if(r.exEnableLo && r.mapping == 0) { + if(((address & 0xe08000) == 0x008000 && r.exMapping == 0) //00-1f:8000-ffff + || ((address & 0xe00000) == 0x400000 && r.exMapping == 1) //40-5f:0000-ffff + ) { + return exAccess(mode, (address & 0x1f0000) >> 1 | (address & 0x7fff), data); + } + } + + if(r.exEnableLo && r.mapping == 1) { + if(((address & 0xf08000) == 0x008000 && r.exMapping == 0) //00-0f:8000-ffff + || ((address & 0xf08000) == 0x208000 && r.exMapping == 1) //20-2f:8000-ffff + || ((address & 0xf00000) == 0x400000 && r.exMapping == 0) //40-4f:0000-ffff + || ((address & 0xf00000) == 0x600000 && r.exMapping == 1) //60-6f:0000-ffff + ) { + return exAccess(mode, address & 0x0fffff, data); + } + } + + if(r.exEnableHi && r.mapping == 0) { + if(((address & 0xe08000) == 0x808000 && r.exMapping == 0) //80-9f:8000-ffff + || ((address & 0xe00000) == 0xc00000 && r.exMapping == 1) //c0-df:0000-ffff + ) { + return exAccess(mode, (address & 0x1f0000) >> 1 | (address & 0x7fff), data); + } + } + + if(r.exEnableHi && r.mapping == 1) { + if(((address & 0xf08000) == 0x808000 && r.exMapping == 0) //80-8f:8000-ffff + || ((address & 0xf08000) == 0xa08000 && r.exMapping == 1) //a0-af:8000-ffff + || ((address & 0xf00000) == 0xc00000 && r.exMapping == 0) //c0-cf:0000-ffff + || ((address & 0xf00000) == 0xe00000 && r.exMapping == 1) //e0-ef:0000-ffff + ) { + return exAccess(mode, address & 0x0fffff, data); + } + } + + //[[BSMEMORY]] + + if(bsmemory.size() && r.mapping == 0) { + if(((address & 0x408000) == 0x008000) //00-3f,80-bf:8000-ffff + || ((address & 0x400000) == 0x400000) //40-7d,c0-ff:0000-ffff + ) { + return bsAccess(mode, (address & 0x3f0000) >> 1 | (address & 0x7fff), data); + } + } + + if(bsmemory.size() && r.mapping == 1) { + if(((address & 0x408000) == 0x008000) //00-3f,80-bf:8000-ffff + || ((address & 0x400000) == 0x400000) //40-7d,c0-ff:0000-ffff + ) { + return bsAccess(mode, address & 0x3fffff, data); + } + } + + return data; +} + +//size: 0x100000 +auto MCC::romAccess(bool mode, uint address, uint8 data) -> uint8 { + address = bus.mirror(address, rom.size()); + if(mode == 0) return rom.read(address); + return data; +} + +//size: 0x80000 +auto MCC::psramAccess(bool mode, uint address, uint8 data) -> uint8 { + address = bus.mirror(address, psram.size()); + if(mode == 0) return psram.read(address); + return psram.write(address, data), data; +} + +//size: 0x100000 (?) +auto MCC::exAccess(bool mode, uint address, uint8 data) -> uint8 { + //not physically present on BSC-1A5B9P-01 + return data; +} + +//size: 0x100000, 0x200000, 0x400000 +auto MCC::bsAccess(bool mode, uint address, uint8 data) -> uint8 { + address = bus.mirror(address, bsmemory.size()); + if(mode == 0) return bsmemory.read(address, data); + if(!r.internallyWritable) return data; + return bsmemory.write(address, data), data; +} + +} diff --git a/sfc/coprocessor/mcc/mcc.hpp b/sfc/coprocessor/mcc/mcc.hpp new file mode 100644 index 0000000..7409e66 --- /dev/null +++ b/sfc/coprocessor/mcc/mcc.hpp @@ -0,0 +1,52 @@ +//MCC - Memory Controller Chip +//Custom logic chip inside the BS-X Satellaview base cartridge + +struct MCC { + ReadableMemory rom; + WritableMemory psram; + + //mcc.cpp + auto unload() -> void; + auto power() -> void; + auto commit() -> void; + + auto read(uint address, uint8 data) -> uint8; + auto write(uint address, uint8 data) -> void; + + auto mcuRead(uint address, uint8 data) -> uint8; + auto mcuWrite(uint address, uint8 data) -> void; + + auto mcuAccess(bool mode, uint address, uint8 data) -> uint8; + auto romAccess(bool mode, uint address, uint8 data) -> uint8; + auto psramAccess(bool mode, uint address, uint8 data) -> uint8; + auto exAccess(bool mode, uint address, uint8 data) -> uint8; + auto bsAccess(bool mode, uint address, uint8 data) -> uint8; + + //serialization.cpp + auto serialize(serializer&) -> void; + +private: + struct IRQ { + uint1 flag; //bit 0 + uint1 enable; //bit 1 + } irq; + + struct Registers { + uint1 mapping; //bit 2 (0 = ignore A15; 1 = use A15) + uint1 psramEnableLo; //bit 3 + uint1 psramEnableHi; //bit 4 + uint2 psramMapping; //bits 5-6 + uint1 romEnableLo; //bit 7 + uint1 romEnableHi; //bit 8 + uint1 exEnableLo; //bit 9 + uint1 exEnableHi; //bit 10 + uint1 exMapping; //bit 11 + uint1 internallyWritable; //bit 12 (1 = MCC allows writes to BS Memory Cassette) + uint1 externallyWritable; //bit 13 (1 = BS Memory Cassette allows writes to flash memory) + } r, w; + + //bit 14 = commit + //bit 15 = unknown (test register interface?) +}; + +extern MCC mcc; diff --git a/sfc/coprocessor/mcc/serialization.cpp b/sfc/coprocessor/mcc/serialization.cpp new file mode 100644 index 0000000..0876c69 --- /dev/null +++ b/sfc/coprocessor/mcc/serialization.cpp @@ -0,0 +1,30 @@ +auto MCC::serialize(serializer& s) -> void { + s.array(psram.data(), psram.size()); + + s.integer(irq.flag); + s.integer(irq.enable); + + s.integer(r.mapping); + s.integer(r.psramEnableLo); + s.integer(r.psramEnableHi); + s.integer(r.psramMapping); + s.integer(r.romEnableLo); + s.integer(r.romEnableHi); + s.integer(r.exEnableLo); + s.integer(r.exEnableHi); + s.integer(r.exMapping); + s.integer(r.internallyWritable); + s.integer(r.externallyWritable); + + s.integer(w.mapping); + s.integer(w.psramEnableLo); + s.integer(w.psramEnableHi); + s.integer(w.psramMapping); + s.integer(w.romEnableLo); + s.integer(w.romEnableHi); + s.integer(w.exEnableLo); + s.integer(w.exEnableHi); + s.integer(w.exMapping); + s.integer(w.internallyWritable); + s.integer(w.externallyWritable); +} diff --git a/sfc/coprocessor/msu1/msu1.cpp b/sfc/coprocessor/msu1/msu1.cpp new file mode 100644 index 0000000..2caf4e2 --- /dev/null +++ b/sfc/coprocessor/msu1/msu1.cpp @@ -0,0 +1,182 @@ +#include + +namespace SuperFamicom { + +MSU1 msu1; + +#include "serialization.cpp" + +auto MSU1::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + + +auto MSU1::Enter() -> void { + while(true) { + scheduler.synchronize(); + msu1.main(); + } +} + +auto MSU1::main() -> void { + double left = 0.0; + double right = 0.0; + + if(io.audioPlay) { + if(audioFile) { + if(audioFile->end()) { + if(!io.audioRepeat) { + io.audioPlay = false; + audioFile->seek(io.audioPlayOffset = 8); + } else { + audioFile->seek(io.audioPlayOffset = io.audioLoopOffset); + } + } else { + io.audioPlayOffset += 4; + left = (double)(int16)audioFile->readl(2) / 32768.0 * (double)io.audioVolume / 255.0; + right = (double)(int16)audioFile->readl(2) / 32768.0 * (double)io.audioVolume / 255.0; + if(dsp.mute()) left = 0, right = 0; + } + } else { + io.audioPlay = false; + } + } + + if(!system.runAhead) stream->sample(float(left), float(right)); + step(1); + synchronizeCPU(); +} + +auto MSU1::step(uint clocks) -> void { + clock += clocks * (uint64_t)cpu.frequency; +} + +auto MSU1::unload() -> void { + dataFile.reset(); + audioFile.reset(); +} + +auto MSU1::power() -> void { + create(MSU1::Enter, 44100); + stream = Emulator::audio.createStream(2, frequency); + + io.dataSeekOffset = 0; + io.dataReadOffset = 0; + + io.audioPlayOffset = 0; + io.audioLoopOffset = 0; + + io.audioTrack = 0; + io.audioVolume = 0; + + io.audioResumeTrack = ~0; //no resume + io.audioResumeOffset = 0; + + io.audioError = false; + io.audioPlay = false; + io.audioRepeat = false; + io.audioBusy = false; + io.dataBusy = false; + + dataOpen(); + audioOpen(); +} + +auto MSU1::dataOpen() -> void { + dataFile.reset(); + string name = {"msu1/data.rom"}; + if(dataFile = platform->open(ID::SuperFamicom, name, File::Read)) { + dataFile->seek(io.dataReadOffset); + } +} + +auto MSU1::audioOpen() -> void { + audioFile.reset(); + string name = {"msu1/track-", io.audioTrack, ".pcm"}; + if(audioFile = platform->open(ID::SuperFamicom, name, File::Read)) { + if(audioFile->size() >= 8) { + uint32 header = audioFile->readm(4); + if(header == 0x4d535531) { //"MSU1" + io.audioLoopOffset = 8 + audioFile->readl(4) * 4; + if(io.audioLoopOffset > audioFile->size()) io.audioLoopOffset = 8; + io.audioError = false; + audioFile->seek(io.audioPlayOffset); + return; + } + } + audioFile.reset(); + } + io.audioError = true; +} + +auto MSU1::readIO(uint addr, uint8) -> uint8 { + cpu.synchronizeCoprocessors(); + + switch(0x2000 | addr & 7) { + case 0x2000: + return ( + Revision << 0 + | io.audioError << 3 + | io.audioPlay << 4 + | io.audioRepeat << 5 + | io.audioBusy << 6 + | io.dataBusy << 7 + ); + case 0x2001: + if(io.dataBusy) return 0x00; + if(!dataFile) return 0x00; + if(dataFile->end()) return 0x00; + io.dataReadOffset++; + return dataFile->read(); + case 0x2002: return 'S'; + case 0x2003: return '-'; + case 0x2004: return 'M'; + case 0x2005: return 'S'; + case 0x2006: return 'U'; + case 0x2007: return '1'; + } + + unreachable; +} + +auto MSU1::writeIO(uint addr, uint8 data) -> void { + cpu.synchronizeCoprocessors(); + + switch(0x2000 | addr & 7) { + case 0x2000: io.dataSeekOffset = io.dataSeekOffset & 0xffffff00 | data << 0; break; + case 0x2001: io.dataSeekOffset = io.dataSeekOffset & 0xffff00ff | data << 8; break; + case 0x2002: io.dataSeekOffset = io.dataSeekOffset & 0xff00ffff | data << 16; break; + case 0x2003: io.dataSeekOffset = io.dataSeekOffset & 0x00ffffff | data << 24; + io.dataReadOffset = io.dataSeekOffset; + if(dataFile) dataFile->seek(io.dataReadOffset); + break; + case 0x2004: io.audioTrack = io.audioTrack & 0xff00 | data << 0; break; + case 0x2005: io.audioTrack = io.audioTrack & 0x00ff | data << 8; + io.audioPlay = false; + io.audioRepeat = false; + io.audioPlayOffset = 8; + if(io.audioTrack == io.audioResumeTrack) { + io.audioPlayOffset = io.audioResumeOffset; + io.audioResumeTrack = ~0; //erase resume track + io.audioResumeOffset = 0; + } + audioOpen(); + break; + case 0x2006: + io.audioVolume = data; + break; + case 0x2007: + if(io.audioBusy) break; + if(io.audioError) break; + io.audioPlay = bool(data & 1); + io.audioRepeat = bool(data & 2); + boolean audioResume = bool(data & 4); + if(!io.audioPlay && audioResume) { + io.audioResumeTrack = io.audioTrack; + io.audioResumeOffset = io.audioPlayOffset; + } + break; + } +} + +} diff --git a/sfc/coprocessor/msu1/msu1.hpp b/sfc/coprocessor/msu1/msu1.hpp new file mode 100644 index 0000000..0b3f937 --- /dev/null +++ b/sfc/coprocessor/msu1/msu1.hpp @@ -0,0 +1,53 @@ +struct MSU1 : Thread { + shared_pointer stream; + + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + auto unload() -> void; + auto power() -> void; + + auto dataOpen() -> void; + auto audioOpen() -> void; + + auto readIO(uint addr, uint8 data) -> uint8; + auto writeIO(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; + +private: + shared_pointer dataFile; + shared_pointer audioFile; + + enum Flag : uint { + Revision = 0x02, //max: 0x07 + AudioError = 0x08, + AudioPlaying = 0x10, + AudioRepeating = 0x20, + AudioBusy = 0x40, + DataBusy = 0x80, + }; + + struct IO { + uint32 dataSeekOffset; + uint32 dataReadOffset; + + uint32 audioPlayOffset; + uint32 audioLoopOffset; + + uint16 audioTrack; + uint8 audioVolume; + + uint32 audioResumeTrack; + uint32 audioResumeOffset; + + boolean audioError; + boolean audioPlay; + boolean audioRepeat; + boolean audioBusy; + boolean dataBusy; + } io; +}; + +extern MSU1 msu1; diff --git a/sfc/coprocessor/msu1/serialization.cpp b/sfc/coprocessor/msu1/serialization.cpp new file mode 100644 index 0000000..d6658df --- /dev/null +++ b/sfc/coprocessor/msu1/serialization.cpp @@ -0,0 +1,24 @@ +auto MSU1::serialize(serializer& s) -> void { + Thread::serialize(s); + + s.integer(io.dataSeekOffset); + s.integer(io.dataReadOffset); + + s.integer(io.audioPlayOffset); + s.integer(io.audioLoopOffset); + + s.integer(io.audioTrack); + s.integer(io.audioVolume); + + s.integer(io.audioResumeTrack); + s.integer(io.audioResumeOffset); + + s.boolean(io.audioError); + s.boolean(io.audioPlay); + s.boolean(io.audioRepeat); + s.boolean(io.audioBusy); + s.boolean(io.dataBusy); + + dataOpen(); + audioOpen(); +} diff --git a/sfc/coprocessor/necdsp/necdsp.cpp b/sfc/coprocessor/necdsp/necdsp.cpp new file mode 100644 index 0000000..3942d98 --- /dev/null +++ b/sfc/coprocessor/necdsp/necdsp.cpp @@ -0,0 +1,63 @@ +#include +#include + +namespace SuperFamicom { + +#include "serialization.cpp" +NECDSP necdsp; + +auto NECDSP::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto NECDSP::Enter() -> void { + while(true) { + scheduler.synchronize(); + necdsp.main(); + } +} + +auto NECDSP::main() -> void { + exec(); + step(1); + synchronizeCPU(); +} + +auto NECDSP::step(uint clocks) -> void { + clock += clocks * (uint64_t)cpu.frequency; +} + +auto NECDSP::read(uint addr, uint8) -> uint8 { + cpu.synchronizeCoprocessors(); + if(addr & 1) { + return uPD96050::readSR(); + } else { + return uPD96050::readDR(); + } +} + +auto NECDSP::write(uint addr, uint8 data) -> void { + cpu.synchronizeCoprocessors(); + if(addr & 1) { + return uPD96050::writeSR(data); + } else { + return uPD96050::writeDR(data); + } +} + +auto NECDSP::readRAM(uint addr, uint8) -> uint8 { + cpu.synchronizeCoprocessors(); + return uPD96050::readDP(addr); +} + +auto NECDSP::writeRAM(uint addr, uint8 data) -> void { + cpu.synchronizeCoprocessors(); + return uPD96050::writeDP(addr, data); +} + +auto NECDSP::power() -> void { + uPD96050::power(); + create(NECDSP::Enter, Frequency); +} + +} diff --git a/sfc/coprocessor/necdsp/necdsp.hpp b/sfc/coprocessor/necdsp/necdsp.hpp new file mode 100644 index 0000000..dd29fbb --- /dev/null +++ b/sfc/coprocessor/necdsp/necdsp.hpp @@ -0,0 +1,21 @@ +struct NECDSP : Processor::uPD96050, Thread { + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto readRAM(uint addr, uint8 data) -> uint8; + auto writeRAM(uint addr, uint8 data) -> void; + + auto power() -> void; + + auto firmware() const -> vector; + auto serialize(serializer&) -> void; + + uint Frequency = 0; +}; + +extern NECDSP necdsp; diff --git a/sfc/coprocessor/necdsp/serialization.cpp b/sfc/coprocessor/necdsp/serialization.cpp new file mode 100644 index 0000000..8708471 --- /dev/null +++ b/sfc/coprocessor/necdsp/serialization.cpp @@ -0,0 +1,25 @@ +auto NECDSP::firmware() const -> vector { + vector buffer; + if(!cartridge.has.NECDSP) return buffer; + uint plength = 2048, dlength = 1024; + if(revision == Revision::uPD96050) plength = 16384, dlength = 2048; + buffer.reserve(plength * 3 + dlength * 2); + + for(auto n : range(plength)) { + buffer.append(programROM[n] >> 0); + buffer.append(programROM[n] >> 8); + buffer.append(programROM[n] >> 16); + } + + for(auto n : range(dlength)) { + buffer.append(dataROM[n] >> 0); + buffer.append(dataROM[n] >> 8); + } + + return buffer; +} + +auto NECDSP::serialize(serializer& s) -> void { + uPD96050::serialize(s); + Thread::serialize(s); +} diff --git a/sfc/coprocessor/obc1/obc1.cpp b/sfc/coprocessor/obc1/obc1.cpp new file mode 100644 index 0000000..9124067 --- /dev/null +++ b/sfc/coprocessor/obc1/obc1.cpp @@ -0,0 +1,70 @@ +#include + +namespace SuperFamicom { + +#include "serialization.cpp" +OBC1 obc1; + +auto OBC1::unload() -> void { + ram.reset(); +} + +auto OBC1::power() -> void { + status.baseptr = (ramRead(0x1ff5) & 1) ? 0x1800 : 0x1c00; + status.address = (ramRead(0x1ff6) & 0x7f); + status.shift = (ramRead(0x1ff6) & 3) << 1; +} + +auto OBC1::read(uint addr, uint8) -> uint8 { + addr &= 0x1fff; + + switch(addr) { + case 0x1ff0: return ramRead(status.baseptr + (status.address << 2) + 0); + case 0x1ff1: return ramRead(status.baseptr + (status.address << 2) + 1); + case 0x1ff2: return ramRead(status.baseptr + (status.address << 2) + 2); + case 0x1ff3: return ramRead(status.baseptr + (status.address << 2) + 3); + case 0x1ff4: return ramRead(status.baseptr + (status.address >> 2) + 0x200); + } + + return ramRead(addr); +} + +auto OBC1::write(uint addr, uint8 data) -> void { + addr &= 0x1fff; + + switch(addr) { + case 0x1ff0: ramWrite(status.baseptr + (status.address << 2) + 0, data); return; + case 0x1ff1: ramWrite(status.baseptr + (status.address << 2) + 1, data); return; + case 0x1ff2: ramWrite(status.baseptr + (status.address << 2) + 2, data); return; + case 0x1ff3: ramWrite(status.baseptr + (status.address << 2) + 3, data); return; + case 0x1ff4: { + uint8 temp = ramRead(status.baseptr + (status.address >> 2) + 0x200); + temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift); + ramWrite(status.baseptr + (status.address >> 2) + 0x200, temp); + } return; + case 0x1ff5: + status.baseptr = (data & 1) ? 0x1800 : 0x1c00; + ramWrite(addr, data); + return; + case 0x1ff6: + status.address = (data & 0x7f); + status.shift = (data & 3) << 1; + ramWrite(addr, data); + return; + case 0x1ff7: + ramWrite(addr, data); + return; + } + + return ramWrite(addr, data); +} + +auto OBC1::ramRead(uint addr) -> uint8 { + return ram.read(addr & 0x1fff); +} + +auto OBC1::ramWrite(uint addr, uint8 data) -> void { + ram.write(addr & 0x1fff, data); +} + +} diff --git a/sfc/coprocessor/obc1/obc1.hpp b/sfc/coprocessor/obc1/obc1.hpp new file mode 100644 index 0000000..4c42eb8 --- /dev/null +++ b/sfc/coprocessor/obc1/obc1.hpp @@ -0,0 +1,23 @@ +struct OBC1 { + auto unload() -> void; + auto power() -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; + + WritableMemory ram; + +private: + auto ramRead(uint addr) -> uint8; + auto ramWrite(uint addr, uint8 data) -> void; + + struct { + uint16 address; + uint16 baseptr; + uint16 shift; + } status; +}; + +extern OBC1 obc1; diff --git a/sfc/coprocessor/obc1/serialization.cpp b/sfc/coprocessor/obc1/serialization.cpp new file mode 100644 index 0000000..851a16d --- /dev/null +++ b/sfc/coprocessor/obc1/serialization.cpp @@ -0,0 +1,7 @@ +auto OBC1::serialize(serializer& s) -> void { + s.array(ram.data(), ram.size()); + + s.integer(status.address); + s.integer(status.baseptr); + s.integer(status.shift); +} diff --git a/sfc/coprocessor/sa1/bwram.cpp b/sfc/coprocessor/sa1/bwram.cpp new file mode 100644 index 0000000..7d6059c --- /dev/null +++ b/sfc/coprocessor/sa1/bwram.cpp @@ -0,0 +1,121 @@ +auto SA1::BWRAM::conflict() const -> bool { + if(configuration.hacks.coprocessor.delayedSync) return false; + + if((cpu.r.mar & 0x40e000) == 0x006000) return true; //00-3f,80-bf:6000-7fff + if((cpu.r.mar & 0xf00000) == 0x400000) return true; //40-4f:0000-ffff + return false; +} + +auto SA1::BWRAM::read(uint address, uint8 data) -> uint8 { + if(!size()) return data; + address = bus.mirror(address, size()); + return WritableMemory::read(address, data); +} + +auto SA1::BWRAM::write(uint address, uint8 data) -> void { + if(!size()) return; + address = bus.mirror(address, size()); + return WritableMemory::write(address, data); +} + +//note: addresses are translated prior to invoking this function: +//00-3f,80-bf:6000-7fff size=0x2000 => 00:0000-1fff +//40-4f:0000-ffff => untranslated +auto SA1::BWRAM::readCPU(uint address, uint8 data) -> uint8 { + cpu.synchronizeCoprocessors(); + + if(address < 0x2000) { //$00-3f,80-bf:6000-7fff + address = sa1.mmio.sbm * 0x2000 + (address & 0x1fff); + } + + if(dma) return sa1.dmaCC1Read(address); + return read(address, data); +} + +auto SA1::BWRAM::writeCPU(uint address, uint8 data) -> void { + cpu.synchronizeCoprocessors(); + + if(address < 0x2000) { //$00-3f,80-bf:6000-7fff + address = sa1.mmio.sbm * 0x2000 + (address & 0x1fff); + } + + return write(address, data); +} + +auto SA1::BWRAM::readSA1(uint address, uint8 data) -> uint8 { + if(sa1.mmio.sw46 == 0) { + //$40-43:0000-ffff x 32 projection + address = (sa1.mmio.cbm & 0x1f) * 0x2000 + (address & 0x1fff); + return readLinear(address, data); + } else { + //$60-6f:0000-ffff x 128 projection + address = sa1.mmio.cbm * 0x2000 + (address & 0x1fff); + return readBitmap(address, data); + } +} + +auto SA1::BWRAM::writeSA1(uint address, uint8 data) -> void { + if(sa1.mmio.sw46 == 0) { + //$40-43:0000-ffff x 32 projection + address = (sa1.mmio.cbm & 0x1f) * 0x2000 + (address & 0x1fff); + return writeLinear(address, data); + } else { + //$60-6f:0000-ffff x 128 projection + address = sa1.mmio.cbm * 0x2000 + (address & 0x1fff); + return writeBitmap(address, data); + } +} + +auto SA1::BWRAM::readLinear(uint address, uint8 data) -> uint8 { + return read(address, data); +} + +auto SA1::BWRAM::writeLinear(uint address, uint8 data) -> void { + return write(address, data); +} + +auto SA1::BWRAM::readBitmap(uint20 address, uint8 data) -> uint8 { + if(sa1.mmio.bbf == 0) { + //4bpp + uint shift = address & 1; + address >>= 1; + switch(shift) { + case 0: return read(address) >> 0 & 15; + case 1: return read(address) >> 4 & 15; + } + } else { + //2bpp + uint shift = address & 3; + address >>= 2; + switch(shift) { + case 0: return read(address) >> 0 & 3; + case 1: return read(address) >> 2 & 3; + case 2: return read(address) >> 4 & 3; + case 3: return read(address) >> 6 & 3; + } + } + unreachable; +} + +auto SA1::BWRAM::writeBitmap(uint20 address, uint8 data) -> void { + if(sa1.mmio.bbf == 0) { + //4bpp + uint shift = address & 1; + address >>= 1; + switch(shift) { + case 0: data = read(address) & 0xf0 | (data & 0x0f) << 0; break; + case 1: data = read(address) & 0x0f | (data & 0x0f) << 4; break; + } + } else { + //2bpp + uint shift = address & 3; + address >>= 2; + switch(shift) { + case 0: data = read(address) & 0xfc | (data & 0x03) << 0; break; + case 1: data = read(address) & 0xf3 | (data & 0x03) << 2; break; + case 2: data = read(address) & 0xcf | (data & 0x03) << 4; break; + case 3: data = read(address) & 0x3f | (data & 0x03) << 6; break; + } + } + write(address, data); +} diff --git a/sfc/coprocessor/sa1/dma.cpp b/sfc/coprocessor/sa1/dma.cpp new file mode 100644 index 0000000..ba494a6 --- /dev/null +++ b/sfc/coprocessor/sa1/dma.cpp @@ -0,0 +1,128 @@ +//direct data transfer +auto SA1::dmaNormal() -> void { + while(mmio.dtc--) { + uint8 data = r.mdr; + uint24 source = mmio.dsa++; + uint16 target = mmio.dda++; + + if(mmio.sd == DMA::SourceROM && mmio.dd == DMA::DestBWRAM) { + step(); + step(); + if(bwram.conflict()) step(); + if(bwram.conflict()) step(); + data = rom.readSA1(source, data); + bwram.write(target, data); + } + + if(mmio.sd == DMA::SourceROM && mmio.dd == DMA::DestIRAM) { + step(); + if(iram.conflict() || rom.conflict()) step(); + if(iram.conflict()) step(); + data = rom.readSA1(source, data); + iram.write(target, data); + } + + if(mmio.sd == DMA::SourceBWRAM && mmio.dd == DMA::DestIRAM) { + step(); + step(); + if(bwram.conflict() || iram.conflict()) step(); + if(bwram.conflict()) step(); + data = bwram.read(source, data); + iram.write(target, data); + } + + if(mmio.sd == DMA::SourceIRAM && mmio.dd == DMA::DestBWRAM) { + step(); + step(); + if(bwram.conflict() || iram.conflict()) step(); + if(bwram.conflict()) step(); + data = iram.read(source, data); + bwram.write(target, data); + } + } + + mmio.dma_irqfl = true; + if(mmio.dma_irqen) mmio.dma_irqcl = 0; +} + +//type-1 character conversion +auto SA1::dmaCC1() -> void { + bwram.dma = true; + mmio.chdma_irqfl = true; + if(mmio.chdma_irqen) { + mmio.chdma_irqcl = 0; + cpu.irq(1); + } +} + +//((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 +auto SA1::dmaCC1Read(uint addr) -> uint8 { + //16 bytes/char (2bpp); 32 bytes/char (4bpp); 64 bytes/char (8bpp) + uint charmask = (1 << (6 - mmio.dmacb)) - 1; + + if((addr & charmask) == 0) { + //buffer next character to I-RAM + uint bpp = 2 << (2 - mmio.dmacb); + uint bpl = (8 << mmio.dmasize) >> mmio.dmacb; + uint bwmask = bwram.size() - 1; + uint tile = ((addr - mmio.dsa) & bwmask) >> (6 - mmio.dmacb); + uint ty = (tile >> mmio.dmasize); + uint tx = tile & ((1 << mmio.dmasize) - 1); + uint bwaddr = mmio.dsa + ty * 8 * bpl + tx * bpp; + + for(auto y : range(8)) { + uint64 data = 0; + for(auto byte : range(bpp)) { + data |= (uint64)bwram.read((bwaddr + byte) & bwmask) << (byte << 3); + } + bwaddr += bpl; + + uint8 out[] = {0, 0, 0, 0, 0, 0, 0, 0}; + for(auto x : range(8)) { + 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(auto byte : range(bpp)) { + uint 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 +auto SA1::dmaCC2() -> void { + //select register file index (0-7 or 8-15) + const uint8* brf = &mmio.brf[(dma.line & 1) << 3]; + uint bpp = 2 << (2 - mmio.dmacb); + uint addr = mmio.dda & 0x07ff; + addr &= ~((1 << (7 - mmio.dmacb)) - 1); + addr += (dma.line & 8) * bpp; + addr += (dma.line & 7) * 2; + + for(auto byte : range(bpp)) { + uint8 output = 0; + for(auto bit : range(8)) { + output |= ((brf[bit] >> byte) & 1) << (7 - bit); + } + iram.write(addr + ((byte & 6) << 3) + (byte & 1), output); + } + + dma.line = (dma.line + 1) & 15; +} diff --git a/sfc/coprocessor/sa1/io.cpp b/sfc/coprocessor/sa1/io.cpp new file mode 100644 index 0000000..5822937 --- /dev/null +++ b/sfc/coprocessor/sa1/io.cpp @@ -0,0 +1,522 @@ +auto SA1::readIOCPU(uint address, uint8 data) -> uint8 { + cpu.synchronizeCoprocessors(); + + switch(0x2200 | address & 0x1ff) { + + //(SFR) S-CPU flag read + case 0x2300: { + 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; + } + + //(VC) version code register + case 0x230e: { + break; //does not actually exist on real hardware ... always returns open bus + } + + } + + return data; +} + +auto SA1::readIOSA1(uint address, uint8) -> uint8 { + synchronizeCPU(); + + switch(0x2200 | address & 0x1ff) { + + //(CFR) SA-1 flag read + case 0x2301: { + 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 + case 0x2302: { + //latch counters + mmio.hcr = status.hcounter >> 2; + mmio.vcr = status.vcounter; + return mmio.hcr >> 0; + } + + case 0x2303: { + return mmio.hcr >> 8; + } + + //(VCR) vcounter read + case 0x2304: return mmio.vcr >> 0; + case 0x2305: return mmio.vcr >> 8; + + //(MR) arithmetic result + case 0x2306: return mmio.mr >> 0; + case 0x2307: return mmio.mr >> 8; + case 0x2308: return mmio.mr >> 16; + case 0x2309: return mmio.mr >> 24; + case 0x230a: return mmio.mr >> 32; + + //(OF) arithmetic overflow flag + case 0x230b: return mmio.overflow << 7; + + //(VDPL) variable-length data read port low + case 0x230c: { + uint24 data; + data.byte(0) = readVBR(mmio.va + 0); + data.byte(1) = readVBR(mmio.va + 1); + data.byte(2) = readVBR(mmio.va + 2); + data >>= mmio.vbit; + + return data >> 0; + } + + //(VDPH) variable-length data read port high + case 0x230d: { + uint24 data; + data.byte(0) = readVBR(mmio.va + 0); + data.byte(1) = readVBR(mmio.va + 1); + data.byte(2) = readVBR(mmio.va + 2); + 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; + } + + } + + return 0xff; +} + +auto SA1::writeIOCPU(uint address, uint8 data) -> void { + cpu.synchronizeCoprocessors(); + + switch(0x2200 | address & 0x1ff) { + + //(CCNT) SA-1 control + case 0x2200: { + if(mmio.sa1_resb && !(data & 0x20)) { + //reset SA-1 CPU (PC bank set to 0x00) + r.pc.d = mmio.crv; + } + + 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; + } + + return; + } + + //(SIE) S-CPU interrupt enable + case 0x2201: { + if(!mmio.cpu_irqen && (data & 0x80)) { + if(mmio.cpu_irqfl) { + mmio.cpu_irqcl = 0; + cpu.irq(1); + } + } + + if(!mmio.chdma_irqen && (data & 0x20)) { + if(mmio.chdma_irqfl) { + mmio.chdma_irqcl = 0; + cpu.irq(1); + } + } + + mmio.cpu_irqen = (data & 0x80); + mmio.chdma_irqen = (data & 0x20); + return; + } + + //(SIC) S-CPU interrupt clear + case 0x2202: { + 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.irq(0); + return; + } + + //(CRV) SA-1 reset vector + case 0x2203: { mmio.crv = (mmio.crv & 0xff00) | data; return; } + case 0x2204: { mmio.crv = (data << 8) | (mmio.crv & 0xff); return; } + + //(CNV) SA-1 NMI vector + case 0x2205: { mmio.cnv = (mmio.cnv & 0xff00) | data; return; } + case 0x2206: { mmio.cnv = (data << 8) | (mmio.cnv & 0xff); return; } + + //(CIV) SA-1 IRQ vector + case 0x2207: { mmio.civ = (mmio.civ & 0xff00) | data; return; } + case 0x2208: { mmio.civ = (data << 8) | (mmio.civ & 0xff); return; } + + //(CXB) Super MMC bank C + case 0x2220: { + mmio.cbmode = (data & 0x80); + mmio.cb = (data & 0x07); + return; + } + + //(DXB) Super MMC bank D + case 0x2221: { + mmio.dbmode = (data & 0x80); + mmio.db = (data & 0x07); + return; + } + + //(EXB) Super MMC bank E + case 0x2222: { + mmio.ebmode = (data & 0x80); + mmio.eb = (data & 0x07); + return; + } + + //(FXB) Super MMC bank F + case 0x2223: { + mmio.fbmode = (data & 0x80); + mmio.fb = (data & 0x07); + return; + } + + //(BMAPS) S-CPU BW-RAM address mapping + case 0x2224: { + mmio.sbm = (data & 0x1f); + return; + } + + //(SWBE) S-CPU BW-RAM write enable + case 0x2226: { + mmio.swen = (data & 0x80); + return; + } + + //(BWPA) BW-RAM write-protected area + case 0x2228: { + mmio.bwp = (data & 0x0f); + return; + } + + //(SIWP) S-CPU I-RAM write protection + case 0x2229: { + mmio.siwp = data; + return; + } + + case 0x2231: case 0x2232: case 0x2233: case 0x2234: case 0x2235: case 0x2236: case 0x2237: { + return writeIOShared(address, data); + } + + } +} + +auto SA1::writeIOSA1(uint address, uint8 data) -> void { + synchronizeCPU(); + + switch(0x2200 | address & 0x1ff) { + + //(SCNT) S-CPU control + case 0x2209: { + 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.irq(1); + } + } + + return; + } + + //(CIE) SA-1 interrupt enable + case 0x220a: { + 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); + return; + } + + //(CIC) SA-1 interrupt clear + case 0x220b: { + 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; + return; + } + + //(SNV) S-CPU NMI vector + case 0x220c: { mmio.snv = (mmio.snv & 0xff00) | data; return; } + case 0x220d: { mmio.snv = (data << 8) | (mmio.snv & 0xff); return; } + + //(SIV) S-CPU IRQ vector + case 0x220e: { mmio.siv = (mmio.siv & 0xff00) | data; return; } + case 0x220f: { mmio.siv = (data << 8) | (mmio.siv & 0xff); return; } + + //(TMC) H/V timer control + case 0x2210: { + mmio.hvselb = (data & 0x80); + mmio.ven = (data & 0x02); + mmio.hen = (data & 0x01); + return; + } + + //(CTR) SA-1 timer restart + case 0x2211: { + status.vcounter = 0; + status.hcounter = 0; + return; + } + + //(HCNT) H-count + case 0x2212: { mmio.hcnt = (mmio.hcnt & 0xff00) | (data << 0); return; } + case 0x2213: { mmio.hcnt = (mmio.hcnt & 0x00ff) | (data << 8); return; } + + //(VCNT) V-count + case 0x2214: { mmio.vcnt = (mmio.vcnt & 0xff00) | (data << 0); return; } + case 0x2215: { mmio.vcnt = (mmio.vcnt & 0x00ff) | (data << 8); return; } + + //(BMAP) SA-1 BW-RAM address mapping + case 0x2225: { + mmio.sw46 = (data & 0x80); + mmio.cbm = (data & 0x7f); + return; + } + + //(CWBE) SA-1 BW-RAM write enable + case 0x2227: { + mmio.cwen = (data & 0x80); + return; + } + + //(CIWP) SA-1 I-RAM write protection + case 0x222a: { + mmio.ciwp = data; + return; + } + + //(DCNT) DMA control + case 0x2230: { + 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; + return; + } + + case 0x2231: case 0x2232: case 0x2233: case 0x2234: case 0x2235: case 0x2236: case 0x2237: { + return writeIOShared(address, data); + } + + //(DTC) DMA terminal counter + case 0x2238: { mmio.dtc = (mmio.dtc & 0xff00) | (data << 0); return; } + case 0x2239: { mmio.dtc = (mmio.dtc & 0x00ff) | (data << 8); return; } + + //(BBF) BW-RAM bitmap format + case 0x223f: { mmio.bbf = (data & 0x80); return; } + + //(BRF) bitmap register files + case 0x2240: { mmio.brf[ 0] = data; return; } + case 0x2241: { mmio.brf[ 1] = data; return; } + case 0x2242: { mmio.brf[ 2] = data; return; } + case 0x2243: { mmio.brf[ 3] = data; return; } + case 0x2244: { mmio.brf[ 4] = data; return; } + case 0x2245: { mmio.brf[ 5] = data; return; } + case 0x2246: { mmio.brf[ 6] = data; return; } + case 0x2247: { mmio.brf[ 7] = data; + if(mmio.dmaen) { + if(mmio.cden == 1 && mmio.cdsel == 0) { + dmaCC2(); + } + } + return; + } + case 0x2248: { mmio.brf[ 8] = data; return; } + case 0x2249: { mmio.brf[ 9] = data; return; } + case 0x224a: { mmio.brf[10] = data; return; } + case 0x224b: { mmio.brf[11] = data; return; } + case 0x224c: { mmio.brf[12] = data; return; } + case 0x224d: { mmio.brf[13] = data; return; } + case 0x224e: { mmio.brf[14] = data; return; } + case 0x224f: { mmio.brf[15] = data; + if(mmio.dmaen) { + if(mmio.cden == 1 && mmio.cdsel == 0) { + dmaCC2(); + } + } + return; + } + + //(MCNT) arithmetic control + case 0x2250: { + mmio.acm = (data & 0x02); + mmio.md = (data & 0x01); + + if(mmio.acm) mmio.mr = 0; + return; + } + + //(MAL) multiplicand / dividend low + case 0x2251: { + mmio.ma = mmio.ma & ~0x00ff | data << 0; + return; + } + + //(MAH) multiplicand / dividend high + case 0x2252: { + mmio.ma = mmio.ma & ~0xff00 | data << 8; + return; + } + + //(MBL) multiplier / divisor low + case 0x2253: { + mmio.mb = mmio.mb & ~0x00ff | data << 0; + return; + } + + //(MBH) multiplier / divisor high + //multiplication / cumulative sum only resets MB + //division resets both MA and MB + case 0x2254: { + mmio.mb = mmio.mb & ~0xff00 | data << 8; + + if(mmio.acm == 0) { + if(mmio.md == 0) { + //signed multiplication + mmio.mr = (uint32)((int16)mmio.ma * (int16)mmio.mb); + mmio.mb = 0; + } else { + //unsigned division + if(mmio.mb == 0) { + mmio.mr = 0; + } else { + int16 dividend = mmio.ma; + uint16 divisor = mmio.mb; + uint16 remainder = dividend >= 0 ? uint16(dividend % divisor) : uint16((dividend % divisor + divisor) % divisor); + uint16 quotient = (dividend - remainder) / divisor; + 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 >> 40; + mmio.mr = (uint40)mmio.mr; + mmio.mb = 0; + } + return; + } + + //(VBD) variable-length bit processing + case 0x2258: { + 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; + } + return; + } + + //(VDA) variable-length bit game pak ROM start address + case 0x2259: { mmio.va = (mmio.va & 0xffff00) | (data << 0); return; } + case 0x225a: { mmio.va = (mmio.va & 0xff00ff) | (data << 8); return; } + case 0x225b: { mmio.va = (mmio.va & 0x00ffff) | (data << 16); mmio.vbit = 0; return; } + + } +} + +auto SA1::writeIOShared(uint address, uint8 data) -> void { + switch(0x2200 | address & 0x1ff) { + + //(CDMA) character conversion DMA parameters + case 0x2231: { + mmio.chdend = (data & 0x80); + mmio.dmasize = (data >> 2) & 7; + mmio.dmacb = (data & 0x03); + + if(mmio.chdend) bwram.dma = false; + if(mmio.dmasize > 5) mmio.dmasize = 5; + if(mmio.dmacb > 2) mmio.dmacb = 2; + return; + } + + //(SDA) DMA source device start address + case 0x2232: { mmio.dsa = (mmio.dsa & 0xffff00) | (data << 0); return; } + case 0x2233: { mmio.dsa = (mmio.dsa & 0xff00ff) | (data << 8); return; } + case 0x2234: { mmio.dsa = (mmio.dsa & 0x00ffff) | (data << 16); return; } + + //(DDA) DMA destination start address + case 0x2235: { mmio.dda = (mmio.dda & 0xffff00) | (data << 0); return; } + case 0x2236: { mmio.dda = (mmio.dda & 0xff00ff) | (data << 8); + if(mmio.dmaen) { + if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) { + dmaNormal(); + } else if(mmio.cden == 1 && mmio.cdsel == 1) { + dmaCC1(); + } + } + return; + } + case 0x2237: { mmio.dda = (mmio.dda & 0x00ffff) | (data << 16); + if(mmio.dmaen) { + if(mmio.cden == 0 && mmio.dd == DMA::DestBWRAM) { + dmaNormal(); + } + } + return; + } + + } +} diff --git a/sfc/coprocessor/sa1/iram.cpp b/sfc/coprocessor/sa1/iram.cpp new file mode 100644 index 0000000..b4b01dd --- /dev/null +++ b/sfc/coprocessor/sa1/iram.cpp @@ -0,0 +1,36 @@ +auto SA1::IRAM::conflict() const -> bool { + if(configuration.hacks.coprocessor.delayedSync) return false; + + if((cpu.r.mar & 0x40f800) == 0x003000) return cpu.refresh() == 0; //00-3f,80-bf:3000-37ff + return false; +} + +auto SA1::IRAM::read(uint address, uint8 data) -> uint8 { + if(!size()) return data; + address = bus.mirror(address, size()); + return WritableMemory::read(address, data); +} + +auto SA1::IRAM::write(uint address, uint8 data) -> void { + if(!size()) return; + address = bus.mirror(address, size()); + return WritableMemory::write(address, data); +} + +auto SA1::IRAM::readCPU(uint address, uint8 data) -> uint8 { + cpu.synchronizeCoprocessors(); + return read(address, data); +} + +auto SA1::IRAM::writeCPU(uint address, uint8 data) -> void { + cpu.synchronizeCoprocessors(); + return write(address, data); +} + +auto SA1::IRAM::readSA1(uint address, uint8 data) -> uint8 { + return read(address, data); +} + +auto SA1::IRAM::writeSA1(uint address, uint8 data) -> void { + return write(address, data); +} diff --git a/sfc/coprocessor/sa1/memory.cpp b/sfc/coprocessor/sa1/memory.cpp new file mode 100644 index 0000000..d82d974 --- /dev/null +++ b/sfc/coprocessor/sa1/memory.cpp @@ -0,0 +1,139 @@ +auto SA1::idle() -> void { + step(); +} + +//RTx, JMx, JSx +auto SA1::idleJump() -> void { + //ROM access penalty cycle: does not apply to BWRAM or IRAM + if((r.pc.d & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff + || (r.pc.d & 0xc00000) == 0xc00000 //c0-ff:0000-ffff + ) { + step(); + if(rom.conflict()) step(); + } +} + +//Bxx +auto SA1::idleBranch() -> void { + if(r.pc.d & 1) idleJump(); +} + +auto SA1::read(uint address) -> uint8 { + r.mar = address; + uint8 data = r.mdr; + + if((address & 0x40fe00) == 0x002200 //00-3f,80-bf:2200-23ff + ) { + step(); + return r.mdr = readIOSA1(address, data); + } + + if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff + || (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff + ) { + step(); + if(rom.conflict()) step(); + return r.mdr = rom.readSA1(address, data); + } + + if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff + || (address & 0xf00000) == 0x400000 //40-4f:0000-ffff + || (address & 0xf00000) == 0x600000 //60-6f:0000-ffff + ) { + step(); + step(); + if(bwram.conflict()) step(); + if(bwram.conflict()) step(); + if((address & 1 << 22) && (address & 1 << 21)) return r.mdr = bwram.readBitmap(address, data); + if((address & 1 << 22)) return r.mdr = bwram.readLinear(address, data); + return r.mdr = bwram.readSA1(address, data); + } + + if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff + || (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff + ) { + step(); + if(iram.conflict()) step(); + if(iram.conflict()) step(); + return r.mdr = iram.readSA1(address, data); + } + + step(); + return data; +} + +auto SA1::write(uint address, uint8 data) -> void { + r.mar = address; + r.mdr = data; + + if((address & 0x40fe00) == 0x002200 //00-3f,80-bf:2200-23ff + ) { + step(); + return writeIOSA1(address, data); + } + + if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff + || (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff + ) { + step(); + if(rom.conflict()) step(); + return rom.writeSA1(address, data); + } + + if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff + || (address & 0xf00000) == 0x400000 //40-4f:0000-ffff + || (address & 0xf00000) == 0x600000 //60-6f:0000-ffff + ) { + step(); + step(); + if(bwram.conflict()) step(); + if(bwram.conflict()) step(); + if((address & 1 << 22) && (address & 1 << 21)) return bwram.writeBitmap(address, data); + if((address & 1 << 22)) return bwram.writeLinear(address, data); + return bwram.writeSA1(address, data); + } + + if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff + || (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff + ) { + step(); + if(iram.conflict()) step(); + if(iram.conflict()) step(); + return iram.writeSA1(address, data); + } + + step(); + return; +} + +//$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. +auto SA1::readVBR(uint address, uint8 data) -> uint8 { + if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff + || (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff + ) { + return rom.readSA1(address, data); + } + + if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff + || (address & 0xf00000) == 0x400000 //40-4f:0000-ffff + ) { + return bwram.read(address, data); + } + + if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff + || (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff + ) { + return iram.read(address, data); + } + + return 0xff; +} + +auto SA1::readDisassembler(uint address) -> uint8 { + //TODO: this is a hack; SA1::read() advances the clock; whereas Bus::read() does not + //the CPU and SA1 bus are identical for ROM, but have differences in BWRAM and IRAM + return bus.read(address, r.mdr); +} diff --git a/sfc/coprocessor/sa1/rom.cpp b/sfc/coprocessor/sa1/rom.cpp new file mode 100644 index 0000000..6aa85f5 --- /dev/null +++ b/sfc/coprocessor/sa1/rom.cpp @@ -0,0 +1,71 @@ +auto SA1::ROM::conflict() const -> bool { + if(configuration.hacks.coprocessor.delayedSync) return false; + + if((cpu.r.mar & 0x408000) == 0x008000) return true; //00-3f,80-bf:8000-ffff + if((cpu.r.mar & 0xc00000) == 0xc00000) return true; //c0-ff:0000-ffff + return false; +} + +auto SA1::ROM::read(uint address, uint8 data) -> uint8 { + address = bus.mirror(address, size()); + return ReadableMemory::read(address, data); +} + +auto SA1::ROM::write(uint address, uint8 data) -> void { +} + +//note: addresses are translated prior to invoking this function: +//00-3f,80-bf:8000-ffff mask=0x408000 => 00-3f:0000-ffff +//c0-ff:0000-ffff => untranslated +auto SA1::ROM::readCPU(uint address, uint8 data) -> uint8 { + //reset vector overrides + if((address & 0xffffe0) == 0x007fe0) { //00:ffe0-ffef + if(address == 0x7fea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0; + if(address == 0x7feb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8; + if(address == 0x7fee && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 0; + if(address == 0x7fef && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 8; + } + + static auto read = [](uint address) { + if((address & 0x400000) && bsmemory.size()) return bsmemory.read(address, 0x00); + return sa1.rom.read(address); + }; + + bool lo = address < 0x400000; //*bmode==0 only applies to 00-3f,80-bf:8000-ffff + address &= 0x3fffff; + + if(address < 0x100000) { //00-1f,8000-ffff; c0-cf:0000-ffff + if(lo && sa1.mmio.cbmode == 0) return read(address); + return read(sa1.mmio.cb << 20 | address & 0x0fffff); + } + + if(address < 0x200000) { //20-3f,8000-ffff; d0-df:0000-ffff + if(lo && sa1.mmio.dbmode == 0) return read(address); + return read(sa1.mmio.db << 20 | address & 0x0fffff); + } + + if(address < 0x300000) { //80-9f,8000-ffff; e0-ef:0000-ffff + if(lo && sa1.mmio.ebmode == 0) return read(address); + return read(sa1.mmio.eb << 20 | address & 0x0fffff); + } + + if(address < 0x400000) { //a0-bf,8000-ffff; f0-ff:0000-ffff + if(lo && sa1.mmio.fbmode == 0) return read(address); + return read(sa1.mmio.fb << 20 | address & 0x0fffff); + } + + return data; //unreachable +} + +auto SA1::ROM::writeCPU(uint address, uint8 data) -> void { +} + +auto SA1::ROM::readSA1(uint address, uint8 data) -> uint8 { + if((address & 0x408000) == 0x008000) { + address = (address & 0x800000) >> 2 | (address & 0x3f0000) >> 1 | address & 0x007fff; + } + return readCPU(address, data); +} + +auto SA1::ROM::writeSA1(uint address, uint8 data) -> void { +} diff --git a/sfc/coprocessor/sa1/sa1.cpp b/sfc/coprocessor/sa1/sa1.cpp new file mode 100644 index 0000000..de9593e --- /dev/null +++ b/sfc/coprocessor/sa1/sa1.cpp @@ -0,0 +1,314 @@ +#include + +namespace SuperFamicom { + +#include "rom.cpp" +#include "bwram.cpp" +#include "iram.cpp" +#include "dma.cpp" +#include "memory.cpp" +#include "io.cpp" +#include "serialization.cpp" +SA1 sa1; + +auto SA1::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto SA1::Enter() -> void { + while(true) { + scheduler.synchronize(); + sa1.main(); + } +} + +auto SA1::main() -> void { + if(r.wai) return instructionWait(); + if(r.stp) return instructionStop(); + + if(mmio.sa1_rdyb || mmio.sa1_resb) { + //SA-1 co-processor is asleep + step(); + return; + } + + if(status.interruptPending) { + status.interruptPending = false; + interrupt(); + return; + } + + instruction(); +} + +//override R65816::interrupt() to support SA-1 vector location IO registers +auto SA1::interrupt() -> void { + read(r.pc.d); + idle(); + if(!r.e) push(r.pc.b); + push(r.pc.h); + push(r.pc.l); + push(r.e ? r.p & ~0x10 : r.p); + r.p.i = 1; + r.p.d = 0; + r.pc.d = r.vector; //PC bank set to 0x00 +} + +auto SA1::lastCycle() -> void { + if(mmio.sa1_nmi && !mmio.sa1_nmicl) { + status.interruptPending = true; + r.vector = mmio.cnv; + mmio.sa1_nmifl = true; + mmio.sa1_nmicl = 1; + r.wai = false; + } else if(!r.p.i) { + if(mmio.timer_irqen && !mmio.timer_irqcl) { + status.interruptPending = true; + r.vector = mmio.civ; + mmio.timer_irqfl = true; + r.wai = false; + } else if(mmio.dma_irqen && !mmio.dma_irqcl) { + status.interruptPending = true; + r.vector = mmio.civ; + mmio.dma_irqfl = true; + r.wai = false; + } else if(mmio.sa1_irq && !mmio.sa1_irqcl) { + status.interruptPending = true; + r.vector = mmio.civ; + mmio.sa1_irqfl = true; + r.wai = false; + } + } +} + +auto SA1::interruptPending() const -> bool { + return status.interruptPending; +} + +auto SA1::step() -> void { + clock += (uint64_t)cpu.frequency << 1; + synchronizeCPU(); + + //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.hen << 0 | mmio.ven << 1) { + case 0: break; + case 1: if(status.hcounter == mmio.hcnt << 2) triggerIRQ(); break; + case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) triggerIRQ(); break; + case 3: if(status.vcounter == mmio.vcnt && status.hcounter == mmio.hcnt << 2) triggerIRQ(); break; + } +} + +auto SA1::triggerIRQ() -> void { + mmio.timer_irqfl = true; + if(mmio.timer_irqen) mmio.timer_irqcl = 0; +} + +auto SA1::unload() -> void { + rom.reset(); + iram.reset(); + bwram.reset(); +} + +auto SA1::power() -> void { + double overclock = max(1.0, min(4.0, configuration.hacks.sa1.overclock / 100.0)); + + WDC65816::power(); + create(SA1::Enter, system.cpuFrequency() * overclock); + + bwram.dma = false; + for(uint address : range(iram.size())) { + iram.write(address, 0x00); + } + + status.counter = 0; + + status.interruptPending = false; + + status.scanlines = Region::PAL() ? 312 : 262; + 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 = 0; + mmio.dbmode = 0; + mmio.ebmode = 0; + mmio.fbmode = 0; + + mmio.cb = 0x00; + mmio.db = 0x01; + mmio.eb = 0x02; + mmio.fb = 0x03; + + //$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(auto& n : mmio.brf) n = 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; +} + +} diff --git a/sfc/coprocessor/sa1/sa1.hpp b/sfc/coprocessor/sa1/sa1.hpp new file mode 100644 index 0000000..66dc6c4 --- /dev/null +++ b/sfc/coprocessor/sa1/sa1.hpp @@ -0,0 +1,287 @@ +//Super Accelerator (SA-1) + +struct SA1 : Processor::WDC65816, Thread { + inline auto synchronizing() const -> bool override { return scheduler.synchronizing(); } + + //sa1.cpp + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto main() -> void; + auto step() -> void; + auto interrupt() -> void override; + + alwaysinline auto triggerIRQ() -> void; + alwaysinline auto lastCycle() -> void override; + alwaysinline auto interruptPending() const -> bool override; + + auto unload() -> void; + auto power() -> void; + + //dma.cpp + struct DMA { + enum CDEN : uint { DmaNormal = 0, DmaCharConversion = 1 }; + enum SD : uint { SourceROM = 0, SourceBWRAM = 1, SourceIRAM = 2 }; + enum DD : uint { DestIRAM = 0, DestBWRAM = 1 }; + uint line; + }; + + auto dmaNormal() -> void; + auto dmaCC1() -> void; + auto dmaCC1Read(uint addr) -> uint8; + auto dmaCC2() -> void; + + //memory.cpp + alwaysinline auto conflictROM() const -> bool; + alwaysinline auto conflictBWRAM() const -> bool; + alwaysinline auto conflictIRAM() const -> bool; + + alwaysinline auto idle() -> void override; + alwaysinline auto idleJump() -> void override; + alwaysinline auto idleBranch() -> void override; + alwaysinline auto read(uint address) -> uint8 override; + alwaysinline auto write(uint address, uint8 data) -> void override; + auto readVBR(uint address, uint8 data = 0) -> uint8; + auto readDisassembler(uint address) -> uint8 override; + + //io.cpp + auto readIOCPU(uint address, uint8 data) -> uint8; + auto readIOSA1(uint address, uint8 data) -> uint8; + auto writeIOCPU(uint address, uint8 data) -> void; + auto writeIOSA1(uint address, uint8 data) -> void; + auto writeIOShared(uint address, uint8 data) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + struct ROM : ReadableMemory { + //rom.cpp + alwaysinline auto conflict() const -> bool; + + alwaysinline auto read(uint address, uint8 data = 0) -> uint8 override; + alwaysinline auto write(uint address, uint8 data) -> void override; + + auto readCPU(uint address, uint8 data = 0) -> uint8; + auto writeCPU(uint address, uint8 data) -> void; + + auto readSA1(uint address, uint8 data = 0) -> uint8; + auto writeSA1(uint address, uint8 data) -> void; + } rom; + + struct BWRAM : WritableMemory { + //bwram.cpp + alwaysinline auto conflict() const -> bool; + + alwaysinline auto read(uint address, uint8 data = 0) -> uint8 override; + alwaysinline auto write(uint address, uint8 data) -> void override; + + auto readCPU(uint address, uint8 data = 0) -> uint8; + auto writeCPU(uint address, uint8 data) -> void; + + auto readSA1(uint address, uint8 data = 0) -> uint8; + auto writeSA1(uint address, uint8 data) -> void; + + auto readLinear(uint address, uint8 data = 0) -> uint8; + auto writeLinear(uint address, uint8 data) -> void; + + auto readBitmap(uint20 address, uint8 data = 0) -> uint8; + auto writeBitmap(uint20 address, uint8 data) -> void; + + bool dma; + } bwram; + + struct IRAM : WritableMemory { + //iram.cpp + alwaysinline auto conflict() const -> bool; + + alwaysinline auto read(uint address, uint8 data = 0) -> uint8 override; + alwaysinline auto write(uint address, uint8 data) -> void override; + + auto readCPU(uint address, uint8 data) -> uint8; + auto writeCPU(uint address, uint8 data) -> void; + + auto readSA1(uint address, uint8 data = 0) -> uint8; + auto writeSA1(uint address, uint8 data) -> void; + } iram; + +private: + DMA dma; + + struct Status { + uint8 counter; + + bool interruptPending; + + uint16 scanlines; + uint16 vcounter; + uint16 hcounter; + } status; + + 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; + uint cb; + + //$2221 DXB + bool dbmode; + uint db; + + //$2222 EXB + bool ebmode; + uint eb; + + //$2223 FXB + bool fbmode; + uint 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; +}; + +extern SA1 sa1; diff --git a/sfc/coprocessor/sa1/serialization.cpp b/sfc/coprocessor/sa1/serialization.cpp new file mode 100644 index 0000000..d528563 --- /dev/null +++ b/sfc/coprocessor/sa1/serialization.cpp @@ -0,0 +1,143 @@ +auto SA1::serialize(serializer& s) -> void { + WDC65816::serialize(s); + Thread::serialize(s); + + s.array(iram.data(), iram.size()); + s.array(bwram.data(), bwram.size()); + s.integer(bwram.dma); + + //sa1.hpp + s.integer(status.counter); + + s.integer(status.interruptPending); + + s.integer(status.scanlines); + s.integer(status.vcounter); + s.integer(status.hcounter); + + //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); +} diff --git a/sfc/coprocessor/sdd1/decompressor.cpp b/sfc/coprocessor/sdd1/decompressor.cpp new file mode 100644 index 0000000..edce9e7 --- /dev/null +++ b/sfc/coprocessor/sdd1/decompressor.cpp @@ -0,0 +1,286 @@ +//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 + +auto SDD1::Decompressor::IM::init(uint offset_) -> void { + offset = offset_; + bitCount = 4; +} + +auto SDD1::Decompressor::IM::getCodeWord(uint8 codeLength) -> uint8 { + uint8 codeWord; + uint8 compCount; + + codeWord = sdd1.mmcRead(offset) << bitCount; + bitCount++; + + if(codeWord & 0x80) { + codeWord |= sdd1.mmcRead(offset + 1) >> (9 - bitCount); + bitCount += codeLength; + } + + if(bitCount & 0x08) { + offset++; + bitCount &= 0x07; + } + + return codeWord; +} + +//golomb-code decoder + +const uint8 SDD1::Decompressor::GCD::runCount[] = { + 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, +}; + +auto SDD1::Decompressor::GCD::getRunCount(uint8 codeNumber, uint8& mpsCount, bool& lpsIndex) -> void { + uint8 codeWord = self.im.getCodeWord(codeNumber); + + if(codeWord & 0x80) { + lpsIndex = 1; + mpsCount = runCount[codeWord >> (codeNumber ^ 0x07)]; + } else { + mpsCount = 1 << codeNumber; + } +} + +//bits generator + +auto SDD1::Decompressor::BG::init() -> void { + mpsCount = 0; + lpsIndex = 0; +} + +auto SDD1::Decompressor::BG::getBit(bool& endOfRun) -> uint8 { + if(!(mpsCount || lpsIndex)) self.gcd.getRunCount(codeNumber, mpsCount, lpsIndex); + + uint8 bit; + if(mpsCount) { + bit = 0; + mpsCount--; + } else { + bit = 1; + lpsIndex = 0; + } + + endOfRun = !(mpsCount || lpsIndex); + return bit; +} + +//probability estimation module + +const SDD1::Decompressor::PEM::State SDD1::Decompressor::PEM::evolutionTable[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}, +}; + +auto SDD1::Decompressor::PEM::init() -> void { + for(auto n : range(32)) { + contextInfo[n].status = 0; + contextInfo[n].mps = 0; + } +} + +auto SDD1::Decompressor::PEM::getBit(uint8 context) -> uint8 { + ContextInfo& info = contextInfo[context]; + uint8 currentStatus = info.status; + uint8 currentMps = info.mps; + const State& s = SDD1::Decompressor::PEM::evolutionTable[currentStatus]; + + uint8 bit; + bool endOfRun; + switch(s.codeNumber) { + case 0: bit = self.bg0.getBit(endOfRun); break; + case 1: bit = self.bg1.getBit(endOfRun); break; + case 2: bit = self.bg2.getBit(endOfRun); break; + case 3: bit = self.bg3.getBit(endOfRun); break; + case 4: bit = self.bg4.getBit(endOfRun); break; + case 5: bit = self.bg5.getBit(endOfRun); break; + case 6: bit = self.bg6.getBit(endOfRun); break; + case 7: bit = self.bg7.getBit(endOfRun); break; + } + + if(endOfRun) { + if(bit) { + if(!(currentStatus & 0xfe)) info.mps ^= 0x01; + info.status = s.nextIfLps; + } else { + info.status = s.nextIfMps; + } + } + + return bit ^ currentMps; +} + +//context model + +auto SDD1::Decompressor::CM::init(uint offset) -> void { + bitplanesInfo = sdd1.mmcRead(offset) & 0xc0; + contextBitsInfo = sdd1.mmcRead(offset) & 0x30; + bitNumber = 0; + for(auto n : range(8)) previousBitplaneBits[n] = 0; + switch(bitplanesInfo) { + case 0x00: currentBitplane = 1; break; + case 0x40: currentBitplane = 7; break; + case 0x80: currentBitplane = 3; break; + } +} + +auto SDD1::Decompressor::CM::getBit() -> uint8 { + switch(bitplanesInfo) { + case 0x00: + currentBitplane ^= 0x01; + break; + case 0x40: + currentBitplane ^= 0x01; + if(!(bitNumber & 0x7f)) currentBitplane = ((currentBitplane + 2) & 0x07); + break; + case 0x80: + currentBitplane ^= 0x01; + if(!(bitNumber & 0x7f)) currentBitplane ^= 0x02; + break; + case 0xc0: + currentBitplane = bitNumber & 0x07; + break; + } + + uint16& contextBits = previousBitplaneBits[currentBitplane]; + uint8 currentContext = (currentBitplane & 0x01) << 4; + switch(contextBitsInfo) { + case 0x00: currentContext |= ((contextBits & 0x01c0) >> 5) | (contextBits & 0x0001); break; + case 0x10: currentContext |= ((contextBits & 0x0180) >> 5) | (contextBits & 0x0001); break; + case 0x20: currentContext |= ((contextBits & 0x00c0) >> 5) | (contextBits & 0x0001); break; + case 0x30: currentContext |= ((contextBits & 0x0180) >> 5) | (contextBits & 0x0003); break; + } + + uint8 bit = self.pem.getBit(currentContext); + contextBits <<= 1; + contextBits |= bit; + bitNumber++; + return bit; +} + +//output logic + +auto SDD1::Decompressor::OL::init(uint offset) -> void { + bitplanesInfo = sdd1.mmcRead(offset) & 0xc0; + r0 = 0x01; +} + +auto SDD1::Decompressor::OL::decompress() -> uint8 { + switch(bitplanesInfo) { + 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.getBit()) r1 |= r0; + if(self.cm.getBit()) r2 |= r0; + } + return r1; + case 0xc0: + for(r0 = 0x01, r1 = 0; r0; r0 <<= 1) { + if(self.cm.getBit()) r1 |= r0; + } + return r1; + } + + return 0; //unreachable? +} + +//core + +SDD1::Decompressor::Decompressor(): +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) { +} + +auto SDD1::Decompressor::init(uint offset) -> void { + 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); +} + +auto SDD1::Decompressor::read() -> uint8 { + return ol.decompress(); +} diff --git a/sfc/coprocessor/sdd1/decompressor.hpp b/sfc/coprocessor/sdd1/decompressor.hpp new file mode 100644 index 0000000..e972c82 --- /dev/null +++ b/sfc/coprocessor/sdd1/decompressor.hpp @@ -0,0 +1,95 @@ +struct Decompressor { + struct IM { //input manager + IM(SDD1::Decompressor& self) : self(self) {} + auto init(uint offset) -> void; + auto getCodeWord(uint8 codeLength) -> uint8; + auto serialize(serializer&) -> void; + + private: + Decompressor& self; + uint offset; + uint bitCount; + }; + + struct GCD { //golomb-code decoder + GCD(SDD1::Decompressor& self) : self(self) {} + auto getRunCount(uint8 codeNumber, uint8& mpsCount, bool& lpsIndex) -> void; + auto serialize(serializer&) -> void; + + private: + Decompressor& self; + static const uint8 runCount[256]; + }; + + struct BG { //bits generator + BG(SDD1::Decompressor& self, uint8 codeNumber) : self(self), codeNumber(codeNumber) {} + auto init() -> void; + auto getBit(bool& endOfRun) -> uint8; + auto serialize(serializer&) -> void; + + private: + Decompressor& self; + const uint8 codeNumber; + uint8 mpsCount; + bool lpsIndex; + }; + + struct PEM { //probability estimation module + PEM(SDD1::Decompressor& self) : self(self) {} + auto init() -> void; + auto getBit(uint8 context) -> uint8; + auto serialize(serializer&) -> void; + + private: + Decompressor& self; + struct State { + uint8 codeNumber; + uint8 nextIfMps; + uint8 nextIfLps; + }; + static const State evolutionTable[33]; + struct ContextInfo { + uint8 status; + uint8 mps; + } contextInfo[32]; + }; + + struct CM { //context model + CM(SDD1::Decompressor& self) : self(self) {} + auto init(uint offset) -> void; + auto getBit() -> uint8; + auto serialize(serializer&) -> void; + + private: + Decompressor& self; + uint8 bitplanesInfo; + uint8 contextBitsInfo; + uint8 bitNumber; + uint8 currentBitplane; + uint16 previousBitplaneBits[8]; + }; + + struct OL { //output logic + OL(SDD1::Decompressor& self) : self(self) {} + auto init(uint offset) -> void; + auto decompress() -> uint8; + auto serialize(serializer&) -> void; + + private: + Decompressor& self; + uint8 bitplanesInfo; + uint8 r0, r1, r2; + }; + + Decompressor(); + auto init(uint offset) -> void; + auto read() -> uint8; + auto serialize(serializer&) -> void; + + IM im; + GCD gcd; + BG bg0, bg1, bg2, bg3, bg4, bg5, bg6, bg7; + PEM pem; + CM cm; + OL ol; +}; diff --git a/sfc/coprocessor/sdd1/sdd1.cpp b/sfc/coprocessor/sdd1/sdd1.cpp new file mode 100644 index 0000000..0727e1b --- /dev/null +++ b/sfc/coprocessor/sdd1/sdd1.cpp @@ -0,0 +1,132 @@ +#include + +namespace SuperFamicom { + +SDD1 sdd1; + +#include "decompressor.cpp" +#include "serialization.cpp" + +auto SDD1::unload() -> void { + rom.reset(); +} + +auto SDD1::power() -> void { + //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({&SDD1::dmaRead, &sdd1}, {&SDD1::dmaWrite, &sdd1}, "00-3f,80-bf:4300-437f"); + + r4800 = 0x00; + r4801 = 0x00; + r4804 = 0x00; + r4805 = 0x01; + r4806 = 0x02; + r4807 = 0x03; + + for(auto n : range(8)) { + dma[n].addr = 0; + dma[n].size = 0; + } + dmaReady = false; +} + +auto SDD1::ioRead(uint addr, uint8 data) -> uint8 { + addr = 0x4800 | addr & 0xf; + + switch(addr) { + case 0x4800: return r4800; + case 0x4801: return r4801; + case 0x4804: return r4804; + case 0x4805: return r4805; + case 0x4806: return r4806; + case 0x4807: return r4807; + } + + //00-3f,80-bf:4802-4803,4808-480f falls through to ROM + return rom.read(addr); +} + +auto SDD1::ioWrite(uint addr, uint8 data) -> void { + addr = 0x4800 | addr & 0xf; + + switch(addr) { + case 0x4800: r4800 = data; break; + case 0x4801: r4801 = data; break; + case 0x4804: r4804 = data & 0x8f; break; + case 0x4805: r4805 = data & 0x8f; break; + case 0x4806: r4806 = data & 0x8f; break; + case 0x4807: r4807 = data & 0x8f; break; + } +} + +auto SDD1::dmaRead(uint addr, uint8 data) -> uint8 { + return cpu.readDMA(addr, data); +} + +auto SDD1::dmaWrite(uint addr, uint8 data) -> void { + uint 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.writeDMA(addr, data); +} + +auto SDD1::mmcRead(uint addr) -> uint8 { + switch(addr >> 20 & 3) { + case 0: return rom.read((r4804 & 0xf) << 20 | addr & 0xfffff); //c0-cf:0000-ffff + case 1: return rom.read((r4805 & 0xf) << 20 | addr & 0xfffff); //d0-df:0000-ffff + case 2: return rom.read((r4806 & 0xf) << 20 | addr & 0xfffff); //e0-ef:0000-ffff + case 3: return rom.read((r4807 & 0xf) << 20 | addr & 0xfffff); //f0-ff:0000-ffff + } + unreachable; +} + +//map address=00-3f,80-bf:8000-ffff +//map address=c0-ff:0000-ffff +auto SDD1::mcuRead(uint addr, uint8 data) -> uint8 { + //map address=00-3f,80-bf:8000-ffff + if(!(addr & 1 << 22)) { + if(!(addr & 1 << 23) && (addr & 1 << 21) && (r4805 & 0x80)) addr &= ~(1 << 21); //20-3f:8000-ffff + if( (addr & 1 << 23) && (addr & 1 << 21) && (r4807 & 0x80)) addr &= ~(1 << 21); //a0-bf:8000-ffff + addr = addr >> 1 & 0x1f8000 | addr & 0x7fff; + return rom.read(addr); + } + + //map address=c0-ff:0000-ffff + if(r4800 & r4801) { + //at least one channel has S-DD1 decompression enabled ... + for(auto n : range(8)) { + if((r4800 & 1 << n) && (r4801 & 1 << n)) { + //S-DD1 always uses fixed transfer mode, so address will not change during transfer + if(addr == dma[n].addr) { + if(!dmaReady) { + //prepare streaming decompression + decompressor.init(addr); + dmaReady = true; + } + + //fetch a decompressed byte; once finished, disable channel and invalidate buffer + data = decompressor.read(); + if(--dma[n].size == 0) { + dmaReady = false; + r4801 &= ~(1 << n); + } + + return data; + } //address matched + } //channel enabled + } //channel loop + } //S-DD1 decompressor enabled + + //S-DD1 decompression mode inactive; return ROM data + return mmcRead(addr); +} + +auto SDD1::mcuWrite(uint addr, uint8 data) -> void { +} + +} diff --git a/sfc/coprocessor/sdd1/sdd1.hpp b/sfc/coprocessor/sdd1/sdd1.hpp new file mode 100644 index 0000000..dd20afe --- /dev/null +++ b/sfc/coprocessor/sdd1/sdd1.hpp @@ -0,0 +1,39 @@ +struct SDD1 { + auto unload() -> void; + auto power() -> void; + + auto ioRead(uint addr, uint8 data) -> uint8; + auto ioWrite(uint addr, uint8 data) -> void; + + auto dmaRead(uint addr, uint8 data) -> uint8; + auto dmaWrite(uint addr, uint8 data) -> void; + + auto mmcRead(uint addr) -> uint8; + + auto mcuRead(uint addr, uint8 data) -> uint8; + auto mcuWrite(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; + + ReadableMemory rom; + +private: + uint8 r4800; //hard enable + uint8 r4801; //soft enable + uint8 r4804; //MMC bank 0 + uint8 r4805; //MMC bank 1 + uint8 r4806; //MMC bank 2 + uint8 r4807; //MMC bank 3 + + struct DMA { + uint24 addr; //$43x2-$43x4 -- DMA transfer address + uint16 size; //$43x5-$43x6 -- DMA transfer size + } dma[8]; + bool dmaReady; //used to initialize decompression module + +public: + #include "decompressor.hpp" + Decompressor decompressor; +}; + +extern SDD1 sdd1; diff --git a/sfc/coprocessor/sdd1/serialization.cpp b/sfc/coprocessor/sdd1/serialization.cpp new file mode 100644 index 0000000..b4b57a8 --- /dev/null +++ b/sfc/coprocessor/sdd1/serialization.cpp @@ -0,0 +1,67 @@ +auto SDD1::serialize(serializer& s) -> void { + s.integer(r4800); + s.integer(r4801); + s.integer(r4804); + s.integer(r4805); + s.integer(r4806); + s.integer(r4807); + + for(auto& channel : dma) { + s.integer(channel.addr); + s.integer(channel.size); + } + s.integer(dmaReady); + + decompressor.serialize(s); +} + +auto SDD1::Decompressor::serialize(serializer& s) -> void { + im.serialize(s); + gcd.serialize(s); + bg0.serialize(s); + bg1.serialize(s); + bg2.serialize(s); + bg3.serialize(s); + bg4.serialize(s); + bg5.serialize(s); + bg6.serialize(s); + bg7.serialize(s); + pem.serialize(s); + cm.serialize(s); + ol.serialize(s); +} + +auto SDD1::Decompressor::IM::serialize(serializer& s) -> void { + s.integer(offset); + s.integer(bitCount); +} + +auto SDD1::Decompressor::GCD::serialize(serializer& s) -> void { +} + +auto SDD1::Decompressor::BG::serialize(serializer& s) -> void { + s.integer(mpsCount); + s.integer(lpsIndex); +} + +auto SDD1::Decompressor::PEM::serialize(serializer& s) -> void { + for(auto& info : contextInfo) { + s.integer(info.status); + s.integer(info.mps); + } +} + +auto SDD1::Decompressor::CM::serialize(serializer& s) -> void { + s.integer(bitplanesInfo); + s.integer(contextBitsInfo); + s.integer(bitNumber); + s.integer(currentBitplane); + s.array(previousBitplaneBits); +} + +auto SDD1::Decompressor::OL::serialize(serializer& s) -> void { + s.integer(bitplanesInfo); + s.integer(r0); + s.integer(r1); + s.integer(r2); +} diff --git a/sfc/coprocessor/sharprtc/memory.cpp b/sfc/coprocessor/sharprtc/memory.cpp new file mode 100644 index 0000000..3803f1e --- /dev/null +++ b/sfc/coprocessor/sharprtc/memory.cpp @@ -0,0 +1,67 @@ +auto SharpRTC::rtcRead(uint4 addr) -> uint4 { + switch(addr) { + case 0: return second % 10; + case 1: return second / 10; + case 2: return minute % 10; + case 3: return minute / 10; + case 4: return hour % 10; + case 5: return hour / 10; + case 6: return day % 10; + case 7: return day / 10; + case 8: return month; + case 9: return year % 10; + case 10: return year / 10 % 10; + case 11: return year / 100; + case 12: return weekday; + default: return 0; + } +} + +auto SharpRTC::rtcWrite(uint4 addr, uint4 data) -> void { + switch(addr) { + case 0: second = second / 10 * 10 + data; break; + case 1: second = data * 10 + second % 10; break; + case 2: minute = minute / 10 * 10 + data; break; + case 3: minute = data * 10 + minute % 10; break; + case 4: hour = hour / 10 * 10 + data; break; + case 5: hour = data * 10 + hour % 10; break; + case 6: day = day / 10 * 10 + data; break; + case 7: day = data * 10 + day % 10; break; + case 8: month = data; break; + case 9: year = year / 10 * 10 + data; break; + case 10: year = year / 100 * 100 + data * 10 + year % 10; break; + case 11: year = data * 100 + year % 100; break; + case 12: weekday = data; break; + } +} + +auto SharpRTC::load(const uint8* data) -> void { + for(auto byte : range(8)) { + rtcWrite(byte * 2 + 0, data[byte] >> 0); + rtcWrite(byte * 2 + 1, data[byte] >> 4); + } + + uint64 timestamp = 0; + for(auto byte : range(8)) { + timestamp |= data[8 + byte] << (byte * 8); + } + + uint64 diff = (uint64)time(0) - timestamp; + while(diff >= 60 * 60 * 24) { tickDay(); diff -= 60 * 60 * 24; } + while(diff >= 60 * 60) { tickHour(); diff -= 60 * 60; } + while(diff >= 60) { tickMinute(); diff -= 60; } + while(diff--) tickSecond(); +} + +auto SharpRTC::save(uint8* data) -> void { + for(auto byte : range(8)) { + data[byte] = rtcRead(byte * 2 + 0) << 0; + data[byte] |= rtcRead(byte * 2 + 1) << 4; + } + + uint64 timestamp = (uint64)time(nullptr); + for(auto byte : range(8)) { + data[8 + byte] = timestamp; + timestamp >>= 8; + } +} diff --git a/sfc/coprocessor/sharprtc/serialization.cpp b/sfc/coprocessor/sharprtc/serialization.cpp new file mode 100644 index 0000000..d4666a1 --- /dev/null +++ b/sfc/coprocessor/sharprtc/serialization.cpp @@ -0,0 +1,14 @@ +auto SharpRTC::serialize(serializer& s) -> void { + Thread::serialize(s); + + s.integer((uint&)state); + s.integer(index); + + s.integer(second); + s.integer(minute); + s.integer(hour); + s.integer(day); + s.integer(month); + s.integer(year); + s.integer(weekday); +} diff --git a/sfc/coprocessor/sharprtc/sharprtc.cpp b/sfc/coprocessor/sharprtc/sharprtc.cpp new file mode 100644 index 0000000..7078265 --- /dev/null +++ b/sfc/coprocessor/sharprtc/sharprtc.cpp @@ -0,0 +1,134 @@ +#include + +namespace SuperFamicom { + +#include "memory.cpp" +#include "time.cpp" +#include "serialization.cpp" +SharpRTC sharprtc; + +auto SharpRTC::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto SharpRTC::Enter() -> void { + while(true) { + scheduler.synchronize(); + sharprtc.main(); + } +} + +auto SharpRTC::main() -> void { + tickSecond(); + + step(1); + synchronizeCPU(); +} + +auto SharpRTC::step(uint clocks) -> void { + clock += clocks * (uint64_t)cpu.frequency; +} + +auto SharpRTC::initialize() -> void { + second = 0; + minute = 0; + hour = 0; + day = 0; + month = 0; + year = 0; + weekday = 0; +} + +auto SharpRTC::power() -> void { + create(SharpRTC::Enter, 1); + + state = State::Read; + index = -1; +} + +auto SharpRTC::synchronize(uint64 timestamp) -> void { + time_t systime = timestamp; + tm* timeinfo = localtime(&systime); + + second = min(59, timeinfo->tm_sec); + minute = timeinfo->tm_min; + hour = timeinfo->tm_hour; + day = timeinfo->tm_mday; + month = 1 + timeinfo->tm_mon; + year = 900 + timeinfo->tm_year; + weekday = timeinfo->tm_wday; +} + +auto SharpRTC::read(uint addr, uint8 data) -> uint8 { + addr &= 1; + + if(addr == 0) { + if(state != State::Read) return 0; + + if(index < 0) { + index++; + return 15; + } else if(index > 12) { + index = -1; + return 15; + } else { + return rtcRead(index++); + } + } + + return data; +} + +auto SharpRTC::write(uint addr, uint8 data) -> void { + addr &= 1, data &= 15; + + if(addr == 1) { + if(data == 0x0d) { + state = State::Read; + index = -1; + return; + } + + if(data == 0x0e) { + state = State::Command; + return; + } + + if(data == 0x0f) return; //unknown behavior + + if(state == State::Command) { + if(data == 0) { + state = State::Write; + index = 0; + } else if(data == 4) { + state = State::Ready; + index = -1; + //reset time + second = 0; + minute = 0; + hour = 0; + day = 0; + month = 0; + year = 0; + weekday = 0; + } else { + //unknown behavior + state = State::Ready; + } + return; + } + + if(state == State::Write) { + if(index >= 0 && index < 12) { + rtcWrite(index++, data); + if(index == 12) { + //day of week is automatically calculated and written + weekday = calculateWeekday(1000 + year, month, day); + } + } + return; + } + } +} + +} diff --git a/sfc/coprocessor/sharprtc/sharprtc.hpp b/sfc/coprocessor/sharprtc/sharprtc.hpp new file mode 100644 index 0000000..9ce97b7 --- /dev/null +++ b/sfc/coprocessor/sharprtc/sharprtc.hpp @@ -0,0 +1,46 @@ +struct SharpRTC : Thread { + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + + auto initialize() -> void; + auto power() -> void; + auto synchronize(uint64 timestamp) -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; + + enum class State : uint { Ready, Command, Read, Write } state; + int index; + + uint second; + uint minute; + uint hour; + uint day; + uint month; + uint year; + uint weekday; + + //memory.cpp + auto rtcRead(uint4 addr) -> uint4; + auto rtcWrite(uint4 addr, uint4 data) -> void; + + auto load(const uint8* data) -> void; + auto save(uint8* data) -> void; + + //time.cpp + static const uint daysInMonth[12]; + auto tickSecond() -> void; + auto tickMinute() -> void; + auto tickHour() -> void; + auto tickDay() -> void; + auto tickMonth() -> void; + auto tickYear() -> void; + + auto calculateWeekday(uint year, uint month, uint day) -> uint; +}; + +extern SharpRTC sharprtc; diff --git a/sfc/coprocessor/sharprtc/time.cpp b/sfc/coprocessor/sharprtc/time.cpp new file mode 100644 index 0000000..be7355d --- /dev/null +++ b/sfc/coprocessor/sharprtc/time.cpp @@ -0,0 +1,83 @@ +const uint SharpRTC::daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +auto SharpRTC::tickSecond() -> void { + if(++second < 60) return; + second = 0; + tickMinute(); +} + +auto SharpRTC::tickMinute() -> void { + if(++minute < 60) return; + minute = 0; + tickHour(); +} + +auto SharpRTC::tickHour() -> void { + if(++hour < 24) return; + hour = 0; + tickDay(); +} + +auto SharpRTC::tickDay() -> void { + uint days = daysInMonth[(month - 1) % 12]; + + //add one day in February for leap years + if(month == 2) { + if(year % 400 == 0) days++; + else if(year % 100 == 0); + else if(year % 4 == 0) days++; + } + + if(day++ < days) return; + day = 1; + tickMonth(); +} + +auto SharpRTC::tickMonth() -> void { + if(month++ < 12) return; + month = 1; + tickYear(); +} + +auto SharpRTC::tickYear() -> void { + year++; + year = (uint12)year; +} + +//returns day of week for specified date +//eg 0 = Sunday, 1 = Monday, ... 6 = Saturday +//usage: calculate_weekday(2008, 1, 1) returns weekday of January 1st, 2008 +auto SharpRTC::calculateWeekday(uint year, uint month, uint day) -> uint { + uint y = 1000, m = 1; //SharpRTC epoch is 1000-01-01 + uint sum = 0; //number of days passed since epoch + + year = max(1000, 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 += 365 + leapyear; + y++; + } + + while(m < month) { + uint days = daysInMonth[(m - 1) % 12]; + bool leapyearmonth = false; + if(days == 28) { + if(y % 4 == 0) { + leapyearmonth = true; + if(y % 100 == 0 && y % 400 != 0) leapyearmonth = false; + } + } + sum += days + leapyearmonth; + m++; + } + + sum += day - 1; + return (sum + 3) % 7; //1000-01-01 was a Wednesday +} diff --git a/sfc/coprocessor/spc7110/alu.cpp b/sfc/coprocessor/spc7110/alu.cpp new file mode 100644 index 0000000..6b71dbc --- /dev/null +++ b/sfc/coprocessor/spc7110/alu.cpp @@ -0,0 +1,83 @@ +auto SPC7110::aluMultiply() -> void { + addClocks(30); + + if(r482e & 1) { + //signed 16-bit x 16-bit multiplication + int16 r0 = (int16)(r4824 | r4825 << 8); + int16 r1 = (int16)(r4820 | r4821 << 8); + + int 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); + + uint result = r0 * r1; + r4828 = result; + r4829 = result >> 8; + r482a = result >> 16; + r482b = result >> 24; + } + + r482f &= 0x7f; +} + +auto SPC7110::aluDivide() -> void { + addClocks(40); + + 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; + } + + 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; + } + + r4828 = quotient; + r4829 = quotient >> 8; + r482a = quotient >> 16; + r482b = quotient >> 24; + + r482c = remainder; + r482d = remainder >> 8; + } + + r482f &= 0x7f; +} diff --git a/sfc/coprocessor/spc7110/data.cpp b/sfc/coprocessor/spc7110/data.cpp new file mode 100644 index 0000000..b10c0f1 --- /dev/null +++ b/sfc/coprocessor/spc7110/data.cpp @@ -0,0 +1,58 @@ +auto SPC7110::dataromRead(uint addr) -> uint8 { + uint size = 1 << (r4834 & 3); //size in MB + uint mask = 0x100000 * size - 1; + uint offset = addr & mask; + if((r4834 & 3) != 3 && (addr & 0x400000)) return 0x00; + return drom.read(Bus::mirror(offset, drom.size())); +} + +auto SPC7110::dataOffset() -> uint { return r4811 | r4812 << 8 | r4813 << 16; } +auto SPC7110::dataAdjust() -> uint { return r4814 | r4815 << 8; } +auto SPC7110::dataStride() -> uint { return r4816 | r4817 << 8; } +auto SPC7110::setDataOffset(uint addr) -> void { r4811 = addr; r4812 = addr >> 8; r4813 = addr >> 16; } +auto SPC7110::setDataAdjust(uint addr) -> void { r4814 = addr; r4815 = addr >> 8; } + +auto SPC7110::dataPortRead() -> void { + uint offset = dataOffset(); + uint adjust = r4818 & 2 ? dataAdjust() : 0; + if(r4818 & 8) adjust = (int16)adjust; + r4810 = dataromRead(offset + adjust); +} + +auto SPC7110::dataPortIncrement4810() -> void { + uint offset = dataOffset(); + uint stride = r4818 & 1 ? dataStride() : 1; + uint adjust = dataAdjust(); + if(r4818 & 4) stride = (int16)stride; + if(r4818 & 8) adjust = (int16)adjust; + if((r4818 & 16) == 0) setDataOffset(offset + stride); + if((r4818 & 16) != 0) setDataAdjust(adjust + stride); + dataPortRead(); +} + +auto SPC7110::dataPortIncrement4814() -> void { + if(r4818 >> 5 != 1) return; + uint offset = dataOffset(); + uint adjust = dataAdjust(); + if(r4818 & 8) adjust = (int16)adjust; + setDataOffset(offset + adjust); + dataPortRead(); +} + +auto SPC7110::dataPortIncrement4815() -> void { + if(r4818 >> 5 != 2) return; + uint offset = dataOffset(); + uint adjust = dataAdjust(); + if(r4818 & 8) adjust = (int16)adjust; + setDataOffset(offset + adjust); + dataPortRead(); +} + +auto SPC7110::dataPortIncrement481a() -> void { + if(r4818 >> 5 != 3) return; + uint offset = dataOffset(); + uint adjust = dataAdjust(); + if(r4818 & 8) adjust = (int16)adjust; + setDataOffset(offset + adjust); + dataPortRead(); +} diff --git a/sfc/coprocessor/spc7110/dcu.cpp b/sfc/coprocessor/spc7110/dcu.cpp new file mode 100644 index 0000000..b91f2b6 --- /dev/null +++ b/sfc/coprocessor/spc7110/dcu.cpp @@ -0,0 +1,57 @@ +#include "decompressor.cpp" + +auto SPC7110::dcuLoadAddress() -> void { + uint table = r4801 | r4802 << 8 | r4803 << 16; + uint index = r4804 << 2; + + uint address = table + index; + dcuMode = dataromRead(address + 0); + dcuAddress = dataromRead(address + 1) << 16; + dcuAddress |= dataromRead(address + 2) << 8; + dcuAddress |= dataromRead(address + 3) << 0; +} + +auto SPC7110::dcuBeginTransfer() -> void { + if(dcuMode == 3) return; //invalid mode + + addClocks(20); + decompressor->initialize(dcuMode, dcuAddress); + decompressor->decode(); + + uint seek = r480b & 2 ? r4805 | r4806 << 8 : 0; + while(seek--) decompressor->decode(); + + r480c |= 0x80; + dcuOffset = 0; +} + +auto SPC7110::dcuRead() -> uint8 { + if((r480c & 0x80) == 0) return 0x00; + + if(dcuOffset == 0) { + for(auto row : range(8)) { + switch(decompressor->bpp) { + case 1: + dcuTile[row] = decompressor->result; + break; + case 2: + dcuTile[row * 2 + 0] = decompressor->result >> 0; + dcuTile[row * 2 + 1] = decompressor->result >> 8; + break; + case 4: + dcuTile[row * 2 + 0] = decompressor->result >> 0; + dcuTile[row * 2 + 1] = decompressor->result >> 8; + dcuTile[row * 2 + 16] = decompressor->result >> 16; + dcuTile[row * 2 + 17] = decompressor->result >> 24; + break; + } + + uint seek = r480b & 1 ? r4807 : (uint8)1; + while(seek--) decompressor->decode(); + } + } + + uint8 data = dcuTile[dcuOffset++]; + dcuOffset &= 8 * decompressor->bpp - 1; + return data; +} diff --git a/sfc/coprocessor/spc7110/decompressor.cpp b/sfc/coprocessor/spc7110/decompressor.cpp new file mode 100644 index 0000000..3ca163c --- /dev/null +++ b/sfc/coprocessor/spc7110/decompressor.cpp @@ -0,0 +1,190 @@ +//SPC7110 decompressor +//original implementation: neviksti +//optimized implementation: talarubi + +struct Decompressor { + SPC7110& spc7110; + + Decompressor(SPC7110& spc7110) : spc7110(spc7110) {} + + auto read() -> uint8 { + return spc7110.dataromRead(offset++); + } + + //inverse morton code transform: unpack big-endian packed pixels + //returns odd bits in lower half; even bits in upper half + auto deinterleave(uint64 data, uint bits) -> uint32 { + data = data & (1ull << bits) - 1; + data = 0x5555555555555555ull & (data << bits | data >> 1); + data = 0x3333333333333333ull & (data | data >> 1); + data = 0x0f0f0f0f0f0f0f0full & (data | data >> 2); + data = 0x00ff00ff00ff00ffull & (data | data >> 4); + data = 0x0000ffff0000ffffull & (data | data >> 8); + return data | data >> 16; + } + + //extract a nibble and move it to the low four bits + auto moveToFront(uint64 list, uint nibble) -> uint64 { + for(uint64 n = 0, mask = ~15; n < 64; n += 4, mask <<= 4) { + if((list >> n & 15) != nibble) continue; + return list = (list & mask) + (list << 4 & ~mask) + nibble; + } + return list; + } + + auto initialize(uint mode, uint origin) -> void { + for(auto& root : context) for(auto& node : root) node = {0, 0}; + bpp = 1 << mode; + offset = origin; + bits = 8; + range = Max + 1; + input = read(); + input = input << 8 | read(); + output = 0; + pixels = 0; + colormap = 0xfedcba9876543210ull; + } + + auto decode() -> void { + for(uint pixel = 0; pixel < 8; pixel++) { + uint64 map = colormap; + uint diff = 0; + + if(bpp > 1) { + uint pa = (bpp == 2 ? pixels >> 2 & 3 : pixels >> 0 & 15); + uint pb = (bpp == 2 ? pixels >> 14 & 3 : pixels >> 28 & 15); + uint pc = (bpp == 2 ? pixels >> 16 & 3 : pixels >> 32 & 15); + + if(pa != pb || pb != pc) { + uint match = pa ^ pb ^ pc; + diff = 4; //no match; all pixels differ + if((match ^ pc) == 0) diff = 3; //a == b; pixel c differs + if((match ^ pb) == 0) diff = 2; //c == a; pixel b differs + if((match ^ pa) == 0) diff = 1; //b == c; pixel a differs + } + + colormap = moveToFront(colormap, pa); + + map = moveToFront(map, pc); + map = moveToFront(map, pb); + map = moveToFront(map, pa); + } + + for(uint plane = 0; plane < bpp; plane++) { + uint bit = bpp > 1 ? 1 << plane : 1 << (pixel & 3); + uint history = bit - 1 & output; + uint set = 0; + + if(bpp == 1) set = pixel >= 4; + if(bpp == 2) set = diff; + if(plane >= 2 && history <= 1) set = diff; + + auto& ctx = context[set][bit + history - 1]; + auto& model = evolution[ctx.prediction]; + uint8 lps_offset = range - model.probability; + bool symbol = input >= (lps_offset << 8); //test only the MSB + + output = output << 1 | (symbol ^ ctx.swap); + + if(symbol == MPS) { //[0 ... range-p] + range = lps_offset; //range = range-p + } else { //[range-p+1 ... range] + range -= lps_offset; //range = p-1, with p < 0.75 + input -= lps_offset << 8; //therefore, always rescale + } + + while(range <= Max / 2) { //scale back into [0.75 ... 1.5] + ctx.prediction = model.next[symbol]; + + range <<= 1; + input <<= 1; + + if(--bits == 0) { + bits = 8; + input += read(); + } + } + + if(symbol == LPS && model.probability > Half) ctx.swap ^= 1; + } + + uint index = output & (1 << bpp) - 1; + if(bpp == 1) index ^= pixels >> 15 & 1; + + pixels = pixels << bpp | (map >> 4 * index & 15); + } + + if(bpp == 1) result = pixels; + if(bpp == 2) result = deinterleave(pixels, 16); + if(bpp == 4) result = deinterleave(deinterleave(pixels, 32), 32); + } + + auto serialize(serializer& s) -> void { + for(auto& root : context) { + for(auto& node : root) { + s.integer(node.prediction); + s.integer(node.swap); + } + } + + s.integer(bpp); + s.integer(offset); + s.integer(bits); + s.integer(range); + s.integer(input); + s.integer(output); + s.integer(pixels); + s.integer(colormap); + s.integer(result); + } + + enum : uint { MPS = 0, LPS = 1 }; + enum : uint { One = 0xaa, Half = 0x55, Max = 0xff }; + + struct ModelState { + uint8 probability; //of the more probable symbol (MPS) + uint8 next[2]; //next state after output {MPS, LPS} + }; + static ModelState evolution[53]; + + struct Context { + uint8 prediction; //current model state + uint8 swap; //if 1, exchange the role of MPS and LPS + } context[5][15]; //not all 75 contexts exists; this simplifies the code + + uint bpp; //bits per pixel (1bpp = 1; 2bpp = 2; 4bpp = 4) + uint offset; //SPC7110 data ROM read offset + uint bits; //bits remaining in input + uint16 range; //arithmetic range: technically 8-bits, but Max+1 = 256 + uint16 input; //input data from SPC7110 data ROM + uint8 output; + uint64 pixels; + uint64 colormap; //most recently used list + uint32 result; //decompressed word after calling decode() +}; + +Decompressor::ModelState Decompressor::evolution[53] = { + {0x5a, { 1, 1}}, {0x25, { 2, 6}}, {0x11, { 3, 8}}, + {0x08, { 4,10}}, {0x03, { 5,12}}, {0x01, { 5,15}}, + + {0x5a, { 7, 7}}, {0x3f, { 8,19}}, {0x2c, { 9,21}}, + {0x20, {10,22}}, {0x17, {11,23}}, {0x11, {12,25}}, + {0x0c, {13,26}}, {0x09, {14,28}}, {0x07, {15,29}}, + {0x05, {16,31}}, {0x04, {17,32}}, {0x03, {18,34}}, + {0x02, { 5,35}}, + + {0x5a, {20,20}}, {0x48, {21,39}}, {0x3a, {22,40}}, + {0x2e, {23,42}}, {0x26, {24,44}}, {0x1f, {25,45}}, + {0x19, {26,46}}, {0x15, {27,25}}, {0x11, {28,26}}, + {0x0e, {29,26}}, {0x0b, {30,27}}, {0x09, {31,28}}, + {0x08, {32,29}}, {0x07, {33,30}}, {0x05, {34,31}}, + {0x04, {35,33}}, {0x04, {36,33}}, {0x03, {37,34}}, + {0x02, {38,35}}, {0x02, { 5,36}}, + + {0x58, {40,39}}, {0x4d, {41,47}}, {0x43, {42,48}}, + {0x3b, {43,49}}, {0x34, {44,50}}, {0x2e, {45,51}}, + {0x29, {46,44}}, {0x25, {24,45}}, + + {0x56, {48,47}}, {0x4f, {49,47}}, {0x47, {50,48}}, + {0x41, {51,49}}, {0x3c, {52,50}}, {0x37, {43,51}}, +}; diff --git a/sfc/coprocessor/spc7110/serialization.cpp b/sfc/coprocessor/spc7110/serialization.cpp new file mode 100644 index 0000000..5860be4 --- /dev/null +++ b/sfc/coprocessor/spc7110/serialization.cpp @@ -0,0 +1,60 @@ +auto SPC7110::serialize(serializer& s) -> void { + Thread::serialize(s); + s.array(ram.data(), ram.size()); + + s.integer(r4801); + s.integer(r4802); + s.integer(r4803); + s.integer(r4804); + s.integer(r4805); + s.integer(r4806); + s.integer(r4807); + s.integer(r4809); + s.integer(r480a); + s.integer(r480b); + s.integer(r480c); + + s.integer(dcuPending); + s.integer(dcuMode); + s.integer(dcuAddress); + s.integer(dcuOffset); + s.array(dcuTile); + decompressor->serialize(s); + + s.integer(r4810); + 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(r481a); + + 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(mulPending); + s.integer(divPending); + + s.integer(r4830); + s.integer(r4831); + s.integer(r4832); + s.integer(r4833); + s.integer(r4834); +} diff --git a/sfc/coprocessor/spc7110/spc7110.cpp b/sfc/coprocessor/spc7110/spc7110.cpp new file mode 100644 index 0000000..a298124 --- /dev/null +++ b/sfc/coprocessor/spc7110/spc7110.cpp @@ -0,0 +1,316 @@ +#include + +namespace SuperFamicom { + +#include "dcu.cpp" +#include "data.cpp" +#include "alu.cpp" +#include "serialization.cpp" +SPC7110 spc7110; + +SPC7110::SPC7110() { + decompressor = new Decompressor(*this); +} + +SPC7110::~SPC7110() { + delete decompressor; +} + +auto SPC7110::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto SPC7110::Enter() -> void { + while(true) { + scheduler.synchronize(); + spc7110.main(); + } +} + +auto SPC7110::main() -> void { + if(dcuPending) { dcuPending = 0; dcuBeginTransfer(); } + if(mulPending) { mulPending = 0; aluMultiply(); } + if(divPending) { divPending = 0; aluDivide(); } + addClocks(1); +} + +auto SPC7110::step(uint clocks) -> void { + clock += clocks * (uint64_t)cpu.frequency; +} + +auto SPC7110::addClocks(uint clocks) -> void { + step(clocks); + synchronizeCPU(); +} + +auto SPC7110::unload() -> void { + prom.reset(); + drom.reset(); + ram.reset(); +} + +auto SPC7110::power() -> void { + create(SPC7110::Enter, 21'477'272); + + r4801 = 0x00; + r4802 = 0x00; + r4803 = 0x00; + r4804 = 0x00; + r4805 = 0x00; + r4806 = 0x00; + r4807 = 0x00; + r4809 = 0x00; + r480a = 0x00; + r480b = 0x00; + r480c = 0x00; + + dcuPending = 0; + dcuMode = 0; + dcuAddress = 0; + + r4810 = 0x00; + r4811 = 0x00; + r4812 = 0x00; + r4813 = 0x00; + r4814 = 0x00; + r4815 = 0x00; + r4816 = 0x00; + r4817 = 0x00; + r4818 = 0x00; + r481a = 0x00; + + 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; + + mulPending = 0; + divPending = 0; + + r4830 = 0x00; + r4831 = 0x00; + r4832 = 0x01; + r4833 = 0x02; + r4834 = 0x00; +} + +auto SPC7110::read(uint addr, uint8 data) -> uint8 { + cpu.synchronizeCoprocessors(); + if((addr & 0xff0000) == 0x500000) addr = 0x4800; //$50:0000-ffff == $4800 + if((addr & 0xff0000) == 0x580000) addr = 0x4808; //$58:0000-ffff == $4808 + addr = 0x4800 | (addr & 0x3f); //$00-3f,80-bf:4800-483f + + switch(addr) { + //================== + //decompression unit + //================== + case 0x4800: { + uint16 counter = r4809 | r480a << 8; + counter--; + r4809 = counter >> 0; + r480a = counter >> 8; + return dcuRead(); + } + 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 0x00; + case 0x4809: return r4809; + case 0x480a: return r480a; + case 0x480b: return r480b; + case 0x480c: return r480c; + + //============== + //data port unit + //============== + case 0x4810: { + data = r4810; + dataPortIncrement4810(); + 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: { + dataPortIncrement481a(); + return 0x00; + } + + //===================== + //arithmetic logic 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: return r482f; + + //=================== + //memory control unit + //=================== + case 0x4830: return r4830; + case 0x4831: return r4831; + case 0x4832: return r4832; + case 0x4833: return r4833; + case 0x4834: return r4834; + } + + return data; +} + +auto SPC7110::write(uint addr, uint8 data) -> void { + cpu.synchronizeCoprocessors(); + if((addr & 0xff0000) == 0x500000) addr = 0x4800; //$50:0000-ffff == $4800 + if((addr & 0xff0000) == 0x580000) addr = 0x4808; //$58:0000-ffff == $4808 + addr = 0x4800 | (addr & 0x3f); //$00-3f,80-bf:4800-483f + + switch(addr) { + //================== + //decompression unit + //================== + case 0x4801: r4801 = data; break; + case 0x4802: r4802 = data; break; + case 0x4803: r4803 = data; break; + case 0x4804: r4804 = data; dcuLoadAddress(); break; + case 0x4805: r4805 = data; break; + case 0x4806: r4806 = data; r480c &= 0x7f; dcuPending = 1; break; + case 0x4807: r4807 = data; break; + case 0x4808: break; + case 0x4809: r4809 = data; break; + case 0x480a: r480a = data; break; + case 0x480b: r480b = data & 0x03; break; + + //============== + //data port unit + //============== + case 0x4811: r4811 = data; break; + case 0x4812: r4812 = data; break; + case 0x4813: r4813 = data; dataPortRead(); break; + case 0x4814: r4814 = data; dataPortIncrement4814(); break; + case 0x4815: r4815 = data; if(r4818 & 2) dataPortRead(); dataPortIncrement4815(); break; + case 0x4816: r4816 = data; break; + case 0x4817: r4817 = data; break; + case 0x4818: r4818 = data & 0x7f; dataPortRead(); break; + + //===================== + //arithmetic logic 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; r482f |= 0x81; mulPending = 1; break; + case 0x4826: r4826 = data; break; + case 0x4827: r4827 = data; r482f |= 0x80; divPending = 1; break; + case 0x482e: r482e = data & 0x01; break; + + //=================== + //memory control unit + //=================== + case 0x4830: r4830 = data & 0x87; break; + case 0x4831: r4831 = data & 0x07; break; + case 0x4832: r4832 = data & 0x07; break; + case 0x4833: r4833 = data & 0x07; break; + case 0x4834: r4834 = data & 0x07; break; + } +} + +//=============== +//SPC7110::MCUROM +//=============== + +//map address=00-3f,80-bf:8000-ffff mask=0x800000 => 00-3f:8000-ffff +//map address=c0-ff:0000-ffff mask=0xc00000 => c0-ff:0000-ffff +auto SPC7110::mcuromRead(uint addr, uint8 data) -> uint8 { + uint mask = (1 << (r4834 & 3)) - 1; //8mbit, 16mbit, 32mbit, 64mbit DROM + + if(addr < 0x100000) { //$00-0f,80-8f:8000-ffff; $c0-cf:0000-ffff + addr &= 0x0fffff; + if(prom.size()) { //8mbit PROM + return prom.read(bus.mirror(0x000000 + addr, prom.size())); + } + addr |= 0x100000 * (r4830 & 7); + return dataromRead(addr); + } + + if(addr < 0x200000) { //$10-1f,90-9f:8000-ffff; $d0-df:0000-ffff + addr &= 0x0fffff; + if(r4834 & 4) { //16mbit PROM + return prom.read(bus.mirror(0x100000 + addr, prom.size())); + } + addr |= 0x100000 * (r4831 & 7); + return dataromRead(addr); + } + + if(addr < 0x300000) { //$20-2f,a0-af:8000-ffff; $e0-ef:0000-ffff + addr &= 0x0fffff; + addr |= 0x100000 * (r4832 & 7); + return dataromRead(addr); + } + + if(addr < 0x400000) { //$30-3f,b0-bf:8000-ffff; $f0-ff:0000-ffff + addr &= 0x0fffff; + addr |= 0x100000 * (r4833 & 7); + return dataromRead(addr); + } + + return data; +} + +auto SPC7110::mcuromWrite(uint addr, uint8 data) -> void { +} + +//=============== +//SPC7110::MCURAM +//=============== + +//map address=00-3f,80-bf:6000-7fff mask=0x80e000 => 00-07:0000-ffff +auto SPC7110::mcuramRead(uint addr, uint8) -> uint8 { + if(r4830 & 0x80) { + addr = bus.mirror(addr, ram.size()); + return ram.read(addr); + } + return 0x00; +} + +auto SPC7110::mcuramWrite(uint addr, uint8 data) -> void { + if(r4830 & 0x80) { + addr = bus.mirror(addr, ram.size()); + ram.write(addr, data); + } +} + +} diff --git a/sfc/coprocessor/spc7110/spc7110.hpp b/sfc/coprocessor/spc7110/spc7110.hpp new file mode 100644 index 0000000..ab8d456 --- /dev/null +++ b/sfc/coprocessor/spc7110/spc7110.hpp @@ -0,0 +1,123 @@ +struct Decompressor; + +struct SPC7110 : Thread { + SPC7110(); + ~SPC7110(); + + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + auto unload() -> void; + auto power() -> void; + + auto addClocks(uint clocks) -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto mcuromRead(uint addr, uint8 data) -> uint8; + auto mcuromWrite(uint addr, uint8 data) -> void; + + auto mcuramRead(uint addr, uint8 data) -> uint8; + auto mcuramWrite(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; + + //dcu.cpp + auto dcuLoadAddress() -> void; + auto dcuBeginTransfer() -> void; + auto dcuRead() -> uint8; + + auto deinterleave1bpp(uint length) -> void; + auto deinterleave2bpp(uint length) -> void; + auto deinterleave4bpp(uint length) -> void; + + //data.cpp + auto dataromRead(uint addr) -> uint8; + + auto dataOffset() -> uint; + auto dataAdjust() -> uint; + auto dataStride() -> uint; + + auto setDataOffset(uint addr) -> void; + auto setDataAdjust(uint addr) -> void; + + auto dataPortRead() -> void; + + auto dataPortIncrement4810() -> void; + auto dataPortIncrement4814() -> void; + auto dataPortIncrement4815() -> void; + auto dataPortIncrement481a() -> void; + + //alu.cpp + auto aluMultiply() -> void; + auto aluDivide() -> void; + + ReadableMemory prom; //program ROM + ReadableMemory drom; //data ROM + WritableMemory ram; + +private: + //decompression unit + uint8 r4801; //compression table B0 + uint8 r4802; //compression table B1 + uint7 r4803; //compression table B2 + uint8 r4804; //compression table index + uint8 r4805; //adjust length B0 + uint8 r4806; //adjust length B1 + uint8 r4807; //stride length + uint8 r4809; //compression counter B0 + uint8 r480a; //compression counter B1 + uint8 r480b; //decompression settings + uint8 r480c; //decompression status + + bool dcuPending; + uint2 dcuMode; + uint23 dcuAddress; + uint dcuOffset; + uint8 dcuTile[32]; + Decompressor* decompressor; + + //data port unit + uint8 r4810; //data port read + seek + uint8 r4811; //data offset B0 + uint8 r4812; //data offset B1 + uint7 r4813; //data offset B2 + uint8 r4814; //data adjust B0 + uint8 r4815; //data adjust B1 + uint8 r4816; //data stride B0 + uint8 r4817; //data stride B1 + uint8 r4818; //data port settings + uint8 r481a; //data port seek + + //arithmetic logic 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 settings + uint8 r482f; //math status + + bool mulPending; + bool divPending; + + //memory control unit + uint8 r4830; //bank 0 mapping + SRAM write enable + uint8 r4831; //bank 1 mapping + uint8 r4832; //bank 2 mapping + uint8 r4833; //bank 3 mapping + uint8 r4834; //bank mapping settings +}; + +extern SPC7110 spc7110; diff --git a/sfc/coprocessor/st0010/data.hpp b/sfc/coprocessor/st0010/data.hpp new file mode 100644 index 0000000..52b251f --- /dev/null +++ b/sfc/coprocessor/st0010/data.hpp @@ -0,0 +1,130 @@ +#ifdef ST0010_CPP + +const int16 ST0010::sin_table[256] = { + 0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2, + 0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, + 0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, + 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, + 0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6, + 0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504, + 0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3, + 0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5, + 0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d, + 0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b, + 0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23, + 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3, + 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, + 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df, + 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b, + 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324, + 0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2, + -0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11, + -0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a, + -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842, + -0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6, + -0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504, + -0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3, + -0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5, + -0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d, + -0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b, + -0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23, + -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3, + -0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3, + -0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de, + -0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b, + -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324 +}; + +const int16 ST0010::mode7_scale[176] = { + 0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3, + 0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b, + 0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8, + 0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6, + 0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5, + 0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d, + 0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c, + 0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e, + 0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063, + 0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a, + 0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052, + 0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c, + 0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047, + 0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042, + 0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e, + 0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a, + 0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037, + 0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034, + 0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031, + 0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f, + 0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d, + 0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b +}; + +const uint8 ST0010::arctan[32][32] = { + { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, + { 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf }, + { 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd }, + { 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8, + 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc }, + { 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5, + 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb }, + { 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 }, + { 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0, + 0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 }, + { 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae, + 0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 }, + { 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac, + 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 }, + { 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa, + 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 }, + { 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 }, + { 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6, + 0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 }, + { 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 }, + { 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 }, + { 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1, + 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf }, + { 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0, + 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae }, + { 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad }, + { 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d, + 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac }, + { 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c, + 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab }, + { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b, + 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa }, + { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a, + 0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 }, + { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99, + 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 }, + { 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 }, + { 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98, + 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 }, + { 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 }, + { 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 }, + { 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 }, + { 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 }, + { 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 }, + { 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 }, + { 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 }, + { 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, + 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 } +}; + +#endif diff --git a/sfc/coprocessor/st0010/opcodes.cpp b/sfc/coprocessor/st0010/opcodes.cpp new file mode 100644 index 0000000..57a5497 --- /dev/null +++ b/sfc/coprocessor/st0010/opcodes.cpp @@ -0,0 +1,301 @@ +#ifdef ST0010_CPP + +int16 ST0010::sin(int16 theta) { + return sin_table[(theta >> 8) & 0xff]; +} + +int16 ST0010::cos(int16 theta) { + return sin_table[((theta + 0x4000) >> 8) & 0xff]; +} + +uint8 ST0010::readb(uint16 addr) { + return ram[addr & 0xfff]; +} + +uint16 ST0010::readw(uint16 addr) { + return (readb(addr + 0) << 0) | + (readb(addr + 1) << 8); +} + +uint32 ST0010::readd(uint16 addr) { + return (readb(addr + 0) << 0) | + (readb(addr + 1) << 8) | + (readb(addr + 2) << 16) | + (readb(addr + 3) << 24); +} + +void ST0010::writeb(uint16 addr, uint8 data) { + ram[addr & 0xfff] = data; +} + +void ST0010::writew(uint16 addr, uint16 data) { + writeb(addr + 0, data >> 0); + writeb(addr + 1, data >> 8); +} + +void ST0010::writed(uint16 addr, uint32 data) { + writeb(addr + 0, data >> 0); + writeb(addr + 1, data >> 8); + writeb(addr + 2, data >> 16); + writeb(addr + 3, data >> 24); +} + +//ST-0010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather +//bsnes port - Copyright (C) 2007 byuu + +void ST0010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) { + if((x0 < 0) && (y0 < 0)) { + x1 = -x0; + y1 = -y0; + quadrant = -0x8000; + } else if(x0 < 0) { + x1 = y0; + y1 = -x0; + quadrant = -0x4000; + } else if(y0 < 0) { + x1 = -y0; + y1 = x0; + quadrant = 0x4000; + } else { + x1 = x0; + y1 = y0; + quadrant = 0x0000; + } + + while((x1 > 0x1f) || (y1 > 0x1f)) { + if(x1 > 1) { x1 >>= 1; } + if(y1 > 1) { y1 >>= 1; } + } + + if(y1 == 0) { quadrant += 0x4000; } + + theta = (arctan[y1][x1] << 8) ^ quadrant; +} + +// + +void ST0010::op_01() { + int16 x0 = readw(0x0000); + int16 y0 = readw(0x0002); + int16 x1, y1, quadrant, theta; + + op_01(x0, y0, x1, y1, quadrant, theta); + + writew(0x0000, x1); + writew(0x0002, y1); + writew(0x0004, quadrant); +//writew(0x0006, y0); //Overload's docs note this write occurs, SNES9x disagrees + writew(0x0010, theta); +} + +void ST0010::op_02() { + int16 positions = readw(0x0024); + uint16 *places = (uint16*)(ram + 0x0040); + uint16 *drivers = (uint16*)(ram + 0x0080); + + bool sorted; + uint16 temp; + if(positions > 1) { + do { + sorted = true; + for(int i = 0; i < positions - 1; i++) { + if(places[i] < places[i + 1]) { + temp = places[i + 1]; + places[i + 1] = places[i]; + places[i] = temp; + + temp = drivers[i + 1]; + drivers[i + 1] = drivers[i]; + drivers[i] = temp; + + sorted = false; + } + } + positions--; + } while(!sorted); + } +} + +void ST0010::op_03() { + int16 x0 = readw(0x0000); + int16 y0 = readw(0x0002); + int16 multiplier = readw(0x0004); + int32 x1, y1; + + x1 = x0 * multiplier << 1; + y1 = y0 * multiplier << 1; + + writed(0x0010, x1); + writed(0x0014, y1); +} + +void ST0010::op_04() { + int16 x = readw(0x0000); + int16 y = readw(0x0002); + int16 square; + //calculate the vector length of (x,y) + square = (int16)sqrt((double)(y * y + x * x)); + + writew(0x0010, square); +} + +void ST0010::op_05() { + int32 dx, dy; + int16 a1, b1, c1; + uint16 o1; + bool wrap = false; + + //target (x,y) coordinates + int16 ypos_max = readw(0x00c0); + int16 xpos_max = readw(0x00c2); + + //current coordinates and direction + int32 ypos = readd(0x00c4); + int32 xpos = readd(0x00c8); + uint16 rot = readw(0x00cc); + + //physics + uint16 speed = readw(0x00d4); + uint16 accel = readw(0x00d6); + uint16 speed_max = readw(0x00d8); + + //special condition acknowledgement + int16 system = readw(0x00da); + int16 flags = readw(0x00dc); + + //new target coordinates + int16 ypos_new = readw(0x00de); + int16 xpos_new = readw(0x00e0); + + //mask upper bit + xpos_new &= 0x7fff; + + //get the current distance + dx = xpos_max - (xpos >> 16); + dy = ypos_max - (ypos >> 16); + + //quirk: clear and move in9 + writew(0x00d2, 0xffff); + writew(0x00da, 0x0000); + + //grab the target angle + op_01(dy, dx, a1, b1, c1, (int16&)o1); + + //check for wrapping + if(abs(o1 - rot) > 0x8000) { + o1 += 0x8000; + rot += 0x8000; + wrap = true; + } + + uint16 old_speed = speed; + + //special case + if(abs(o1 - rot) == 0x8000) { + speed = 0x100; + } + + //slow down for sharp curves + else if(abs(o1 - rot) >= 0x1000) { + uint32 slow = abs(o1 - rot); + slow >>= 4; //scaling + speed -= slow; + } + + //otherwise accelerate + else { + speed += accel; + if(speed > speed_max) { + speed = speed_max; //clip speed + } + } + + //prevent negative/positive overflow + if(abs(old_speed - speed) > 0x8000) { + if(old_speed < speed) { speed = 0; } + else speed = 0xff00; + } + + //adjust direction by so many degrees + //be careful of negative adjustments + if((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) { + if(o1 < rot) { rot -= 0x280; } + else if(o1 > rot) { rot += 0x280; } + } + + //turn off wrapping + if(wrap) { rot -= 0x8000; } + + //now check the distances (store for later) + dx = (xpos_max << 16) - xpos; + dy = (ypos_max << 16) - ypos; + dx >>= 16; + dy >>= 16; + + //if we're in so many units of the target, signal it + if((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) { + //announce our new destination and flag it + xpos_max = xpos_new & 0x7fff; + ypos_max = ypos_new; + flags |= 0x08; + } + + //update position + xpos -= (cos(rot) * 0x400 >> 15) * (speed >> 8) << 1; + ypos -= (sin(rot) * 0x400 >> 15) * (speed >> 8) << 1; + + //quirk: mask upper byte + xpos &= 0x1fffffff; + ypos &= 0x1fffffff; + + writew(0x00c0, ypos_max); + writew(0x00c2, xpos_max); + writed(0x00c4, ypos); + writed(0x00c8, xpos); + writew(0x00cc, rot); + writew(0x00d4, speed); + writew(0x00dc, flags); +} + +void ST0010::op_06() { + int16 multiplicand = readw(0x0000); + int16 multiplier = readw(0x0002); + int32 product; + + product = multiplicand * multiplier << 1; + + writed(0x0010, product); +} + +void ST0010::op_07() { + int16 theta = readw(0x0000); + + int16 data; + for(int i = 0, offset = 0; i < 176; i++) { + data = mode7_scale[i] * cos(theta) >> 15; + writew(0x00f0 + offset, data); + writew(0x0510 + offset, data); + + data = mode7_scale[i] * sin(theta) >> 15; + writew(0x0250 + offset, data); + if(data) { data = ~data; } + writew(0x03b0 + offset, data); + + offset += 2; + } +} + +void ST0010::op_08() { + int16 x0 = readw(0x0000); + int16 y0 = readw(0x0002); + int16 theta = readw(0x0004); + int16 x1, y1; + + x1 = (y0 * sin(theta) >> 15) + (x0 * cos(theta) >> 15); + y1 = (y0 * cos(theta) >> 15) - (x0 * sin(theta) >> 15); + + writew(0x0010, x1); + writew(0x0012, y1); +} + +#endif diff --git a/sfc/coprocessor/st0010/serialization.cpp b/sfc/coprocessor/st0010/serialization.cpp new file mode 100644 index 0000000..25bf478 --- /dev/null +++ b/sfc/coprocessor/st0010/serialization.cpp @@ -0,0 +1,3 @@ +auto ST0010::serialize(serializer& s) -> void { + s.array(ram); +} diff --git a/sfc/coprocessor/st0010/st0010.cpp b/sfc/coprocessor/st0010/st0010.cpp new file mode 100644 index 0000000..55eb815 --- /dev/null +++ b/sfc/coprocessor/st0010/st0010.cpp @@ -0,0 +1,39 @@ +#include + +namespace SuperFamicom { + +#define ST0010_CPP +#include "data.hpp" +#include "opcodes.cpp" + +ST0010 st0010; +#include "serialization.cpp" + +auto ST0010::power() -> void { + memset(ram, 0x00, sizeof ram); +} + +auto ST0010::read(uint addr, uint8 data) -> uint8 { + return readb(addr); +} + +auto ST0010::write(uint addr, uint8 data) -> void { + writeb(addr, data); + + if((addr & 0xfff) == 0x0021 && (data & 0x80)) { + switch(ram[0x0020]) { + case 0x01: op_01(); break; + case 0x02: op_02(); break; + case 0x03: op_03(); break; + case 0x04: op_04(); break; + case 0x05: op_05(); break; + case 0x06: op_06(); break; + case 0x07: op_07(); break; + case 0x08: op_08(); break; + } + + ram[0x0021] &= ~0x80; + } +} + +} diff --git a/sfc/coprocessor/st0010/st0010.hpp b/sfc/coprocessor/st0010/st0010.hpp new file mode 100644 index 0000000..8dd2036 --- /dev/null +++ b/sfc/coprocessor/st0010/st0010.hpp @@ -0,0 +1,39 @@ +struct ST0010 { + auto power() -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + + auto serialize(serializer&) -> void; + + uint8 ram[0x1000]; + static const int16 sin_table[256]; + static const int16 mode7_scale[176]; + static const uint8 arctan[32][32]; + + //interfaces to sin table + int16 sin(int16 theta); + int16 cos(int16 theta); + + //interfaces to ram buffer + uint8 readb (uint16 addr); + uint16 readw (uint16 addr); + uint32 readd (uint16 addr); + void writeb(uint16 addr, uint8 data); + void writew(uint16 addr, uint16 data); + void writed(uint16 addr, uint32 data); + + //opcodes + void op_01(); + void op_02(); + void op_03(); + void op_04(); + void op_05(); + void op_06(); + void op_07(); + void op_08(); + + void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta); +}; + +extern ST0010 st0010; diff --git a/sfc/coprocessor/superfx/bus.cpp b/sfc/coprocessor/superfx/bus.cpp new file mode 100644 index 0000000..416383b --- /dev/null +++ b/sfc/coprocessor/superfx/bus.cpp @@ -0,0 +1,41 @@ +//ROM / RAM access from the S-CPU + +auto SuperFX::CPUROM::data() -> uint8* { + return superfx.rom.data(); +} + +auto SuperFX::CPUROM::size() const -> uint { + return superfx.rom.size(); +} + +auto SuperFX::CPUROM::read(uint addr, uint8 data) -> uint8 { + if(superfx.regs.sfr.g && superfx.regs.scmr.ron) { + static const uint8 vector[16] = { + 0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x0c, 0x01, + }; + return vector[addr & 15]; + } + return superfx.rom.read(addr, data); +} + +auto SuperFX::CPUROM::write(uint addr, uint8 data) -> void { + superfx.rom.write(addr, data); +} + +auto SuperFX::CPURAM::data() -> uint8* { + return superfx.ram.data(); +} + +auto SuperFX::CPURAM::size() const -> uint { + return superfx.ram.size(); +} + +auto SuperFX::CPURAM::read(uint addr, uint8 data) -> uint8 { + if(superfx.regs.sfr.g && superfx.regs.scmr.ran) return data; + return superfx.ram.read(addr, data); +} + +auto SuperFX::CPURAM::write(uint addr, uint8 data) -> void { + superfx.ram.write(addr, data); +} diff --git a/sfc/coprocessor/superfx/core.cpp b/sfc/coprocessor/superfx/core.cpp new file mode 100644 index 0000000..eb44044 --- /dev/null +++ b/sfc/coprocessor/superfx/core.cpp @@ -0,0 +1,103 @@ +auto SuperFX::stop() -> void { + cpu.irq(1); +} + +auto SuperFX::color(uint8 source) -> uint8 { + if(regs.por.highnibble) return (regs.colr & 0xf0) | (source >> 4); + if(regs.por.freezehigh) return (regs.colr & 0xf0) | (source & 0x0f); + return source; +} + +auto SuperFX::plot(uint8 x, uint8 y) -> void { + if(!regs.por.transparent) { + if(regs.scmr.md == 3) { + if(regs.por.freezehigh) { + if((regs.colr & 0x0f) == 0) return; + } else { + if(regs.colr == 0) return; + } + } else { + if((regs.colr & 0x0f) == 0) return; + } + } + + uint8 color = regs.colr; + if(regs.por.dither && regs.scmr.md != 3) { + if((x ^ y) & 1) color >>= 4; + color &= 0x0f; + } + + uint16 offset = (y << 5) + (x >> 3); + if(offset != pixelcache[0].offset) { + flushPixelCache(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) { + flushPixelCache(pixelcache[1]); + pixelcache[1] = pixelcache[0]; + pixelcache[0].bitpend = 0x00; + } +} + +auto SuperFX::rpix(uint8 x, uint8 y) -> uint8 { + flushPixelCache(pixelcache[1]); + flushPixelCache(pixelcache[0]); + + uint 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; + } + uint bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 }; + uint addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2); + uint8 data = 0x00; + x = (x & 7) ^ 7; + + for(uint n : range(bpp)) { + uint byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 }; + step(regs.clsr ? 5 : 6); + data |= ((read(addr + byte) >> x) & 1) << n; + } + + return data; +} + +auto SuperFX::flushPixelCache(PixelCache& cache) -> void { + if(cache.bitpend == 0x00) return; + + uint8 x = cache.offset << 3; + uint8 y = cache.offset >> 5; + + uint 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; + } + uint bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 }; + uint addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2); + + for(uint n : range(bpp)) { + uint byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 }; + uint8 data = 0x00; + for(uint x : range(8)) data |= ((cache.data[x] >> n) & 1) << x; + if(cache.bitpend != 0xff) { + step(regs.clsr ? 5 : 6); + data &= cache.bitpend; + data |= read(addr + byte) & ~cache.bitpend; + } + step(regs.clsr ? 5 : 6); + write(addr + byte, data); + } + + cache.bitpend = 0x00; +} diff --git a/sfc/coprocessor/superfx/io.cpp b/sfc/coprocessor/superfx/io.cpp new file mode 100644 index 0000000..e3808e7 --- /dev/null +++ b/sfc/coprocessor/superfx/io.cpp @@ -0,0 +1,113 @@ +auto SuperFX::readIO(uint addr, uint8) -> uint8 { + cpu.synchronizeCoprocessors(); + addr = 0x3000 | addr & 0x3ff; + + if(addr >= 0x3100 && addr <= 0x32ff) { + return readCache(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.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; +} + +auto SuperFX::writeIO(uint addr, uint8 data) -> void { + cpu.synchronizeCoprocessors(); + addr = 0x3000 | addr & 0x3ff; + + if(addr >= 0x3100 && addr <= 0x32ff) { + return writeCache(addr - 0x3100, data); + } + + if(addr >= 0x3000 && addr <= 0x301f) { + uint 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(n == 14) updateROMBuffer(); + + 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; + flushCache(); + } + } break; + + case 0x3031: { + regs.sfr = (data << 8) | (regs.sfr & 0x00ff); + } break; + + case 0x3033: { + regs.bramr = data & 0x01; + } break; + + case 0x3034: { + regs.pbr = data & 0x7f; + flushCache(); + } break; + + case 0x3037: { + regs.cfgr = data; + } break; + + case 0x3038: { + regs.scbr = data; + } break; + + case 0x3039: { + regs.clsr = data & 0x01; + } break; + + case 0x303a: { + regs.scmr = data; + } break; + } +} diff --git a/sfc/coprocessor/superfx/memory.cpp b/sfc/coprocessor/superfx/memory.cpp new file mode 100644 index 0000000..01a8c82 --- /dev/null +++ b/sfc/coprocessor/superfx/memory.cpp @@ -0,0 +1,100 @@ +auto SuperFX::read(uint addr, uint8 data) -> uint8 { + if((addr & 0xc00000) == 0x000000) { //$00-3f:0000-7fff,:8000-ffff + while(!regs.scmr.ron) { + step(6); + synchronizeCPU(); + if(synchronizing()) break; + } + return rom.read((((addr & 0x3f0000) >> 1) | (addr & 0x7fff)) & romMask); + } + + if((addr & 0xe00000) == 0x400000) { //$40-5f:0000-ffff + while(!regs.scmr.ron) { + step(6); + synchronizeCPU(); + if(synchronizing()) break; + } + return rom.read(addr & romMask); + } + + if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff + while(!regs.scmr.ran) { + step(6); + synchronizeCPU(); + if(synchronizing()) break; + } + return ram.read(addr & ramMask); + } + + return data; +} + +auto SuperFX::write(uint addr, uint8 data) -> void { + if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff + while(!regs.scmr.ran) { + step(6); + synchronizeCPU(); + if(synchronizing()) break; + } + return ram.write(addr & ramMask, data); + } +} + +auto SuperFX::readOpcode(uint16 addr) -> uint8 { + uint16 offset = addr - regs.cbr; + if(offset < 512) { + if(cache.valid[offset >> 4] == false) { + uint dp = offset & 0xfff0; + uint sp = (regs.pbr << 16) + ((regs.cbr + dp) & 0xfff0); + for(uint n : range(16)) { + step(regs.clsr ? 5 : 6); + cache.buffer[dp++] = read(sp++); + } + cache.valid[offset >> 4] = true; + } else { + step(regs.clsr ? 1 : 2); + } + return cache.buffer[offset]; + } + + if(regs.pbr <= 0x5f) { + //$00-5f:0000-ffff ROM + syncROMBuffer(); + step(regs.clsr ? 5 : 6); + return read(regs.pbr << 16 | addr); + } else { + //$60-7f:0000-ffff RAM + syncRAMBuffer(); + step(regs.clsr ? 5 : 6); + return read(regs.pbr << 16 | addr); + } +} + +auto SuperFX::peekpipe() -> uint8 { + uint8 result = regs.pipeline; + regs.pipeline = readOpcode(regs.r[15]); + regs.r[15].modified = false; + return result; +} + +auto SuperFX::pipe() -> uint8 { + uint8 result = regs.pipeline; + regs.pipeline = readOpcode(++regs.r[15]); + regs.r[15].modified = false; + return result; +} + +auto SuperFX::flushCache() -> void { + for(uint n : range(32)) cache.valid[n] = false; +} + +auto SuperFX::readCache(uint16 addr) -> uint8 { + addr = (addr + regs.cbr) & 511; + return cache.buffer[addr]; +} + +auto SuperFX::writeCache(uint16 addr, uint8 data) -> void { + addr = (addr + regs.cbr) & 511; + cache.buffer[addr] = data; + if((addr & 15) == 15) cache.valid[addr >> 4] = true; +} diff --git a/sfc/coprocessor/superfx/serialization.cpp b/sfc/coprocessor/superfx/serialization.cpp new file mode 100644 index 0000000..214f5dd --- /dev/null +++ b/sfc/coprocessor/superfx/serialization.cpp @@ -0,0 +1,6 @@ +auto SuperFX::serialize(serializer& s) -> void { + GSU::serialize(s); + Thread::serialize(s); + + s.array(ram.data(), ram.size()); +} diff --git a/sfc/coprocessor/superfx/superfx.cpp b/sfc/coprocessor/superfx/superfx.cpp new file mode 100644 index 0000000..847f6a0 --- /dev/null +++ b/sfc/coprocessor/superfx/superfx.cpp @@ -0,0 +1,71 @@ +#include +#include + +namespace SuperFamicom { + +#include "bus.cpp" +#include "core.cpp" +#include "memory.cpp" +#include "io.cpp" +#include "timing.cpp" +#include "serialization.cpp" +SuperFX superfx; + +auto SuperFX::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto SuperFX::Enter() -> void { + while(true) { + scheduler.synchronize(); + superfx.main(); + } +} + +auto SuperFX::main() -> void { + if(regs.sfr.g == 0) return step(6); + + instruction(peekpipe()); + + if(regs.r[14].modified) { + regs.r[14].modified = false; + updateROMBuffer(); + } + + if(regs.r[15].modified) { + regs.r[15].modified = false; + } else { + regs.r[15]++; + } +} + +auto SuperFX::unload() -> void { + rom.reset(); + ram.reset(); +} + +auto SuperFX::power() -> void { + double overclock = max(1.0, min(8.0, configuration.hacks.superfx.overclock / 100.0)); + + GSU::power(); + create(SuperFX::Enter, Frequency * overclock); + + romMask = rom.size() - 1; + ramMask = ram.size() - 1; + + for(uint n : range(512)) cache.buffer[n] = 0x00; + for(uint n : range(32)) cache.valid[n] = false; + for(uint n : range(2)) { + pixelcache[n].offset = ~0; + pixelcache[n].bitpend = 0x00; + } + + regs.romcl = 0; + regs.romdr = 0; + + regs.ramcl = 0; + regs.ramar = 0; + regs.ramdr = 0; +} + +} diff --git a/sfc/coprocessor/superfx/superfx.hpp b/sfc/coprocessor/superfx/superfx.hpp new file mode 100644 index 0000000..97df3df --- /dev/null +++ b/sfc/coprocessor/superfx/superfx.hpp @@ -0,0 +1,77 @@ +struct SuperFX : Processor::GSU, Thread { + ReadableMemory rom; + WritableMemory ram; + + inline auto synchronizing() const -> bool { return scheduler.synchronizing(); } + + //superfx.cpp + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto main() -> void; + auto unload() -> void; + auto power() -> void; + + //bus.cpp + struct CPUROM : Memory { + auto data() -> uint8* override; + auto size() const -> uint override; + auto read(uint, uint8) -> uint8 override; + auto write(uint, uint8) -> void override; + }; + + struct CPURAM : Memory { + auto data() -> uint8* override; + auto size() const -> uint override; + auto read(uint, uint8) -> uint8 override; + auto write(uint, uint8) -> void override; + }; + + //core.cpp + auto stop() -> void override; + auto color(uint8 source) -> uint8 override; + auto plot(uint8 x, uint8 y) -> void override; + auto rpix(uint8 x, uint8 y) -> uint8 override; + + auto flushPixelCache(PixelCache& cache) -> void; + + //memory.cpp + auto read(uint addr, uint8 data = 0x00) -> uint8 override; + auto write(uint addr, uint8 data) -> void override; + + auto readOpcode(uint16 addr) -> uint8; + alwaysinline auto peekpipe() -> uint8; + alwaysinline auto pipe() -> uint8 override; + + auto flushCache() -> void override; + auto readCache(uint16 addr) -> uint8; + auto writeCache(uint16 addr, uint8 data) -> void; + + //io.cpp + auto readIO(uint addr, uint8 data) -> uint8; + auto writeIO(uint addr, uint8 data) -> void; + + //timing.cpp + auto step(uint clocks) -> void override; + + auto syncROMBuffer() -> void override; + auto readROMBuffer() -> uint8 override; + auto updateROMBuffer() -> void; + + auto syncRAMBuffer() -> void override; + auto readRAMBuffer(uint16 addr) -> uint8 override; + auto writeRAMBuffer(uint16 addr, uint8 data) -> void override; + + //serialization.cpp + auto serialize(serializer&) -> void; + + uint Frequency; + + CPUROM cpurom; + CPURAM cpuram; + +private: + uint romMask; + uint ramMask; +}; + +extern SuperFX superfx; diff --git a/sfc/coprocessor/superfx/timing.cpp b/sfc/coprocessor/superfx/timing.cpp new file mode 100644 index 0000000..0b4bf65 --- /dev/null +++ b/sfc/coprocessor/superfx/timing.cpp @@ -0,0 +1,49 @@ +auto SuperFX::step(uint clocks) -> void { + if(regs.romcl) { + regs.romcl -= min(clocks, regs.romcl); + if(regs.romcl == 0) { + regs.sfr.r = 0; + regs.romdr = read((regs.rombr << 16) + regs.r[14]); + } + } + + if(regs.ramcl) { + regs.ramcl -= min(clocks, regs.ramcl); + if(regs.ramcl == 0) { + write(0x700000 + (regs.rambr << 16) + regs.ramar, regs.ramdr); + } + } + + clock += clocks * (uint64_t)cpu.frequency; + synchronizeCPU(); +} + +auto SuperFX::syncROMBuffer() -> void { + if(regs.romcl) step(regs.romcl); +} + +auto SuperFX::readROMBuffer() -> uint8 { + syncROMBuffer(); + return regs.romdr; +} + +auto SuperFX::updateROMBuffer() -> void { + regs.sfr.r = 1; + regs.romcl = regs.clsr ? 5 : 6; +} + +auto SuperFX::syncRAMBuffer() -> void { + if(regs.ramcl) step(regs.ramcl); +} + +auto SuperFX::readRAMBuffer(uint16 addr) -> uint8 { + syncRAMBuffer(); + return read(0x700000 + (regs.rambr << 16) + addr); +} + +auto SuperFX::writeRAMBuffer(uint16 addr, uint8 data) -> void { + syncRAMBuffer(); + regs.ramcl = regs.clsr ? 5 : 6; + regs.ramar = addr; + regs.ramdr = data; +} diff --git a/sfc/cpu/cpu.cpp b/sfc/cpu/cpu.cpp new file mode 100644 index 0000000..b6fec16 --- /dev/null +++ b/sfc/cpu/cpu.cpp @@ -0,0 +1,123 @@ +#include + +namespace SuperFamicom { + +CPU cpu; +#include "dma.cpp" +#include "memory.cpp" +#include "io.cpp" +#include "timing.cpp" +#include "irq.cpp" +#include "serialization.cpp" + +auto CPU::synchronizeSMP() -> void { + if(smp.clock < 0) scheduler.resume(smp.thread); +} + +auto CPU::synchronizePPU() -> void { + if(ppu.clock < 0) scheduler.resume(ppu.thread); +} + +auto CPU::synchronizeCoprocessors() -> void { + for(auto coprocessor : coprocessors) { + if(coprocessor->clock < 0) scheduler.resume(coprocessor->thread); + } +} + +auto CPU::Enter() -> void { + while(true) { + scheduler.synchronize(); + cpu.main(); + } +} + +auto CPU::main() -> void { + if(r.wai) return instructionWait(); + if(r.stp) return instructionStop(); + if(!status.interruptPending) return instruction(); + + if(status.nmiPending) { + status.nmiPending = 0; + r.vector = r.e ? 0xfffa : 0xffea; + return interrupt(); + } + + if(status.irqPending) { + status.irqPending = 0; + r.vector = r.e ? 0xfffe : 0xffee; + return interrupt(); + } + + if(status.resetPending) { + status.resetPending = 0; + for(uint repeat : range(22)) step<6,0>(); //step(132); + r.vector = 0xfffc; + return interrupt(); + } + + status.interruptPending = 0; +} + +auto CPU::load() -> bool { + version = configuration.system.cpu.version; + if(version < 1) version = 1; + if(version > 2) version = 2; + return true; +} + +auto CPU::power(bool reset) -> void { + WDC65816::power(); + Thread::create(Enter, system.cpuFrequency()); + coprocessors.reset(); + PPUcounter::reset(); + PPUcounter::scanline = {&CPU::scanline, this}; + + function reader; + function writer; + + reader = {&CPU::readRAM, this}; + writer = {&CPU::writeRAM, this}; + bus.map(reader, writer, "00-3f,80-bf:0000-1fff", 0x2000); + bus.map(reader, writer, "7e-7f:0000-ffff", 0x20000); + + reader = {&CPU::readAPU, this}; + writer = {&CPU::writeAPU, this}; + bus.map(reader, writer, "00-3f,80-bf:2140-217f"); + + reader = {&CPU::readCPU, this}; + writer = {&CPU::writeCPU, this}; + bus.map(reader, writer, "00-3f,80-bf:2180-2183,4016-4017,4200-421f"); + + reader = {&CPU::readDMA, this}; + writer = {&CPU::writeDMA, this}; + bus.map(reader, writer, "00-3f,80-bf:4300-437f"); + + if(!reset) random.array(wram, sizeof(wram)); + + if(configuration.hacks.hotfixes) { + //Dirt Racer (Europe) relies on uninitialized memory containing certain values to boot without freezing. + //the game itself is broken and will fail to run sometimes on real hardware, but for the sake of expedience, + //WRAM is initialized to a constant value that will allow this game to always boot in successfully. + if(cartridge.headerTitle() == "DIRT RACER") { + for(auto& byte : wram) byte = 0xff; + } + } + + for(uint n : range(8)) { + channels[n] = {}; + if(n != 7) channels[n].next = channels[n + 1]; + } + + counter = {}; + io = {}; + alu = {}; + + status = {}; + status.dramRefreshPosition = (version == 1 ? 530 : 538); + status.hdmaSetupPosition = (version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter()); + status.hdmaPosition = 1104; + status.resetPending = 1; + status.interruptPending = 1; +} + +} diff --git a/sfc/cpu/cpu.hpp b/sfc/cpu/cpu.hpp new file mode 100644 index 0000000..fa69da4 --- /dev/null +++ b/sfc/cpu/cpu.hpp @@ -0,0 +1,244 @@ +struct CPU : Processor::WDC65816, Thread, PPUcounter { + inline auto interruptPending() const -> bool override { return status.interruptPending; } + inline auto pio() const -> uint8 { return io.pio; } + inline auto refresh() const -> bool { return status.dramRefresh == 1; } + inline auto synchronizing() const -> bool override { return scheduler.synchronizing(); } + + //cpu.cpp + auto synchronizeSMP() -> void; + auto synchronizePPU() -> void; + auto synchronizeCoprocessors() -> void; + static auto Enter() -> void; + auto main() -> void; + auto load() -> bool; + auto power(bool reset) -> void; + + //dma.cpp + inline auto dmaEnable() -> bool; + inline auto hdmaEnable() -> bool; + inline auto hdmaActive() -> bool; + + auto dmaRun() -> void; + auto hdmaReset() -> void; + auto hdmaSetup() -> void; + auto hdmaRun() -> void; + + //memory.cpp + auto idle() -> void override; + auto read(uint addr) -> uint8 override; + auto write(uint addr, uint8 data) -> void override; + auto readDisassembler(uint addr) -> uint8 override; + + //io.cpp + auto readRAM(uint address, uint8 data) -> uint8; + auto readAPU(uint address, uint8 data) -> uint8; + auto readCPU(uint address, uint8 data) -> uint8; + auto readDMA(uint address, uint8 data) -> uint8; + auto writeRAM(uint address, uint8 data) -> void; + auto writeAPU(uint address, uint8 data) -> void; + auto writeCPU(uint address, uint8 data) -> void; + auto writeDMA(uint address, uint8 data) -> void; + + //timing.cpp + inline auto dmaCounter() const -> uint; + inline auto joypadCounter() const -> uint; + + alwaysinline auto stepOnce() -> void; + alwaysinline auto step(uint clocks) -> void; + template auto step() -> void; + auto scanline() -> void; + + alwaysinline auto aluEdge() -> void; + alwaysinline auto dmaEdge() -> void; + + //irq.cpp + alwaysinline auto nmiPoll() -> void; + alwaysinline auto irqPoll() -> void; + auto nmitimenUpdate(uint8 data) -> void; + auto rdnmi() -> bool; + auto timeup() -> bool; + + alwaysinline auto nmiTest() -> bool; + alwaysinline auto irqTest() -> bool; + alwaysinline auto lastCycle() -> void; + + //joypad.cpp + auto joypadEdge() -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + uint8 wram[128 * 1024]; + vector coprocessors; + + struct Overclocking { + uint counter = 0; + uint target = 0; + } overclocking; + +private: + uint version = 2; //allowed: 1, 2 + + struct Counter { + uint cpu = 0; + uint dma = 0; + } counter; + + struct Status { + uint clockCount = 0; + + bool irqLock = 0; + + uint dramRefreshPosition = 0; + uint dramRefresh = 0; //0 = not refreshed; 1 = refresh active; 2 = refresh inactive + + uint hdmaSetupPosition = 0; + bool hdmaSetupTriggered = 0; + + uint hdmaPosition = 0; + bool hdmaTriggered = 0; + + boolean nmiValid = 0; + boolean nmiLine = 0; + boolean nmiTransition = 0; + boolean nmiPending = 0; + boolean nmiHold = 0; + + boolean irqValid = 0; + boolean irqLine = 0; + boolean irqTransition = 0; + boolean irqPending = 0; + boolean irqHold = 0; + + bool resetPending = 0; + bool interruptPending = 0; + + bool dmaActive = 0; + bool dmaPending = 0; + bool hdmaPending = 0; + bool hdmaMode = 0; //0 = init, 1 = run + + bool autoJoypadActive = 0; + bool autoJoypadLatch = 0; + uint autoJoypadCounter = 0; + } status; + + struct IO { + //$2181-$2183 + uint17 wramAddress = 0; + + //$4200 + boolean hirqEnable = 0; + boolean virqEnable = 0; + boolean irqEnable = 0; + boolean nmiEnable = 0; + boolean autoJoypadPoll = 0; + + //$4201 + uint8 pio = 0xff; + + //$4202-$4203 + uint8 wrmpya = 0xff; + uint8 wrmpyb = 0xff; + + //$4204-$4206 + uint16 wrdiva = 0xffff; + uint8 wrdivb = 0xff; + + //$4207-$420a + uint12 htime = 0x1ff + 1 << 2; + uint9 vtime = 0x1ff; + + //$420d + uint1 fastROM = 0; + + //$4214-$4217 + uint16 rddiv = 0; + uint16 rdmpy = 0; + + //$4218-$421f + uint16 joy1 = 0; + uint16 joy2 = 0; + uint16 joy3 = 0; + uint16 joy4 = 0; + } io; + + struct ALU { + uint mpyctr = 0; + uint divctr = 0; + uint shift = 0; + } alu; + + struct Channel { + //dma.cpp + template inline auto step() -> void; + inline auto edge() -> void; + + inline auto validA(uint24 address) -> bool; + inline auto readA(uint24 address) -> uint8; + inline auto readB(uint8 address, bool valid) -> uint8; + inline auto writeA(uint24 address, uint8 data) -> void; + inline auto writeB(uint8 address, uint8 data, bool valid) -> void; + inline auto transfer(uint24 address, uint2 index) -> void; + + inline auto dmaRun() -> void; + inline auto hdmaActive() -> bool; + inline auto hdmaFinished() -> bool; + inline auto hdmaReset() -> void; + inline auto hdmaSetup() -> void; + inline auto hdmaReload() -> void; + inline auto hdmaTransfer() -> void; + inline auto hdmaAdvance() -> void; + + //$420b + uint1 dmaEnable = 0; + + //$420c + uint1 hdmaEnable = 0; + + //$43x0 + uint3 transferMode = 7; + uint1 fixedTransfer = 1; + uint1 reverseTransfer = 1; + uint1 unused = 1; + uint1 indirect = 1; + uint1 direction = 1; + + //$43x1 + uint8 targetAddress = 0xff; + + //$43x2-$43x3 + uint16 sourceAddress = 0xffff; + + //$43x4 + uint8 sourceBank = 0xff; + + //$43x5-$43x6 + union { + uint16 transferSize; + uint16 indirectAddress; + }; + + //$43x7 + uint8 indirectBank = 0xff; + + //$43x8-$43x9 + uint16 hdmaAddress = 0xffff; + + //$43xa + uint8 lineCounter = 0xff; + + //$43xb/$43xf + uint8 unknown = 0xff; + + //internal state + uint1 hdmaCompleted = 0; + uint1 hdmaDoTransfer = 0; + + maybe next; + + Channel() : transferSize(0xffff) {} + } channels[8]; +}; + +extern CPU cpu; diff --git a/sfc/cpu/dma.cpp b/sfc/cpu/dma.cpp new file mode 100644 index 0000000..9f4a10f --- /dev/null +++ b/sfc/cpu/dma.cpp @@ -0,0 +1,189 @@ +auto CPU::dmaEnable() -> bool { + for(auto& channel : channels) if(channel.dmaEnable) return true; + return false; +} + +auto CPU::hdmaEnable() -> bool { + for(auto& channel : channels) if(channel.hdmaEnable) return true; + return false; +} + +auto CPU::hdmaActive() -> bool { + for(auto& channel : channels) if(channel.hdmaActive()) return true; + return false; +} + +auto CPU::dmaRun() -> void { + counter.dma += 8; + step<8,0>(); + dmaEdge(); + for(auto& channel : channels) channel.dmaRun(); + status.irqLock = true; +} + +auto CPU::hdmaReset() -> void { + for(auto& channel : channels) channel.hdmaReset(); +} + +auto CPU::hdmaSetup() -> void { + counter.dma += 8; + step<8,0>(); + for(auto& channel : channels) channel.hdmaSetup(); + status.irqLock = true; +} + +auto CPU::hdmaRun() -> void { + counter.dma += 8; + step<8,0>(); + for(auto& channel : channels) channel.hdmaTransfer(); + for(auto& channel : channels) channel.hdmaAdvance(); + status.irqLock = true; +} + +// + +template +auto CPU::Channel::step() -> void { + cpu.counter.dma += Clocks; + cpu.step(); +} + +auto CPU::Channel::edge() -> void { + cpu.dmaEdge(); +} + +auto CPU::Channel::validA(uint24 address) -> bool { + //A-bus cannot access the B-bus or CPU I/O registers + if((address & 0x40ff00) == 0x2100) return false; //00-3f,80-bf:2100-21ff + if((address & 0x40fe00) == 0x4000) return false; //00-3f,80-bf:4000-41ff + if((address & 0x40ffe0) == 0x4200) return false; //00-3f,80-bf:4200-421f + if((address & 0x40ff80) == 0x4300) return false; //00-3f,80-bf:4300-437f + return true; +} + +auto CPU::Channel::readA(uint24 address) -> uint8 { + step<4,1>(); + cpu.r.mdr = validA(address) ? bus.read(address, cpu.r.mdr) : (uint8)0x00; + step<4,1>(); + return cpu.r.mdr; +} + +auto CPU::Channel::readB(uint8 address, bool valid) -> uint8 { + step<4,1>(); + cpu.r.mdr = valid ? bus.read(0x2100 | address, cpu.r.mdr) : (uint8)0x00; + step<4,1>(); + return cpu.r.mdr; +} + +auto CPU::Channel::writeA(uint24 address, uint8 data) -> void { + if(validA(address)) bus.write(address, data); +} + +auto CPU::Channel::writeB(uint8 address, uint8 data, bool valid) -> void { + if(valid) bus.write(0x2100 | address, data); +} + +auto CPU::Channel::transfer(uint24 addressA, uint2 index) -> void { + uint8 addressB = targetAddress; + switch(transferMode) { + case 1: case 5: addressB += index.bit(0); break; + case 3: case 7: addressB += index.bit(1); break; + case 4: addressB += index; break; + } + + //transfers from WRAM to WRAM are invalid + bool valid = addressB != 0x80 || ((addressA & 0xfe0000) != 0x7e0000 && (addressA & 0x40e000) != 0x0000); + + cpu.r.mar = addressA; + if(direction == 0) { + auto data = readA(addressA); + writeB(addressB, data, valid); + } else { + auto data = readB(addressB, valid); + writeA(addressA, data); + } +} + +auto CPU::Channel::dmaRun() -> void { + if(!dmaEnable) return; + + step<8,0>(); + edge(); + + uint2 index = 0; + do { + transfer(sourceBank << 16 | sourceAddress, index++); + if(!fixedTransfer) !reverseTransfer ? sourceAddress++ : sourceAddress--; + edge(); + } while(dmaEnable && --transferSize); + + dmaEnable = false; +} + +auto CPU::Channel::hdmaActive() -> bool { + return hdmaEnable && !hdmaCompleted; +} + +auto CPU::Channel::hdmaFinished() -> bool { + auto channel = next; + while(channel) { + if(channel->hdmaActive()) return false; + channel = channel->next; + } + return true; +} + +auto CPU::Channel::hdmaReset() -> void { + hdmaCompleted = false; + hdmaDoTransfer = false; +} + +auto CPU::Channel::hdmaSetup() -> void { + hdmaDoTransfer = true; //note: needs hardware verification + if(!hdmaEnable) return; + + dmaEnable = false; //HDMA will stop active DMA mid-transfer + hdmaAddress = sourceAddress; + lineCounter = 0; + hdmaReload(); +} + +auto CPU::Channel::hdmaReload() -> void { + auto data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress); + + if((uint7)lineCounter == 0) { + lineCounter = data; + hdmaAddress++; + + hdmaCompleted = lineCounter == 0; + hdmaDoTransfer = !hdmaCompleted; + + if(indirect) { + data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress++); + indirectAddress = data << 8 | 0x00; //todo: should 0x00 be indirectAddress >> 8 ? + if(hdmaCompleted && hdmaFinished()) return; + + data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress++); + indirectAddress = data << 8 | indirectAddress >> 8; + } + } +} + +auto CPU::Channel::hdmaTransfer() -> void { + if(!hdmaActive()) return; + dmaEnable = false; //HDMA will stop active DMA mid-transfer + if(!hdmaDoTransfer) return; + + static const uint lengths[8] = {1, 2, 2, 4, 4, 4, 2, 4}; + for(uint2 index : range(lengths[transferMode])) { + uint24 address = !indirect ? sourceBank << 16 | hdmaAddress++ : indirectBank << 16 | indirectAddress++; + transfer(address, index); + } +} + +auto CPU::Channel::hdmaAdvance() -> void { + if(!hdmaActive()) return; + lineCounter--; + hdmaDoTransfer = bool(lineCounter & 0x80); + hdmaReload(); +} diff --git a/sfc/cpu/io.cpp b/sfc/cpu/io.cpp new file mode 100644 index 0000000..dd10da7 --- /dev/null +++ b/sfc/cpu/io.cpp @@ -0,0 +1,293 @@ +auto CPU::readRAM(uint addr, uint8 data) -> uint8 { + return wram[addr]; +} + +auto CPU::readAPU(uint addr, uint8 data) -> uint8 { + synchronizeSMP(); + return smp.portRead(addr & 3); +} + +auto CPU::readCPU(uint addr, uint8 data) -> uint8 { + switch(addr & 0xffff) { + case 0x2180: //WMDATA + return bus.read(0x7e0000 | io.wramAddress++, data); + + case 0x4016: //JOYSER0 + data &= 0xfc; + data |= controllerPort1.device->data(); + return data; + + case 0x4017: //JOYSER1 + data &= 0xe0; + data |= 0x1c; //pins are connected to GND + data |= controllerPort2.device->data(); + return data; + + case 0x4210: //RDNMI + data &= 0x70; + data |= rdnmi() << 7; + data |= (uint4)version; + return data; + + case 0x4211: //TIMEUP + data &= 0x7f; + data |= timeup() << 7; + return data; + + case 0x4212: //HVBJOY + data &= 0x3e; + data |= (status.autoJoypadActive) << 0; + data |= (hcounter() <= 2 || hcounter() >= 1096) << 6; //hblank + data |= (vcounter() >= ppu.vdisp()) << 7; //vblank + return data; + + case 0x4213: return io.pio; //RDIO + + case 0x4214: return io.rddiv >> 0; //RDDIVL + case 0x4215: return io.rddiv >> 8; //RDDIVH + case 0x4216: return io.rdmpy >> 0; //RDMPYL + case 0x4217: return io.rdmpy >> 8; //RDMPYH + + case 0x4218: return io.joy1 >> 0; //JOY1L + case 0x4219: return io.joy1 >> 8; //JOY1H + case 0x421a: return io.joy2 >> 0; //JOY2L + case 0x421b: return io.joy2 >> 8; //JOY2H + case 0x421c: return io.joy3 >> 0; //JOY3L + case 0x421d: return io.joy3 >> 8; //JOY3H + case 0x421e: return io.joy4 >> 0; //JOY4L + case 0x421f: return io.joy4 >> 8; //JOY4H + + } + + return data; +} + +auto CPU::readDMA(uint addr, uint8 data) -> uint8 { + auto& channel = this->channels[addr >> 4 & 7]; + + switch(addr & 0xff8f) { + + case 0x4300: //DMAPx + return ( + channel.transferMode << 0 + | channel.fixedTransfer << 3 + | channel.reverseTransfer << 4 + | channel.unused << 5 + | channel.indirect << 6 + | channel.direction << 7 + ); + + case 0x4301: return channel.targetAddress; //BBADx + case 0x4302: return channel.sourceAddress >> 0; //A1TxL + case 0x4303: return channel.sourceAddress >> 8; //A1TxH + case 0x4304: return channel.sourceBank; //A1Bx + case 0x4305: return channel.transferSize >> 0; //DASxL + case 0x4306: return channel.transferSize >> 8; //DASxH + case 0x4307: return channel.indirectBank; //DASBx + case 0x4308: return channel.hdmaAddress >> 0; //A2AxL + case 0x4309: return channel.hdmaAddress >> 8; //A2AxH + case 0x430a: return channel.lineCounter; //NTRLx + case 0x430b: return channel.unknown; //???x + case 0x430f: return channel.unknown; //???x ($43xb mirror) + + } + + return data; +} + +auto CPU::writeRAM(uint addr, uint8 data) -> void { + wram[addr] = data; +} + +auto CPU::writeAPU(uint addr, uint8 data) -> void { + synchronizeSMP(); + return smp.portWrite(addr & 3, data); +} + +auto CPU::writeCPU(uint addr, uint8 data) -> void { + switch(addr & 0xffff) { + + case 0x2180: //WMDATA + return bus.write(0x7e0000 | io.wramAddress++, data); + + case 0x2181: //WMADDL + io.wramAddress = io.wramAddress & 0x1ff00 | data << 0; + return; + + case 0x2182: //WMADDM + io.wramAddress = io.wramAddress & 0x100ff | data << 8; + return; + + case 0x2183: //WMADDH + io.wramAddress = io.wramAddress & 0x0ffff | (data & 1) << 16; + return; + + case 0x4016: //JOYSER0 + //bit 0 is shared between JOYSER0 and JOYSER1: + //strobing $4016.d0 affects both controller port latches. + //$4017 bit 0 writes are ignored. + controllerPort1.device->latch(data & 1); + controllerPort2.device->latch(data & 1); + return; + + case 0x4200: //NMITIMEN + io.autoJoypadPoll = data & 1; + nmitimenUpdate(data); + return; + + case 0x4201: //WRIO + if((io.pio & 0x80) && !(data & 0x80)) ppu.latchCounters(); + io.pio = data; + return; + + case 0x4202: //WRMPYA + io.wrmpya = data; + return; + + case 0x4203: //WRMPYB + io.rdmpy = 0; + if(alu.mpyctr || alu.divctr) return; + + io.wrmpyb = data; + io.rddiv = io.wrmpyb << 8 | io.wrmpya; + + if(!configuration.hacks.cpu.fastMath) { + alu.mpyctr = 8; //perform multiplication over the next eight cycles + alu.shift = io.wrmpyb; + } else { + io.rdmpy = io.wrmpya * io.wrmpyb; + } + return; + + case 0x4204: //WRDIVL + io.wrdiva = io.wrdiva & 0xff00 | data << 0; + return; + + case 0x4205: //WRDIVH + io.wrdiva = io.wrdiva & 0x00ff | data << 8; + return; + + case 0x4206: //WRDIVB + io.rdmpy = io.wrdiva; + if(alu.mpyctr || alu.divctr) return; + + io.wrdivb = data; + + if(!configuration.hacks.cpu.fastMath) { + alu.divctr = 16; //perform division over the next sixteen cycles + alu.shift = io.wrdivb << 16; + } else { + if(io.wrdivb) { + io.rddiv = io.wrdiva / io.wrdivb; + io.rdmpy = io.wrdiva % io.wrdivb; + } else { + io.rddiv = 0xffff; + io.rdmpy = io.wrdiva; + } + } + return; + + case 0x4207: //HTIMEL + io.htime = (io.htime >> 2) - 1; + io.htime = io.htime & 0x100 | data << 0; + io.htime = (io.htime + 1) << 2; + irqPoll(); //unverified + return; + + case 0x4208: //HTIMEH + io.htime = (io.htime >> 2) - 1; + io.htime = io.htime & 0x0ff | (data & 1) << 8; + io.htime = (io.htime + 1) << 2; + irqPoll(); //unverified + return; + + case 0x4209: //VTIMEL + io.vtime = io.vtime & 0x100 | data << 0; + irqPoll(); //unverified + return; + + case 0x420a: //VTIMEH + io.vtime = io.vtime & 0x0ff | (data & 1) << 8; + irqPoll(); //unverified + return; + + case 0x420b: //DMAEN + for(auto n : range(8)) channels[n].dmaEnable = bool(data & 1 << n); + if(data) status.dmaPending = true; + return; + + case 0x420c: //HDMAEN + for(auto n : range(8)) channels[n].hdmaEnable = bool(data & 1 << n); + return; + + case 0x420d: //MEMSEL + io.fastROM = data & 1; + return; + + } +} + +auto CPU::writeDMA(uint addr, uint8 data) -> void { + auto& channel = this->channels[addr >> 4 & 7]; + + switch(addr & 0xff8f) { + + case 0x4300: //DMAPx + channel.transferMode = data >> 0 & 7; + channel.fixedTransfer = data >> 3 & 1; + channel.reverseTransfer = data >> 4 & 1; + channel.unused = data >> 5 & 1; + channel.indirect = data >> 6 & 1; + channel.direction = data >> 7 & 1; + return; + + case 0x4301: //BBADx + channel.targetAddress = data; + return; + + case 0x4302: //A1TxL + channel.sourceAddress = channel.sourceAddress & 0xff00 | data << 0; + return; + + case 0x4303: //A1TxH + channel.sourceAddress = channel.sourceAddress & 0x00ff | data << 8; + return; + + case 0x4304: //A1Bx + channel.sourceBank = data; + return; + + case 0x4305: //DASxL + channel.transferSize = channel.transferSize & 0xff00 | data << 0; + return; + + case 0x4306: //DASxH + channel.transferSize = channel.transferSize & 0x00ff | data << 8; + return; + + case 0x4307: //DASBx + channel.indirectBank = data; + return; + + case 0x4308: //A2AxL + channel.hdmaAddress = channel.hdmaAddress & 0xff00 | data << 0; + return; + + case 0x4309: //A2AxH + channel.hdmaAddress = channel.hdmaAddress & 0x00ff | data << 8; + return; + + case 0x430a: //NTRLx + channel.lineCounter = data; + return; + + case 0x430b: //???x + channel.unknown = data; + return; + + case 0x430f: //???x ($43xb mirror) + channel.unknown = data; + return; + + } +} diff --git a/sfc/cpu/irq.cpp b/sfc/cpu/irq.cpp new file mode 100644 index 0000000..05deed3 --- /dev/null +++ b/sfc/cpu/irq.cpp @@ -0,0 +1,94 @@ +//nmiPoll() and irqPoll() are 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. + +auto CPU::nmiPoll() -> void { + //NMI hold + if(status.nmiHold.lower() && io.nmiEnable) { + status.nmiTransition = 1; + } + + //NMI test + if(status.nmiValid.flip(vcounter(2) >= ppu.vdisp())) { + if(status.nmiLine = status.nmiValid) status.nmiHold = 1; //hold /NMI for four cycles + } +} + +auto CPU::irqPoll() -> void { + //IRQ hold + status.irqHold = 0; + if(status.irqLine && io.irqEnable) { + status.irqTransition = 1; + } + + //IRQ test + if(status.irqValid.raise(io.irqEnable + && (!io.virqEnable || vcounter(10) == io.vtime) + && (!io.hirqEnable || hcounter(10) == io.htime) + && (vcounter(6) || hcounter(6)) //IRQs cannot trigger on last dot of fields + )) status.irqLine = status.irqHold = 1; //hold /IRQ for four cycles +} + +auto CPU::nmitimenUpdate(uint8 data) -> void { + io.hirqEnable = data & 0x10; + io.virqEnable = data & 0x20; + io.irqEnable = io.hirqEnable || io.virqEnable; + + if(io.virqEnable && !io.hirqEnable && status.irqLine) { + status.irqTransition = 1; + } else if(!io.irqEnable) { + status.irqLine = 0; + status.irqTransition = 0; + } + + if(io.nmiEnable.raise(data & 0x80) && status.nmiLine) { + status.nmiTransition = 1; + } + + status.irqLock = 1; +} + +auto CPU::rdnmi() -> bool { + bool result = status.nmiLine; + if(!status.nmiHold) { + status.nmiLine = 0; + } + return result; +} + +auto CPU::timeup() -> bool { + bool result = status.irqLine; + if(!status.irqHold) { + status.irqLine = 0; + status.irqTransition = 0; + } + return result; +} + +auto CPU::nmiTest() -> bool { + if(!status.nmiTransition) return 0; + status.nmiTransition = 0; + r.wai = 0; + return 1; +} + +auto CPU::irqTest() -> bool { + if(!status.irqTransition && !r.irq) return 0; + status.irqTransition = 0; + r.wai = 0; + return !r.p.i; +} + +//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 the 65816 CPU. +// +//status.irqLock is used to simulate hardware delay before interrupts can +//trigger during certain events (immediately after DMA, writes to $4200, etc) +auto CPU::lastCycle() -> void { + if(!status.irqLock) { + if(nmiTest()) status.nmiPending = 1, status.interruptPending = 1; + if(irqTest()) status.irqPending = 1, status.interruptPending = 1; + } +} diff --git a/sfc/cpu/memory.cpp b/sfc/cpu/memory.cpp new file mode 100644 index 0000000..c63de17 --- /dev/null +++ b/sfc/cpu/memory.cpp @@ -0,0 +1,86 @@ +auto CPU::idle() -> void { + status.clockCount = 6; + dmaEdge(); + step<6,0>(); + status.irqLock = 0; + aluEdge(); +} + +auto CPU::read(uint address) -> uint8 { + if(address & 0x408000) { + if(address & 0x800000 && io.fastROM) { + status.clockCount = 6; + dmaEdge(); + r.mar = address; + step<2,1>(); + } else { + status.clockCount = 8; + dmaEdge(); + r.mar = address; + step<4,1>(); + } + } else if(address + 0x6000 & 0x4000) { + status.clockCount = 8; + dmaEdge(); + r.mar = address; + step<4,1>(); + } else if(address - 0x4000 & 0x7e00) { + status.clockCount = 6; + dmaEdge(); + r.mar = address; + step<2,1>(); + } else { + status.clockCount = 12; + dmaEdge(); + r.mar = address; + step<8,1>(); + } + + status.irqLock = 0; + auto data = bus.read(address, r.mdr); + step<4,0>(); + aluEdge(); + //$00-3f,80-bf:4000-43ff reads are internal to CPU, and do not update the MDR + if((address & 0x40fc00) != 0x4000) r.mdr = data; + return data; +} + +auto CPU::write(uint address, uint8 data) -> void { + aluEdge(); + + if(address & 0x408000) { + if(address & 0x800000 && io.fastROM) { + status.clockCount = 6; + dmaEdge(); + r.mar = address; + step<6,1>(); + } else { + status.clockCount = 8; + dmaEdge(); + r.mar = address; + step<8,1>(); + } + } else if(address + 0x6000 & 0x4000) { + status.clockCount = 8; + dmaEdge(); + r.mar = address; + step<8,1>(); + } else if(address - 0x4000 & 0x7e00) { + status.clockCount = 6; + dmaEdge(); + r.mar = address; + step<6,1>(); + } else { + status.clockCount = 12; + dmaEdge(); + r.mar = address; + step<12,1>(); + } + + status.irqLock = 0; + bus.write(address, r.mdr = data); +} + +auto CPU::readDisassembler(uint address) -> uint8 { + return bus.read(address, r.mdr); +} diff --git a/sfc/cpu/serialization.cpp b/sfc/cpu/serialization.cpp new file mode 100644 index 0000000..298079b --- /dev/null +++ b/sfc/cpu/serialization.cpp @@ -0,0 +1,103 @@ +auto CPU::serialize(serializer& s) -> void { + WDC65816::serialize(s); + Thread::serialize(s); + PPUcounter::serialize(s); + + s.array(wram); + + s.integer(version); + + s.integer(counter.cpu); + s.integer(counter.dma); + + s.integer(status.clockCount); + + s.integer(status.irqLock); + + s.integer(status.dramRefreshPosition); + s.integer(status.dramRefresh); + + s.integer(status.hdmaSetupPosition); + s.integer(status.hdmaSetupTriggered); + + s.integer(status.hdmaPosition); + s.integer(status.hdmaTriggered); + + s.boolean(status.nmiValid); + s.boolean(status.nmiLine); + s.boolean(status.nmiTransition); + s.boolean(status.nmiPending); + s.boolean(status.nmiHold); + + s.boolean(status.irqValid); + s.boolean(status.irqLine); + s.boolean(status.irqTransition); + s.boolean(status.irqPending); + s.boolean(status.irqHold); + + s.integer(status.resetPending); + s.integer(status.interruptPending); + + s.integer(status.dmaActive); + s.integer(status.dmaPending); + s.integer(status.hdmaPending); + s.integer(status.hdmaMode); + + s.integer(status.autoJoypadActive); + s.integer(status.autoJoypadLatch); + s.integer(status.autoJoypadCounter); + + s.integer(io.wramAddress); + + s.boolean(io.hirqEnable); + s.boolean(io.virqEnable); + s.boolean(io.irqEnable); + s.boolean(io.nmiEnable); + s.boolean(io.autoJoypadPoll); + + s.integer(io.pio); + + s.integer(io.wrmpya); + s.integer(io.wrmpyb); + + s.integer(io.wrdiva); + s.integer(io.wrdivb); + + s.integer(io.htime); + s.integer(io.vtime); + + s.integer(io.fastROM); + + s.integer(io.rddiv); + s.integer(io.rdmpy); + + s.integer(io.joy1); + s.integer(io.joy2); + s.integer(io.joy3); + s.integer(io.joy4); + + s.integer(alu.mpyctr); + s.integer(alu.divctr); + s.integer(alu.shift); + + for(auto& channel : channels) { + s.integer(channel.dmaEnable); + s.integer(channel.hdmaEnable); + s.integer(channel.direction); + s.integer(channel.indirect); + s.integer(channel.unused); + s.integer(channel.reverseTransfer); + s.integer(channel.fixedTransfer); + s.integer(channel.transferMode); + s.integer(channel.targetAddress); + s.integer(channel.sourceAddress); + s.integer(channel.sourceBank); + s.integer(channel.transferSize); + s.integer(channel.indirectBank); + s.integer(channel.hdmaAddress); + s.integer(channel.lineCounter); + s.integer(channel.unknown); + s.integer(channel.hdmaCompleted); + s.integer(channel.hdmaDoTransfer); + } +} diff --git a/sfc/cpu/timing.cpp b/sfc/cpu/timing.cpp new file mode 100644 index 0000000..987c0dd --- /dev/null +++ b/sfc/cpu/timing.cpp @@ -0,0 +1,274 @@ +//DMA clock divider +auto CPU::dmaCounter() const -> uint { + return counter.cpu & 7; +} + +//joypad auto-poll clock divider +auto CPU::joypadCounter() const -> uint { + return counter.cpu & 255; +} + +auto CPU::stepOnce() -> void { + counter.cpu += 2; + tick(); + if(hcounter() & 2) nmiPoll(), irqPoll(); + if(joypadCounter() == 0) joypadEdge(); +} + +template +auto CPU::step() -> void { + static_assert(Clocks == 2 || Clocks == 4 || Clocks == 6 || Clocks == 8 || Clocks == 10 || Clocks == 12); + + for(auto coprocessor : coprocessors) { + if(coprocessor == &icd || coprocessor == &msu1) continue; + coprocessor->clock -= Clocks * (uint64)coprocessor->frequency; + } + + if(overclocking.target) { + overclocking.counter += Clocks; + if(overclocking.counter < overclocking.target) { + if constexpr(Synchronize) { + if(configuration.hacks.coprocessor.delayedSync) return; + synchronizeCoprocessors(); + } + return; + } + } + + if constexpr(Clocks >= 2) stepOnce(); + if constexpr(Clocks >= 4) stepOnce(); + if constexpr(Clocks >= 6) stepOnce(); + if constexpr(Clocks >= 8) stepOnce(); + if constexpr(Clocks >= 10) stepOnce(); + if constexpr(Clocks >= 12) stepOnce(); + + smp.clock -= Clocks * (uint64)smp.frequency; + ppu.clock -= Clocks; + for(auto coprocessor : coprocessors) { + if(coprocessor != &icd && coprocessor != &msu1) continue; + coprocessor->clock -= Clocks * (uint64)coprocessor->frequency; + } + + if(!status.dramRefresh && hcounter() >= status.dramRefreshPosition) { + //note: pattern should technically be 5-3, 5-3, 5-3, 5-3, 5-3 per logic analyzer + //result averages out the same as no coprocessor polls refresh() at > frequency()/2 + status.dramRefresh = 1; step<6,0>(); status.dramRefresh = 2; step<2,0>(); aluEdge(); + status.dramRefresh = 1; step<6,0>(); status.dramRefresh = 2; step<2,0>(); aluEdge(); + status.dramRefresh = 1; step<6,0>(); status.dramRefresh = 2; step<2,0>(); aluEdge(); + status.dramRefresh = 1; step<6,0>(); status.dramRefresh = 2; step<2,0>(); aluEdge(); + status.dramRefresh = 1; step<6,0>(); status.dramRefresh = 2; step<2,0>(); aluEdge(); + } + + if(!status.hdmaSetupTriggered && hcounter() >= status.hdmaSetupPosition) { + status.hdmaSetupTriggered = true; + hdmaReset(); + if(hdmaEnable()) { + status.hdmaPending = true; + status.hdmaMode = 0; + } + } + + if(!status.hdmaTriggered && hcounter() >= status.hdmaPosition) { + status.hdmaTriggered = true; + if(hdmaActive()) { + status.hdmaPending = true; + status.hdmaMode = 1; + } + } + + if constexpr(Synchronize) { + if(configuration.hacks.coprocessor.delayedSync) return; + synchronizeCoprocessors(); + } +} + +auto CPU::step(uint clocks) -> void { + switch(clocks) { + case 2: return step< 2,1>(); + case 4: return step< 4,1>(); + case 6: return step< 6,1>(); + case 8: return step< 8,1>(); + case 10: return step<10,1>(); + case 12: return step<12,1>(); + } +} + +//called by ppu.tick() when Hcounter=0 +auto CPU::scanline() -> void { + //forcefully sync S-CPU to other processors, in case chips are not communicating + synchronizeSMP(); + synchronizePPU(); + synchronizeCoprocessors(); + + if(vcounter() == 0) { + //HDMA setup triggers once every frame + status.hdmaSetupPosition = (version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter()); + status.hdmaSetupTriggered = false; + + status.autoJoypadCounter = 0; + } + + //DRAM refresh occurs once every scanline + if(version == 2) status.dramRefreshPosition = 530 + 8 - dmaCounter(); + status.dramRefresh = 0; + + //HDMA triggers once every visible scanline + if(vcounter() < ppu.vdisp()) { + status.hdmaPosition = 1104; + status.hdmaTriggered = false; + } + + //overclocking + if(vcounter() == (Region::NTSC() ? 261 : 311)) { + overclocking.counter = 0; + overclocking.target = 0; + double overclock = configuration.hacks.cpu.overclock / 100.0; + if(overclock > 1.0) { + int clocks = (Region::NTSC() ? 262 : 312) * 1364; + overclocking.target = clocks * overclock - clocks; + } + } + + //handle video frame events from the CPU core to prevent a race condition between + //games polling inputs during NMI and the PPU thread not being 100% synchronized. + if(vcounter() == ppu.vdisp()) { + if(auto device = controllerPort2.device) device->latch(); //light guns + synchronizePPU(); + if(system.fastPPU()) PPUfast::Line::flush(); + scheduler.leave(Scheduler::Event::Frame); + } +} + +auto CPU::aluEdge() -> void { + if(alu.mpyctr) { + alu.mpyctr--; + if(io.rddiv & 1) io.rdmpy += alu.shift; + io.rddiv >>= 1; + alu.shift <<= 1; + } + + if(alu.divctr) { + alu.divctr--; + io.rddiv <<= 1; + alu.shift >>= 1; + if(io.rdmpy >= alu.shift) { + io.rdmpy -= alu.shift; + io.rddiv |= 1; + } + } +} + +auto CPU::dmaEdge() -> void { + //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.dmaActive) { + if(status.hdmaPending) { + status.hdmaPending = false; + if(hdmaEnable()) { + if(!dmaEnable()) { + step(counter.dma = 8 - dmaCounter()); + } + status.hdmaMode == 0 ? hdmaSetup() : hdmaRun(); + if(!dmaEnable()) { + step(status.clockCount - counter.dma % status.clockCount); + status.dmaActive = false; + } + } + } + + if(status.dmaPending) { + status.dmaPending = false; + if(dmaEnable()) { + step(counter.dma = 8 - dmaCounter()); + dmaRun(); + step(status.clockCount - counter.dma % status.clockCount); + status.dmaActive = false; + } + } + } + + if(!status.dmaActive) { + if(status.dmaPending || status.hdmaPending) { + status.dmaActive = true; + } + } +} + +//called every 256 clocks; see CPU::step() +auto CPU::joypadEdge() -> void { + //fast joypad polling is a hack to work around edge cases not currently emulated in auto-joypad polling. + //below is a list of games that have had input issues over the years. + //Nuke (PD): inputs do not work + //Super Conflict: sends random inputs even with no buttons pressed + //Super Star Wars: Start button auto-unpauses + //Taikyoku Igo - Goliath: start button not acknowledged + //Tatakae Genshijin 2: attract sequence ends early + //Williams Arcade's Greatest Hits: inputs fire on their own; or menu items sometimes skipped + //World Masters Golf: inputs fail to register; or holding D-pad should only move the cursor once, not continuously + + if(configuration.hacks.cpu.fastJoypadPolling) { + //Taikyoku Igo - Goliath + //Williams Arcade's Greatest Hits + //World Masters Golf + if(!status.autoJoypadCounter && vcounter() >= ppu.vdisp()) { + controllerPort1.device->latch(1); + controllerPort2.device->latch(1); + controllerPort1.device->latch(0); + controllerPort2.device->latch(0); + + io.joy1 = 0; + io.joy2 = 0; + io.joy3 = 0; + io.joy4 = 0; + + for(uint index : range(16)) { + uint2 port0 = controllerPort1.device->data(); + uint2 port1 = controllerPort2.device->data(); + + io.joy1 = io.joy1 << 1 | port0.bit(0); + io.joy2 = io.joy2 << 1 | port1.bit(0); + io.joy3 = io.joy3 << 1 | port0.bit(1); + io.joy4 = io.joy4 << 1 | port1.bit(1); + } + + status.autoJoypadCounter = 16; + } + } else { + if(vcounter() >= ppu.vdisp()) { + //cache enable state at first iteration + if(status.autoJoypadCounter == 0) status.autoJoypadLatch = io.autoJoypadPoll; + status.autoJoypadActive = status.autoJoypadCounter <= 15; + + if(status.autoJoypadActive && status.autoJoypadLatch) { + if(status.autoJoypadCounter == 0) { + controllerPort1.device->latch(1); + controllerPort2.device->latch(1); + controllerPort1.device->latch(0); + controllerPort2.device->latch(0); + + //shift registers are cleared at start of auto joypad polling + io.joy1 = 0; + io.joy2 = 0; + io.joy3 = 0; + io.joy4 = 0; + } + + uint2 port0 = controllerPort1.device->data(); + uint2 port1 = controllerPort2.device->data(); + + io.joy1 = io.joy1 << 1 | port0.bit(0); + io.joy2 = io.joy2 << 1 | port1.bit(0); + io.joy3 = io.joy3 << 1 | port0.bit(1); + io.joy4 = io.joy4 << 1 | port1.bit(1); + } + + status.autoJoypadCounter++; + } + } +} diff --git a/sfc/dsp/SPC_DSP.cpp b/sfc/dsp/SPC_DSP.cpp new file mode 100644 index 0000000..a89d491 --- /dev/null +++ b/sfc/dsp/SPC_DSP.cpp @@ -0,0 +1,1048 @@ +// 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 ) +{ + int out; + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + //in[3] is the newest sample, in[0] is the oldest sample + + if(configuration.hacks.dsp.cubic) { + float a = in[0] / 32768.0; + float b = in[1] / 32768.0; + float c = in[2] / 32768.0; + float d = in[3] / 32768.0; + + float A = d - c - a + b; + float B = a - b - A; + float C = c - a; + float D = b; + + float P = (v->interp_pos & 0xFFF) / 4096.0; + float O = (A * P * P * P) + (B * P * P) + (C * P) + (D); + + out = O * 32768.0; + } else { + // 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 + + 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) & 0xffff; + 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.echo [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, void* echo_64k ) +{ + m.ram = (uint8_t*) ram_64k; + m.echo = (uint8_t*) echo_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 + require( m.echo ); + + 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/sfc/dsp/SPC_DSP.h b/sfc/dsp/SPC_DSP.h new file mode 100644 index 0000000..50fd7be --- /dev/null +++ b/sfc/dsp/SPC_DSP.h @@ -0,0 +1,308 @@ +// 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, void* echo_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 + uint8_t* echo; // should point at the same memory as ram; used for older hack compatibility + 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(); + +public: + bool mute() { return m.regs[r_flg] & 0x40; } +}; + +#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/sfc/dsp/blargg_common.h b/sfc/dsp/blargg_common.h new file mode 100644 index 0000000..75edff3 --- /dev/null +++ b/sfc/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/sfc/dsp/blargg_config.h b/sfc/dsp/blargg_config.h new file mode 100644 index 0000000..94570ca --- /dev/null +++ b/sfc/dsp/blargg_config.h @@ -0,0 +1,26 @@ +// 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 +#ifndef NDEBUG + #define NDEBUG 1 +#endif + +// 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/sfc/dsp/blargg_endian.h b/sfc/dsp/blargg_endian.h new file mode 100644 index 0000000..f2daca6 --- /dev/null +++ b/sfc/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/sfc/dsp/blargg_source.h b/sfc/dsp/blargg_source.h new file mode 100644 index 0000000..5e45c4f --- /dev/null +++ b/sfc/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/sfc/dsp/dsp.cpp b/sfc/dsp/dsp.cpp new file mode 100644 index 0000000..eb6f78b --- /dev/null +++ b/sfc/dsp/dsp.cpp @@ -0,0 +1,80 @@ +#include + +namespace SuperFamicom { + +DSP dsp; + +#include "serialization.cpp" +#include "SPC_DSP.cpp" + +auto DSP::main() -> void { + if(!configuration.hacks.dsp.fast) { + spc_dsp.run(1); + clock += 2; + } else { + spc_dsp.run(32); + clock += 2 * 32; + } + + int count = spc_dsp.sample_count(); + if(count > 0) { + if(!system.runAhead) + for(uint n = 0; n < count; n += 2) { + float left = samplebuffer[n + 0] / 32768.0f; + float right = samplebuffer[n + 1] / 32768.0f; + stream->sample(left, right); + } + spc_dsp.set_output(samplebuffer, 8192); + } +} + +auto DSP::read(uint8 address) -> uint8 { + return spc_dsp.read(address); +} + +auto DSP::write(uint8 address, uint8 data) -> void { + if(configuration.hacks.dsp.echoShadow) { + if(address == 0x6c && (data & 0x20)) { + memset(echoram, 0x00, 65536); + } + } + + spc_dsp.write(address, data); +} + +auto DSP::load() -> bool { + return true; +} + +auto DSP::power(bool reset) -> void { + clock = 0; + stream = Emulator::audio.createStream(2, system.apuFrequency() / 768.0); + + if(!reset) { + if(!configuration.hacks.dsp.echoShadow) { + spc_dsp.init(apuram, apuram); + } else { + memset(echoram, 0x00, 65536); + spc_dsp.init(apuram, echoram); + } + spc_dsp.reset(); + spc_dsp.set_output(samplebuffer, 8192); + } else { + spc_dsp.soft_reset(); + spc_dsp.set_output(samplebuffer, 8192); + } + + if(configuration.hacks.hotfixes) { + //Magical Drop (Japan) does not initialize the DSP registers at startup: + //tokoton mode will hang forever in some instances even on real hardware. + if(cartridge.headerTitle() == "MAGICAL DROP") { + for(uint address : range(0x80)) spc_dsp.write(address, 0xff); + } + } +} + +auto DSP::mute() -> bool { + return spc_dsp.mute(); +} + +} diff --git a/sfc/dsp/dsp.hpp b/sfc/dsp/dsp.hpp new file mode 100644 index 0000000..1cc97f0 --- /dev/null +++ b/sfc/dsp/dsp.hpp @@ -0,0 +1,28 @@ +#include "SPC_DSP.h" + +struct DSP { + shared_pointer stream; + uint8 apuram[64 * 1024] = {}; + + auto main() -> void; + auto read(uint8 address) -> uint8; + auto write(uint8 address, uint8 data) -> void; + + auto load() -> bool; + auto power(bool reset) -> void; + auto mute() -> bool; + + auto serialize(serializer&) -> void; + + int64 clock = 0; + +private: + bool fastDSP = false; + SPC_DSP spc_dsp; + int16 samplebuffer[8192]; + +//unserialized: + uint8 echoram[64 * 1024] = {}; +}; + +extern DSP dsp; diff --git a/sfc/dsp/serialization.cpp b/sfc/dsp/serialization.cpp new file mode 100644 index 0000000..ec45155 --- /dev/null +++ b/sfc/dsp/serialization.cpp @@ -0,0 +1,28 @@ +static auto dsp_state_save(unsigned char** out, void* in, size_t size) -> void { + memcpy(*out, in, size); + *out += size; +} + +static auto dsp_state_load(unsigned char** in, void* out, size_t size) -> void { + memcpy(out, *in, size); + *in += size; +} + +auto DSP::serialize(serializer& s) -> void { + s.array(apuram); + s.array(samplebuffer); + s.integer(clock); + + 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); + } +} diff --git a/sfc/expansion/21fx/21fx.cpp b/sfc/expansion/21fx/21fx.cpp new file mode 100644 index 0000000..dbf891c --- /dev/null +++ b/sfc/expansion/21fx/21fx.cpp @@ -0,0 +1,145 @@ +#include + +namespace SuperFamicom { + +S21FX::S21FX() { + create(S21FX::Enter, 10'000'000); + + resetVector.byte(0) = bus.read(0xfffc, 0x00); + resetVector.byte(1) = bus.read(0xfffd, 0x00); + + bus.map({&S21FX::read, this}, {&S21FX::write, this}, "00-3f,80-bf:2184-21ff"); + bus.map({&S21FX::read, this}, {&S21FX::write, this}, "00:fffc-fffd"); + + booted = false; + + for(auto& byte : ram) byte = 0xdb; //stp + ram[0] = 0x6c; //jmp ($fffc) + ram[1] = 0xfc; + ram[2] = 0xff; + + if(auto buffer = file::read({platform->path(ID::System), "21fx.rom"})) { + memory::copy(ram, sizeof(ram), buffer.data(), buffer.size()); + } + + string filename{platform->path(ID::SuperFamicom), "21fx.so"}; + if(link.openAbsolute(filename)) { + linkInit = link.sym("fx_init"); + linkMain = link.sym("fx_main"); + } +} + +S21FX::~S21FX() { + scheduler.remove(*this); + bus.unmap("00-3f,80-bf:2184-21ff"); + bus.unmap("00:fffc-fffd"); + + //note: this is an awful hack ... + //since the bus maps are lambdas, we can't safely restore the original reset vector handler + //as such, we install a basic read-only lambda that simply returns the known reset vector + //the downside is that if 00:fffc-fffd were anything but ROM; it will now only act as ROM + //given that this is the only device that hooks the reset vector like this, + //it's not worth the added complexity to support some form of reversible bus mapping hooks + uint vector = resetVector; + bus.map([vector](uint24 addr, uint8) -> uint8 { + return vector >> addr * 8; + }, [](uint24, uint8) -> void { + }, "00:fffc-fffd", 2); + + if(link.open()) link.close(); + linkInit.reset(); + linkMain.reset(); +} + +auto S21FX::Enter() -> void { + while(true) scheduler.synchronize(), expansionPort.device->main(); +} + +auto S21FX::step(uint clocks) -> void { + Thread::step(clocks); + synchronize(cpu); +} + +auto S21FX::main() -> void { + if(linkInit) linkInit( + {&S21FX::quit, this}, + {&S21FX::usleep, this}, + {&S21FX::readable, this}, + {&S21FX::writable, this}, + {&S21FX::read, this}, + {&S21FX::write, this} + ); + if(linkMain) linkMain({}); + while(true) step(10'000'000); +} + +auto S21FX::read(uint addr, uint8 data) -> uint8 { + addr &= 0x40ffff; + + if(addr == 0xfffc) return booted ? resetVector.byte(0) : (uint8)0x84; + if(addr == 0xfffd) return booted ? resetVector.byte(1) : (booted = true, (uint8)0x21); + + if(addr >= 0x2184 && addr <= 0x21fd) return ram[addr - 0x2184]; + + if(addr == 0x21fe) return !link.open() ? 0 : ( + (linkBuffer.size() > 0) << 7 //1 = readable + | (snesBuffer.size() < 1024) << 6 //1 = writable + | (link.open()) << 5 //1 = connected + ); + + if(addr == 0x21ff) { + if(linkBuffer.size() > 0) { + return linkBuffer.takeLeft(); + } + } + + return data; +} + +auto S21FX::write(uint addr, uint8 data) -> void { + addr &= 0x40ffff; + + if(addr == 0x21ff) { + if(snesBuffer.size() < 1024) { + snesBuffer.append(data); + } + } +} + +auto S21FX::quit() -> bool { + step(1); + return false; +} + +auto S21FX::usleep(uint microseconds) -> void { + step(10 * microseconds); +} + +auto S21FX::readable() -> bool { + step(1); + return snesBuffer.size() > 0; +} + +auto S21FX::writable() -> bool { + step(1); + return linkBuffer.size() < 1024; +} + +//SNES -> Link +auto S21FX::read() -> uint8 { + step(1); + if(snesBuffer.size() > 0) { + return snesBuffer.takeLeft(); + } + return 0x00; +} + +//Link -> SNES +auto S21FX::write(uint8 data) -> void { + step(1); + if(linkBuffer.size() < 1024) { + linkBuffer.append(data); + } +} + +} diff --git a/sfc/expansion/21fx/21fx.hpp b/sfc/expansion/21fx/21fx.hpp new file mode 100644 index 0000000..63e7c9d --- /dev/null +++ b/sfc/expansion/21fx/21fx.hpp @@ -0,0 +1,37 @@ +struct S21FX : Expansion { + S21FX(); + ~S21FX(); + + static auto Enter() -> void; + auto step(uint clocks) -> void; + auto main() -> void; + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + +private: + auto quit() -> bool; + auto usleep(uint) -> void; + auto readable() -> bool; + auto writable() -> bool; + auto read() -> uint8; + auto write(uint8) -> void; + + bool booted = false; + uint16 resetVector; + uint8 ram[122]; + + nall::library link; + function, //quit + function, //usleep + function, //readable + function, //writable + function, //read + function //write + )> linkInit; + function)> linkMain; + + vector snesBuffer; //SNES -> Link + vector linkBuffer; //Link -> SNES +}; diff --git a/sfc/expansion/expansion.cpp b/sfc/expansion/expansion.cpp new file mode 100644 index 0000000..497a8f1 --- /dev/null +++ b/sfc/expansion/expansion.cpp @@ -0,0 +1,39 @@ +#include +#include +//#include + +namespace SuperFamicom { + +ExpansionPort expansionPort; + +Expansion::Expansion() { +} + +Expansion::~Expansion() { +} + +// + +auto ExpansionPort::connect(uint deviceID) -> void { + if(!system.loaded()) return; + delete device; + + switch(deviceID) { default: + case ID::Device::None: device = new Expansion; break; + case ID::Device::Satellaview: device = new Satellaview; break; +//case ID::Device::S21FX: device = new S21FX; break; + } +} + +auto ExpansionPort::power() -> void { +} + +auto ExpansionPort::unload() -> void { + delete device; + device = nullptr; +} + +auto ExpansionPort::serialize(serializer& s) -> void { +} + +} diff --git a/sfc/expansion/expansion.hpp b/sfc/expansion/expansion.hpp new file mode 100644 index 0000000..78e0e0e --- /dev/null +++ b/sfc/expansion/expansion.hpp @@ -0,0 +1,19 @@ +struct Expansion : Thread { + Expansion(); + virtual ~Expansion(); +}; + +struct ExpansionPort { + auto connect(uint deviceID) -> void; + + auto power() -> void; + auto unload() -> void; + auto serialize(serializer&) -> void; + + Expansion* device = nullptr; +}; + +extern ExpansionPort expansionPort; + +#include +//#include diff --git a/sfc/expansion/satellaview/satellaview.cpp b/sfc/expansion/satellaview/satellaview.cpp new file mode 100644 index 0000000..74ffa9f --- /dev/null +++ b/sfc/expansion/satellaview/satellaview.cpp @@ -0,0 +1,129 @@ +#include + +namespace SuperFamicom { + +Satellaview::Satellaview() { + bus.map({&Satellaview::read, this}, {&Satellaview::write, this}, "00-3f,80-bf:2188-219f"); + regs = {}; +} + +Satellaview::~Satellaview() { + bus.unmap("00-3f,80-bf:2188-219f"); +} + +auto Satellaview::read(uint addr, uint8 data) -> uint8 { + switch(addr &= 0xffff) { + 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: { + uint counter = regs.rtcCounter++; + if(regs.rtcCounter >= 18) regs.rtcCounter = 0; + + if(counter == 0) { + time_t rawtime; + time(&rawtime); + tm* t = localtime(&rawtime); + + regs.rtcHour = t->tm_hour; + regs.rtcMinute = t->tm_min; + regs.rtcSecond = 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.rtcSecond; + case 11: return regs.rtcMinute; + case 12: return regs.rtcHour; + 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 data; +} + +auto Satellaview::write(uint addr, uint8 data) -> void { + switch(addr &= 0xffff) { + 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.rtcCounter = 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; + } +} + +} diff --git a/sfc/expansion/satellaview/satellaview.hpp b/sfc/expansion/satellaview/satellaview.hpp new file mode 100644 index 0000000..57c355c --- /dev/null +++ b/sfc/expansion/satellaview/satellaview.hpp @@ -0,0 +1,22 @@ +struct Satellaview : Expansion { + Satellaview(); + ~Satellaview(); + + auto read(uint addr, uint8 data) -> uint8; + auto write(uint addr, uint8 data) -> void; + +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 rtcCounter; + uint8 rtcHour; + uint8 rtcMinute; + uint8 rtcSecond; + } regs; +}; diff --git a/sfc/interface/configuration.cpp b/sfc/interface/configuration.cpp new file mode 100644 index 0000000..c689ad1 --- /dev/null +++ b/sfc/interface/configuration.cpp @@ -0,0 +1,76 @@ +Configuration configuration; + +auto Configuration::process(Markup::Node document, bool load) -> void { + #define bind(type, path, name) \ + if(load) { \ + if(auto node = document[path]) name = node.type(); \ + } else { \ + document(path).setValue(name); \ + } \ + + bind(natural, "System/CPU/Version", system.cpu.version); + bind(natural, "System/PPU1/Version", system.ppu1.version); + bind(natural, "System/PPU1/VRAM/Size", system.ppu1.vram.size); + bind(natural, "System/PPU2/Version", system.ppu2.version); + bind(text, "System/Serialization/Method", system.serialization.method); + + bind(boolean, "Video/BlurEmulation", video.blurEmulation); + bind(boolean, "Video/ColorEmulation", video.colorEmulation); + + bind(boolean, "Hacks/Hotfixes", hacks.hotfixes); + bind(text, "Hacks/Entropy", hacks.entropy); + bind(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock); + bind(boolean, "Hacks/CPU/FastMath", hacks.cpu.fastMath); + bind(boolean, "Hacks/CPU/FastJoypadPolling", hacks.cpu.fastJoypadPolling); + bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast); + bind(boolean, "Hacks/PPU/Deinterlace", hacks.ppu.deinterlace); + bind(natural, "Hacks/PPU/RenderCycle", hacks.ppu.renderCycle); + bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit); + bind(boolean, "Hacks/PPU/NoVRAMBlocking", hacks.ppu.noVRAMBlocking); + bind(natural, "Hacks/PPU/Mode7/Scale", hacks.ppu.mode7.scale); + bind(boolean, "Hacks/PPU/Mode7/Perspective", hacks.ppu.mode7.perspective); + bind(boolean, "Hacks/PPU/Mode7/Supersample", hacks.ppu.mode7.supersample); + bind(boolean, "Hacks/PPU/Mode7/Mosaic", hacks.ppu.mode7.mosaic); + bind(boolean, "Hacks/DSP/Fast", hacks.dsp.fast); + bind(boolean, "Hacks/DSP/Cubic", hacks.dsp.cubic); + bind(boolean, "Hacks/DSP/EchoShadow", hacks.dsp.echoShadow); + bind(boolean, "Hacks/Coprocessor/DelayedSync", hacks.coprocessor.delayedSync); + bind(boolean, "Hacks/Coprocessor/PreferHLE", hacks.coprocessor.preferHLE); + bind(natural, "Hacks/SA1/Overclock", hacks.sa1.overclock); + bind(natural, "Hacks/SuperFX/Overclock", hacks.superfx.overclock); + + #undef bind +} + +auto Configuration::read() -> string { + Markup::Node document; + process(document, false); + return BML::serialize(document, " "); +} + +auto Configuration::read(string name) -> string { + auto document = BML::unserialize(read()); + return document[name].text(); +} + +auto Configuration::write(string configuration) -> bool { + *this = {}; + + if(auto document = BML::unserialize(configuration)) { + return process(document, true), true; + } + + return false; +} + +auto Configuration::write(string name, string value) -> bool { + if(SuperFamicom::system.loaded() && name.beginsWith("System/")) return false; + + auto document = BML::unserialize(read()); + if(auto node = document[name]) { + node.setValue(value); + return process(document, true), true; + } + + return false; +} diff --git a/sfc/interface/configuration.hpp b/sfc/interface/configuration.hpp new file mode 100644 index 0000000..bcf6345 --- /dev/null +++ b/sfc/interface/configuration.hpp @@ -0,0 +1,72 @@ +struct Configuration { + auto read() -> string; + auto read(string) -> string; + auto write(string) -> bool; + auto write(string, string) -> bool; + + struct System { + struct CPU { + uint version = 2; + } cpu; + struct PPU1 { + uint version = 1; + struct VRAM { + uint size = 0x10000; + } vram; + } ppu1; + struct PPU2 { + uint version = 3; + } ppu2; + struct Serialization { + string method = "Fast"; + } serialization; + } system; + + struct Video { + bool blurEmulation = true; + bool colorEmulation = true; + } video; + + struct Hacks { + bool hotfixes = true; + string entropy = "Low"; + struct CPU { + uint overclock = 100; + bool fastMath = false; + bool fastJoypadPolling = false; + } cpu; + struct PPU { + bool fast = true; + bool deinterlace = true; + bool noSpriteLimit = false; + bool noVRAMBlocking = false; + uint renderCycle = 512; + struct Mode7 { + uint scale = 1; + bool perspective = true; + bool supersample = false; + bool mosaic = true; + } mode7; + } ppu; + struct DSP { + bool fast = true; + bool cubic = false; + bool echoShadow = false; + } dsp; + struct Coprocessor { + bool delayedSync = true; + bool preferHLE = false; + } coprocessor; + struct SA1 { + uint overclock = 100; + } sa1; + struct SuperFX { + uint overclock = 100; + } superfx; + } hacks; + +private: + auto process(Markup::Node document, bool load) -> void; +}; + +extern Configuration configuration; diff --git a/sfc/interface/interface.cpp b/sfc/interface/interface.cpp new file mode 100644 index 0000000..51d3b9b --- /dev/null +++ b/sfc/interface/interface.cpp @@ -0,0 +1,344 @@ +#include + +namespace SuperFamicom { + +Settings settings; +#include "configuration.cpp" + +auto Interface::information() -> Information { + Information information; + information.manufacturer = "Nintendo"; + information.name = "Super Famicom"; + information.extension = "sfc"; + information.resettable = true; + return information; +} + +auto Interface::display() -> Display { + Display display; + display.type = Display::Type::CRT; + display.colors = 1 << 19; + display.width = 256; + display.height = 240; + display.internalWidth = 512; + display.internalHeight = 480; + display.aspectCorrection = 8.0 / 7.0; + return display; +} + +auto Interface::color(uint32 color) -> uint64 { + uint r = color >> 0 & 31; + uint g = color >> 5 & 31; + uint b = color >> 10 & 31; + uint l = color >> 15 & 15; + + //luma=0 is not 100% black; but it's much darker than normal linear scaling + //exact effect seems to be analog; requires > 24-bit color depth to represent accurately + double L = (1.0 + l) / 16.0 * (l ? 1.0 : 0.25); + uint64 R = L * image::normalize(r, 5, 16); + uint64 G = L * image::normalize(g, 5, 16); + uint64 B = L * image::normalize(b, 5, 16); + + if(SuperFamicom::configuration.video.colorEmulation) { + static const uint8 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, + }; + R = L * gammaRamp[r] * 0x0101; + G = L * gammaRamp[g] * 0x0101; + B = L * gammaRamp[b] * 0x0101; + } + + return R << 32 | G << 16 | B << 0; +} + +auto Interface::loaded() -> bool { + return system.loaded(); +} + +auto Interface::hashes() -> vector { + return cartridge.hashes(); +} + +auto Interface::manifests() -> vector { + return cartridge.manifests(); +} + +auto Interface::titles() -> vector { + return cartridge.titles(); +} + +auto Interface::title() -> string { + return cartridge.title(); +} + +auto Interface::load() -> bool { + return system.load(this); +} + +auto Interface::save() -> void { + system.save(); +} + +auto Interface::unload() -> void { + save(); + system.unload(); +} + +auto Interface::ports() -> vector { return { + {ID::Port::Controller1, "Controller Port 1"}, + {ID::Port::Controller2, "Controller Port 2"}, + {ID::Port::Expansion, "Expansion Port" }}; +} + +auto Interface::devices(uint port) -> vector { + if(port == ID::Port::Controller1) return { + {ID::Device::None, "None" }, + {ID::Device::Gamepad, "Gamepad"}, + {ID::Device::Mouse, "Mouse" } + }; + + if(port == ID::Port::Controller2) return { + {ID::Device::None, "None" }, + {ID::Device::Gamepad, "Gamepad" }, + {ID::Device::Mouse, "Mouse" }, + {ID::Device::SuperMultitap, "Super Multitap"}, + {ID::Device::SuperScope, "Super Scope" }, + {ID::Device::Justifier, "Justifier" }, + {ID::Device::Justifiers, "Justifiers" } + }; + + if(port == ID::Port::Expansion) return { + {ID::Device::None, "None" }, + {ID::Device::Satellaview, "Satellaview"}, + {ID::Device::S21FX, "21fx" } + }; + + return {}; +} + +auto Interface::inputs(uint device) -> vector { + using Type = Input::Type; + + if(device == ID::Device::None) return { + }; + + if(device == ID::Device::Gamepad) return { + {Type::Hat, "Up" }, + {Type::Hat, "Down" }, + {Type::Hat, "Left" }, + {Type::Hat, "Right" }, + {Type::Button, "B" }, + {Type::Button, "A" }, + {Type::Button, "Y" }, + {Type::Button, "X" }, + {Type::Trigger, "L" }, + {Type::Trigger, "R" }, + {Type::Control, "Select"}, + {Type::Control, "Start" } + }; + + if(device == ID::Device::Mouse) return { + {Type::Axis, "X-axis"}, + {Type::Axis, "Y-axis"}, + {Type::Button, "Left" }, + {Type::Button, "Right" } + }; + + if(device == ID::Device::SuperMultitap) { + vector inputs; + for(uint p = 2; p <= 5; p++) inputs.append({ + {Type::Hat, {"Port ", p, " - ", "Up" }}, + {Type::Hat, {"Port ", p, " - ", "Down" }}, + {Type::Hat, {"Port ", p, " - ", "Left" }}, + {Type::Hat, {"Port ", p, " - ", "Right" }}, + {Type::Button, {"Port ", p, " - ", "B" }}, + {Type::Button, {"Port ", p, " - ", "A" }}, + {Type::Button, {"Port ", p, " - ", "Y" }}, + {Type::Button, {"Port ", p, " - ", "X" }}, + {Type::Trigger, {"Port ", p, " - ", "L" }}, + {Type::Trigger, {"Port ", p, " - ", "R" }}, + {Type::Control, {"Port ", p, " - ", "Select"}}, + {Type::Control, {"Port ", p, " - ", "Start" }} + }); + return inputs; + } + + if(device == ID::Device::SuperScope) return { + {Type::Axis, "X-axis" }, + {Type::Axis, "Y-axis" }, + {Type::Control, "Trigger"}, + {Type::Control, "Cursor" }, + {Type::Control, "Turbo" }, + {Type::Control, "Pause" } + }; + + if(device == ID::Device::Justifier) return { + {Type::Axis, "X-axis" }, + {Type::Axis, "Y-axis" }, + {Type::Control, "Trigger"}, + {Type::Control, "Start" } + }; + + if(device == ID::Device::Justifiers) return { + {Type::Axis, "Port 1 - X-axis" }, + {Type::Axis, "Port 1 - Y-axis" }, + {Type::Control, "Port 1 - Trigger"}, + {Type::Control, "Port 1 - Start" }, + {Type::Axis, "Port 2 - X-axis" }, + {Type::Axis, "Port 2 - Y-axis" }, + {Type::Control, "Port 2 - Trigger"}, + {Type::Control, "Port 2 - Start" } + }; + + if(device == ID::Device::Satellaview) return { + }; + + if(device == ID::Device::S21FX) return { + }; + + return {}; +} + +auto Interface::connected(uint port) -> uint { + if(port == ID::Port::Controller1) return settings.controllerPort1; + if(port == ID::Port::Controller2) return settings.controllerPort2; + if(port == ID::Port::Expansion) return settings.expansionPort; + return 0; +} + +auto Interface::connect(uint port, uint device) -> void { + if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); + if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); + if(port == ID::Port::Expansion) expansionPort.connect(settings.expansionPort = device); +} + +auto Interface::power() -> void { + system.power(/* reset = */ false); +} + +auto Interface::reset() -> void { + system.power(/* reset = */ true); +} + +auto Interface::run() -> void { + system.run(); +} + +auto Interface::rtc() -> bool { + if(cartridge.has.EpsonRTC) return true; + if(cartridge.has.SharpRTC) return true; + return false; +} + +auto Interface::synchronize(uint64 timestamp) -> void { + if(!timestamp) timestamp = chrono::timestamp(); + if(cartridge.has.EpsonRTC) epsonrtc.synchronize(timestamp); + if(cartridge.has.SharpRTC) sharprtc.synchronize(timestamp); +} + +auto Interface::serialize(bool synchronize) -> serializer { + return system.serialize(synchronize); +} + +auto Interface::unserialize(serializer& s) -> bool { + return system.unserialize(s); +} + +auto Interface::read(uint24 address) -> uint8 { + return cpu.readDisassembler(address); +} + +auto Interface::cheats(const vector& list) -> void { + if(cartridge.has.ICD) { + icd.cheats.assign(list); + return; + } + + //make all ROM data writable temporarily + Memory::GlobalWriteEnable = true; + + Cheat oldCheat = cheat; + Cheat newCheat; + newCheat.assign(list); + + //determine all old codes to remove + for(auto& oldCode : oldCheat.codes) { + bool found = false; + for(auto& newCode : newCheat.codes) { + if(oldCode == newCode) { + found = true; + break; + } + } + if(!found) { + //remove old cheat + if(oldCode.enable) { + bus.write(oldCode.address, oldCode.restore); + } + } + } + + //determine all new codes to create + for(auto& newCode : newCheat.codes) { + bool found = false; + for(auto& oldCode : oldCheat.codes) { + if(newCode == oldCode) { + found = true; + break; + } + } + if(!found) { + //create new cheat + newCode.restore = bus.read(newCode.address); + if(!newCode.compare || newCode.compare() == newCode.restore) { + newCode.enable = true; + bus.write(newCode.address, newCode.data); + } else { + newCode.enable = false; + } + } + } + + cheat = newCheat; + + //restore ROM write protection + Memory::GlobalWriteEnable = false; +} + +auto Interface::configuration() -> string { + return SuperFamicom::configuration.read(); +} + +auto Interface::configuration(string name) -> string { + return SuperFamicom::configuration.read(name); +} + +auto Interface::configure(string configuration) -> bool { + return SuperFamicom::configuration.write(configuration); +} + +auto Interface::configure(string name, string value) -> bool { + return SuperFamicom::configuration.write(name, value); +} + +auto Interface::frameSkip() -> uint { + return system.frameSkip; +} + +auto Interface::setFrameSkip(uint frameSkip) -> void { + system.frameSkip = frameSkip; + system.frameCounter = frameSkip; +} + +auto Interface::runAhead() -> bool { + return system.runAhead; +} + +auto Interface::setRunAhead(bool runAhead) -> void { + system.runAhead = runAhead; +} + +} diff --git a/sfc/interface/interface.hpp b/sfc/interface/interface.hpp new file mode 100644 index 0000000..d943748 --- /dev/null +++ b/sfc/interface/interface.hpp @@ -0,0 +1,90 @@ +namespace SuperFamicom { + +struct ID { + enum : uint { + System, + SuperFamicom, + GameBoy, + BSMemory, + SufamiTurboA, + SufamiTurboB, + }; + + struct Port { enum : uint { + Controller1, + Controller2, + Expansion, + };}; + + struct Device { enum : uint { + None, + Gamepad, + Mouse, + SuperMultitap, + SuperScope, + Justifier, + Justifiers, + + Satellaview, + S21FX, + };}; +}; + +struct Interface : Emulator::Interface { + auto information() -> Information; + + auto display() -> Display override; + auto color(uint32 color) -> uint64 override; + + auto loaded() -> bool override; + auto hashes() -> vector override; + auto manifests() -> vector override; + auto titles() -> vector override; + auto title() -> string override; + auto load() -> bool override; + auto save() -> void override; + auto unload() -> void override; + + auto ports() -> vector override; + auto devices(uint port) -> vector override; + auto inputs(uint device) -> vector override; + + auto connected(uint port) -> uint override; + auto connect(uint port, uint device) -> void override; + auto power() -> void override; + auto reset() -> void override; + auto run() -> void override; + + auto rtc() -> bool override; + auto synchronize(uint64 timestamp) -> void override; + + auto serialize(bool synchronize = true) -> serializer override; + auto unserialize(serializer&) -> bool override; + + auto read(uint24 address) -> uint8 override; + auto cheats(const vector&) -> void override; + + auto configuration() -> string override; + auto configuration(string name) -> string override; + auto configure(string configuration) -> bool override; + auto configure(string name, string value) -> bool override; + + auto frameSkip() -> uint override; + auto setFrameSkip(uint frameSkip) -> void override; + + auto runAhead() -> bool override; + auto setRunAhead(bool runAhead) -> void override; +}; + +#include "configuration.hpp" + +struct Settings { + uint controllerPort1 = ID::Device::Gamepad; + uint controllerPort2 = ID::Device::Gamepad; + uint expansionPort = ID::Device::None; + bool random = true; +}; + +extern Settings settings; + +} diff --git a/sfc/memory/memory-inline.hpp b/sfc/memory/memory-inline.hpp new file mode 100644 index 0000000..c20d0ec --- /dev/null +++ b/sfc/memory/memory-inline.hpp @@ -0,0 +1,32 @@ +auto Bus::mirror(uint addr, uint size) -> uint { + if(size == 0) return 0; + uint base = 0; + uint mask = 1 << 23; + while(addr >= size) { + while(!(addr & mask)) mask >>= 1; + addr -= mask; + if(size > mask) { + size -= mask; + base += mask; + } + mask >>= 1; + } + return base + addr; +} + +auto Bus::reduce(uint addr, uint mask) -> uint { + while(mask) { + uint bits = (mask & -mask) - 1; + addr = ((addr >> 1) & ~bits) | (addr & bits); + mask = (mask & (mask - 1)) >> 1; + } + return addr; +} + +auto Bus::read(uint addr, uint8 data) -> uint8 { + return reader[lookup[addr]](target[addr], data); +} + +auto Bus::write(uint addr, uint8 data) -> void { + return writer[lookup[addr]](target[addr], data); +} diff --git a/sfc/memory/memory.cpp b/sfc/memory/memory.cpp new file mode 100644 index 0000000..4b76009 --- /dev/null +++ b/sfc/memory/memory.cpp @@ -0,0 +1,106 @@ +#include + +namespace SuperFamicom { + +bool Memory::GlobalWriteEnable = false; +Bus bus; + +Bus::~Bus() { + if(lookup) delete[] lookup; + if(target) delete[] target; +} + +auto Bus::reset() -> void { + for(uint id : range(256)) { + reader[id].reset(); + writer[id].reset(); + counter[id] = 0; + } + + if(lookup) delete[] lookup; + if(target) delete[] target; + + lookup = new uint8 [16 * 1024 * 1024](); + target = new uint32[16 * 1024 * 1024](); + + reader[0] = [](uint, uint8 data) -> uint8 { return data; }; + writer[0] = [](uint, uint8) -> void {}; +} + +auto Bus::map( + const function& read, + const function& write, + const string& addr, uint size, uint base, uint mask +) -> uint { + uint id = 1; + while(counter[id]) { + if(++id >= 256) return print("SFC error: bus map exhausted\n"), 0; + } + + reader[id] = read; + writer[id] = write; + + auto p = addr.split(":", 1L); + auto banks = p(0).split(","); + auto addrs = p(1).split(","); + for(auto& bank : banks) { + for(auto& addr : addrs) { + auto bankRange = bank.split("-", 1L); + auto addrRange = addr.split("-", 1L); + uint bankLo = bankRange(0).hex(); + uint bankHi = bankRange(1, bankRange(0)).hex(); + uint addrLo = addrRange(0).hex(); + uint addrHi = addrRange(1, addrRange(0)).hex(); + + for(uint bank = bankLo; bank <= bankHi; bank++) { + for(uint addr = addrLo; addr <= addrHi; addr++) { + uint pid = lookup[bank << 16 | addr]; + if(pid && --counter[pid] == 0) { + reader[pid].reset(); + writer[pid].reset(); + } + + uint offset = reduce(bank << 16 | addr, mask); + if(size) base = mirror(base, size); + if(size) offset = base + mirror(offset, size - base); + lookup[bank << 16 | addr] = id; + target[bank << 16 | addr] = offset; + counter[id]++; + } + } + } + } + + return id; +} + +auto Bus::unmap(const string& addr) -> void { + auto p = addr.split(":", 1L); + auto banks = p(0).split(","); + auto addrs = p(1).split(","); + for(auto& bank : banks) { + for(auto& addr : addrs) { + auto bankRange = bank.split("-", 1L); + auto addrRange = addr.split("-", 1L); + uint bankLo = bankRange(0).hex(); + uint bankHi = bankRange(1, bankRange(0)).hex(); + uint addrLo = addrRange(0).hex(); + uint addrHi = addrRange(1, addrRange(1)).hex(); + + for(uint bank = bankLo; bank <= bankHi; bank++) { + for(uint addr = addrLo; addr <= addrHi; addr++) { + uint pid = lookup[bank << 16 | addr]; + if(pid && --counter[pid] == 0) { + reader[pid].reset(); + writer[pid].reset(); + } + + lookup[bank << 16 | addr] = 0; + target[bank << 16 | addr] = 0; + } + } + } + } +} + +} diff --git a/sfc/memory/memory.hpp b/sfc/memory/memory.hpp new file mode 100644 index 0000000..fa02830 --- /dev/null +++ b/sfc/memory/memory.hpp @@ -0,0 +1,49 @@ +struct Memory { + static bool GlobalWriteEnable; + + virtual ~Memory() { reset(); } + inline explicit operator bool() const { return size() > 0; } + + virtual auto reset() -> void {} + virtual auto allocate(uint, uint8 = 0xff) -> void {} + + virtual auto data() -> uint8* = 0; + virtual auto size() const -> uint = 0; + + virtual auto read(uint address, uint8 data = 0) -> uint8 = 0; + virtual auto write(uint address, uint8 data) -> void = 0; + + uint id = 0; +}; + +#include "readable.hpp" +#include "writable.hpp" +#include "protectable.hpp" + +struct Bus { + alwaysinline static auto mirror(uint address, uint size) -> uint; + alwaysinline static auto reduce(uint address, uint mask) -> uint; + + ~Bus(); + + alwaysinline auto read(uint address, uint8 data = 0) -> uint8; + alwaysinline auto write(uint address, uint8 data) -> void; + + auto reset() -> void; + auto map( + const function& read, + const function& write, + const string& address, uint size = 0, uint base = 0, uint mask = 0 + ) -> uint; + auto unmap(const string& address) -> void; + +private: + uint8* lookup = nullptr; + uint32* target = nullptr; + + function reader[256]; + function writer[256]; + uint counter[256]; +}; + +extern Bus bus; diff --git a/sfc/memory/protectable.hpp b/sfc/memory/protectable.hpp new file mode 100644 index 0000000..a6f8a5b --- /dev/null +++ b/sfc/memory/protectable.hpp @@ -0,0 +1,54 @@ +struct ProtectableMemory : Memory { + inline auto reset() -> void override { + delete[] self.data; + self.data = nullptr; + self.size = 0; + } + + inline auto allocate(uint size, uint8 fill = 0xff) -> void override { + if(self.size != size) { + delete[] self.data; + self.data = new uint8[self.size = size]; + } + for(uint address : range(size)) { + self.data[address] = fill; + } + } + + inline auto data() -> uint8* override { + return self.data; + } + + inline auto size() const -> uint override { + return self.size; + } + + inline auto writable() const -> bool { + return self.writable; + } + + inline auto writable(bool writable) -> void { + self.writable = writable; + } + + inline auto read(uint address, uint8 data = 0) -> uint8 override { + return self.data[address]; + } + + inline auto write(uint address, uint8 data) -> void override { + if(self.writable || Memory::GlobalWriteEnable) { + self.data[address] = data; + } + } + + inline auto operator[](uint address) const -> uint8 { + return self.data[address]; + } + +private: + struct { + uint8* data = nullptr; + uint size = 0; + bool writable = false; + } self; +}; diff --git a/sfc/memory/readable.hpp b/sfc/memory/readable.hpp new file mode 100644 index 0000000..fcaf14b --- /dev/null +++ b/sfc/memory/readable.hpp @@ -0,0 +1,45 @@ +struct ReadableMemory : Memory { + inline auto reset() -> void override { + delete[] self.data; + self.data = nullptr; + self.size = 0; + } + + inline auto allocate(uint size, uint8 fill = 0xff) -> void override { + if(self.size != size) { + delete[] self.data; + self.data = new uint8[self.size = size]; + } + for(uint address : range(size)) { + self.data[address] = fill; + } + } + + inline auto data() -> uint8* override { + return self.data; + } + + inline auto size() const -> uint override { + return self.size; + } + + inline auto read(uint address, uint8 data = 0) -> uint8 override { + return self.data[address]; + } + + inline auto write(uint address, uint8 data) -> void override { + if(Memory::GlobalWriteEnable) { + self.data[address] = data; + } + } + + inline auto operator[](uint address) const -> uint8 { + return self.data[address]; + } + +private: + struct { + uint8* data = nullptr; + uint size = 0; + } self; +}; diff --git a/sfc/memory/writable.hpp b/sfc/memory/writable.hpp new file mode 100644 index 0000000..7d51303 --- /dev/null +++ b/sfc/memory/writable.hpp @@ -0,0 +1,43 @@ +struct WritableMemory : Memory { + inline auto reset() -> void override { + delete[] self.data; + self.data = nullptr; + self.size = 0; + } + + inline auto allocate(uint size, uint8 fill = 0xff) -> void override { + if(self.size != size) { + delete[] self.data; + self.data = new uint8[self.size = size]; + } + for(uint address : range(size)) { + self.data[address] = fill; + } + } + + inline auto data() -> uint8* override { + return self.data; + } + + inline auto size() const -> uint override { + return self.size; + } + + inline auto read(uint address, uint8 data = 0) -> uint8 override { + return self.data[address]; + } + + inline auto write(uint address, uint8 data) -> void override { + self.data[address] = data; + } + + inline auto operator[](uint address) -> uint8& { + return self.data[address]; + } + +private: + struct { + uint8* data = nullptr; + uint size = 0; + } self; +}; diff --git a/sfc/ppu-fast/background.cpp b/sfc/ppu-fast/background.cpp new file mode 100644 index 0000000..ffa6867 --- /dev/null +++ b/sfc/ppu-fast/background.cpp @@ -0,0 +1,158 @@ +auto PPU::Line::renderBackground(PPU::IO::Background& self, uint8 source) -> void { + if(!self.aboveEnable && !self.belowEnable) return; + if(self.tileMode == TileMode::Mode7) return renderMode7(self, source); + if(self.tileMode == TileMode::Inactive) return; + + bool windowAbove[256]; + bool windowBelow[256]; + renderWindow(self.window, self.window.aboveEnable, windowAbove); + renderWindow(self.window, self.window.belowEnable, windowBelow); + + bool hires = io.bgMode == 5 || io.bgMode == 6; + bool offsetPerTileMode = io.bgMode == 2 || io.bgMode == 4 || io.bgMode == 6; + bool directColorMode = io.col.directColor && source == Source::BG1 && (io.bgMode == 3 || io.bgMode == 4); + uint colorShift = 3 + self.tileMode; + int width = 256 << hires; + + uint tileHeight = 3 + self.tileSize; + uint tileWidth = !hires ? tileHeight : 4; + uint tileMask = 0x0fff >> self.tileMode; + uint tiledataIndex = self.tiledataAddress >> 3 + self.tileMode; + + uint paletteBase = io.bgMode == 0 ? source << 5 : 0; + uint paletteShift = 2 << self.tileMode; + + uint hscroll = self.hoffset; + uint vscroll = self.voffset; + uint hmask = (width << self.tileSize << !!(self.screenSize & 1)) - 1; + uint vmask = (width << self.tileSize << !!(self.screenSize & 2)) - 1; + + uint y = this->y; + if(self.mosaicEnable) y -= io.mosaic.size - io.mosaic.counter; + if(hires) { + hscroll <<= 1; + if(io.interlace) { + y = y << 1 | field(); + if(self.mosaicEnable) y -= io.mosaic.size - io.mosaic.counter + field(); + } + } + + uint mosaicCounter = 1; + uint mosaicPalette = 0; + uint8 mosaicPriority = 0; + uint16 mosaicColor = 0; + + int x = 0 - (hscroll & 7); + while(x < width) { + uint hoffset = x + hscroll; + uint voffset = y + vscroll; + if(offsetPerTileMode) { + uint validBit = 0x2000 << source; + uint offsetX = x + (hscroll & 7); + if(offsetX >= 8) { //first column is exempt + uint hlookup = getTile(io.bg3, (offsetX - 8) + (io.bg3.hoffset & ~7), io.bg3.voffset + 0); + if(io.bgMode == 4) { + if(hlookup & validBit) { + if(!(hlookup & 0x8000)) { + hoffset = offsetX + (hlookup & ~7); + } else { + voffset = y + hlookup; + } + } + } else { + uint vlookup = getTile(io.bg3, (offsetX - 8) + (io.bg3.hoffset & ~7), io.bg3.voffset + 8); + if(hlookup & validBit) { + hoffset = offsetX + (hlookup & ~7); + } + if(vlookup & validBit) { + voffset = y + vlookup; + } + } + } + } + hoffset &= hmask; + voffset &= vmask; + + uint tileNumber = getTile(self, hoffset, voffset); + uint mirrorY = tileNumber & 0x8000 ? 7 : 0; + uint mirrorX = tileNumber & 0x4000 ? 7 : 0; + uint8 tilePriority = self.priority[bool(tileNumber & 0x2000)]; + uint paletteNumber = tileNumber >> 10 & 7; + uint paletteIndex = paletteBase + (paletteNumber << paletteShift) & 0xff; + + if(tileWidth == 4 && (bool(hoffset & 8) ^ bool(mirrorX))) tileNumber += 1; + if(tileHeight == 4 && (bool(voffset & 8) ^ bool(mirrorY))) tileNumber += 16; + tileNumber = (tileNumber & 0x03ff) + tiledataIndex & tileMask; + + uint16 address; + address = (tileNumber << colorShift) + (voffset & 7 ^ mirrorY) & 0x7fff; + + uint64 data; + data = (uint64)ppu.vram[address + 0] << 0; + data |= (uint64)ppu.vram[address + 8] << 16; + data |= (uint64)ppu.vram[address + 16] << 32; + data |= (uint64)ppu.vram[address + 24] << 48; + + for(uint tileX = 0; tileX < 8; tileX++, x++) { + if(x & width) continue; //x < 0 || x >= width + if(--mosaicCounter == 0) { + uint color, shift = mirrorX ? tileX : 7 - tileX; + /*if(self.tileMode >= TileMode::BPP2)*/ { + color = data >> shift + 0 & 1; + color += data >> shift + 7 & 2; + } + if(self.tileMode >= TileMode::BPP4) { + color += data >> shift + 14 & 4; + color += data >> shift + 21 & 8; + } + if(self.tileMode >= TileMode::BPP8) { + color += data >> shift + 28 & 16; + color += data >> shift + 35 & 32; + color += data >> shift + 42 & 64; + color += data >> shift + 49 & 128; + } + + mosaicCounter = self.mosaicEnable ? io.mosaic.size : 1; + mosaicPalette = color; + mosaicPriority = tilePriority; + if(directColorMode) { + mosaicColor = directColor(paletteNumber, mosaicPalette); + } else { + mosaicColor = cgram[paletteIndex + mosaicPalette]; + } + } + if(!mosaicPalette) continue; + + if(!hires) { + if(self.aboveEnable && !windowAbove[x]) plotAbove(x, source, mosaicPriority, mosaicColor); + if(self.belowEnable && !windowBelow[x]) plotBelow(x, source, mosaicPriority, mosaicColor); + } else { + uint X = x >> 1; + if(!ppu.hd()) { + if(x & 1) { + if(self.aboveEnable && !windowAbove[X]) plotAbove(X, source, mosaicPriority, mosaicColor); + } else { + if(self.belowEnable && !windowBelow[X]) plotBelow(X, source, mosaicPriority, mosaicColor); + } + } else { + if(self.aboveEnable && !windowAbove[X]) plotHD(above, X, source, mosaicPriority, mosaicColor, true, x & 1); + if(self.belowEnable && !windowBelow[X]) plotHD(below, X, source, mosaicPriority, mosaicColor, true, x & 1); + } + } + } + } +} + +auto PPU::Line::getTile(PPU::IO::Background& self, uint hoffset, uint voffset) -> uint { + bool hires = io.bgMode == 5 || io.bgMode == 6; + uint tileHeight = 3 + self.tileSize; + uint tileWidth = !hires ? tileHeight : 4; + uint screenX = self.screenSize & 1 ? 32 << 5 : 0; + uint screenY = self.screenSize & 2 ? 32 << 5 + (self.screenSize & 1) : 0; + uint tileX = hoffset >> tileWidth; + uint tileY = voffset >> tileHeight; + uint offset = (tileY & 0x1f) << 5 | (tileX & 0x1f); + if(tileX & 0x20) offset += screenX; + if(tileY & 0x20) offset += screenY; + return ppu.vram[self.screenAddress + offset & 0x7fff]; +} diff --git a/sfc/ppu-fast/io.cpp b/sfc/ppu-fast/io.cpp new file mode 100644 index 0000000..4e445a0 --- /dev/null +++ b/sfc/ppu-fast/io.cpp @@ -0,0 +1,699 @@ +auto PPU::latchCounters(uint hcounter, uint vcounter) -> void { + io.hcounter = hcounter; + io.vcounter = vcounter; + latch.counters = 1; +} + +auto PPU::latchCounters() -> void { + io.hcounter = cpu.hdot(); + io.vcounter = cpu.vcounter(); + latch.counters = 1; +} + +auto PPU::vramAddress() const -> uint { + uint address = io.vramAddress; + switch(io.vramMapping) { + case 0: return address & 0x7fff; + case 1: return address & 0x7f00 | address << 3 & 0x00f8 | address >> 5 & 7; + case 2: return address & 0x7e00 | address << 3 & 0x01f8 | address >> 6 & 7; + case 3: return address & 0x7c00 | address << 3 & 0x03f8 | address >> 7 & 7; + } + unreachable; +} + +auto PPU::readVRAM() -> uint16 { + if(!io.displayDisable && cpu.vcounter() < vdisp()) return 0x0000; + auto address = vramAddress(); + return vram[address]; +} + +template +auto PPU::writeVRAM(uint8 data) -> void { + if(!io.displayDisable && cpu.vcounter() < vdisp() && !noVRAMBlocking()) return; + Line::flush(); + auto address = vramAddress(); + if constexpr(Byte == 0) { + vram[address] = vram[address] & 0xff00 | data << 0; + } + if constexpr(Byte == 1) { + vram[address] = vram[address] & 0x00ff | data << 8; + } +} + +auto PPU::readOAM(uint10 address) -> uint8 { + if(!io.displayDisable && cpu.vcounter() < vdisp()) address = latch.oamAddress; + return readObject(address); +} + +auto PPU::writeOAM(uint10 address, uint8 data) -> void { + Line::flush(); + //0x0218: Uniracers (2-player mode) hack; requires cycle timing for latch.oamAddress to be correct + if(!io.displayDisable && cpu.vcounter() < vdisp()) address = 0x0218; //latch.oamAddress; + return writeObject(address, data); +} + +template +auto PPU::readCGRAM(uint8 address) -> uint8 { + if(!io.displayDisable + && cpu.vcounter() > 0 && cpu.vcounter() < vdisp() + && cpu.hcounter() >= 88 && cpu.hcounter() < 1096 + ) address = latch.cgramAddress; + if constexpr(Byte == 0) { + return cgram[address] >> 0; + } + if constexpr(Byte == 1) { + return cgram[address] >> 8; + } +} + +auto PPU::writeCGRAM(uint8 address, uint15 data) -> void { + if(!io.displayDisable + && cpu.vcounter() > 0 && cpu.vcounter() < vdisp() + && cpu.hcounter() >= 88 && cpu.hcounter() < 1096 + ) address = latch.cgramAddress; + cgram[address] = data; +} + +auto PPU::readIO(uint address, uint8 data) -> uint8 { + cpu.synchronizePPU(); + + switch(address & 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 latch.ppu1.mdr; + } + + case 0x2134: { //MPYL + uint result = (int16)io.mode7.a * (int8)(io.mode7.b >> 8); + return latch.ppu1.mdr = result >> 0; + } + + case 0x2135: { //MPYM + uint result = (int16)io.mode7.a * (int8)(io.mode7.b >> 8); + return latch.ppu1.mdr = result >> 8; + } + + case 0x2136: { //MPYH + uint result = (int16)io.mode7.a * (int8)(io.mode7.b >> 8); + return latch.ppu1.mdr = result >> 16; + } + + case 0x2137: { //SLHV + if(cpu.pio() & 0x80) latchCounters(); + return data; //CPU MDR + } + + case 0x2138: { //OAMDATAREAD + data = readOAM(io.oamAddress); + io.oamAddress = io.oamAddress + 1 & 0x3ff; + oamSetFirstObject(); + return latch.ppu1.mdr = data; + } + + case 0x2139: { //VMDATALREAD + data = latch.vram >> 0; + if(io.vramIncrementMode == 0) { + latch.vram = readVRAM(); + io.vramAddress += io.vramIncrementSize; + } + return latch.ppu1.mdr = data; + } + + case 0x213a: { //VMDATAHREAD + data = latch.vram >> 8; + if(io.vramIncrementMode == 1) { + latch.vram = readVRAM(); + io.vramAddress += io.vramIncrementSize; + } + return latch.ppu1.mdr = data; + } + + case 0x213b: { //CGDATAREAD + if(io.cgramAddressLatch == 0) { + io.cgramAddressLatch = 1; + latch.ppu2.mdr = readCGRAM<0>(io.cgramAddress); + } else { + io.cgramAddressLatch = 0; + latch.ppu2.mdr = readCGRAM<1>(io.cgramAddress++) & 0x7f | latch.ppu2.mdr & 0x80; + } + return latch.ppu2.mdr; + } + + case 0x213c: { //OPHCT + if(latch.hcounter == 0) { + latch.hcounter = 1; + latch.ppu2.mdr = io.hcounter; + } else { + latch.hcounter = 0; + latch.ppu2.mdr = io.hcounter >> 8 | latch.ppu2.mdr & 0xfe; + } + return latch.ppu2.mdr; + } + + case 0x213d: { //OPVCT + if(latch.vcounter == 0) { + latch.vcounter = 1; + latch.ppu2.mdr = io.vcounter; + } else { + latch.vcounter = 0; + latch.ppu2.mdr = io.vcounter >> 8 | latch.ppu2.mdr & 0xfe; + } + return latch.ppu2.mdr; + } + + case 0x213e: { //STAT77 + latch.ppu1.mdr = 0x01 | io.obj.rangeOver << 6 | io.obj.timeOver << 7; + return latch.ppu1.mdr; + } + + case 0x213f: { //STAT78 + latch.hcounter = 0; + latch.vcounter = 0; + latch.ppu2.mdr &= 1 << 5; + latch.ppu2.mdr |= 0x03 | Region::PAL() << 4 | field() << 7; + if(!(cpu.pio() & 0x80)) { + latch.ppu2.mdr |= 1 << 6; + } else { + latch.ppu2.mdr |= latch.counters << 6; + latch.counters = 0; + } + return latch.ppu2.mdr; + } + + } + + return data; +} + +auto PPU::writeIO(uint address, uint8 data) -> void { + cpu.synchronizePPU(); + + switch(address & 0xffff) { + + case 0x2100: { //INIDISP + if(io.displayDisable && cpu.vcounter() == vdisp()) oamAddressReset(); + io.displayBrightness = data >> 0 & 15; + io.displayDisable = data >> 7 & 1; + return; + } + + case 0x2101: { //OBSEL + io.obj.tiledataAddress = data << 13 & 0x6000; + io.obj.nameselect = data >> 3 & 3; + io.obj.baseSize = data >> 5 & 7; + return; + } + + case 0x2102: { //OAMADDL + io.oamBaseAddress = (io.oamBaseAddress & 0x0200) | data << 1; + oamAddressReset(); + return; + } + + case 0x2103: { //OAMADDH + io.oamBaseAddress = (data & 1) << 9 | io.oamBaseAddress & 0x01fe; + io.oamPriority = data >> 7 & 1; + oamAddressReset(); + return; + } + + case 0x2104: { //OAMDATA + bool latchBit = io.oamAddress & 1; + uint address = io.oamAddress; + io.oamAddress = io.oamAddress + 1 & 0x3ff; + if(latchBit == 0) latch.oam = data; + if(address & 0x200) { + writeOAM(address, data); + } else if(latchBit == 1) { + writeOAM((address & ~1) + 0, latch.oam); + writeOAM((address & ~1) + 1, data); + } + oamSetFirstObject(); + return; + } + + case 0x2105: { //BGMODE + io.bgMode = data >> 0 & 7; + io.bgPriority = data >> 3 & 1; + io.bg1.tileSize = data >> 4 & 1; + io.bg2.tileSize = data >> 5 & 1; + io.bg3.tileSize = data >> 6 & 1; + io.bg4.tileSize = data >> 7 & 1; + updateVideoMode(); + return; + } + + case 0x2106: { //MOSAIC + bool mosaicEnable = io.bg1.mosaicEnable || io.bg2.mosaicEnable || io.bg3.mosaicEnable || io.bg4.mosaicEnable; + io.bg1.mosaicEnable = data >> 0 & 1; + io.bg2.mosaicEnable = data >> 1 & 1; + io.bg3.mosaicEnable = data >> 2 & 1; + io.bg4.mosaicEnable = data >> 3 & 1; + io.mosaic.size = (data >> 4 & 15) + 1; + if(!mosaicEnable && (data >> 0 & 15)) { + //mosaic vcounter is reloaded when mosaic becomes enabled + io.mosaic.counter = io.mosaic.size + 1; + } + return; + } + + case 0x2107: { //BG1SC + io.bg1.screenSize = data >> 0 & 3; + io.bg1.screenAddress = data << 8 & 0x7c00; + return; + } + + case 0x2108: { //BG2SC + io.bg2.screenSize = data >> 0 & 3; + io.bg2.screenAddress = data << 8 & 0x7c00; + return; + } + + case 0x2109: { //BG3SC + io.bg3.screenSize = data >> 0 & 3; + io.bg3.screenAddress = data << 8 & 0x7c00; + return; + } + + case 0x210a: { //BG4SC + io.bg4.screenSize = data >> 0 & 3; + io.bg4.screenAddress = data << 8 & 0x7c00; + return; + } + + case 0x210b: { //BG12NBA + io.bg1.tiledataAddress = data << 12 & 0x7000; + io.bg2.tiledataAddress = data << 8 & 0x7000; + return; + } + + case 0x210c: { //BG34NBA + io.bg3.tiledataAddress = data << 12 & 0x7000; + io.bg4.tiledataAddress = data << 8 & 0x7000; + return; + } + + case 0x210d: { //BG1HOFS + io.mode7.hoffset = data << 8 | latch.mode7; + latch.mode7 = data; + + io.bg1.hoffset = data << 8 | (latch.ppu1.bgofs & ~7) | (latch.ppu2.bgofs & 7); + latch.ppu1.bgofs = data; + latch.ppu2.bgofs = data; + return; + } + + case 0x210e: { //BG1VOFS + io.mode7.voffset = data << 8 | latch.mode7; + latch.mode7 = data; + + io.bg1.voffset = data << 8 | latch.ppu1.bgofs; + latch.ppu1.bgofs = data; + return; + } + + case 0x210f: { //BG2HOFS + io.bg2.hoffset = data << 8 | (latch.ppu1.bgofs & ~7) | (latch.ppu2.bgofs & 7); + latch.ppu1.bgofs = data; + latch.ppu2.bgofs = data; + return; + } + + case 0x2110: { //BG2VOFS + io.bg2.voffset = data << 8 | latch.ppu1.bgofs; + latch.ppu1.bgofs = data; + return; + } + + case 0x2111: { //BG3HOFS + io.bg3.hoffset = data << 8 | (latch.ppu1.bgofs & ~7) | (latch.ppu2.bgofs & 7); + latch.ppu1.bgofs = data; + latch.ppu2.bgofs = data; + return; + } + + case 0x2112: { //BG3VOFS + io.bg3.voffset = data << 8 | latch.ppu1.bgofs; + latch.ppu1.bgofs = data; + return; + } + + case 0x2113: { //BG4HOFS + io.bg4.hoffset = data << 8 | (latch.ppu1.bgofs & ~7) | (latch.ppu2.bgofs & 7); + latch.ppu1.bgofs = data; + latch.ppu2.bgofs = data; + return; + } + + case 0x2114: { //BG4VOFS + io.bg4.voffset = data << 8 | latch.ppu1.bgofs; + latch.ppu1.bgofs = data; + return; + } + + case 0x2115: { //VMAIN + static const uint size[4] = {1, 32, 128, 128}; + io.vramIncrementSize = size[data & 3]; + io.vramMapping = data >> 2 & 3; + io.vramIncrementMode = data >> 7 & 1; + return; + } + + case 0x2116: { //VMADDL + io.vramAddress = io.vramAddress & 0xff00 | data << 0; + latch.vram = readVRAM(); + return; + } + + case 0x2117: { //VMADDH + io.vramAddress = io.vramAddress & 0x00ff | data << 8; + latch.vram = readVRAM(); + return; + } + + case 0x2118: { //VMDATAL + writeVRAM<0>(data); + if(io.vramIncrementMode == 0) io.vramAddress += io.vramIncrementSize; + return; + } + + case 0x2119: { //VMDATAH + writeVRAM<1>(data); + if(io.vramIncrementMode == 1) io.vramAddress += io.vramIncrementSize; + return; + } + + case 0x211a: { //M7SEL + io.mode7.hflip = data >> 0 & 1; + io.mode7.vflip = data >> 1 & 1; + io.mode7.repeat = data >> 6 & 3; + return; + } + + case 0x211b: { //M7A + io.mode7.a = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + case 0x211c: { //M7B + io.mode7.b = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + case 0x211d: { //M7C + io.mode7.c = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + case 0x211e: { //M7D + io.mode7.d = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + case 0x211f: { //M7X + io.mode7.x = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + case 0x2120: { //M7Y + io.mode7.y = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + case 0x2121: { //CGADD + io.cgramAddress = data; + io.cgramAddressLatch = 0; + return; + } + + case 0x2122: { //CGDATA + if(io.cgramAddressLatch == 0) { + io.cgramAddressLatch = 1; + latch.cgram = data; + } else { + io.cgramAddressLatch = 0; + writeCGRAM(io.cgramAddress++, (data & 0x7f) << 8 | latch.cgram); + } + return; + } + + case 0x2123: { //W12SEL + io.bg1.window.oneInvert = data >> 0 & 1; + io.bg1.window.oneEnable = data >> 1 & 1; + io.bg1.window.twoInvert = data >> 2 & 1; + io.bg1.window.twoEnable = data >> 3 & 1; + io.bg2.window.oneInvert = data >> 4 & 1; + io.bg2.window.oneEnable = data >> 5 & 1; + io.bg2.window.twoInvert = data >> 6 & 1; + io.bg2.window.twoEnable = data >> 7 & 1; + return; + } + + case 0x2124: { //W34SEL + io.bg3.window.oneInvert = data >> 0 & 1; + io.bg3.window.oneEnable = data >> 1 & 1; + io.bg3.window.twoInvert = data >> 2 & 1; + io.bg3.window.twoEnable = data >> 3 & 1; + io.bg4.window.oneInvert = data >> 4 & 1; + io.bg4.window.oneEnable = data >> 5 & 1; + io.bg4.window.twoInvert = data >> 6 & 1; + io.bg4.window.twoEnable = data >> 7 & 1; + return; + } + + case 0x2125: { //WOBJSEL + io.obj.window.oneInvert = data >> 0 & 1; + io.obj.window.oneEnable = data >> 1 & 1; + io.obj.window.twoInvert = data >> 2 & 1; + io.obj.window.twoEnable = data >> 3 & 1; + io.col.window.oneInvert = data >> 4 & 1; + io.col.window.oneEnable = data >> 5 & 1; + io.col.window.twoInvert = data >> 6 & 1; + io.col.window.twoEnable = data >> 7 & 1; + return; + } + + case 0x2126: { //WH0 + io.window.oneLeft = data; + return; + } + + case 0x2127: { //WH1 + io.window.oneRight = data; + return; + } + + case 0x2128: { //WH2 + io.window.twoLeft = data; + return; + } + + case 0x2129: { //WH3 + io.window.twoRight = data; + return; + } + + case 0x212a: { //WBGLOG + io.bg1.window.mask = data >> 0 & 3; + io.bg2.window.mask = data >> 2 & 3; + io.bg3.window.mask = data >> 4 & 3; + io.bg4.window.mask = data >> 6 & 3; + return; + } + + case 0x212b: { //WOBJLOG + io.obj.window.mask = data >> 0 & 3; + io.col.window.mask = data >> 2 & 3; + return; + } + + case 0x212c: { //TM + io.bg1.aboveEnable = data >> 0 & 1; + io.bg2.aboveEnable = data >> 1 & 1; + io.bg3.aboveEnable = data >> 2 & 1; + io.bg4.aboveEnable = data >> 3 & 1; + io.obj.aboveEnable = data >> 4 & 1; + return; + } + + case 0x212d: { //TS + io.bg1.belowEnable = data >> 0 & 1; + io.bg2.belowEnable = data >> 1 & 1; + io.bg3.belowEnable = data >> 2 & 1; + io.bg4.belowEnable = data >> 3 & 1; + io.obj.belowEnable = data >> 4 & 1; + return; + } + + case 0x212e: { //TMW + io.bg1.window.aboveEnable = data >> 0 & 1; + io.bg2.window.aboveEnable = data >> 1 & 1; + io.bg3.window.aboveEnable = data >> 2 & 1; + io.bg4.window.aboveEnable = data >> 3 & 1; + io.obj.window.aboveEnable = data >> 4 & 1; + return; + } + + case 0x212f: { //TSW + io.bg1.window.belowEnable = data >> 0 & 1; + io.bg2.window.belowEnable = data >> 1 & 1; + io.bg3.window.belowEnable = data >> 2 & 1; + io.bg4.window.belowEnable = data >> 3 & 1; + io.obj.window.belowEnable = data >> 4 & 1; + return; + } + + case 0x2130: { //CGWSEL + io.col.directColor = data >> 0 & 1; + io.col.blendMode = data >> 1 & 1; + io.col.window.belowMask = data >> 4 & 3; + io.col.window.aboveMask = data >> 6 & 3; + return; + } + + case 0x2131: { //CGADDSUB + io.col.enable[Source::BG1 ] = data >> 0 & 1; + io.col.enable[Source::BG2 ] = data >> 1 & 1; + io.col.enable[Source::BG3 ] = data >> 2 & 1; + io.col.enable[Source::BG4 ] = data >> 3 & 1; + io.col.enable[Source::OBJ1] = 0; + io.col.enable[Source::OBJ2] = data >> 4 & 1; + io.col.enable[Source::COL ] = data >> 5 & 1; + io.col.halve = data >> 6 & 1; + io.col.mathMode = data >> 7 & 1; + return; + } + + case 0x2132: { //COLDATA + if(data & 0x20) io.col.fixedColor = io.col.fixedColor & 0b11111'11111'00000 | (data & 31) << 0; + if(data & 0x40) io.col.fixedColor = io.col.fixedColor & 0b11111'00000'11111 | (data & 31) << 5; + if(data & 0x80) io.col.fixedColor = io.col.fixedColor & 0b00000'11111'11111 | (data & 31) << 10; + return; + } + + case 0x2133: { //SETINI + io.interlace = data >> 0 & 1; + io.obj.interlace = data >> 1 & 1; + io.overscan = data >> 2 & 1; + io.pseudoHires = data >> 3 & 1; + io.extbg = data >> 6 & 1; + updateVideoMode(); + return; + } + + } +} + +auto PPU::updateVideoMode() -> void { + ppubase.display.vdisp = !io.overscan ? 225 : 240; + + switch(io.bgMode) { + case 0: + io.bg1.tileMode = TileMode::BPP2; + io.bg2.tileMode = TileMode::BPP2; + io.bg3.tileMode = TileMode::BPP2; + io.bg4.tileMode = TileMode::BPP2; + memory::assign(io.bg1.priority, 8, 11); + memory::assign(io.bg2.priority, 7, 10); + memory::assign(io.bg3.priority, 2, 5); + memory::assign(io.bg4.priority, 1, 4); + memory::assign(io.obj.priority, 3, 6, 9, 12); + break; + + case 1: + io.bg1.tileMode = TileMode::BPP4; + io.bg2.tileMode = TileMode::BPP4; + io.bg3.tileMode = TileMode::BPP2; + io.bg4.tileMode = TileMode::Inactive; + if(io.bgPriority) { + memory::assign(io.bg1.priority, 5, 8); + memory::assign(io.bg2.priority, 4, 7); + memory::assign(io.bg3.priority, 1, 10); + memory::assign(io.obj.priority, 2, 3, 6, 9); + } else { + memory::assign(io.bg1.priority, 6, 9); + memory::assign(io.bg2.priority, 5, 8); + memory::assign(io.bg3.priority, 1, 3); + memory::assign(io.obj.priority, 2, 4, 7, 10); + } + break; + + case 2: + io.bg1.tileMode = TileMode::BPP4; + io.bg2.tileMode = TileMode::BPP4; + io.bg3.tileMode = TileMode::Inactive; + io.bg4.tileMode = TileMode::Inactive; + memory::assign(io.bg1.priority, 3, 7); + memory::assign(io.bg2.priority, 1, 5); + memory::assign(io.obj.priority, 2, 4, 6, 8); + break; + + case 3: + io.bg1.tileMode = TileMode::BPP8; + io.bg2.tileMode = TileMode::BPP4; + io.bg3.tileMode = TileMode::Inactive; + io.bg4.tileMode = TileMode::Inactive; + memory::assign(io.bg1.priority, 3, 7); + memory::assign(io.bg2.priority, 1, 5); + memory::assign(io.obj.priority, 2, 4, 6, 8); + break; + + case 4: + io.bg1.tileMode = TileMode::BPP8; + io.bg2.tileMode = TileMode::BPP2; + io.bg3.tileMode = TileMode::Inactive; + io.bg4.tileMode = TileMode::Inactive; + memory::assign(io.bg1.priority, 3, 7); + memory::assign(io.bg2.priority, 1, 5); + memory::assign(io.obj.priority, 2, 4, 6, 8); + break; + + case 5: + io.bg1.tileMode = TileMode::BPP4; + io.bg2.tileMode = TileMode::BPP2; + io.bg3.tileMode = TileMode::Inactive; + io.bg4.tileMode = TileMode::Inactive; + memory::assign(io.bg1.priority, 3, 7); + memory::assign(io.bg2.priority, 1, 5); + memory::assign(io.obj.priority, 2, 4, 6, 8); + break; + + case 6: + io.bg1.tileMode = TileMode::BPP4; + io.bg2.tileMode = TileMode::Inactive; + io.bg3.tileMode = TileMode::Inactive; + io.bg4.tileMode = TileMode::Inactive; + memory::assign(io.bg1.priority, 2, 5); + memory::assign(io.obj.priority, 1, 3, 4, 6); + break; + + case 7: + if(!io.extbg) { + io.bg1.tileMode = TileMode::Mode7; + io.bg2.tileMode = TileMode::Inactive; + io.bg3.tileMode = TileMode::Inactive; + io.bg4.tileMode = TileMode::Inactive; + memory::assign(io.bg1.priority, 2); + memory::assign(io.obj.priority, 1, 3, 4, 5); + } else { + io.bg1.tileMode = TileMode::Mode7; + io.bg2.tileMode = TileMode::Mode7; + io.bg3.tileMode = TileMode::Inactive; + io.bg4.tileMode = TileMode::Inactive; + memory::assign(io.bg1.priority, 3); + memory::assign(io.bg2.priority, 1, 5); + memory::assign(io.obj.priority, 2, 4, 6, 7); + } + break; + } +} diff --git a/sfc/ppu-fast/line.cpp b/sfc/ppu-fast/line.cpp new file mode 100644 index 0000000..7edf7e1 --- /dev/null +++ b/sfc/ppu-fast/line.cpp @@ -0,0 +1,171 @@ +uint PPU::Line::start = 0; +uint PPU::Line::count = 0; + +auto PPU::Line::flush() -> void { + if(Line::count) { + if(ppu.hdScale() > 1) cacheMode7HD(); + #pragma omp parallel for if(Line::count >= 8) + for(uint y = 0; y < Line::count; y++) { + if(ppu.deinterlace()) { + if(!ppu.interlace()) { + //some games enable interlacing in 240p mode, just force these to even fields + ppu.lines[Line::start + y].render(0); + } else { + //for actual interlaced frames, render both fields every farme for 480i -> 480p + ppu.lines[Line::start + y].render(0); + ppu.lines[Line::start + y].render(1); + } + } else { + //standard 240p (progressive) and 480i (interlaced) rendering + ppu.lines[Line::start + y].render(ppu.field()); + } + } + Line::start = 0; + Line::count = 0; + } +} + +auto PPU::Line::cache() -> void { + uint y = ppu.vcounter(); + if(ppu.io.displayDisable || y >= ppu.vdisp()) { + io.displayDisable = true; + } else { + memcpy(&io, &ppu.io, sizeof(io)); + memcpy(&cgram, &ppu.cgram, sizeof(cgram)); + } + if(!Line::count) Line::start = y; + Line::count++; +} + +auto PPU::Line::render(bool fieldID) -> void { + this->fieldID = fieldID; + uint y = this->y + (!ppu.latch.overscan ? 7 : 0); + + auto hd = ppu.hd(); + auto ss = ppu.ss(); + auto scale = ppu.hdScale(); + auto output = ppu.output + (!hd + ? (y * 1024 + (ppu.interlace() && field() ? 512 : 0)) + : (y * 256 * scale * scale) + ); + auto width = (!hd + ? (!ppu.hires() ? 256 : 512) + : (256 * scale * scale)); + + if(io.displayDisable) { + memory::fill(output, width); + return; + } + + bool hires = io.pseudoHires || io.bgMode == 5 || io.bgMode == 6; + uint16 aboveColor = cgram[0]; + uint16 belowColor = hires ? cgram[0] : io.col.fixedColor; + uint xa = (hd || ss) && ppu.interlace() && field() ? 256 * scale * scale / 2 : 0; + uint xb = !(hd || ss) ? 256 : ppu.interlace() && !field() ? 256 * scale * scale / 2 : 256 * scale * scale; + for(uint x = xa; x < xb; x++) { + above[x] = {Source::COL, 0, aboveColor}; + below[x] = {Source::COL, 0, belowColor}; + } + + //hack: generally, renderBackground/renderObject ordering do not matter. + //but for HD mode 7, a larger grid of pixels are generated, and so ordering ends up mattering. + //as a hack for Mohawk & Headphone Jack, we reorder things for BG2 to render properly. + //longer-term, we need to devise a better solution that can work for every game. + renderBackground(io.bg1, Source::BG1); + if(io.extbg == 0) renderBackground(io.bg2, Source::BG2); + renderBackground(io.bg3, Source::BG3); + renderBackground(io.bg4, Source::BG4); + renderObject(io.obj); + if(io.extbg == 1) renderBackground(io.bg2, Source::BG2); + renderWindow(io.col.window, io.col.window.aboveMask, windowAbove); + renderWindow(io.col.window, io.col.window.belowMask, windowBelow); + + auto luma = ppu.lightTable[io.displayBrightness]; + uint curr = 0, prev = 0; + if(hd) for(uint x : range(256 * scale * scale)) { + *output++ = luma[pixel(x / scale & 255, above[x], below[x])]; + } else if(width == 256) for(uint x : range(256)) { + *output++ = luma[pixel(x, above[x], below[x])]; + } else if(!hires) for(uint x : range(256)) { + auto color = luma[pixel(x, above[x], below[x])]; + *output++ = color; + *output++ = color; + } else if(!configuration.video.blurEmulation) for(uint x : range(256)) { + *output++ = luma[pixel(x, below[x], above[x])]; + *output++ = luma[pixel(x, above[x], below[x])]; + } else for(uint x : range(256)) { + curr = luma[pixel(x, below[x], above[x])]; + *output++ = (prev + curr - ((prev ^ curr) & 0x0421)) >> 1; + prev = curr; + curr = luma[pixel(x, above[x], below[x])]; + *output++ = (prev + curr - ((prev ^ curr) & 0x0421)) >> 1; + prev = curr; + } +} + +auto PPU::Line::pixel(uint x, Pixel above, Pixel below) const -> uint16 { + if(!windowAbove[x]) above.color = 0x0000; + if(!windowBelow[x]) return above.color; + if(!io.col.enable[above.source]) return above.color; + if(!io.col.blendMode) return blend(above.color, io.col.fixedColor, io.col.halve && windowAbove[x]); + return blend(above.color, below.color, io.col.halve && windowAbove[x] && below.source != Source::COL); +} + +auto PPU::Line::blend(uint x, uint y, bool halve) const -> uint16 { + if(!io.col.mathMode) { //add + if(!halve) { + uint sum = x + y; + uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420; + return (sum - carry) | (carry - (carry >> 5)); + } else { + return (x + y - ((x ^ y) & 0x0421)) >> 1; + } + } else { //sub + uint diff = x - y + 0x8420; + uint borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420; + if(!halve) { + return (diff - borrow) & (borrow - (borrow >> 5)); + } else { + return (((diff - borrow) & (borrow - (borrow >> 5))) & 0x7bde) >> 1; + } + } +} + +auto PPU::Line::directColor(uint paletteIndex, uint paletteColor) const -> uint16 { + //paletteIndex = bgr + //paletteColor = BBGGGRRR + //output = 0 BBb00 GGGg0 RRRr0 + return (paletteColor << 2 & 0x001c) + (paletteIndex << 1 & 0x0002) //R + + (paletteColor << 4 & 0x0380) + (paletteIndex << 5 & 0x0040) //G + + (paletteColor << 7 & 0x6000) + (paletteIndex << 10 & 0x1000); //B +} + +auto PPU::Line::plotAbove(uint x, uint8 source, uint8 priority, uint16 color) -> void { + if(ppu.hd()) return plotHD(above, x, source, priority, color, false, false); + if(priority > above[x].priority) above[x] = {source, priority, color}; +} + +auto PPU::Line::plotBelow(uint x, uint8 source, uint8 priority, uint16 color) -> void { + if(ppu.hd()) return plotHD(below, x, source, priority, color, false, false); + if(priority > below[x].priority) below[x] = {source, priority, color}; +} + +//todo: name these variables more clearly ... +auto PPU::Line::plotHD(Pixel* pixel, uint x, uint8 source, uint8 priority, uint16 color, bool hires, bool subpixel) -> void { + auto scale = ppu.hdScale(); + int xss = hires && subpixel ? scale / 2 : 0; + int ys = ppu.interlace() && field() ? scale / 2 : 0; + if(priority > pixel[x * scale + xss + ys * 256 * scale].priority) { + Pixel p = {source, priority, color}; + int xsm = hires && !subpixel ? scale / 2 : scale; + int ysm = ppu.interlace() && !field() ? scale / 2 : scale; + for(int xs = xss; xs < xsm; xs++) { + pixel[x * scale + xs + ys * 256 * scale] = p; + } + int size = sizeof(Pixel) * (xsm - xss); + Pixel* source = &pixel[x * scale + xss + ys * 256 * scale]; + for(int yst = ys + 1; yst < ysm; yst++) { + memcpy(&pixel[x * scale + xss + yst * 256 * scale], source, size); + } + } +} diff --git a/sfc/ppu-fast/mode7.cpp b/sfc/ppu-fast/mode7.cpp new file mode 100644 index 0000000..dc44acc --- /dev/null +++ b/sfc/ppu-fast/mode7.cpp @@ -0,0 +1,69 @@ +auto PPU::Line::renderMode7(PPU::IO::Background& self, uint8 source) -> void { + //HD mode 7 support + if(!ppu.hdMosaic() || !self.mosaicEnable || io.mosaic.size == 1) { + if(ppu.hdScale() > 1) return renderMode7HD(self, source); + } + + int Y = this->y; + if(self.mosaicEnable) Y -= io.mosaic.size - io.mosaic.counter; + int y = !io.mode7.vflip ? Y : 255 - Y; + + int a = (int16)io.mode7.a; + int b = (int16)io.mode7.b; + int c = (int16)io.mode7.c; + int d = (int16)io.mode7.d; + int hcenter = (int13)io.mode7.x; + int vcenter = (int13)io.mode7.y; + int hoffset = (int13)io.mode7.hoffset; + int voffset = (int13)io.mode7.voffset; + + uint mosaicCounter = 1; + uint mosaicPalette = 0; + uint8 mosaicPriority = 0; + uint16 mosaicColor = 0; + + auto clip = [](int n) -> int { return n & 0x2000 ? (n | ~1023) : (n & 1023); }; + int originX = (a * clip(hoffset - hcenter) & ~63) + (b * clip(voffset - vcenter) & ~63) + (b * y & ~63) + (hcenter << 8); + int originY = (c * clip(hoffset - hcenter) & ~63) + (d * clip(voffset - vcenter) & ~63) + (d * y & ~63) + (vcenter << 8); + + bool windowAbove[256]; + bool windowBelow[256]; + renderWindow(self.window, self.window.aboveEnable, windowAbove); + renderWindow(self.window, self.window.belowEnable, windowBelow); + + for(int X : range(256)) { + int x = !io.mode7.hflip ? X : 255 - X; + int pixelX = originX + a * x >> 8; + int pixelY = originY + c * x >> 8; + int tileX = pixelX >> 3 & 127; + int tileY = pixelY >> 3 & 127; + bool outOfBounds = (pixelX | pixelY) & ~1023; + uint15 tileAddress = tileY * 128 + tileX; + uint15 paletteAddress = ((pixelY & 7) << 3) + (pixelX & 7); + uint8 tile = io.mode7.repeat == 3 && outOfBounds ? 0 : ppu.vram[tileAddress] >> 0; + uint8 palette = io.mode7.repeat == 2 && outOfBounds ? 0 : ppu.vram[tile << 6 | paletteAddress] >> 8; + + uint8 priority; + if(source == Source::BG1) { + priority = self.priority[0]; + } else if(source == Source::BG2) { + priority = self.priority[palette >> 7]; + palette &= 0x7f; + } + + if(--mosaicCounter == 0) { + mosaicCounter = self.mosaicEnable ? io.mosaic.size : 1; + mosaicPalette = palette; + mosaicPriority = priority; + if(io.col.directColor && source == Source::BG1) { + mosaicColor = directColor(0, palette); + } else { + mosaicColor = cgram[palette]; + } + } + if(!mosaicPalette) continue; + + if(self.aboveEnable && !windowAbove[X]) plotAbove(X, source, mosaicPriority, mosaicColor); + if(self.belowEnable && !windowBelow[X]) plotBelow(X, source, mosaicPriority, mosaicColor); + } +} diff --git a/sfc/ppu-fast/mode7hd.cpp b/sfc/ppu-fast/mode7hd.cpp new file mode 100644 index 0000000..892ad25 --- /dev/null +++ b/sfc/ppu-fast/mode7hd.cpp @@ -0,0 +1,253 @@ +//determine mode 7 line groups for perspective correction +auto PPU::Line::cacheMode7HD() -> void { + ppu.mode7LineGroups.count = 0; + if(ppu.hdPerspective()) { + #define isLineMode7(line) (line.io.bg1.tileMode == TileMode::Mode7 && !line.io.displayDisable && ( \ + (line.io.bg1.aboveEnable || line.io.bg1.belowEnable) \ + )) + bool state = false; + uint y; + //find the moe 7 groups + for(y = 0; y < Line::count; y++) { + if(state != isLineMode7(ppu.lines[Line::start + y])) { + state = !state; + if(state) { + ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count] = ppu.lines[Line::start + y].y; + } else { + ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] = ppu.lines[Line::start + y].y - 1; + //the lines at the edges of mode 7 groups may be erroneous, so start and end lines for interpolation are moved inside + int offset = (ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count]) / 8; + ppu.mode7LineGroups.startLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count] + offset; + ppu.mode7LineGroups.endLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - offset; + ppu.mode7LineGroups.count++; + } + } + } + #undef isLineMode7 + if(state) { + //close the last group if necessary + ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] = ppu.lines[Line::start + y].y - 1; + int offset = (ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count]) / 8; + ppu.mode7LineGroups.startLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count] + offset; + ppu.mode7LineGroups.endLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - offset; + ppu.mode7LineGroups.count++; + } + + //detect groups that do not have perspective + for(int i : range(ppu.mode7LineGroups.count)) { + int a = -1, b = -1, c = -1, d = -1; //the mode 7 scale factors of the current line + int aPrev = -1, bPrev = -1, cPrev = -1, dPrev = -1; //the mode 7 scale factors of the previous line + bool aVar = false, bVar = false, cVar = false, dVar = false; //has a varying value been found for the factors? + bool aInc = false, bInc = false, cInc = false, dInc = false; //has the variation been an increase or decrease? + for(y = ppu.mode7LineGroups.startLerpLine[i]; y <= ppu.mode7LineGroups.endLerpLine[i]; y++) { + a = ((int)((int16)(ppu.lines[y].io.mode7.a))); + b = ((int)((int16)(ppu.lines[y].io.mode7.b))); + c = ((int)((int16)(ppu.lines[y].io.mode7.c))); + d = ((int)((int16)(ppu.lines[y].io.mode7.d))); + //has the value of 'a' changed compared to the last line? + //(and is the factor larger than zero, which happens sometimes and seems to be game-specific, mostly at the edges of the screen) + if(aPrev > 0 && a > 0 && a != aPrev) { + if(!aVar) { + //if there has been no variation yet, store that there is one and store if it is an increase or decrease + aVar = true; + aInc = a > aPrev; + } else if(aInc != a > aPrev) { + //if there has been an increase and now we have a decrease, or vice versa, set the interpolation lines to -1 + //to deactivate perspective correction for this group and stop analyzing it further + ppu.mode7LineGroups.startLerpLine[i] = -1; + ppu.mode7LineGroups.endLerpLine[i] = -1; + break; + } + } + if(bPrev > 0 && b > 0 && b != bPrev) { + if(!bVar) { + bVar = true; + bInc = b > bPrev; + } else if(bInc != b > bPrev) { + ppu.mode7LineGroups.startLerpLine[i] = -1; + ppu.mode7LineGroups.endLerpLine[i] = -1; + break; + } + } + if(cPrev > 0 && c > 0 && c != cPrev) { + if(!cVar) { + cVar = true; + cInc = c > cPrev; + } else if(cInc != c > cPrev) { + ppu.mode7LineGroups.startLerpLine[i] = -1; + ppu.mode7LineGroups.endLerpLine[i] = -1; + break; + } + } + if(dPrev > 0 && d > 0 && d != bPrev) { + if(!dVar) { + dVar = true; + dInc = d > dPrev; + } else if(dInc != d > dPrev) { + ppu.mode7LineGroups.startLerpLine[i] = -1; + ppu.mode7LineGroups.endLerpLine[i] = -1; + break; + } + } + aPrev = a, bPrev = b, cPrev = c, dPrev = d; + } + } + } +} + +auto PPU::Line::renderMode7HD(PPU::IO::Background& self, uint8 source) -> void { + const bool extbg = source == Source::BG2; + const uint scale = ppu.hdScale(); + + Pixel pixel; + Pixel* above = &this->above[-1]; + Pixel* below = &this->below[-1]; + + //find the first and last scanline for interpolation + int y_a = -1; + int y_b = -1; + #define isLineMode7(n) (ppu.lines[n].io.bg1.tileMode == TileMode::Mode7 && !ppu.lines[n].io.displayDisable && ( \ + (ppu.lines[n].io.bg1.aboveEnable || ppu.lines[n].io.bg1.belowEnable) \ + )) + if(ppu.hdPerspective()) { + //find the mode 7 line group this line is in and use its interpolation lines + for(int i : range(ppu.mode7LineGroups.count)) { + if(y >= ppu.mode7LineGroups.startLine[i] && y <= ppu.mode7LineGroups.endLine[i]) { + y_a = ppu.mode7LineGroups.startLerpLine[i]; + y_b = ppu.mode7LineGroups.endLerpLine[i]; + break; + } + } + } + if(y_a == -1 || y_b == -1) { + //if perspective correction is disabled or the group was detected as non-perspective, use the neighboring lines + y_a = y; + y_b = y; + if(y_a > 1 && isLineMode7(y_a)) y_a--; + if(y_b < 239 && isLineMode7(y_b)) y_b++; + } + #undef isLineMode7 + + Line line_a = ppu.lines[y_a]; + float a_a = (int16)line_a.io.mode7.a; + float b_a = (int16)line_a.io.mode7.b; + float c_a = (int16)line_a.io.mode7.c; + float d_a = (int16)line_a.io.mode7.d; + + Line line_b = ppu.lines[y_b]; + float a_b = (int16)line_b.io.mode7.a; + float b_b = (int16)line_b.io.mode7.b; + float c_b = (int16)line_b.io.mode7.c; + float d_b = (int16)line_b.io.mode7.d; + + int hcenter = (int13)io.mode7.x; + int vcenter = (int13)io.mode7.y; + int hoffset = (int13)io.mode7.hoffset; + int voffset = (int13)io.mode7.voffset; + + if(io.mode7.vflip) { + y_a = 255 - y_a; + y_b = 255 - y_b; + } + + bool windowAbove[256]; + bool windowBelow[256]; + renderWindow(self.window, self.window.aboveEnable, windowAbove); + renderWindow(self.window, self.window.belowEnable, windowBelow); + + int pixelYp = INT_MIN; + for(int ys : range(scale)) { + float yf = y + ys * 1.0 / scale - 0.5; + if(io.mode7.vflip) yf = 255 - yf; + + float a = 1.0 / lerp(y_a, 1.0 / a_a, y_b, 1.0 / a_b, yf); + float b = 1.0 / lerp(y_a, 1.0 / b_a, y_b, 1.0 / b_b, yf); + float c = 1.0 / lerp(y_a, 1.0 / c_a, y_b, 1.0 / c_b, yf); + float d = 1.0 / lerp(y_a, 1.0 / d_a, y_b, 1.0 / d_b, yf); + + int ht = (hoffset - hcenter) % 1024; + float vty = ((voffset - vcenter) % 1024) + yf; + float originX = (a * ht) + (b * vty) + (hcenter << 8); + float originY = (c * ht) + (d * vty) + (vcenter << 8); + + int pixelXp = INT_MIN; + for(int x : range(256)) { + bool doAbove = self.aboveEnable && !windowAbove[x]; + bool doBelow = self.belowEnable && !windowBelow[x]; + + for(int xs : range(scale)) { + float xf = x + xs * 1.0 / scale - 0.5; + if(io.mode7.hflip) xf = 255 - xf; + + int pixelX = (originX + a * xf) / 256; + int pixelY = (originY + c * xf) / 256; + + above++; + below++; + + //only compute color again when coordinates have changed + if(pixelX != pixelXp || pixelY != pixelYp) { + uint tile = io.mode7.repeat == 3 && ((pixelX | pixelY) & ~1023) ? 0 : (ppu.vram[(pixelY >> 3 & 127) * 128 + (pixelX >> 3 & 127)] & 0xff); + uint palette = io.mode7.repeat == 2 && ((pixelX | pixelY) & ~1023) ? 0 : (ppu.vram[(((pixelY & 7) << 3) + (pixelX & 7)) + (tile << 6)] >> 8); + + uint8 priority; + if(!extbg) { + priority = self.priority[0]; + } else { + priority = self.priority[palette >> 7]; + palette &= 0x7f; + } + if(!palette) continue; + + uint16 color; + if(io.col.directColor && !extbg) { + color = directColor(0, palette); + } else { + color = cgram[palette]; + } + + pixel = {source, priority, color}; + pixelXp = pixelX; + pixelYp = pixelY; + } + + if(doAbove && (!extbg || pixel.priority > above->priority)) *above = pixel; + if(doBelow && (!extbg || pixel.priority > below->priority)) *below = pixel; + } + } + } + + if(ppu.ss()) { + uint divisor = scale * scale; + for(uint p : range(256)) { + uint ab = 0, bb = 0; + uint ag = 0, bg = 0; + uint ar = 0, br = 0; + for(uint y : range(scale)) { + auto above = &this->above[p * scale]; + auto below = &this->below[p * scale]; + for(uint x : range(scale)) { + uint a = above[x].color; + uint b = below[x].color; + ab += a >> 0 & 31; + ag += a >> 5 & 31; + ar += a >> 10 & 31; + bb += b >> 0 & 31; + bg += b >> 5 & 31; + br += b >> 10 & 31; + } + } + uint16 aboveColor = ab / divisor << 0 | ag / divisor << 5 | ar / divisor << 10; + uint16 belowColor = bb / divisor << 0 | bg / divisor << 5 | br / divisor << 10; + this->above[p] = {source, this->above[p * scale].priority, aboveColor}; + this->below[p] = {source, this->below[p * scale].priority, belowColor}; + } + } +} + +//interpolation and extrapolation +auto PPU::Line::lerp(float pa, float va, float pb, float vb, float pr) -> float { + if(va == vb || pr == pa) return va; + if(pr == pb) return vb; + return va + (vb - va) / (pb - pa) * (pr - pa); +} diff --git a/sfc/ppu-fast/object.cpp b/sfc/ppu-fast/object.cpp new file mode 100644 index 0000000..c0456cf --- /dev/null +++ b/sfc/ppu-fast/object.cpp @@ -0,0 +1,192 @@ +auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { + if(!self.aboveEnable && !self.belowEnable) return; + + bool windowAbove[256]; + bool windowBelow[256]; + renderWindow(self.window, self.window.aboveEnable, windowAbove); + renderWindow(self.window, self.window.belowEnable, windowBelow); + + uint itemCount = 0; + uint tileCount = 0; + for(uint n : range(ppu.ItemLimit)) items[n].valid = false; + for(uint n : range(ppu.TileLimit)) tiles[n].valid = false; + + for(uint n : range(128)) { + ObjectItem item{true, uint8_t(self.first + n & 127)}; + const auto& object = ppu.objects[item.index]; + + if(object.size == 0) { + static const uint widths[] = { 8, 8, 8, 16, 16, 32, 16, 16}; + static const uint heights[] = { 8, 8, 8, 16, 16, 32, 32, 32}; + item.width = widths [self.baseSize]; + item.height = heights[self.baseSize]; + if(self.interlace && self.baseSize >= 6) item.height = 16; //hardware quirk + } else { + static const uint widths[] = {16, 32, 64, 32, 64, 64, 32, 32}; + static const uint heights[] = {16, 32, 64, 32, 64, 64, 64, 32}; + item.width = widths [self.baseSize]; + item.height = heights[self.baseSize]; + } + + if(object.x > 256 && object.x + item.width - 1 < 512) continue; + uint height = item.height >> self.interlace; + if((y >= object.y && y < object.y + height) + || (object.y + height >= 256 && y < (object.y + height & 255)) + ) { + if(itemCount++ >= ppu.ItemLimit) break; + items[itemCount - 1] = item; + } + } + + for(int n : reverse(range(ppu.ItemLimit))) { + const auto& item = items[n]; + if(!item.valid) continue; + + const auto& object = ppu.objects[item.index]; + uint tileWidth = item.width >> 3; + int x = object.x; + int y = this->y - object.y & 0xff; + if(self.interlace) y <<= 1; + + if(object.vflip) { + if(item.width == item.height) { + y = item.height - 1 - y; + } else if(y < item.width) { + y = item.width - 1 - y; + } else { + y = item.width + (item.width - 1) - (y - item.width); + } + } + + if(self.interlace) { + y = !object.vflip ? y + field() : y - field(); + } + + x &= 511; + y &= 255; + + uint16 tiledataAddress = self.tiledataAddress; + if(object.nameselect) tiledataAddress += 1 + self.nameselect << 12; + uint16 characterX = (object.character & 15); + uint16 characterY = ((object.character >> 4) + (y >> 3) & 15) << 4; + + for(uint tileX : range(tileWidth)) { + uint objectX = x + (tileX << 3) & 511; + if(x != 256 && objectX >= 256 && objectX + 7 < 512) continue; + + ObjectTile tile{true}; + tile.x = objectX; + tile.y = y; + tile.priority = object.priority; + tile.palette = 128 + (object.palette << 4); + tile.hflip = object.hflip; + + uint mirrorX = !object.hflip ? tileX : tileWidth - 1 - tileX; + uint address = tiledataAddress + ((characterY + (characterX + mirrorX & 15)) << 4); + address = (address & 0x7ff0) + (y & 7); + tile.data = ppu.vram[address + 0] << 0; + tile.data |= ppu.vram[address + 8] << 16; + + if(tileCount++ >= ppu.TileLimit) break; + tiles[tileCount - 1] = tile; + } + } + + ppu.io.obj.rangeOver |= itemCount > ppu.ItemLimit; + ppu.io.obj.timeOver |= tileCount > ppu.TileLimit; + + uint8_t palette[256] = {}; + uint8_t priority[256] = {}; + + for(uint n : range(ppu.TileLimit)) { + auto& tile = tiles[n]; + if(!tile.valid) continue; + + uint tileX = tile.x; + for(uint x : range(8)) { + tileX &= 511; + if(tileX < 256) { + uint color, shift = tile.hflip ? x : 7 - x; + color = tile.data >> shift + 0 & 1; + color += tile.data >> shift + 7 & 2; + color += tile.data >> shift + 14 & 4; + color += tile.data >> shift + 21 & 8; + if(color) { + palette[tileX] = tile.palette + color; + priority[tileX] = self.priority[tile.priority]; + } + } + tileX++; + } + } + + for(uint x : range(256)) { + if(!priority[x]) continue; + uint8 source = palette[x] < 192 ? Source::OBJ1 : Source::OBJ2; + if(self.aboveEnable && !windowAbove[x]) plotAbove(x, source, priority[x], cgram[palette[x]]); + if(self.belowEnable && !windowBelow[x]) plotBelow(x, source, priority[x], cgram[palette[x]]); + } +} + +auto PPU::oamAddressReset() -> void { + io.oamAddress = io.oamBaseAddress; + oamSetFirstObject(); +} + +auto PPU::oamSetFirstObject() -> void { + io.obj.first = !io.oamPriority ? 0 : io.oamAddress >> 2 & 0x7f; +} + +auto PPU::readObject(uint10 address) -> uint8 { + if(!(address & 0x200)) { + uint n = address >> 2; //object# + address &= 3; + if(address == 0) return objects[n].x; + if(address == 1) return objects[n].y - 1; //-1 => rendering happens one scanline late + if(address == 2) return objects[n].character; + return ( + objects[n].nameselect << 0 + | objects[n].palette << 1 + | objects[n].priority << 4 + | objects[n].hflip << 6 + | objects[n].vflip << 7 + ); + } else { + uint n = (address & 0x1f) << 2; //object# + return ( + objects[n + 0].x >> 8 << 0 + | objects[n + 0].size << 1 + | objects[n + 1].x >> 8 << 2 + | objects[n + 1].size << 3 + | objects[n + 2].x >> 8 << 4 + | objects[n + 2].size << 5 + | objects[n + 3].x >> 8 << 6 + | objects[n + 3].size << 7 + ); + } +} + +auto PPU::writeObject(uint10 address, uint8 data) -> void { + if(!(address & 0x200)) { + uint n = address >> 2; //object# + address &= 3; + if(address == 0) { objects[n].x = objects[n].x & 0x100 | data; return; } + if(address == 1) { objects[n].y = data + 1; return; } //+1 => rendering happens one scanline late + if(address == 2) { objects[n].character = data; return; } + objects[n].nameselect = data >> 0 & 1; + objects[n].palette = data >> 1 & 7; + objects[n].priority = data >> 4 & 3; + objects[n].hflip = data >> 6 & 1; + objects[n].vflip = data >> 7 & 1; + } else { + uint n = (address & 0x1f) << 2; //object# + objects[n + 0].x = objects[n + 0].x & 0xff | data << 8 & 0x100; + objects[n + 1].x = objects[n + 1].x & 0xff | data << 6 & 0x100; + objects[n + 2].x = objects[n + 2].x & 0xff | data << 4 & 0x100; + objects[n + 3].x = objects[n + 3].x & 0xff | data << 2 & 0x100; + objects[n + 0].size = data >> 1 & 1; + objects[n + 1].size = data >> 3 & 1; + objects[n + 2].size = data >> 5 & 1; + objects[n + 3].size = data >> 7 & 1; + } +} diff --git a/sfc/ppu-fast/ppu.cpp b/sfc/ppu-fast/ppu.cpp new file mode 100644 index 0000000..718a633 --- /dev/null +++ b/sfc/ppu-fast/ppu.cpp @@ -0,0 +1,206 @@ +#include + +namespace SuperFamicom { + +PPU& ppubase = ppu; + +#define PPU PPUfast +#define ppu ppufast + +PPU ppu; +#include "io.cpp" +#include "line.cpp" +#include "background.cpp" +#include "mode7.cpp" +#include "mode7hd.cpp" +#include "object.cpp" +#include "window.cpp" +#include "serialization.cpp" + +auto PPU::interlace() const -> bool { return ppubase.display.interlace; } +auto PPU::overscan() const -> bool { return ppubase.display.overscan; } +auto PPU::vdisp() const -> uint { return ppubase.display.vdisp; } +auto PPU::hires() const -> bool { return latch.hires; } +auto PPU::hd() const -> bool { return latch.hd; } +auto PPU::ss() const -> bool { return latch.ss; } +#undef ppu +auto PPU::hdScale() const -> uint { return configuration.hacks.ppu.mode7.scale; } +auto PPU::hdPerspective() const -> bool { return configuration.hacks.ppu.mode7.perspective; } +auto PPU::hdSupersample() const -> bool { return configuration.hacks.ppu.mode7.supersample; } +auto PPU::hdMosaic() const -> bool { return configuration.hacks.ppu.mode7.mosaic; } +auto PPU::deinterlace() const -> bool { return configuration.hacks.ppu.deinterlace; } +auto PPU::renderCycle() const -> uint { return configuration.hacks.ppu.renderCycle; } +auto PPU::noVRAMBlocking() const -> bool { return configuration.hacks.ppu.noVRAMBlocking; } +#define ppu ppufast + +PPU::PPU() { + output = new uint16_t[2304 * 2160](); + + for(uint l : range(16)) { + lightTable[l] = new uint16_t[32768]; + for(uint r : range(32)) { + for(uint g : range(32)) { + for(uint b : range(32)) { + double luma = (double)l / 15.0; + uint ar = (luma * r + 0.5); + uint ag = (luma * g + 0.5); + uint ab = (luma * b + 0.5); + lightTable[l][r << 10 | g << 5 | b << 0] = ab << 10 | ag << 5 | ar << 0; + } + } + } + } + + for(uint y : range(240)) { + lines[y].y = y; + } +} + +PPU::~PPU() { + delete[] output; + for(uint l : range(16)) delete[] lightTable[l]; +} + +auto PPU::synchronizeCPU() -> void { + if(ppubase.clock >= 0) scheduler.resume(cpu.thread); +} + +auto PPU::Enter() -> void { + while(true) { + scheduler.synchronize(); + ppu.main(); + } +} + +auto PPU::step(uint clocks) -> void { + tick(clocks); + ppubase.clock += clocks; + synchronizeCPU(); +} + +auto PPU::main() -> void { + scanline(); + + if(system.frameCounter == 0 && !system.runAhead) { + uint y = vcounter(); + if(y >= 1 && y <= 239) { + step(renderCycle()); + bool mosaicEnable = io.bg1.mosaicEnable || io.bg2.mosaicEnable || io.bg3.mosaicEnable || io.bg4.mosaicEnable; + if(y == 1) { + io.mosaic.counter = mosaicEnable ? io.mosaic.size + 1 : 0; + } + if(io.mosaic.counter && !--io.mosaic.counter) { + io.mosaic.counter = mosaicEnable ? io.mosaic.size + 0 : 0; + } + lines[y].cache(); + } + } + + step(hperiod() - hcounter()); +} + +auto PPU::scanline() -> void { + if(vcounter() == 0) { + if(latch.overscan && !io.overscan) { + //when disabling overscan, clear the overscan area that won't be rendered to: + for(uint y = 1; y <= 240; y++) { + if(y >= 8 && y <= 231) continue; + auto output = ppu.output + y * 1024; + memory::fill(output, 1024); + } + } + + ppubase.display.interlace = io.interlace; + ppubase.display.overscan = io.overscan; + latch.overscan = io.overscan; + latch.hires = false; + latch.hd = false; + latch.ss = false; + io.obj.timeOver = false; + io.obj.rangeOver = false; + } + + if(vcounter() > 0 && vcounter() < vdisp()) { + latch.hires |= io.pseudoHires || io.bgMode == 5 || io.bgMode == 6; + //supersampling and EXTBG mode are not compatible, so disable supersampling in EXTBG mode + latch.hd |= io.bgMode == 7 && hdScale() > 1 && (hdSupersample() == 0 || io.extbg == 1); + latch.ss |= io.bgMode == 7 && hdScale() > 1 && (hdSupersample() == 1 && io.extbg == 0); + } + + if(vcounter() == vdisp()) { + if(!io.displayDisable) oamAddressReset(); + } + + if(vcounter() == 240) { + Line::flush(); + } +} + +auto PPU::refresh() -> void { + if(system.frameCounter == 0 && !system.runAhead) { + auto output = this->output; + uint pitch, width, height; + if(!hd()) { + pitch = 512 << !interlace(); + width = 256 << hires(); + height = 240 << interlace(); + } else { + pitch = 256 * hdScale(); + width = 256 * hdScale(); + height = 240 * hdScale(); + } + + //clear the areas of the screen that won't be rendered: + //previous video frames may have drawn data here that would now be stale otherwise. + if(!latch.overscan && pitch != frame.pitch && width != frame.width && height != frame.height) { + for(uint y : range(240)) { + if(y >= 8 && y <= 230) continue; //these scanlines are always rendered. + auto output = this->output + (!hd() ? (y * 1024 + (interlace() && field() ? 512 : 0)) : (y * 256 * hdScale() * hdScale())); + auto width = (!hd() ? (!hires() ? 256 : 512) : (256 * hdScale() * hdScale())); + memory::fill(output, width); + } + } + + if(auto device = controllerPort2.device) device->draw(output, pitch * sizeof(uint16), width, height); + platform->videoFrame(output, pitch * sizeof(uint16), width, height, hd() ? hdScale() : 1); + + frame.pitch = pitch; + frame.width = width; + frame.height = height; + } + if(system.frameCounter++ >= system.frameSkip) system.frameCounter = 0; +} + +auto PPU::load() -> bool { + return true; +} + +auto PPU::power(bool reset) -> void { + PPUcounter::reset(); + memory::fill(output, 1024 * 960); + + function reader{&PPU::readIO, this}; + function writer{&PPU::writeIO, this}; + bus.map(reader, writer, "00-3f,80-bf:2100-213f"); + + if(!reset) { + for(auto& word : vram) word = 0x0000; + for(auto& color : cgram) color = 0x0000; + for(auto& object : objects) object = {}; + } + + latch = {}; + io = {}; + updateVideoMode(); + + #undef ppu + ItemLimit = !configuration.hacks.ppu.noSpriteLimit ? 32 : 128; + TileLimit = !configuration.hacks.ppu.noSpriteLimit ? 34 : 128; + + Line::start = 0; + Line::count = 0; + + frame = {}; +} + +} diff --git a/sfc/ppu-fast/ppu.hpp b/sfc/ppu-fast/ppu.hpp new file mode 100644 index 0000000..2ef93c4 --- /dev/null +++ b/sfc/ppu-fast/ppu.hpp @@ -0,0 +1,370 @@ +//performance-focused, scanline-based, parallelized implementation of PPU + +//limitations: +//* mid-scanline effects not support +//* vertical mosaic coordinates are not exact +//* (hardware-mod) 128KB VRAM mode not supported + +#define PPU PPUfast + +struct PPU : PPUcounter { + alwaysinline auto interlace() const -> bool; + alwaysinline auto overscan() const -> bool; + alwaysinline auto vdisp() const -> uint; + alwaysinline auto hires() const -> bool; + alwaysinline auto hd() const -> bool; + alwaysinline auto ss() const -> bool; + alwaysinline auto hdScale() const -> uint; + alwaysinline auto hdPerspective() const -> bool; + alwaysinline auto hdSupersample() const -> bool; + alwaysinline auto hdMosaic() const -> bool; + alwaysinline auto deinterlace() const -> bool; + alwaysinline auto renderCycle() const -> uint; + alwaysinline auto noVRAMBlocking() const -> bool; + + //ppu.cpp + PPU(); + ~PPU(); + + auto synchronizeCPU() -> void; + static auto Enter() -> void; + alwaysinline auto step(uint clocks) -> void; + auto main() -> void; + auto scanline() -> void; + auto refresh() -> void; + auto load() -> bool; + auto power(bool reset) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + +public: + struct Source { enum : uint8 { BG1, BG2, BG3, BG4, OBJ1, OBJ2, COL }; }; + struct TileMode { enum : uint8 { BPP2, BPP4, BPP8, Mode7, Inactive }; }; + struct ScreenMode { enum : uint8 { Above, Below }; }; + + struct Latch { + //serialization.cpp + auto serialize(serializer&) -> void; + + bool interlace = 0; + bool overscan = 0; + bool hires = 0; + bool hd = 0; + bool ss = 0; + + uint16 vram = 0; + uint8 oam = 0; + uint8 cgram = 0; + + uint16 oamAddress = 0; + uint8 cgramAddress = 0; + + uint8 mode7 = 0; + bool counters = 0; + bool hcounter = 0; //hdot + bool vcounter = 0; + + struct PPUstate { + //serialization.cpp + auto serialize(serializer&) -> void; + + uint8 mdr = 0; + uint8 bgofs = 0; + } ppu1, ppu2; + }; + + struct IO { + //serialization.cpp + auto serialize(serializer&) -> void; + + bool displayDisable = 1; + uint8 displayBrightness = 0; + uint16 oamBaseAddress = 0; + uint16 oamAddress = 0; + bool oamPriority = 0; + bool bgPriority = 0; + uint8 bgMode = 0; + bool vramIncrementMode = 0; + uint8 vramMapping = 0; + uint8 vramIncrementSize = 0; + uint16 vramAddress = 0; + uint8 cgramAddress = 0; + bool cgramAddressLatch = 0; + uint16 hcounter = 0; //hdot + uint16 vcounter = 0; + bool interlace = 0; + bool overscan = 0; + bool pseudoHires = 0; + bool extbg = 0; + + struct Mosaic { + //serialization.cpp + auto serialize(serializer&) -> void; + + uint8 size = 1; + uint8 counter = 0; + } mosaic; + + struct Mode7 { + //serialization.cpp + auto serialize(serializer&) -> void; + + bool hflip = 0; + bool vflip = 0; + uint repeat = 0; + uint16 a = 0; + uint16 b = 0; + uint16 c = 0; + uint16 d = 0; + uint16 x = 0; + uint16 y = 0; + uint16 hoffset = 0; + uint16 voffset = 0; + } mode7; + + struct Window { + //serialization.cpp + auto serialize(serializer&) -> void; + + uint8 oneLeft = 0; + uint8 oneRight = 0; + uint8 twoLeft = 0; + uint8 twoRight = 0; + } window; + + struct WindowLayer { + //serialization.cpp + auto serialize(serializer&) -> void; + + bool oneEnable = 0; + bool oneInvert = 0; + bool twoEnable = 0; + bool twoInvert = 0; + uint mask = 0; + bool aboveEnable = 0; + bool belowEnable = 0; + }; + + struct WindowColor { + //serialization.cpp + auto serialize(serializer&) -> void; + + bool oneEnable = 0; + bool oneInvert = 0; + bool twoEnable = 0; + bool twoInvert = 0; + uint mask = 0; + uint aboveMask = 0; + uint belowMask = 0; + }; + + struct Background { + //serialization.cpp + auto serialize(serializer&) -> void; + + WindowLayer window; + + bool aboveEnable = 0; + bool belowEnable = 0; + bool mosaicEnable = 0; + uint16 tiledataAddress = 0; + uint16 screenAddress = 0; + uint8 screenSize = 0; + bool tileSize = 0; + uint16 hoffset = 0; + uint16 voffset = 0; + uint8 tileMode = 0; + uint8 priority[2] = {}; + } bg1, bg2, bg3, bg4; + + struct Object { + //serialization.cpp + auto serialize(serializer&) -> void; + + WindowLayer window; + + bool aboveEnable = 0; + bool belowEnable = 0; + bool interlace = 0; + uint8 baseSize = 0; + uint8 nameselect = 0; + uint16 tiledataAddress = 0; + uint8 first = 0; + bool rangeOver = 0; + bool timeOver = 0; + uint8 priority[4] = {}; + } obj; + + struct Color { + //serialization.cpp + auto serialize(serializer&) -> void; + + WindowColor window; + + bool enable[7] = {}; + bool directColor = 0; + bool blendMode = 0; //0 = fixed; 1 = pixel + bool halve = 0; + bool mathMode = 0; //0 = add; 1 = sub + uint16 fixedColor = 0; + } col; + }; + + struct Object { + //serialization.cpp + auto serialize(serializer&) -> void; + + uint16 x = 0; + uint8 y = 0; + uint8 character = 0; + bool nameselect = 0; + bool vflip = 0; + bool hflip = 0; + uint8 priority = 0; + uint8 palette = 0; + bool size = 0; + }; + + struct ObjectItem { + bool valid = 0; + uint8 index = 0; + uint8 width = 0; + uint8 height = 0; + }; + + struct ObjectTile { + bool valid = 0; + uint16 x = 0; + uint8 y = 0; + uint8 priority = 0; + uint8 palette = 0; + bool hflip = 0; + uint32 data = 0; + }; + + struct Pixel { + uint8 source = 0; + uint8 priority = 0; + uint16 color = 0; + }; + + //io.cpp + auto latchCounters(uint hcounter, uint vcounter) -> void; + auto latchCounters() -> void; + alwaysinline auto vramAddress() const -> uint; + alwaysinline auto readVRAM() -> uint16; + template alwaysinline auto writeVRAM(uint8 data) -> void; + alwaysinline auto readOAM(uint10 address) -> uint8; + alwaysinline auto writeOAM(uint10 address, uint8 data) -> void; + template alwaysinline auto readCGRAM(uint8 address) -> uint8; + alwaysinline auto writeCGRAM(uint8 address, uint15 data) -> void; + auto readIO(uint address, uint8 data) -> uint8; + auto writeIO(uint address, uint8 data) -> void; + auto updateVideoMode() -> void; + + //object.cpp + auto oamAddressReset() -> void; + auto oamSetFirstObject() -> void; + auto readObject(uint10 address) -> uint8; + auto writeObject(uint10 address, uint8 data) -> void; + +//serialized: + Latch latch; + IO io; + + uint16 vram[32 * 1024] = {}; + uint16 cgram[256] = {}; + Object objects[128] = {}; + + //[unserialized] + uint16* output = {}; + uint16* lightTable[16] = {}; + + uint ItemLimit = 0; + uint TileLimit = 0; + + struct Line { + //line.cpp + inline auto field() const -> bool { return fieldID; } + static auto flush() -> void; + auto cache() -> void; + auto render(bool field) -> void; + auto pixel(uint x, Pixel above, Pixel below) const -> uint16; + auto blend(uint x, uint y, bool halve) const -> uint16; + alwaysinline auto directColor(uint paletteIndex, uint paletteColor) const -> uint16; + alwaysinline auto plotAbove(uint x, uint8 source, uint8 priority, uint16 color) -> void; + alwaysinline auto plotBelow(uint x, uint8 source, uint8 priority, uint16 color) -> void; + alwaysinline auto plotHD(Pixel*, uint x, uint8 source, uint8 priority, uint16 color, bool hires, bool subpixel) -> void; + + //background.cpp + auto renderBackground(PPU::IO::Background&, uint8 source) -> void; + auto getTile(PPU::IO::Background&, uint hoffset, uint voffset) -> uint; + + //mode7.cpp + auto renderMode7(PPU::IO::Background&, uint8 source) -> void; + + //mode7hd.cpp + static auto cacheMode7HD() -> void; + auto renderMode7HD(PPU::IO::Background&, uint8 source) -> void; + alwaysinline auto lerp(float pa, float va, float pb, float vb, float pr) -> float; + + //mode7hd-avx2.cpp + auto renderMode7HD_AVX2( + PPU::IO::Background&, uint8 source, + Pixel* above, Pixel* below, + bool* windowAbove, bool* windowBelow, + float originX, float a, + float originY, float c + ) -> void; + + //object.cpp + auto renderObject(PPU::IO::Object&) -> void; + + //window.cpp + auto renderWindow(PPU::IO::WindowLayer&, bool enable, bool output[256]) -> void; + auto renderWindow(PPU::IO::WindowColor&, uint mask, bool output[256]) -> void; + + //unserialized: + uint y; //constant + bool fieldID; + + IO io; + uint16 cgram[256]; + + ObjectItem items[128]; //32 on real hardware + ObjectTile tiles[128]; //34 on real hardware; 1024 max (128 * 64-width tiles) + + Pixel above[256 * 9 * 9]; + Pixel below[256 * 9 * 9]; + + bool windowAbove[256]; + bool windowBelow[256]; + + //flush() + static uint start; + static uint count; + }; + +//unserialized: + Line lines[240]; + + //used to help detect when the video output size changes between frames to clear overscan area. + struct Frame { + uint pitch = 0; + uint width = 0; + uint height = 0; + } frame; + + struct Mode7LineGroups { + int count = -1; + int startLine[32]; + int endLine[32]; + int startLerpLine[32]; + int endLerpLine[32]; + } mode7LineGroups; +}; + +extern PPU ppufast; + +#undef PPU diff --git a/sfc/ppu-fast/serialization.cpp b/sfc/ppu-fast/serialization.cpp new file mode 100644 index 0000000..ff6b417 --- /dev/null +++ b/sfc/ppu-fast/serialization.cpp @@ -0,0 +1,166 @@ +auto PPU::serialize(serializer& s) -> void { + ppubase.Thread::serialize(s); + PPUcounter::serialize(s); + + latch.serialize(s); + io.serialize(s); + s.array(vram); + s.array(cgram); + for(auto& object : objects) object.serialize(s); + + Line::start = 0; + Line::count = 0; +} + +auto PPU::Latch::serialize(serializer& s) -> void { + s.integer(interlace); + s.integer(overscan); + s.integer(hires); + s.integer(hd); + s.integer(ss); + s.integer(vram); + s.integer(oam); + s.integer(cgram); + s.integer(oamAddress); + s.integer(cgramAddress); + s.integer(mode7); + s.integer(counters); + s.integer(hcounter); + s.integer(vcounter); + ppu1.serialize(s); + ppu2.serialize(s); +} + +auto PPU::Latch::PPUstate::serialize(serializer& s) -> void { + s.integer(mdr); + s.integer(bgofs); +} + +auto PPU::IO::serialize(serializer& s) -> void { + s.integer(displayDisable); + s.integer(displayBrightness); + s.integer(oamBaseAddress); + s.integer(oamAddress); + s.integer(oamPriority); + s.integer(bgPriority); + s.integer(bgMode); + s.integer(vramIncrementMode); + s.integer(vramMapping); + s.integer(vramIncrementSize); + s.integer(vramAddress); + s.integer(cgramAddress); + s.integer(cgramAddressLatch); + s.integer(hcounter); + s.integer(vcounter); + s.integer(interlace); + s.integer(overscan); + s.integer(pseudoHires); + s.integer(extbg); + + mosaic.serialize(s); + mode7.serialize(s); + window.serialize(s); + bg1.serialize(s); + bg2.serialize(s); + bg3.serialize(s); + bg4.serialize(s); + obj.serialize(s); + col.serialize(s); +} + +auto PPU::IO::Mosaic::serialize(serializer& s) -> void { + s.integer(size); + s.integer(counter); +} + +auto PPU::IO::Mode7::serialize(serializer& s) -> void { + s.integer(hflip); + s.integer(vflip); + s.integer(repeat); + s.integer(a); + s.integer(b); + s.integer(c); + s.integer(d); + s.integer(x); + s.integer(y); + s.integer(hoffset); + s.integer(voffset); +} + +auto PPU::IO::Window::serialize(serializer& s) -> void { + s.integer(oneLeft); + s.integer(oneRight); + s.integer(twoLeft); + s.integer(twoRight); +} + +auto PPU::IO::WindowLayer::serialize(serializer& s) -> void { + s.integer(oneEnable); + s.integer(oneInvert); + s.integer(twoEnable); + s.integer(twoInvert); + s.integer(mask); + s.integer(aboveEnable); + s.integer(belowEnable); +} + +auto PPU::IO::WindowColor::serialize(serializer& s) -> void { + s.integer(oneEnable); + s.integer(oneInvert); + s.integer(twoEnable); + s.integer(twoInvert); + s.integer(mask); + s.integer(aboveMask); + s.integer(belowMask); +} + +auto PPU::IO::Background::serialize(serializer& s) -> void { + window.serialize(s); + s.integer(aboveEnable); + s.integer(belowEnable); + s.integer(mosaicEnable); + s.integer(tiledataAddress); + s.integer(screenAddress); + s.integer(screenSize); + s.integer(tileSize); + s.integer(hoffset); + s.integer(voffset); + s.integer(tileMode); + s.array(priority); +} + +auto PPU::IO::Object::serialize(serializer& s) -> void { + window.serialize(s); + s.integer(aboveEnable); + s.integer(belowEnable); + s.integer(interlace); + s.integer(baseSize); + s.integer(nameselect); + s.integer(tiledataAddress); + s.integer(first); + s.integer(rangeOver); + s.integer(timeOver); + s.array(priority); +} + +auto PPU::IO::Color::serialize(serializer& s) -> void { + window.serialize(s); + s.array(enable); + s.integer(directColor); + s.integer(blendMode); + s.integer(halve); + s.integer(mathMode); + s.integer(fixedColor); +} + +auto PPU::Object::serialize(serializer& s) -> void { + s.integer(x); + s.integer(y); + s.integer(character); + s.integer(nameselect); + s.integer(vflip); + s.integer(hflip); + s.integer(priority); + s.integer(palette); + s.integer(size); +} diff --git a/sfc/ppu-fast/window.cpp b/sfc/ppu-fast/window.cpp new file mode 100644 index 0000000..1794b99 --- /dev/null +++ b/sfc/ppu-fast/window.cpp @@ -0,0 +1,75 @@ +auto PPU::Line::renderWindow(PPU::IO::WindowLayer& self, bool enable, bool output[256]) -> void { + if(!enable || (!self.oneEnable && !self.twoEnable)) { + memory::fill(output, 256, 0); + return; + } + + if(self.oneEnable && !self.twoEnable) { + bool set = 1 ^ self.oneInvert, clear = !set; + for(uint x : range(256)) { + output[x] = x >= io.window.oneLeft && x <= io.window.oneRight ? set : clear; + } + return; + } + + if(self.twoEnable && !self.oneEnable) { + bool set = 1 ^ self.twoInvert, clear = !set; + for(uint x : range(256)) { + output[x] = x >= io.window.twoLeft && x <= io.window.twoRight ? set : clear; + } + return; + } + + for(uint x : range(256)) { + bool oneMask = (x >= io.window.oneLeft && x <= io.window.oneRight) ^ self.oneInvert; + bool twoMask = (x >= io.window.twoLeft && x <= io.window.twoRight) ^ self.twoInvert; + switch(self.mask) { + case 0: output[x] = (oneMask | twoMask) == 1; break; + case 1: output[x] = (oneMask & twoMask) == 1; break; + case 2: output[x] = (oneMask ^ twoMask) == 1; break; + case 3: output[x] = (oneMask ^ twoMask) == 0; break; + } + } +} + +auto PPU::Line::renderWindow(PPU::IO::WindowColor& self, uint mask, bool output[256]) -> void { + bool set, clear; + switch(mask) { + case 0: memory::fill(output, 256, 1); return; //always + case 1: set = 1, clear = 0; break; //inside + case 2: set = 0, clear = 1; break; //outside + case 3: memory::fill(output, 256, 0); return; //never + } + + if(!self.oneEnable && !self.twoEnable) { + memory::fill(output, 256, clear); + return; + } + + if(self.oneEnable && !self.twoEnable) { + if(self.oneInvert) set ^= 1, clear ^= 1; + for(uint x : range(256)) { + output[x] = x >= io.window.oneLeft && x <= io.window.oneRight ? set : clear; + } + return; + } + + if(self.twoEnable && !self.oneEnable) { + if(self.twoInvert) set ^= 1, clear ^= 1; + for(uint x : range(256)) { + output[x] = x >= io.window.twoLeft && x <= io.window.twoRight ? set : clear; + } + return; + } + + for(uint x : range(256)) { + bool oneMask = (x >= io.window.oneLeft && x <= io.window.oneRight) ^ self.oneInvert; + bool twoMask = (x >= io.window.twoLeft && x <= io.window.twoRight) ^ self.twoInvert; + switch(self.mask) { + case 0: output[x] = (oneMask | twoMask) == 1 ? set : clear; break; + case 1: output[x] = (oneMask & twoMask) == 1 ? set : clear; break; + case 2: output[x] = (oneMask ^ twoMask) == 1 ? set : clear; break; + case 3: output[x] = (oneMask ^ twoMask) == 0 ? set : clear; break; + } + } +} diff --git a/sfc/ppu/background.cpp b/sfc/ppu/background.cpp new file mode 100644 index 0000000..dcf3cc9 --- /dev/null +++ b/sfc/ppu/background.cpp @@ -0,0 +1,232 @@ +#include "mode7.cpp" + +auto PPU::Background::hires() const -> bool { + return ppu.io.bgMode == 5 || ppu.io.bgMode == 6; +} + +//V = 0, H = 0 +auto PPU::Background::frame() -> void { +} + +//H = 0 +auto PPU::Background::scanline() -> void { + mosaic.hcounter = ppu.mosaic.size; + mosaic.hoffset = 0; + + renderingIndex = 0; + pixelCounter = (io.hoffset & 7) << hires(); + + opt.hoffset = 0; + opt.voffset = 0; +} + +//H = 56 +auto PPU::Background::begin() -> void { + //remove partial tile columns that have been scrolled offscreen + for(auto& data : tiles[0].data) data >>= pixelCounter << 1; +} + +auto PPU::Background::fetchNameTable() -> void { + if(ppu.vcounter() == 0) return; + + uint nameTableIndex = ppu.hcounter() >> 5 << hires(); + int x = (ppu.hcounter() & ~31) >> 2; + + uint hpixel = x << hires(); + uint vpixel = ppu.vcounter(); + uint hscroll = io.hoffset; + uint vscroll = io.voffset; + + if(mosaic.enable) vpixel -= ppu.mosaic.voffset(); + if(hires()) { + hscroll <<= 1; + if(ppu.io.interlace) { + vpixel = vpixel << 1 | ppu.field(); + if(mosaic.enable) vpixel -= ppu.mosaic.voffset() + ppu.field(); + } + } + + bool repeated = false; + repeat: + + uint hoffset = hpixel + hscroll; + uint voffset = vpixel + vscroll; + + if(ppu.io.bgMode == 2 || ppu.io.bgMode == 4 || ppu.io.bgMode == 6) { + auto hlookup = ppu.bg3.opt.hoffset; + auto vlookup = ppu.bg3.opt.voffset; + uint valid = 1 << 13 + id; + + if(ppu.io.bgMode == 4) { + if(hlookup & valid) { + if(!(hlookup & 0x8000)) { + hoffset = hpixel + (hlookup & ~7) + (hscroll & 7); + } else { + voffset = vpixel + (vlookup); + } + } + } else { + if(hlookup & valid) hoffset = hpixel + (hlookup & ~7) + (hscroll & 7); + if(vlookup & valid) voffset = vpixel + (vlookup); + } + } + + uint width = 256 << hires(); + uint hsize = width << io.tileSize << io.screenSize.bit(0); + uint vsize = width << io.tileSize << io.screenSize.bit(1); + + hoffset &= hsize - 1; + voffset &= vsize - 1; + + uint vtiles = 3 + io.tileSize; + uint htiles = !hires() ? vtiles : 4; + + uint htile = hoffset >> htiles; + uint vtile = voffset >> vtiles; + + uint hscreen = io.screenSize.bit(0) ? 32 << 5 : 0; + uint vscreen = io.screenSize.bit(1) ? 32 << 5 + io.screenSize.bit(0) : 0; + + uint16 offset = (uint5)htile << 0 | (uint5)vtile << 5; + if(htile & 0x20) offset += hscreen; + if(vtile & 0x20) offset += vscreen; + + uint16 address = io.screenAddress + offset; + uint16 attributes = ppu.vram[address]; + + auto& tile = tiles[nameTableIndex]; + tile.character = attributes & 0x03ff; + tile.paletteGroup = attributes >> 10 & 7; + tile.priority = io.priority[attributes >> 13 & 1]; + tile.hmirror = bool(attributes & 0x4000); + tile.vmirror = bool(attributes & 0x8000); + + if(htiles == 4 && bool(hoffset & 8) != tile.hmirror) tile.character += 1; + if(vtiles == 4 && bool(voffset & 8) != tile.vmirror) tile.character += 16; + + uint characterMask = ppu.vram.mask >> 3 + io.mode; + uint characterIndex = io.tiledataAddress >> 3 + io.mode; + uint16 origin = tile.character + characterIndex & characterMask; + + if(tile.vmirror) voffset ^= 7; + tile.address = (origin << 3 + io.mode) + (voffset & 7); + + uint paletteOffset = ppu.io.bgMode == 0 ? id << 5 : 0; + uint paletteSize = 2 << io.mode; + tile.palette = paletteOffset + (tile.paletteGroup << paletteSize); + + nameTableIndex++; + if(hires() && !repeated) { + repeated = true; + hpixel += 8; + goto repeat; + } +} + +auto PPU::Background::fetchOffset(uint y) -> void { + if(ppu.vcounter() == 0) return; + + uint characterIndex = ppu.hcounter() >> 5 << hires(); + uint x = characterIndex << 3; + + uint hoffset = x + (io.hoffset & ~7); + uint voffset = y + (io.voffset); + + uint vtiles = 3 + io.tileSize; + uint htiles = !hires() ? vtiles : 4; + + uint htile = hoffset >> htiles; + uint vtile = voffset >> vtiles; + + uint hscreen = io.screenSize.bit(0) ? 32 << 5 : 0; + uint vscreen = io.screenSize.bit(1) ? 32 << 5 + io.screenSize.bit(0) : 0; + + uint16 offset = (uint5)htile << 0 | (uint5)vtile << 5; + if(htile & 0x20) offset += hscreen; + if(vtile & 0x20) offset += vscreen; + + uint16 address = io.screenAddress + offset; + if(y == 0) opt.hoffset = ppu.vram[address]; + if(y == 8) opt.voffset = ppu.vram[address]; +} + +auto PPU::Background::fetchCharacter(uint index, bool half) -> void { + if(ppu.vcounter() == 0) return; + + uint characterIndex = (ppu.hcounter() >> 5 << hires()) + half; + + auto& tile = tiles[characterIndex]; + uint16 data = ppu.vram[tile.address + (index << 3)]; + + //reverse bits so that the lowest bit is the left-most pixel + if(!tile.hmirror) { + data = data >> 4 & 0x0f0f | data << 4 & 0xf0f0; + data = data >> 2 & 0x3333 | data << 2 & 0xcccc; + data = data >> 1 & 0x5555 | data << 1 & 0xaaaa; + } + + //interleave two bitplanes for faster planar decoding later + tile.data[index] = ( + ((uint8(data >> 0) * 0x0101010101010101ull & 0x8040201008040201ull) * 0x0102040810204081ull >> 49) & 0x5555 + | ((uint8(data >> 8) * 0x0101010101010101ull & 0x8040201008040201ull) * 0x0102040810204081ull >> 48) & 0xaaaa + ); +} + +auto PPU::Background::run(bool screen) -> void { + if(ppu.vcounter() == 0) return; + + if(screen == Screen::Below) { + output.above.priority = 0; + output.below.priority = 0; + if(!hires()) return; + } + + if(io.mode == Mode::Mode7) return runMode7(); + + auto& tile = tiles[renderingIndex]; + uint8 color = 0; + if(io.mode >= Mode::BPP2) color |= (tile.data[0] & 3) << 0; tile.data[0] >>= 2; + if(io.mode >= Mode::BPP4) color |= (tile.data[1] & 3) << 2; tile.data[1] >>= 2; + if(io.mode >= Mode::BPP8) color |= (tile.data[2] & 3) << 4; tile.data[2] >>= 2; + if(io.mode >= Mode::BPP8) color |= (tile.data[3] & 3) << 6; tile.data[3] >>= 2; + + Pixel pixel; + pixel.priority = tile.priority; + pixel.palette = color ? uint(tile.palette + color) : 0; + pixel.paletteGroup = tile.paletteGroup; + if(++pixelCounter == 0) renderingIndex++; + + uint x = ppu.hcounter() - 56 >> 2; + if(x == 0) { + mosaic.hcounter = ppu.mosaic.size; + mosaic.pixel = pixel; + } else if((!hires() || screen == Screen::Below) && --mosaic.hcounter == 0) { + mosaic.hcounter = ppu.mosaic.size; + mosaic.pixel = pixel; + } else if(mosaic.enable) { + pixel = mosaic.pixel; + } + if(screen == Screen::Above) x++; + if(pixel.palette == 0) return; + + if(!hires() || screen == Screen::Above) if(io.aboveEnable) output.above = pixel; + if(!hires() || screen == Screen::Below) if(io.belowEnable) output.below = pixel; +} + +auto PPU::Background::power() -> void { + io = {}; + io.tiledataAddress = (random() & 0x0f) << 12; + io.screenAddress = (random() & 0xfc) << 8; + io.screenSize = random(); + io.tileSize = random(); + io.aboveEnable = random(); + io.belowEnable = random(); + io.hoffset = random(); + io.voffset = random(); + + output.above = {}; + output.below = {}; + + mosaic = {}; + mosaic.enable = random(); +} diff --git a/sfc/ppu/background.hpp b/sfc/ppu/background.hpp new file mode 100644 index 0000000..5df47dc --- /dev/null +++ b/sfc/ppu/background.hpp @@ -0,0 +1,85 @@ +struct Background { + Background(uint id) : id(id) {} + + alwaysinline auto hires() const -> bool; + + //background.cpp + auto frame() -> void; + auto scanline() -> void; + auto begin() -> void; + auto fetchNameTable() -> void; + auto fetchOffset(uint y) -> void; + auto fetchCharacter(uint index, bool half = 0) -> void; + auto run(bool screen) -> void; + auto power() -> void; + + //mode7.cpp + alwaysinline auto clip(int n) -> int; + auto runMode7() -> void; + + auto serialize(serializer&) -> void; + + struct ID { enum : uint { BG1, BG2, BG3, BG4 }; }; + const uint id; + + struct Mode { enum : uint { BPP2, BPP4, BPP8, Mode7, Inactive }; }; + struct ScreenSize { enum : uint { Size32x32, Size32x64, Size64x32, Size64x64 }; }; + struct TileSize { enum : uint { Size8x8, Size16x16 }; }; + struct Screen { enum : uint { Above, Below }; }; + + struct IO { + uint16 tiledataAddress; + uint16 screenAddress; + uint2 screenSize; + uint1 tileSize; + + uint8 mode; + uint8 priority[2]; + + uint1 aboveEnable; + uint1 belowEnable; + + uint16 hoffset; + uint16 voffset; + } io; + + struct Pixel { + uint8 priority; //0 = none (transparent) + uint8 palette; + uint3 paletteGroup; + } above, below; + + struct Output { + Pixel above; + Pixel below; + } output; + + struct Mosaic { + uint1 enable; + uint16 hcounter; + uint16 hoffset; + Pixel pixel; + } mosaic; + + struct OffsetPerTile { + //set in BG3 only; used by BG1 and BG2 + uint16 hoffset; + uint16 voffset; + } opt; + + struct Tile { + uint16 address; + uint10 character; + uint8 palette; + uint3 paletteGroup; + uint8 priority; + uint1 hmirror; + uint1 vmirror; + uint16 data[4]; + } tiles[66]; + + uint7 renderingIndex; + uint3 pixelCounter; + + friend class PPU; +}; diff --git a/sfc/ppu/counter/counter-inline.hpp b/sfc/ppu/counter/counter-inline.hpp new file mode 100755 index 0000000..687a7fa --- /dev/null +++ b/sfc/ppu/counter/counter-inline.hpp @@ -0,0 +1,84 @@ +auto PPUcounter::tick() -> void { + time.hcounter += 2; //increment by smallest unit of time. + if(time.hcounter == hperiod()) { + last.hperiod = hperiod(); + time.hcounter = 0; + tickScanline(); + } +} + +auto PPUcounter::tick(uint clocks) -> void { + time.hcounter += clocks; + if(time.hcounter >= hperiod()) { + last.hperiod = hperiod(); + time.hcounter -= hperiod(); + tickScanline(); + } +} + +auto PPUcounter::tickScanline() -> void { + if(++time.vcounter == 128) { + //it's not important when this is captured: it is only needed at V=240 or V=311. + time.interlace = ppu.interlace(); + time.vperiod += interlace() && !field(); + } + + if(vcounter() == vperiod()) { + last.vperiod = vperiod(); + //this may be off by one until V=128, hence why vperiod() is a private function. + time.vperiod = Region::NTSC() ? 262 : 312; + time.vcounter = 0; + time.field ^= 1; + } + + time.hperiod = 1364; + //NTSC and PAL scanline rates would not match up with color clocks if every scanline were 1364 clocks. + //to offset for this error, NTSC has one short scanline, and PAL has one long scanline. + if(Region::NTSC() && interlace() == 0 && field() == 1 && vcounter() == 240) time.hperiod -= 4; + if(Region::PAL() && interlace() == 1 && field() == 1 && vcounter() == 311) time.hperiod += 4; + if(scanline) scanline(); +} + +auto PPUcounter::interlace() const -> bool { return time.interlace; } +auto PPUcounter::field() const -> bool { return time.field; } +auto PPUcounter::vcounter() const -> uint { return time.vcounter; } +auto PPUcounter::hcounter() const -> uint { return time.hcounter; } +auto PPUcounter::vperiod() const -> uint { return time.vperiod; } +auto PPUcounter::hperiod() const -> uint { return time.hperiod; } + +auto PPUcounter::vcounter(uint offset) const -> uint { + if(offset <= hcounter()) return vcounter(); + if(vcounter() > 0) return vcounter() - 1; + return last.vperiod - 1; +} + +auto PPUcounter::hcounter(uint offset) const -> uint { + if(offset <= hcounter()) return hcounter() - offset; + return hcounter() + last.hperiod - offset; +} + +//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. +//it is not known what happens for PAL 1368 clock scanlines. +// +//dot 323 range = {1292, 1294, 1296} +//dot 327 range = {1310, 1312, 1314} + +auto PPUcounter::hdot() const -> uint { + if(hperiod() == 1360) { + return hcounter() >> 2; + } else { + return hcounter() - ((hcounter() > 1292) << 1) - ((hcounter() > 1310) << 1) >> 2; + } +} + +auto PPUcounter::reset() -> void { + time = {}; + last = {}; + + time.vperiod = last.vperiod = Region::NTSC() ? 262 : 312; + time.hperiod = last.hperiod = 1364; +} diff --git a/sfc/ppu/counter/counter.hpp b/sfc/ppu/counter/counter.hpp new file mode 100755 index 0000000..d4e5371 --- /dev/null +++ b/sfc/ppu/counter/counter.hpp @@ -0,0 +1,48 @@ +//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. + +struct PPUcounter { + alwaysinline auto tick() -> void; + alwaysinline auto tick(uint clocks) -> void; private: + alwaysinline auto tickScanline() -> void; public: + + alwaysinline auto interlace() const -> bool; + alwaysinline auto field() const -> bool; + alwaysinline auto vcounter() const -> uint; + alwaysinline auto hcounter() const -> uint; + alwaysinline auto hdot() const -> uint; private: + alwaysinline auto vperiod() const -> uint; public: + alwaysinline auto hperiod() const -> uint; + + alwaysinline auto vcounter(uint offset) const -> uint; + alwaysinline auto hcounter(uint offset) const -> uint; + + inline auto reset() -> void; + auto serialize(serializer&) -> void; + + function scanline; + +private: + struct { + bool interlace = 0; + bool field = 0; + uint vperiod = 0; + uint hperiod = 0; + uint vcounter = 0; + uint hcounter = 0; + } time; + + struct { + uint vperiod = 0; + uint hperiod = 0; + } last; +}; diff --git a/sfc/ppu/counter/serialization.cpp b/sfc/ppu/counter/serialization.cpp new file mode 100644 index 0000000..aa798af --- /dev/null +++ b/sfc/ppu/counter/serialization.cpp @@ -0,0 +1,11 @@ +auto PPUcounter::serialize(serializer& s) -> void { + s.integer(time.interlace); + s.integer(time.field); + s.integer(time.vperiod); + s.integer(time.hperiod); + s.integer(time.vcounter); + s.integer(time.hcounter); + + s.integer(last.vperiod); + s.integer(last.hperiod); +} diff --git a/sfc/ppu/io.cpp b/sfc/ppu/io.cpp new file mode 100644 index 0000000..745b333 --- /dev/null +++ b/sfc/ppu/io.cpp @@ -0,0 +1,755 @@ +auto PPU::latchCounters(uint hcounter, uint vcounter) -> void { + if(system.fastPPU()) { + return ppufast.latchCounters(hcounter, vcounter); + } + + io.hcounter = hcounter; + io.vcounter = vcounter; + latch.counters = 1; +} + +auto PPU::latchCounters() -> void { + if(system.fastPPU()) { + return ppufast.latchCounters(); + } + + cpu.synchronizePPU(); + io.hcounter = hdot(); + io.vcounter = vcounter(); + latch.counters = 1; +} + +auto PPU::addressVRAM() const -> uint16 { + uint16 address = io.vramAddress; + switch(io.vramMapping) { + case 0: return address; + case 1: return address & 0xff00 | address << 3 & 0x00f8 | address >> 5 & 7; + case 2: return address & 0xfe00 | address << 3 & 0x01f8 | address >> 6 & 7; + case 3: return address & 0xfc00 | address << 3 & 0x03f8 | address >> 7 & 7; + } + unreachable; +} + +auto PPU::readVRAM() -> uint16 { + if(!io.displayDisable && vcounter() < vdisp()) return 0x0000; + auto address = addressVRAM(); + return vram[address]; +} + +auto PPU::writeVRAM(bool byte, uint8 data) -> void { + if(!io.displayDisable && vcounter() < vdisp()) return; + auto address = addressVRAM(); + if(byte == 0) vram[address] = vram[address] & 0xff00 | data << 0; + if(byte == 1) vram[address] = vram[address] & 0x00ff | data << 8; +} + +auto PPU::readOAM(uint10 addr) -> uint8 { + if(!io.displayDisable && vcounter() < vdisp()) addr = latch.oamAddress; + return obj.oam.read(addr); +} + +auto PPU::writeOAM(uint10 addr, uint8 data) -> void { + if(!io.displayDisable && vcounter() < vdisp()) addr = latch.oamAddress; + obj.oam.write(addr, data); +} + +auto PPU::readCGRAM(bool byte, uint8 addr) -> uint8 { + if(!io.displayDisable + && vcounter() > 0 && vcounter() < vdisp() + && hcounter() >= 88 && hcounter() < 1096 + ) addr = latch.cgramAddress; + return screen.cgram[addr].byte(byte); +} + +auto PPU::writeCGRAM(uint8 addr, uint15 data) -> void { + if(!io.displayDisable + && vcounter() > 0 && vcounter() < vdisp() + && hcounter() >= 88 && hcounter() < 1096 + ) addr = latch.cgramAddress; + screen.cgram[addr] = data; +} + +auto PPU::readIO(uint addr, uint8 data) -> uint8 { + cpu.synchronizePPU(); + + 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 ppu1.mdr; + } + + //MPYL + case 0x2134: { + uint24 result = (int16)io.m7a * (int8)(io.m7b >> 8); + return ppu1.mdr = result.byte(0); + } + + //MPYM + case 0x2135: { + uint24 result = (int16)io.m7a * (int8)(io.m7b >> 8); + return ppu1.mdr = result.byte(1); + } + + //MPYH + case 0x2136: { + uint24 result = (int16)io.m7a * (int8)(io.m7b >> 8); + return ppu1.mdr = result.byte(2); + } + + //SLHV + case 0x2137: { + if(cpu.pio() & 0x80) latchCounters(); + return data; //CPU MDR + } + + //OAMDATAREAD + case 0x2138: { + ppu1.mdr = readOAM(io.oamAddress++); + obj.setFirstSprite(); + return ppu1.mdr; + } + + //VMDATALREAD + case 0x2139: { + ppu1.mdr = latch.vram >> 0; + if(io.vramIncrementMode == 0) { + latch.vram = readVRAM(); + io.vramAddress += io.vramIncrementSize; + } + return ppu1.mdr; + } + + //VMDATAHREAD + case 0x213a: { + ppu1.mdr = latch.vram >> 8; + if(io.vramIncrementMode == 1) { + latch.vram = readVRAM(); + io.vramAddress += io.vramIncrementSize; + } + return ppu1.mdr; + } + + //CGDATAREAD + case 0x213b: { + if(io.cgramAddressLatch++ == 0) { + ppu2.mdr = readCGRAM(0, io.cgramAddress); + } else { + ppu2.mdr &= 0x80; + ppu2.mdr |= readCGRAM(1, io.cgramAddress++) & 0x7f; + } + return ppu2.mdr; + } + + //OPHCT + case 0x213c: { + if(latch.hcounter++ == 0) { + ppu2.mdr = io.hcounter >> 0; + } else { + ppu2.mdr &= 0xfe; + ppu2.mdr |= io.hcounter >> 8 & 1; + } + return ppu2.mdr; + } + + //OPVCT + case 0x213d: { + if(latch.vcounter++ == 0) { + ppu2.mdr = io.vcounter >> 0; + } else { + ppu2.mdr &= 0xfe; + ppu2.mdr |= io.vcounter >> 8 & 1; + } + return ppu2.mdr; + } + + //STAT77 + case 0x213e: { + ppu1.mdr &= 1 << 4; + ppu1.mdr |= ppu1.version << 0; + ppu1.mdr |= obj.io.rangeOver << 6; + ppu1.mdr |= obj.io.timeOver << 7; + return ppu1.mdr; + } + + //STAT78 + case 0x213f: { + latch.hcounter = 0; + latch.vcounter = 0; + ppu2.mdr &= 1 << 5; + ppu2.mdr |= ppu2.version; + ppu2.mdr |= Region::PAL() << 4; //0 = NTSC, 1 = PAL + if(!(cpu.pio() & 0x80)) { + ppu2.mdr |= 1 << 6; + } else { + ppu2.mdr |= latch.counters << 6; + latch.counters = 0; + } + ppu2.mdr |= field() << 7; + return ppu2.mdr; + } + + } + + return data; +} + +auto PPU::writeIO(uint addr, uint8 data) -> void { + cpu.synchronizePPU(); + + switch(addr & 0xffff) { + + //INIDISP + case 0x2100: { + if(io.displayDisable && vcounter() == vdisp()) obj.addressReset(); + io.displayBrightness = data >> 0 & 15; + io.displayDisable = data >> 7 & 1; + return; + } + + //OBSEL + case 0x2101: { + obj.io.tiledataAddress = (data & 7) << 13; + obj.io.nameselect = data >> 3 & 3; + obj.io.baseSize = data >> 5 & 7; + return; + } + + //OAMADDL + case 0x2102: { + io.oamBaseAddress = (io.oamBaseAddress & 0x0200) | data << 1; + obj.addressReset(); + return; + } + + //OAMADDH + case 0x2103: { + io.oamBaseAddress = (data & 1) << 9 | (io.oamBaseAddress & 0x01fe); + io.oamPriority = bool(data & 0x80); + obj.addressReset(); + return; + } + + //OAMDATA + case 0x2104: { + uint1 latchBit = io.oamAddress & 1; + uint10 address = io.oamAddress++; + if(latchBit == 0) latch.oam = data; + if(address & 0x200) { + writeOAM(address, data); + } else if(latchBit == 1) { + writeOAM((address & ~1) + 0, latch.oam); + writeOAM((address & ~1) + 1, data); + } + obj.setFirstSprite(); + return; + } + + //BGMODE + case 0x2105: { + io.bgMode = data >> 0 & 7; + io.bgPriority = data >> 3 & 1; + bg1.io.tileSize = data >> 4 & 1; + bg2.io.tileSize = data >> 5 & 1; + bg3.io.tileSize = data >> 6 & 1; + bg4.io.tileSize = data >> 7 & 1; + updateVideoMode(); + return; + } + + //MOSAIC + case 0x2106: { + bool mosaicEnable = mosaic.enable(); + bg1.mosaic.enable = data >> 0 & 1; + bg2.mosaic.enable = data >> 1 & 1; + bg3.mosaic.enable = data >> 2 & 1; + bg4.mosaic.enable = data >> 3 & 1; + mosaic.size = (data >> 4 & 15) + 1; + if(!mosaicEnable && mosaic.enable()) { + //mosaic vcounter is reloaded when mosaic becomes enabled + mosaic.vcounter = mosaic.size + 1; + } + return; + } + + //BG1SC + case 0x2107: { + bg1.io.screenSize = data & 3; + bg1.io.screenAddress = data >> 2 << 10; + return; + } + + //BG2SC + case 0x2108: { + bg2.io.screenSize = data & 3; + bg2.io.screenAddress = data >> 2 << 10; + return; + } + + //BG3SC + case 0x2109: { + bg3.io.screenSize = data & 3; + bg3.io.screenAddress = data >> 2 << 10; + return; + } + + //BG4SC + case 0x210a: { + bg4.io.screenSize = data & 3; + bg4.io.screenAddress = data >> 2 << 10; + return; + } + + //BG12NBA + case 0x210b: { + bg1.io.tiledataAddress = (data >> 0 & 15) << 12; + bg2.io.tiledataAddress = (data >> 4 & 15) << 12; + return; + } + + //BG34NBA + case 0x210c: { + bg3.io.tiledataAddress = (data >> 0 & 15) << 12; + bg4.io.tiledataAddress = (data >> 4 & 15) << 12; + return; + } + + //BG1HOFS + case 0x210d: { + io.hoffsetMode7 = data << 8 | latch.mode7; + latch.mode7 = data; + + bg1.io.hoffset = data << 8 | (latch.bgofsPPU1 & ~7) | (latch.bgofsPPU2 & 7); + latch.bgofsPPU1 = data; + latch.bgofsPPU2 = data; + return; + } + + //BG1VOFS + case 0x210e: { + io.voffsetMode7 = data << 8 | latch.mode7; + latch.mode7 = data; + + bg1.io.voffset = data << 8 | latch.bgofsPPU1; + latch.bgofsPPU1 = data; + return; + } + + //BG2HOFS + case 0x210f: { + bg2.io.hoffset = data << 8 | (latch.bgofsPPU1 & ~7) | (latch.bgofsPPU2 & 7); + latch.bgofsPPU1 = data; + latch.bgofsPPU2 = data; + return; + } + + //BG2VOFS + case 0x2110: { + bg2.io.voffset = data << 8 | latch.bgofsPPU1; + latch.bgofsPPU1 = data; + return; + } + + //BG3HOFS + case 0x2111: { + bg3.io.hoffset = data << 8 | (latch.bgofsPPU1 & ~7) | (latch.bgofsPPU2 & 7); + latch.bgofsPPU1 = data; + latch.bgofsPPU2 = data; + return; + } + + //BG3VOFS + case 0x2112: { + bg3.io.voffset = data << 8 | latch.bgofsPPU1; + latch.bgofsPPU1 = data; + return; + } + + //BG4HOFS + case 0x2113: { + bg4.io.hoffset = data << 8 | (latch.bgofsPPU1 & ~7) | (latch.bgofsPPU2 & 7); + latch.bgofsPPU1 = data; + latch.bgofsPPU2 = data; + return; + } + + //BG4VOFS + case 0x2114: { + bg4.io.voffset = data << 8 | latch.bgofsPPU1; + latch.bgofsPPU1 = data; + return; + } + + //VMAIN + case 0x2115: { + static const uint size[4] = {1, 32, 128, 128}; + io.vramIncrementSize = size[data & 3]; + io.vramMapping = data >> 2 & 3; + io.vramIncrementMode = data >> 7 & 1; + return; + } + + //VMADDL + case 0x2116: { + io.vramAddress = io.vramAddress & 0xff00 | data << 0; + latch.vram = readVRAM(); + return; + } + + //VMADDH + case 0x2117: { + io.vramAddress = io.vramAddress & 0x00ff | data << 8; + latch.vram = readVRAM(); + return; + } + + //VMDATAL + case 0x2118: { + writeVRAM(0, data); + if(io.vramIncrementMode == 0) io.vramAddress += io.vramIncrementSize; + return; + } + + //VMDATAH + case 0x2119: { + writeVRAM(1, data); + if(io.vramIncrementMode == 1) io.vramAddress += io.vramIncrementSize; + return; + } + + //M7SEL + case 0x211a: { + io.hflipMode7 = data >> 0 & 1; + io.vflipMode7 = data >> 1 & 1; + io.repeatMode7 = data >> 6 & 3; + return; + } + + //M7A + case 0x211b: { + io.m7a = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + //M7B + case 0x211c: { + io.m7b = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + //M7C + case 0x211d: { + io.m7c = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + //M7D + case 0x211e: { + io.m7d = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + //M7X + case 0x211f: { + io.m7x = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + //M7Y + case 0x2120: { + io.m7y = data << 8 | latch.mode7; + latch.mode7 = data; + return; + } + + //CGADD + case 0x2121: { + io.cgramAddress = data; + io.cgramAddressLatch = 0; + return; + } + + //CGDATA + case 0x2122: { + if(io.cgramAddressLatch++ == 0) { + latch.cgram = data; + } else { + writeCGRAM(io.cgramAddress++, (data & 0x7f) << 8 | latch.cgram); + } + return; + } + + //W12SEL + case 0x2123: { + window.io.bg1.oneInvert = data >> 0 & 1; + window.io.bg1.oneEnable = data >> 1 & 1; + window.io.bg1.twoInvert = data >> 2 & 1; + window.io.bg1.twoEnable = data >> 3 & 1; + window.io.bg2.oneInvert = data >> 4 & 1; + window.io.bg2.oneEnable = data >> 5 & 1; + window.io.bg2.twoInvert = data >> 6 & 1; + window.io.bg2.twoEnable = data >> 7 & 1; + return; + } + + //W34SEL + case 0x2124: { + window.io.bg3.oneInvert = data >> 0 & 1; + window.io.bg3.oneEnable = data >> 1 & 1; + window.io.bg3.twoInvert = data >> 2 & 1; + window.io.bg3.twoEnable = data >> 3 & 1; + window.io.bg4.oneInvert = data >> 4 & 1; + window.io.bg4.oneEnable = data >> 5 & 1; + window.io.bg4.twoInvert = data >> 6 & 1; + window.io.bg4.twoEnable = data >> 7 & 1; + return; + } + + //WOBJSEL + case 0x2125: { + window.io.obj.oneInvert = data >> 0 & 1; + window.io.obj.oneEnable = data >> 1 & 1; + window.io.obj.twoInvert = data >> 2 & 1; + window.io.obj.twoEnable = data >> 3 & 1; + window.io.col.oneInvert = data >> 4 & 1; + window.io.col.oneEnable = data >> 5 & 1; + window.io.col.twoInvert = data >> 6 & 1; + window.io.col.twoEnable = data >> 7 & 1; + return; + } + + //WH0 + case 0x2126: { + window.io.oneLeft = data; + return; + } + + //WH1 + case 0x2127: { + window.io.oneRight = data; + return; + } + + //WH2 + case 0x2128: { + window.io.twoLeft = data; + return; + } + + //WH3 + case 0x2129: { + window.io.twoRight = data; + return; + } + + //WBGLOG + case 0x212a: { + window.io.bg1.mask = data >> 0 & 3; + window.io.bg2.mask = data >> 2 & 3; + window.io.bg3.mask = data >> 4 & 3; + window.io.bg4.mask = data >> 6 & 3; + return; + } + + //WOBJLOG + case 0x212b: { + window.io.obj.mask = data >> 0 & 3; + window.io.col.mask = data >> 2 & 3; + return; + } + + //TM + case 0x212c: { + bg1.io.aboveEnable = data >> 0 & 1; + bg2.io.aboveEnable = data >> 1 & 1; + bg3.io.aboveEnable = data >> 2 & 1; + bg4.io.aboveEnable = data >> 3 & 1; + obj.io.aboveEnable = data >> 4 & 1; + return; + } + + //TS + case 0x212d: { + bg1.io.belowEnable = data >> 0 & 1; + bg2.io.belowEnable = data >> 1 & 1; + bg3.io.belowEnable = data >> 2 & 1; + bg4.io.belowEnable = data >> 3 & 1; + obj.io.belowEnable = data >> 4 & 1; + return; + } + + //TMW + case 0x212e: { + window.io.bg1.aboveEnable = data >> 0 & 1; + window.io.bg2.aboveEnable = data >> 1 & 1; + window.io.bg3.aboveEnable = data >> 2 & 1; + window.io.bg4.aboveEnable = data >> 3 & 1; + window.io.obj.aboveEnable = data >> 4 & 1; + return; + } + + //TSW + case 0x212f: { + window.io.bg1.belowEnable = data >> 0 & 1; + window.io.bg2.belowEnable = data >> 1 & 1; + window.io.bg3.belowEnable = data >> 2 & 1; + window.io.bg4.belowEnable = data >> 3 & 1; + window.io.obj.belowEnable = data >> 4 & 1; + return; + } + + //CGWSEL + case 0x2130: { + screen.io.directColor = data >> 0 & 1; + screen.io.blendMode = data >> 1 & 1; + window.io.col.belowMask = data >> 4 & 3; + window.io.col.aboveMask = data >> 6 & 3; + return; + } + + //CGADDSUB + case 0x2131: { + screen.io.bg1.colorEnable = data >> 0 & 1; + screen.io.bg2.colorEnable = data >> 1 & 1; + screen.io.bg3.colorEnable = data >> 2 & 1; + screen.io.bg4.colorEnable = data >> 3 & 1; + screen.io.obj.colorEnable = data >> 4 & 1; + screen.io.back.colorEnable = data >> 5 & 1; + screen.io.colorHalve = data >> 6 & 1; + screen.io.colorMode = data >> 7 & 1; + return; + } + + //COLDATA + case 0x2132: { + if(data & 0x20) screen.io.colorRed = data & 0x1f; + if(data & 0x40) screen.io.colorGreen = data & 0x1f; + if(data & 0x80) screen.io.colorBlue = data & 0x1f; + return; + } + + //SETINI + case 0x2133: { + io.interlace = data >> 0 & 1; + obj.io.interlace = data >> 1 & 1; + io.overscan = data >> 2 & 1; + io.pseudoHires = data >> 3 & 1; + io.extbg = data >> 6 & 1; + updateVideoMode(); + return; + } + + } +} + +auto PPU::updateVideoMode() -> void { + display.vdisp = !io.overscan ? 225 : 240; + + switch(io.bgMode) { + case 0: + bg1.io.mode = Background::Mode::BPP2; + bg2.io.mode = Background::Mode::BPP2; + bg3.io.mode = Background::Mode::BPP2; + bg4.io.mode = Background::Mode::BPP2; + memory::assign(bg1.io.priority, 8, 11); + memory::assign(bg2.io.priority, 7, 10); + memory::assign(bg3.io.priority, 2, 5); + memory::assign(bg4.io.priority, 1, 4); + memory::assign(obj.io.priority, 3, 6, 9, 12); + break; + + case 1: + bg1.io.mode = Background::Mode::BPP4; + bg2.io.mode = Background::Mode::BPP4; + bg3.io.mode = Background::Mode::BPP2; + bg4.io.mode = Background::Mode::Inactive; + if(io.bgPriority) { + memory::assign(bg1.io.priority, 5, 8); + memory::assign(bg2.io.priority, 4, 7); + memory::assign(bg3.io.priority, 1, 10); + memory::assign(obj.io.priority, 2, 3, 6, 9); + } else { + memory::assign(bg1.io.priority, 6, 9); + memory::assign(bg2.io.priority, 5, 8); + memory::assign(bg3.io.priority, 1, 3); + memory::assign(obj.io.priority, 2, 4, 7, 10); + } + break; + + case 2: + bg1.io.mode = Background::Mode::BPP4; + bg2.io.mode = Background::Mode::BPP4; + bg3.io.mode = Background::Mode::Inactive; + bg4.io.mode = Background::Mode::Inactive; + memory::assign(bg1.io.priority, 3, 7); + memory::assign(bg2.io.priority, 1, 5); + memory::assign(obj.io.priority, 2, 4, 6, 8); + break; + + case 3: + bg1.io.mode = Background::Mode::BPP8; + bg2.io.mode = Background::Mode::BPP4; + bg3.io.mode = Background::Mode::Inactive; + bg4.io.mode = Background::Mode::Inactive; + memory::assign(bg1.io.priority, 3, 7); + memory::assign(bg2.io.priority, 1, 5); + memory::assign(obj.io.priority, 2, 4, 6, 8); + break; + + case 4: + bg1.io.mode = Background::Mode::BPP8; + bg2.io.mode = Background::Mode::BPP2; + bg3.io.mode = Background::Mode::Inactive; + bg4.io.mode = Background::Mode::Inactive; + memory::assign(bg1.io.priority, 3, 7); + memory::assign(bg2.io.priority, 1, 5); + memory::assign(obj.io.priority, 2, 4, 6, 8); + break; + + case 5: + bg1.io.mode = Background::Mode::BPP4; + bg2.io.mode = Background::Mode::BPP2; + bg3.io.mode = Background::Mode::Inactive; + bg4.io.mode = Background::Mode::Inactive; + memory::assign(bg1.io.priority, 3, 7); + memory::assign(bg2.io.priority, 1, 5); + memory::assign(obj.io.priority, 2, 4, 6, 8); + break; + + case 6: + bg1.io.mode = Background::Mode::BPP4; + bg2.io.mode = Background::Mode::Inactive; + bg3.io.mode = Background::Mode::Inactive; + bg4.io.mode = Background::Mode::Inactive; + memory::assign(bg1.io.priority, 2, 5); + memory::assign(obj.io.priority, 1, 3, 4, 6); + break; + + case 7: + if(!io.extbg) { + bg1.io.mode = Background::Mode::Mode7; + bg2.io.mode = Background::Mode::Inactive; + bg3.io.mode = Background::Mode::Inactive; + bg4.io.mode = Background::Mode::Inactive; + memory::assign(bg1.io.priority, 2); + memory::assign(obj.io.priority, 1, 3, 4, 5); + } else { + bg1.io.mode = Background::Mode::Mode7; + bg2.io.mode = Background::Mode::Mode7; + bg3.io.mode = Background::Mode::Inactive; + bg4.io.mode = Background::Mode::Inactive; + memory::assign(bg1.io.priority, 3); + memory::assign(bg2.io.priority, 1, 5); + memory::assign(obj.io.priority, 2, 4, 6, 7); + } + break; + } +} diff --git a/sfc/ppu/main.cpp b/sfc/ppu/main.cpp new file mode 100644 index 0000000..68f994c --- /dev/null +++ b/sfc/ppu/main.cpp @@ -0,0 +1,195 @@ +auto PPU::main() -> void { + if(vcounter() == 0) { + if(display.overscan && !io.overscan) { + //when disabling overscan, clear the overscan area that won't be rendered to: + for(uint y = 1; y <= 240; y++) { + if(y >= 8 && y <= 231) continue; + auto output = ppu.output + y * 1024; + memory::fill(output, 1024); + } + } + display.interlace = io.interlace; + display.overscan = io.overscan; + bg1.frame(); + bg2.frame(); + bg3.frame(); + bg4.frame(); + obj.frame(); + } + + mosaic.scanline(); + bg1.scanline(); + bg2.scanline(); + bg3.scanline(); + bg4.scanline(); + obj.scanline(); + window.scanline(); + screen.scanline(); + + if(vcounter() > 240) { + step(hperiod()); + return; + } + + #define cycles02(index) cycle() + #define cycles04(index) cycles02(index); cycles02(index + 2) + #define cycles08(index) cycles04(index); cycles04(index + 4) + #define cycles16(index) cycles08(index); cycles08(index + 8) + #define cycles32(index) cycles16(index); cycles16(index + 16) + #define cycles64(index) cycles32(index); cycles32(index + 32) + cycles16( 0); + cycles04( 16); + //H = 20 + cycles04( 20); + cycles04( 24); + //H = 28 + cycles04( 28); + cycles32( 32); + cycles64( 64); + cycles64( 128); + cycles64( 192); + cycles64( 256); + cycles64( 320); + cycles64( 384); + cycles64( 448); + cycles64( 512); + cycles64( 576); + cycles64( 640); + cycles64( 704); + cycles64( 768); + cycles64( 832); + cycles64( 896); + cycles64( 960); + cycles32(1024); + cycles16(1056); + cycles08(1072); + //H = 1080 + obj.fetch(); + //H = 1352 (max) + step(hperiod() - hcounter()); +} + +//it would be lovely if we could put these functions inside cycle(), +//but due to the multiple template instantiations, that destroys L1 cache. +//it's a performance penalty of about 25% for the entire(!!) emulator. + +auto PPU::cycleObjectEvaluate() -> void { + obj.evaluate(hcounter() >> 3); +} + +template +auto PPU::cycleBackgroundFetch() -> void { + switch(io.bgMode) { + case 0: + if constexpr(Cycle == 0) bg4.fetchNameTable(); + if constexpr(Cycle == 1) bg3.fetchNameTable(); + if constexpr(Cycle == 2) bg2.fetchNameTable(); + if constexpr(Cycle == 3) bg1.fetchNameTable(); + if constexpr(Cycle == 4) bg4.fetchCharacter(0); + if constexpr(Cycle == 5) bg3.fetchCharacter(0); + if constexpr(Cycle == 6) bg2.fetchCharacter(0); + if constexpr(Cycle == 7) bg1.fetchCharacter(0); + break; + case 1: + if constexpr(Cycle == 0) bg3.fetchNameTable(); + if constexpr(Cycle == 1) bg2.fetchNameTable(); + if constexpr(Cycle == 2) bg1.fetchNameTable(); + if constexpr(Cycle == 3) bg3.fetchCharacter(0); + if constexpr(Cycle == 4) bg2.fetchCharacter(0); + if constexpr(Cycle == 5) bg2.fetchCharacter(1); + if constexpr(Cycle == 6) bg1.fetchCharacter(0); + if constexpr(Cycle == 7) bg1.fetchCharacter(1); + break; + case 2: + if constexpr(Cycle == 0) bg2.fetchNameTable(); + if constexpr(Cycle == 1) bg1.fetchNameTable(); + if constexpr(Cycle == 2) bg3.fetchOffset(0); + if constexpr(Cycle == 3) bg3.fetchOffset(8); + if constexpr(Cycle == 4) bg2.fetchCharacter(0); + if constexpr(Cycle == 5) bg2.fetchCharacter(1); + if constexpr(Cycle == 6) bg1.fetchCharacter(0); + if constexpr(Cycle == 7) bg1.fetchCharacter(1); + break; + case 3: + if constexpr(Cycle == 0) bg2.fetchNameTable(); + if constexpr(Cycle == 1) bg1.fetchNameTable(); + if constexpr(Cycle == 2) bg2.fetchCharacter(0); + if constexpr(Cycle == 3) bg2.fetchCharacter(1); + if constexpr(Cycle == 4) bg1.fetchCharacter(0); + if constexpr(Cycle == 5) bg1.fetchCharacter(1); + if constexpr(Cycle == 6) bg1.fetchCharacter(2); + if constexpr(Cycle == 7) bg1.fetchCharacter(3); + break; + case 4: + if constexpr(Cycle == 0) bg2.fetchNameTable(); + if constexpr(Cycle == 1) bg1.fetchNameTable(); + if constexpr(Cycle == 2) bg3.fetchOffset(0); + if constexpr(Cycle == 3) bg2.fetchCharacter(0); + if constexpr(Cycle == 4) bg1.fetchCharacter(0); + if constexpr(Cycle == 5) bg1.fetchCharacter(1); + if constexpr(Cycle == 6) bg1.fetchCharacter(2); + if constexpr(Cycle == 7) bg1.fetchCharacter(3); + break; + case 5: + if constexpr(Cycle == 0) bg2.fetchNameTable(); + if constexpr(Cycle == 1) bg1.fetchNameTable(); + if constexpr(Cycle == 2) bg2.fetchCharacter(0, 0); + if constexpr(Cycle == 3) bg2.fetchCharacter(0, 1); + if constexpr(Cycle == 4) bg1.fetchCharacter(0, 0); + if constexpr(Cycle == 5) bg1.fetchCharacter(1, 0); + if constexpr(Cycle == 6) bg1.fetchCharacter(0, 1); + if constexpr(Cycle == 7) bg1.fetchCharacter(1, 1); + break; + case 6: + if constexpr(Cycle == 0) bg2.fetchNameTable(); + if constexpr(Cycle == 1) bg1.fetchNameTable(); + if constexpr(Cycle == 2) bg3.fetchOffset(0); + if constexpr(Cycle == 3) bg3.fetchOffset(8); + if constexpr(Cycle == 4) bg1.fetchCharacter(0, 0); + if constexpr(Cycle == 5) bg1.fetchCharacter(1, 0); + if constexpr(Cycle == 6) bg1.fetchCharacter(0, 1); + if constexpr(Cycle == 7) bg1.fetchCharacter(1, 1); + break; + case 7: + //handled separately by mode7.cpp + break; + } +} + +auto PPU::cycleBackgroundBegin() -> void { + bg1.begin(); + bg2.begin(); + bg3.begin(); + bg4.begin(); +} + +auto PPU::cycleBackgroundBelow() -> void { + bg1.run(1); + bg2.run(1); + bg3.run(1); + bg4.run(1); +} + +auto PPU::cycleBackgroundAbove() -> void { + bg1.run(0); + bg2.run(0); + bg3.run(0); + bg4.run(0); +} + +auto PPU::cycleRenderPixel() -> void { + obj.run(); + window.run(); + screen.run(); +} + +template +auto PPU::cycle() -> void { + if constexpr(Cycle >= 0 && Cycle <= 1016 && (Cycle - 0) % 8 == 0) cycleObjectEvaluate(); + if constexpr(Cycle >= 0 && Cycle <= 1054 && (Cycle - 0) % 4 == 0) cycleBackgroundFetch<(Cycle - 0) / 4 & 7>(); + if constexpr(Cycle == 56 ) cycleBackgroundBegin(); + if constexpr(Cycle >= 56 && Cycle <= 1078 && (Cycle - 56) % 4 == 0) cycleBackgroundBelow(); + if constexpr(Cycle >= 56 && Cycle <= 1078 && (Cycle - 56) % 4 == 2) cycleBackgroundAbove(); + if constexpr(Cycle >= 56 && Cycle <= 1078 && (Cycle - 56) % 4 == 2) cycleRenderPixel(); + step(); +} diff --git a/sfc/ppu/mode7.cpp b/sfc/ppu/mode7.cpp new file mode 100644 index 0000000..4b4413b --- /dev/null +++ b/sfc/ppu/mode7.cpp @@ -0,0 +1,68 @@ +auto PPU::Background::clip(int n) -> int { + //13-bit sign extend: --s---nnnnnnnnnn -> ssssssnnnnnnnnnn + return n & 0x2000 ? (n | ~1023) : (n & 1023); +} + +auto PPU::Background::runMode7() -> void { + int a = (int16)ppu.io.m7a; + int b = (int16)ppu.io.m7b; + int c = (int16)ppu.io.m7c; + int d = (int16)ppu.io.m7d; + + int hcenter = (int13)ppu.io.m7x; + int vcenter = (int13)ppu.io.m7y; + int hoffset = (int13)ppu.io.hoffsetMode7; + int voffset = (int13)ppu.io.voffsetMode7; + + uint x = mosaic.hoffset; + uint y = ppu.vcounter(); + if(ppu.bg1.mosaic.enable) y -= ppu.mosaic.voffset(); //BG2 vertical mosaic uses BG1 mosaic enable + + if(!mosaic.enable) { + mosaic.hoffset += 1; + } else if(--mosaic.hcounter == 0) { + mosaic.hcounter = ppu.mosaic.size; + mosaic.hoffset += ppu.mosaic.size; + } + + if(ppu.io.hflipMode7) x = 255 - x; + if(ppu.io.vflipMode7) y = 255 - y; + + int originX = (a * clip(hoffset - hcenter) & ~63) + (b * clip(voffset - vcenter) & ~63) + (b * y & ~63) + (hcenter << 8); + int originY = (c * clip(hoffset - hcenter) & ~63) + (d * clip(voffset - vcenter) & ~63) + (d * y & ~63) + (vcenter << 8); + + int pixelX = originX + a * x >> 8; + int pixelY = originY + c * x >> 8; + uint16 paletteAddress = (uint3)pixelY << 3 | (uint3)pixelX; + + uint7 tileX = pixelX >> 3; + uint7 tileY = pixelY >> 3; + uint16 tileAddress = tileY << 7 | tileX; + + bool outOfBounds = (pixelX | pixelY) & ~1023; + + uint8 tile = ppu.io.repeatMode7 == 3 && outOfBounds ? 0 : ppu.vram[tileAddress] >> 0; + uint8 palette = ppu.io.repeatMode7 == 2 && outOfBounds ? 0 : ppu.vram[tile << 6 | paletteAddress] >> 8; + + uint priority; + if(id == ID::BG1) { + priority = io.priority[0]; + } else if(id == ID::BG2) { + priority = io.priority[palette >> 7]; + palette &= 0x7f; + } + + if(palette == 0) return; + + if(io.aboveEnable) { + output.above.priority = priority; + output.above.palette = palette; + output.above.paletteGroup = 0; + } + + if(io.belowEnable) { + output.below.priority = priority; + output.below.palette = palette; + output.below.paletteGroup = 0; + } +} diff --git a/sfc/ppu/mosaic.cpp b/sfc/ppu/mosaic.cpp new file mode 100644 index 0000000..79fe4d5 --- /dev/null +++ b/sfc/ppu/mosaic.cpp @@ -0,0 +1,26 @@ +auto PPU::Mosaic::enable() const -> bool { + if(ppu.bg1.mosaic.enable) return true; + if(ppu.bg2.mosaic.enable) return true; + if(ppu.bg3.mosaic.enable) return true; + if(ppu.bg4.mosaic.enable) return true; + return false; +} + +auto PPU::Mosaic::voffset() const -> uint { + return size - vcounter; +} + +//H = 0 +auto PPU::Mosaic::scanline() -> void { + if(ppu.vcounter() == 1) { + vcounter = enable() ? size + 1 : 0; + } + if(vcounter && !--vcounter) { + vcounter = enable() ? size + 0 : 0; + } +} + +auto PPU::Mosaic::power() -> void { + size = (random() & 15) + 1; + vcounter = 0; +} diff --git a/sfc/ppu/mosaic.hpp b/sfc/ppu/mosaic.hpp new file mode 100644 index 0000000..261739e --- /dev/null +++ b/sfc/ppu/mosaic.hpp @@ -0,0 +1,13 @@ +struct Mosaic { + //mosaic.cpp + alwaysinline auto enable() const -> bool; + alwaysinline auto voffset() const -> uint; + auto scanline() -> void; + auto power() -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + uint5 size; + uint5 vcounter; +}; diff --git a/sfc/ppu/oam.cpp b/sfc/ppu/oam.cpp new file mode 100644 index 0000000..b3d59fd --- /dev/null +++ b/sfc/ppu/oam.cpp @@ -0,0 +1,74 @@ +auto PPU::OAM::read(uint10 address) -> uint8 { + if(!(address & 0x200)) { + uint n = address >> 2; //object# + address &= 3; + if(address == 0) return object[n].x & 0xff; + if(address == 1) return object[n].y; + if(address == 2) return object[n].character; + return ( + object[n].nameselect << 0 + | object[n].palette << 1 + | object[n].priority << 4 + | object[n].hflip << 6 + | object[n].vflip << 7 + ); + } else { + uint n = (address & 0x1f) << 2; //object# + return ( + object[n + 0].x >> 8 << 0 + | object[n + 0].size << 1 + | object[n + 1].x >> 8 << 2 + | object[n + 1].size << 3 + | object[n + 2].x >> 8 << 4 + | object[n + 2].size << 5 + | object[n + 3].x >> 8 << 6 + | object[n + 3].size << 7 + ); + } +} + +auto PPU::OAM::write(uint10 address, uint8 data) -> void { + if(!(address & 0x200)) { + uint n = address >> 2; //object# + address &= 3; + if(address == 0) { object[n].x = object[n].x & 0x100 | data; return; } + if(address == 1) { object[n].y = data; return; } + if(address == 2) { object[n].character = data; return; } + object[n].nameselect = data >> 0 & 1; + object[n].palette = data >> 1 & 7; + object[n].priority = data >> 4 & 3; + object[n].hflip = data >> 6 & 1; + object[n].vflip = data >> 7 & 1; + } else { + uint n = (address & 0x1f) << 2; //object# + object[n + 0].x = object[n + 0].x & 0xff | bool(data & 0x01) << 8; + object[n + 0].size = bool(data & 0x02); + object[n + 1].x = object[n + 1].x & 0xff | bool(data & 0x04) << 8; + object[n + 1].size = bool(data & 0x08); + object[n + 2].x = object[n + 2].x & 0xff | bool(data & 0x10) << 8; + object[n + 2].size = bool(data & 0x20); + object[n + 3].x = object[n + 3].x & 0xff | bool(data & 0x40) << 8; + object[n + 3].size = bool(data & 0x80); + } +} + +auto PPU::OAM::Object::width() const -> uint { + if(size == 0) { + static const uint width[] = { 8, 8, 8, 16, 16, 32, 16, 16}; + return width[ppu.obj.io.baseSize]; + } else { + static const uint width[] = {16, 32, 64, 32, 64, 64, 32, 32}; + return width[ppu.obj.io.baseSize]; + } +} + +auto PPU::OAM::Object::height() const -> uint { + if(size == 0) { + if(ppu.obj.io.interlace && ppu.obj.io.baseSize >= 6) return 16; //hardware quirk + static const uint height[] = { 8, 8, 8, 16, 16, 32, 32, 32}; + return height[ppu.obj.io.baseSize]; + } else { + static const uint height[] = {16, 32, 64, 32, 64, 64, 64, 32}; + return height[ppu.obj.io.baseSize]; + } +} diff --git a/sfc/ppu/object.cpp b/sfc/ppu/object.cpp new file mode 100644 index 0000000..d22068b --- /dev/null +++ b/sfc/ppu/object.cpp @@ -0,0 +1,221 @@ +#include "oam.cpp" + +auto PPU::Object::addressReset() -> void { + ppu.io.oamAddress = ppu.io.oamBaseAddress; + setFirstSprite(); +} + +auto PPU::Object::setFirstSprite() -> void { + io.firstSprite = !ppu.io.oamPriority ? 0 : uint(ppu.io.oamAddress >> 2); +} + +auto PPU::Object::frame() -> void { + io.timeOver = false; + io.rangeOver = false; +} + +auto PPU::Object::scanline() -> void { + latch.firstSprite = io.firstSprite; + + t.x = 0; + t.y = ppu.vcounter(); + t.itemCount = 0; + t.tileCount = 0; + + t.active = !t.active; + auto oamItem = t.item[t.active]; + auto oamTile = t.tile[t.active]; + + for(uint n : range(32)) oamItem[n].valid = false; + for(uint n : range(34)) oamTile[n].valid = false; + + if(t.y == ppu.vdisp() && !ppu.io.displayDisable) addressReset(); + if(t.y >= ppu.vdisp() - 1 || ppu.io.displayDisable) return; +} + +auto PPU::Object::evaluate(uint7 index) -> void { + if(ppu.io.displayDisable) return; + if(t.itemCount > 32) return; + + auto oamItem = t.item[t.active]; + auto oamTile = t.tile[t.active]; + + uint7 sprite = latch.firstSprite + index; + if(!onScanline(oam.object[sprite])) return; + ppu.latch.oamAddress = sprite; + + if(t.itemCount++ < 32) { + oamItem[t.itemCount - 1] = {true, sprite}; + } +} + +auto PPU::Object::onScanline(PPU::OAM::Object& sprite) -> bool { + if(sprite.x > 256 && sprite.x + sprite.width() - 1 < 512) return false; + uint height = sprite.height() >> io.interlace; + 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; +} + +auto PPU::Object::run() -> void { + output.above.priority = 0; + output.below.priority = 0; + + auto oamTile = t.tile[!t.active]; + uint x = t.x++; + + for(uint n : range(34)) { + const auto& tile = oamTile[n]; + if(!tile.valid) break; + + int px = x - (int9)tile.x; + if(px & ~7) continue; + + uint color = 0, shift = tile.hflip ? px : 7 - px; + color += tile.data >> shift + 0 & 1; + color += tile.data >> shift + 7 & 2; + color += tile.data >> shift + 14 & 4; + color += tile.data >> shift + 21 & 8; + + if(color) { + if(io.aboveEnable) { + output.above.palette = tile.palette + color; + output.above.priority = io.priority[tile.priority]; + } + + if(io.belowEnable) { + output.below.palette = tile.palette + color; + output.below.priority = io.priority[tile.priority]; + } + } + } +} + +auto PPU::Object::fetch() -> void { + auto oamItem = t.item[t.active]; + auto oamTile = t.tile[t.active]; + + for(uint i : reverse(range(32))) { + if(!oamItem[i].valid) continue; + + if(ppu.io.displayDisable || ppu.vcounter() >= ppu.vdisp() - 1) { + ppu.step(8); + continue; + } + + ppu.latch.oamAddress = 0x0200 + (oamItem[i].index >> 2); + const auto& sprite = oam.object[oamItem[i].index]; + + uint tileWidth = sprite.width() >> 3; + int x = sprite.x; + int y = t.y - sprite.y & 0xff; + if(io.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(io.interlace) { + y = !sprite.vflip ? y + ppu.field() : y - ppu.field(); + } + + x &= 511; + y &= 255; + + uint16 tiledataAddress = io.tiledataAddress; + if(sprite.nameselect) tiledataAddress += 1 + io.nameselect << 12; + uint16 chrx = (sprite.character & 15); + uint16 chry = ((sprite.character >> 4) + (y >> 3) & 15) << 4; + + for(uint tx : range(tileWidth)) { + uint sx = x + (tx << 3) & 511; + if(x != 256 && sx >= 256 && sx + 7 < 512) continue; + if(t.tileCount++ >= 34) break; + + uint n = t.tileCount - 1; + oamTile[n].valid = true; + oamTile[n].x = sx; + oamTile[n].priority = sprite.priority; + oamTile[n].palette = 128 + (sprite.palette << 4); + oamTile[n].hflip = sprite.hflip; + + uint mx = !sprite.hflip ? tx : tileWidth - 1 - tx; + uint pos = tiledataAddress + ((chry + (chrx + mx & 15)) << 4); + uint16 address = (pos & 0xfff0) + (y & 7); + + if(!ppu.io.displayDisable) + oamTile[n].data = ppu.vram[address + 0] << 0; + ppu.step(4); + + if(!ppu.io.displayDisable) + oamTile[n].data |= ppu.vram[address + 8] << 16; + ppu.step(4); + } + } + + io.timeOver |= (t.tileCount > 34); + io.rangeOver |= (t.itemCount > 32); +} + +auto PPU::Object::power() -> void { + for(auto& object : oam.object) { + object.x = 0; + object.y = 0; + object.character = 0; + object.nameselect = 0; + object.vflip = 0; + object.hflip = 0; + object.priority = 0; + object.palette = 0; + object.size = 0; + } + + t.x = 0; + t.y = 0; + + t.itemCount = 0; + t.tileCount = 0; + + t.active = 0; + for(uint p : range(2)) { + for(uint n : range(32)) { + t.item[p][n].valid = false; + t.item[p][n].index = 0; + } + for(uint n : range(34)) { + t.tile[p][n].valid = false; + t.tile[p][n].x = 0; + t.tile[p][n].priority = 0; + t.tile[p][n].palette = 0; + t.tile[p][n].hflip = 0; + t.tile[p][n].data = 0; + } + } + + io.aboveEnable = random(); + io.belowEnable = random(); + io.interlace = random(); + + io.baseSize = random(); + io.nameselect = random(); + io.tiledataAddress = (random() & 7) << 13; + io.firstSprite = 0; + + for(auto& p : io.priority) p = 0; + + io.timeOver = false; + io.rangeOver = false; + + latch = {}; + + output.above.palette = 0; + output.above.priority = 0; + output.below.palette = 0; + output.below.priority = 0; +} diff --git a/sfc/ppu/object.hpp b/sfc/ppu/object.hpp new file mode 100644 index 0000000..a368784 --- /dev/null +++ b/sfc/ppu/object.hpp @@ -0,0 +1,91 @@ +struct OAM { + auto read(uint10 address) -> uint8; + auto write(uint10 address, uint8 data) -> void; + + struct Object { + alwaysinline auto width() const -> uint; + alwaysinline auto height() const -> uint; + + uint9 x; + uint8 y; + uint8 character; + uint1 nameselect; + uint1 vflip; + uint1 hflip; + uint2 priority; + uint3 palette; + uint1 size; + } object[128]; +}; + +struct Object { + alwaysinline auto addressReset() -> void; + alwaysinline auto setFirstSprite() -> void; + auto frame() -> void; + auto scanline() -> void; + auto evaluate(uint7 index) -> void; + auto run() -> void; + auto fetch() -> void; + auto power() -> void; + + auto onScanline(PPU::OAM::Object&) -> bool; + + auto serialize(serializer&) -> void; + + OAM oam; + + struct IO { + uint1 aboveEnable; + uint1 belowEnable; + uint1 interlace; + + uint3 baseSize; + uint2 nameselect; + uint16 tiledataAddress; + uint7 firstSprite; + + uint8 priority[4]; + + uint1 timeOver; + uint1 rangeOver; + } io; + + struct Latch { + uint7 firstSprite; + } latch; + + struct Item { + uint1 valid; + uint7 index; + }; + + struct Tile { + uint1 valid; + uint9 x; + uint2 priority; + uint8 palette; + uint1 hflip; + uint32 data; + }; + + struct State { + uint x; + uint y; + + uint itemCount; + uint tileCount; + + bool active; + Item item[2][32]; + Tile tile[2][34]; + } t; + + struct Output { + struct Pixel { + uint8 priority; //0 = none (transparent) + uint8 palette; + } above, below; + } output; + + friend class PPU; +}; diff --git a/sfc/ppu/ppu.cpp b/sfc/ppu/ppu.cpp new file mode 100644 index 0000000..dc8d135 --- /dev/null +++ b/sfc/ppu/ppu.cpp @@ -0,0 +1,214 @@ +#include + +namespace SuperFamicom { + +PPU ppu; +#include "main.cpp" +#include "io.cpp" +#include "mosaic.cpp" +#include "background.cpp" +#include "object.cpp" +#include "window.cpp" +#include "screen.cpp" +#include "serialization.cpp" +#include "counter/serialization.cpp" + +PPU::PPU() : +bg1(Background::ID::BG1), +bg2(Background::ID::BG2), +bg3(Background::ID::BG3), +bg4(Background::ID::BG4) { + ppu1.version = 1; //allowed values: 1 + ppu2.version = 3; //allowed values: 1, 2, 3 + + for(uint l = 0; l < 16; l++) { + for(uint r = 0; r < 32; r++) { + for(uint g = 0; g < 32; g++) { + for(uint b = 0; b < 32; b++) { + double luma = (double)l / 15.0; + uint ar = (luma * r + 0.5); + uint ag = (luma * g + 0.5); + uint ab = (luma * b + 0.5); + lightTable[l][(r << 10) + (g << 5) + b] = (ab << 10) + (ag << 5) + ar; + } + } + } + } +} + +PPU::~PPU() { +} + +auto PPU::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto PPU::step() -> void { + tick(2); + clock += 2; + synchronizeCPU(); +} + +auto PPU::step(uint clocks) -> void { + clocks >>= 1; + while(clocks--) { + tick(2); + clock += 2; + synchronizeCPU(); + } +} + +auto PPU::Enter() -> void { + while(true) { + scheduler.synchronize(); + ppu.main(); + } +} + +auto PPU::load() -> bool { + ppu1.version = max(1, min(1, configuration.system.ppu1.version)); + ppu2.version = max(1, min(3, configuration.system.ppu2.version)); + vram.mask = configuration.system.ppu1.vram.size / sizeof(uint16) - 1; + if(vram.mask != 0xffff) vram.mask = 0x7fff; + return true && ppufast.load(); +} + +auto PPU::power(bool reset) -> void { + if(system.fastPPU()) { + create(PPUfast::Enter, system.cpuFrequency()); + ppufast.power(reset); + return; + } + + create(Enter, system.cpuFrequency()); + PPUcounter::reset(); + memory::fill(output, 512 * 480); + + function reader{&PPU::readIO, this}; + function writer{&PPU::writeIO, this}; + bus.map(reader, writer, "00-3f,80-bf:2100-213f"); + + if(!reset) random.array((uint8*)vram.data, sizeof(vram.data)); + + ppu1.mdr = random.bias(0xff); + ppu2.mdr = random.bias(0xff); + + latch.vram = random(); + latch.oam = random(); + latch.cgram = random(); + latch.bgofsPPU1 = random(); + latch.bgofsPPU2 = random(); + latch.mode7 = random(); + latch.counters = false; + latch.hcounter = 0; + latch.vcounter = 0; + + latch.oamAddress = 0x0000; + latch.cgramAddress = 0x00; + + //$2100 INIDISP + io.displayDisable = true; + io.displayBrightness = 0; + + //$2102 OAMADDL + //$2103 OAMADDH + io.oamBaseAddress = random() & ~1; + io.oamAddress = random(); + io.oamPriority = random(); + + //$2105 BGMODE + io.bgPriority = false; + io.bgMode = 0; + + //$210d BG1HOFS + io.hoffsetMode7 = random(); + + //$210e BG1VOFS + io.voffsetMode7 = random(); + + //$2115 VMAIN + io.vramIncrementMode = random.bias(1); + io.vramMapping = random(); + io.vramIncrementSize = 1; + + //$2116 VMADDL + //$2117 VMADDH + io.vramAddress = random(); + + //$211a M7SEL + io.repeatMode7 = random(); + io.vflipMode7 = random(); + io.hflipMode7 = random(); + + //$211b M7A + io.m7a = random(); + + //$211c M7B + io.m7b = random(); + + //$211d M7C + io.m7c = random(); + + //$211e M7D + io.m7d = random(); + + //$211f M7X + io.m7x = random(); + + //$2120 M7Y + io.m7y = random(); + + //$2121 CGADD + io.cgramAddress = random(); + io.cgramAddressLatch = random(); + + //$2133 SETINI + io.extbg = random(); + io.pseudoHires = random(); + io.overscan = false; + io.interlace = false; + + //$213c OPHCT + io.hcounter = 0; + + //$213d OPVCT + io.vcounter = 0; + + mosaic.power(); + bg1.power(); + bg2.power(); + bg3.power(); + bg4.power(); + obj.power(); + window.power(); + screen.power(); + + updateVideoMode(); +} + +auto PPU::refresh() -> void { + if(system.fastPPU()) { + return ppufast.refresh(); + } + + if(system.runAhead) return; + + auto output = this->output; + auto pitch = 512; + auto width = 512; + auto height = 480; + if(configuration.video.blurEmulation) { + for(uint y : range(height)) { + auto data = output + y * pitch; + for(uint x : range(width - 1)) { + auto a = data[x + 0]; + auto b = data[x + 1]; + data[x] = (a + b - ((a ^ b) & 0x0421)) >> 1; + } + } + } + if(auto device = controllerPort2.device) device->draw(output, pitch * sizeof(uint16), width, height); + platform->videoFrame(output, pitch * sizeof(uint16), width, height, /* scale = */ 1); +} + +} diff --git a/sfc/ppu/ppu.hpp b/sfc/ppu/ppu.hpp new file mode 100644 index 0000000..353acf2 --- /dev/null +++ b/sfc/ppu/ppu.hpp @@ -0,0 +1,179 @@ +struct PPU : Thread, PPUcounter { + alwaysinline auto interlace() const -> bool { return display.interlace; } + alwaysinline auto overscan() const -> bool { return display.overscan; } + alwaysinline auto vdisp() const -> uint { return display.vdisp; } + + //ppu.cpp + PPU(); + ~PPU(); + + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto load() -> bool; + auto power(bool reset) -> void; + + //main.cpp + auto main() -> void; + noinline auto cycleObjectEvaluate() -> void; + template noinline auto cycleBackgroundFetch() -> void; + noinline auto cycleBackgroundBegin() -> void; + noinline auto cycleBackgroundBelow() -> void; + noinline auto cycleBackgroundAbove() -> void; + noinline auto cycleRenderPixel() -> void; + template auto cycle() -> void; + + //io.cpp + auto latchCounters(uint hcounter, uint vcounter) -> void; + auto latchCounters() -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + +private: + //ppu.cpp + alwaysinline auto step() -> void; + alwaysinline auto step(uint clocks) -> void; + + //io.cpp + alwaysinline auto addressVRAM() const -> uint16; + alwaysinline auto readVRAM() -> uint16; + alwaysinline auto writeVRAM(bool byte, uint8 data) -> void; + alwaysinline auto readOAM(uint10 address) -> uint8; + alwaysinline auto writeOAM(uint10 address, uint8 data) -> void; + alwaysinline auto readCGRAM(bool byte, uint8 address) -> uint8; + alwaysinline auto writeCGRAM(uint8 address, uint15 data) -> void; + auto readIO(uint address, uint8 data) -> uint8; + auto writeIO(uint address, uint8 data) -> void; + auto updateVideoMode() -> void; + + struct VRAM { + auto& operator[](uint address) { return data[address & mask]; } + uint16 data[64 * 1024]; + uint16 mask = 0x7fff; + } vram; + + uint16 output[512 * 480]; + uint16 lightTable[16][32768]; + + struct { + bool interlace; + bool overscan; + uint vdisp; + } display; + + auto refresh() -> void; + + struct { + uint4 version; + uint8 mdr; + } ppu1, ppu2; + + struct Latch { + uint16 vram; + uint8 oam; + uint8 cgram; + uint8 bgofsPPU1; + uint3 bgofsPPU2; + uint8 mode7; + uint1 counters; + uint1 hcounter; + uint1 vcounter; + + uint10 oamAddress; + uint8 cgramAddress; + } latch; + + struct IO { + //$2100 INIDISP + uint1 displayDisable; + uint4 displayBrightness; + + //$2102 OAMADDL + //$2103 OAMADDH + uint10 oamBaseAddress; + uint10 oamAddress; + uint1 oamPriority; + + //$2105 BGMODE + uint1 bgPriority; + uint8 bgMode; + + //$210d BG1HOFS + uint16 hoffsetMode7; + + //$210e BG1VOFS + uint16 voffsetMode7; + + //$2115 VMAIN + uint1 vramIncrementMode; + uint2 vramMapping; + uint8 vramIncrementSize; + + //$2116 VMADDL + //$2117 VMADDH + uint16 vramAddress; + + //$211a M7SEL + uint2 repeatMode7; + uint1 vflipMode7; + uint1 hflipMode7; + + //$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 + uint8 cgramAddress; + uint1 cgramAddressLatch; + + //$2133 SETINI + uint1 extbg; + uint1 pseudoHires; + uint1 overscan; + uint1 interlace; + + //$213c OPHCT + uint16 hcounter; + + //$213d OPVCT + uint16 vcounter; + } io; + + #include "mosaic.hpp" + #include "background.hpp" + #include "object.hpp" + #include "window.hpp" + #include "screen.hpp" + + Mosaic mosaic; + Background bg1; + Background bg2; + Background bg3; + Background bg4; + Object obj; + Window window; + Screen screen; + + friend class PPU::Background; + friend class PPU::Object; + friend class PPU::Window; + friend class PPU::Screen; + friend class System; + friend class PPUfast; +}; + +extern PPU ppu; diff --git a/sfc/ppu/screen.cpp b/sfc/ppu/screen.cpp new file mode 100644 index 0000000..7455eff --- /dev/null +++ b/sfc/ppu/screen.cpp @@ -0,0 +1,182 @@ +auto PPU::Screen::scanline() -> void { + auto y = ppu.vcounter() + (!ppu.display.overscan ? 7 : 0); + + lineA = ppu.output + y * 1024; + lineB = lineA + (ppu.display.interlace ? 0 : 512); + if(ppu.display.interlace && ppu.field()) lineA += 512, lineB += 512; + + //the first hires pixel of each scanline is transparent + //note: exact value initializations are not confirmed on hardware + math.above.color = paletteColor(0); + math.below.color = math.above.color; + + math.above.colorEnable = false; + math.below.colorEnable = false; + + math.transparent = true; + math.blendMode = false; + math.colorHalve = io.colorHalve && !io.blendMode && math.above.colorEnable; +} + +auto PPU::Screen::run() -> void { + if(ppu.vcounter() == 0) return; + + bool hires = ppu.io.pseudoHires || ppu.io.bgMode == 5 || ppu.io.bgMode == 6; + auto belowColor = below(hires); + auto aboveColor = above(); + + *lineA++ = *lineB++ = ppu.lightTable[ppu.io.displayBrightness][hires ? belowColor : aboveColor]; + *lineA++ = *lineB++ = ppu.lightTable[ppu.io.displayBrightness][aboveColor]; +} + +auto PPU::Screen::below(bool hires) -> uint16 { + if(ppu.io.displayDisable || (!ppu.io.overscan && ppu.vcounter() >= 225)) return 0; + + uint priority = 0; + if(ppu.bg1.output.below.priority) { + priority = ppu.bg1.output.below.priority; + if(io.directColor && (ppu.io.bgMode == 3 || ppu.io.bgMode == 4 || ppu.io.bgMode == 7)) { + math.below.color = directColor(ppu.bg1.output.below.palette, ppu.bg1.output.below.paletteGroup); + } else { + math.below.color = paletteColor(ppu.bg1.output.below.palette); + } + } + if(ppu.bg2.output.below.priority > priority) { + priority = ppu.bg2.output.below.priority; + math.below.color = paletteColor(ppu.bg2.output.below.palette); + } + if(ppu.bg3.output.below.priority > priority) { + priority = ppu.bg3.output.below.priority; + math.below.color = paletteColor(ppu.bg3.output.below.palette); + } + if(ppu.bg4.output.below.priority > priority) { + priority = ppu.bg4.output.below.priority; + math.below.color = paletteColor(ppu.bg4.output.below.palette); + } + if(ppu.obj.output.below.priority > priority) { + priority = ppu.obj.output.below.priority; + math.below.color = paletteColor(ppu.obj.output.below.palette); + } + if(math.transparent = (priority == 0)) math.below.color = paletteColor(0); + + if(!hires) return 0; + if(!math.below.colorEnable) return math.above.colorEnable ? math.below.color : (uint15)0; + + return blend( + math.above.colorEnable ? math.below.color : (uint15)0, + math.blendMode ? math.above.color : fixedColor() + ); +} + +auto PPU::Screen::above() -> uint16 { + if(ppu.io.displayDisable || (!ppu.io.overscan && ppu.vcounter() >= 225)) return 0; + + uint priority = 0; + if(ppu.bg1.output.above.priority) { + priority = ppu.bg1.output.above.priority; + if(io.directColor && (ppu.io.bgMode == 3 || ppu.io.bgMode == 4 || ppu.io.bgMode == 7)) { + math.above.color = directColor(ppu.bg1.output.above.palette, ppu.bg1.output.above.paletteGroup); + } else { + math.above.color = paletteColor(ppu.bg1.output.above.palette); + } + math.below.colorEnable = io.bg1.colorEnable; + } + if(ppu.bg2.output.above.priority > priority) { + priority = ppu.bg2.output.above.priority; + math.above.color = paletteColor(ppu.bg2.output.above.palette); + math.below.colorEnable = io.bg2.colorEnable; + } + if(ppu.bg3.output.above.priority > priority) { + priority = ppu.bg3.output.above.priority; + math.above.color = paletteColor(ppu.bg3.output.above.palette); + math.below.colorEnable = io.bg3.colorEnable; + } + if(ppu.bg4.output.above.priority > priority) { + priority = ppu.bg4.output.above.priority; + math.above.color = paletteColor(ppu.bg4.output.above.palette); + math.below.colorEnable = io.bg4.colorEnable; + } + if(ppu.obj.output.above.priority > priority) { + priority = ppu.obj.output.above.priority; + math.above.color = paletteColor(ppu.obj.output.above.palette); + math.below.colorEnable = io.obj.colorEnable && ppu.obj.output.above.palette >= 192; + } + if(priority == 0) { + math.above.color = paletteColor(0); + math.below.colorEnable = io.back.colorEnable; + } + + if(!ppu.window.output.below.colorEnable) math.below.colorEnable = false; + math.above.colorEnable = ppu.window.output.above.colorEnable; + if(!math.below.colorEnable) return math.above.colorEnable ? math.above.color : (uint15)0; + + if(io.blendMode && math.transparent) { + math.blendMode = false; + math.colorHalve = false; + } else { + math.blendMode = io.blendMode; + math.colorHalve = io.colorHalve && math.above.colorEnable; + } + + return blend( + math.above.colorEnable ? math.above.color : (uint15)0, + math.blendMode ? math.below.color : fixedColor() + ); +} + +auto PPU::Screen::blend(uint x, uint y) const -> uint15 { + if(!io.colorMode) { //add + if(!math.colorHalve) { + uint sum = x + y; + uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420; + return (sum - carry) | (carry - (carry >> 5)); + } else { + return (x + y - ((x ^ y) & 0x0421)) >> 1; + } + } else { //sub + uint diff = x - y + 0x8420; + uint borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420; + if(!math.colorHalve) { + return (diff - borrow) & (borrow - (borrow >> 5)); + } else { + return (((diff - borrow) & (borrow - (borrow >> 5))) & 0x7bde) >> 1; + } + } +} + +auto PPU::Screen::paletteColor(uint8 palette) const -> uint15 { + ppu.latch.cgramAddress = palette; + return cgram[palette]; +} + +auto PPU::Screen::directColor(uint8 palette, uint3 paletteGroup) const -> uint15 { + //palette = -------- BBGGGRRR + //group = -------- -----bgr + //output = 0BBb00GG Gg0RRRr0 + return (palette << 7 & 0x6000) + (paletteGroup << 10 & 0x1000) + + (palette << 4 & 0x0380) + (paletteGroup << 5 & 0x0040) + + (palette << 2 & 0x001c) + (paletteGroup << 1 & 0x0002); +} + +auto PPU::Screen::fixedColor() const -> uint15 { + return io.colorBlue << 10 | io.colorGreen << 5 | io.colorRed << 0; +} + +auto PPU::Screen::power() -> void { + random.array((uint8*)cgram, sizeof(cgram)); + for(auto& word : cgram) word &= 0x7fff; + + io.blendMode = random(); + io.directColor = random(); + io.colorMode = random(); + io.colorHalve = random(); + io.bg1.colorEnable = random(); + io.bg2.colorEnable = random(); + io.bg3.colorEnable = random(); + io.bg4.colorEnable = random(); + io.obj.colorEnable = random(); + io.back.colorEnable = random(); + io.colorBlue = random(); + io.colorGreen = random(); + io.colorRed = random(); +} diff --git a/sfc/ppu/screen.hpp b/sfc/ppu/screen.hpp new file mode 100644 index 0000000..87dac3c --- /dev/null +++ b/sfc/ppu/screen.hpp @@ -0,0 +1,47 @@ +struct Screen { + auto scanline() -> void; + auto run() -> void; + auto power() -> void; + + auto below(bool hires) -> uint16; + auto above() -> uint16; + + auto blend(uint x, uint y) const -> uint15; + alwaysinline auto paletteColor(uint8 palette) const -> uint15; + alwaysinline auto directColor(uint8 palette, uint3 paletteGroup) const -> uint15; + alwaysinline auto fixedColor() const -> uint15; + + auto serialize(serializer&) -> void; + + uint16* lineA; + uint16* lineB; + + uint15 cgram[256]; + + struct IO { + uint1 blendMode; + uint1 directColor; + + uint1 colorMode; + uint1 colorHalve; + struct Layer { + uint1 colorEnable; + } bg1, bg2, bg3, bg4, obj, back; + + uint5 colorBlue; + uint5 colorGreen; + uint5 colorRed; + } io; + + struct Math { + struct Screen { + uint15 color; + uint1 colorEnable; + } above, below; + uint1 transparent; + uint1 blendMode; + uint1 colorHalve; + } math; + + friend class PPU; +}; diff --git a/sfc/ppu/serialization.cpp b/sfc/ppu/serialization.cpp new file mode 100644 index 0000000..9a02221 --- /dev/null +++ b/sfc/ppu/serialization.cpp @@ -0,0 +1,281 @@ +auto PPU::serialize(serializer& s) -> void { + s.integer(display.interlace); + s.integer(display.overscan); + s.integer(display.vdisp); + + if(system.fastPPU()) { + return ppufast.serialize(s); + } + + Thread::serialize(s); + PPUcounter::serialize(s); + + s.integer(vram.mask); + s.array(vram.data, vram.mask + 1); + + s.integer(ppu1.version); + s.integer(ppu1.mdr); + + s.integer(ppu2.version); + s.integer(ppu2.mdr); + + s.integer(latch.vram); + s.integer(latch.oam); + s.integer(latch.cgram); + s.integer(latch.bgofsPPU1); + s.integer(latch.bgofsPPU2); + s.integer(latch.mode7); + s.integer(latch.counters); + s.integer(latch.hcounter); + s.integer(latch.vcounter); + + s.integer(latch.oamAddress); + s.integer(latch.cgramAddress); + + s.integer(io.displayDisable); + s.integer(io.displayBrightness); + + s.integer(io.oamBaseAddress); + s.integer(io.oamAddress); + s.integer(io.oamPriority); + + s.integer(io.bgMode); + s.integer(io.bgPriority); + + s.integer(io.hoffsetMode7); + s.integer(io.voffsetMode7); + + s.integer(io.vramIncrementMode); + s.integer(io.vramMapping); + s.integer(io.vramIncrementSize); + + s.integer(io.vramAddress); + + s.integer(io.repeatMode7); + s.integer(io.vflipMode7); + s.integer(io.hflipMode7); + + s.integer(io.m7a); + s.integer(io.m7b); + s.integer(io.m7c); + s.integer(io.m7d); + s.integer(io.m7x); + s.integer(io.m7y); + + s.integer(io.cgramAddress); + s.integer(io.cgramAddressLatch); + + s.integer(io.extbg); + s.integer(io.pseudoHires); + s.integer(io.overscan); + s.integer(io.interlace); + + s.integer(io.hcounter); + s.integer(io.vcounter); + + mosaic.serialize(s); + bg1.serialize(s); + bg2.serialize(s); + bg3.serialize(s); + bg4.serialize(s); + obj.serialize(s); + window.serialize(s); + screen.serialize(s); +} + +auto PPU::Mosaic::serialize(serializer& s) -> void { + s.integer(size); + s.integer(vcounter); +} + +auto PPU::Background::serialize(serializer& s) -> void { + s.integer(io.tiledataAddress); + s.integer(io.screenAddress); + s.integer(io.screenSize); + s.integer(io.tileSize); + s.integer(io.mode); + s.array(io.priority); + s.integer(io.aboveEnable); + s.integer(io.belowEnable); + s.integer(io.hoffset); + s.integer(io.voffset); + + s.integer(output.above.priority); + s.integer(output.above.palette); + s.integer(output.above.paletteGroup); + + s.integer(output.below.priority); + s.integer(output.below.palette); + s.integer(output.below.paletteGroup); + + s.integer(mosaic.enable); + s.integer(mosaic.hcounter); + s.integer(mosaic.hoffset); + + s.integer(mosaic.pixel.priority); + s.integer(mosaic.pixel.palette); + s.integer(mosaic.pixel.paletteGroup); + + s.integer(opt.hoffset); + s.integer(opt.voffset); + + for(auto& tile : tiles) { + s.integer(tile.address); + s.integer(tile.character); + s.integer(tile.palette); + s.integer(tile.paletteGroup); + s.integer(tile.priority); + s.integer(tile.hmirror); + s.integer(tile.vmirror); + s.array(tile.data); + } + + s.integer(renderingIndex); + s.integer(pixelCounter); +} + +auto PPU::Object::serialize(serializer& s) -> void { + for(auto& object : oam.object) { + s.integer(object.x); + s.integer(object.y); + s.integer(object.character); + s.integer(object.nameselect); + s.integer(object.vflip); + s.integer(object.hflip); + s.integer(object.priority); + s.integer(object.palette); + s.integer(object.size); + } + + s.integer(io.aboveEnable); + s.integer(io.belowEnable); + s.integer(io.interlace); + + s.integer(io.baseSize); + s.integer(io.nameselect); + s.integer(io.tiledataAddress); + s.integer(io.firstSprite); + + s.array(io.priority); + + s.integer(io.timeOver); + s.integer(io.rangeOver); + + s.integer(latch.firstSprite); + + s.integer(t.x); + s.integer(t.y); + + s.integer(t.itemCount); + s.integer(t.tileCount); + + s.integer(t.active); + for(auto p : range(2)) { + for(auto n : range(32)) { + s.integer(t.item[p][n].valid); + s.integer(t.item[p][n].index); + } + for(auto n : range(34)) { + s.integer(t.tile[p][n].valid); + s.integer(t.tile[p][n].x); + s.integer(t.tile[p][n].priority); + s.integer(t.tile[p][n].palette); + s.integer(t.tile[p][n].hflip); + s.integer(t.tile[p][n].data); + } + } + + s.integer(output.above.priority); + s.integer(output.above.palette); + + s.integer(output.below.priority); + s.integer(output.below.palette); +} + +auto PPU::Window::serialize(serializer& s) -> void { + s.integer(io.bg1.oneEnable); + s.integer(io.bg1.oneInvert); + s.integer(io.bg1.twoEnable); + s.integer(io.bg1.twoInvert); + s.integer(io.bg1.mask); + s.integer(io.bg1.aboveEnable); + s.integer(io.bg1.belowEnable); + + s.integer(io.bg2.oneEnable); + s.integer(io.bg2.oneInvert); + s.integer(io.bg2.twoEnable); + s.integer(io.bg2.twoInvert); + s.integer(io.bg2.mask); + s.integer(io.bg2.aboveEnable); + s.integer(io.bg2.belowEnable); + + s.integer(io.bg3.oneEnable); + s.integer(io.bg3.oneInvert); + s.integer(io.bg3.twoEnable); + s.integer(io.bg3.twoInvert); + s.integer(io.bg3.mask); + s.integer(io.bg3.aboveEnable); + s.integer(io.bg3.belowEnable); + + s.integer(io.bg4.oneEnable); + s.integer(io.bg4.oneInvert); + s.integer(io.bg4.twoEnable); + s.integer(io.bg4.twoInvert); + s.integer(io.bg4.mask); + s.integer(io.bg4.aboveEnable); + s.integer(io.bg4.belowEnable); + + s.integer(io.obj.oneEnable); + s.integer(io.obj.oneInvert); + s.integer(io.obj.twoEnable); + s.integer(io.obj.twoInvert); + s.integer(io.obj.mask); + s.integer(io.obj.aboveEnable); + s.integer(io.obj.belowEnable); + + s.integer(io.col.oneEnable); + s.integer(io.col.oneInvert); + s.integer(io.col.twoEnable); + s.integer(io.col.twoInvert); + s.integer(io.col.mask); + s.integer(io.col.aboveMask); + s.integer(io.col.belowMask); + + s.integer(io.oneLeft); + s.integer(io.oneRight); + s.integer(io.twoLeft); + s.integer(io.twoRight); + + s.integer(output.above.colorEnable); + s.integer(output.below.colorEnable); + + s.integer(x); +} + +auto PPU::Screen::serialize(serializer& s) -> void { + s.array(cgram); + + s.integer(io.blendMode); + s.integer(io.directColor); + + s.integer(io.colorMode); + s.integer(io.colorHalve); + s.integer(io.bg1.colorEnable); + s.integer(io.bg2.colorEnable); + s.integer(io.bg3.colorEnable); + s.integer(io.bg4.colorEnable); + s.integer(io.obj.colorEnable); + s.integer(io.back.colorEnable); + + s.integer(io.colorBlue); + s.integer(io.colorGreen); + s.integer(io.colorRed); + + s.integer(math.above.color); + s.integer(math.above.colorEnable); + s.integer(math.below.color); + s.integer(math.below.colorEnable); + s.integer(math.transparent); + s.integer(math.blendMode); + s.integer(math.colorHalve); +} diff --git a/sfc/ppu/window.cpp b/sfc/ppu/window.cpp new file mode 100644 index 0000000..96d83d5 --- /dev/null +++ b/sfc/ppu/window.cpp @@ -0,0 +1,107 @@ +auto PPU::Window::scanline() -> void { + x = 0; +} + +auto PPU::Window::run() -> void { + bool one = (x >= io.oneLeft && x <= io.oneRight); + bool two = (x >= io.twoLeft && x <= io.twoRight); + x++; + + if(test(io.bg1.oneEnable, one ^ io.bg1.oneInvert, io.bg1.twoEnable, two ^ io.bg1.twoInvert, io.bg1.mask)) { + if(io.bg1.aboveEnable) ppu.bg1.output.above.priority = 0; + if(io.bg1.belowEnable) ppu.bg1.output.below.priority = 0; + } + + if(test(io.bg2.oneEnable, one ^ io.bg2.oneInvert, io.bg2.twoEnable, two ^ io.bg2.twoInvert, io.bg2.mask)) { + if(io.bg2.aboveEnable) ppu.bg2.output.above.priority = 0; + if(io.bg2.belowEnable) ppu.bg2.output.below.priority = 0; + } + + if(test(io.bg3.oneEnable, one ^ io.bg3.oneInvert, io.bg3.twoEnable, two ^ io.bg3.twoInvert, io.bg3.mask)) { + if(io.bg3.aboveEnable) ppu.bg3.output.above.priority = 0; + if(io.bg3.belowEnable) ppu.bg3.output.below.priority = 0; + } + + if(test(io.bg4.oneEnable, one ^ io.bg4.oneInvert, io.bg4.twoEnable, two ^ io.bg4.twoInvert, io.bg4.mask)) { + if(io.bg4.aboveEnable) ppu.bg4.output.above.priority = 0; + if(io.bg4.belowEnable) ppu.bg4.output.below.priority = 0; + } + + if(test(io.obj.oneEnable, one ^ io.obj.oneInvert, io.obj.twoEnable, two ^ io.obj.twoInvert, io.obj.mask)) { + if(io.obj.aboveEnable) ppu.obj.output.above.priority = 0; + if(io.obj.belowEnable) ppu.obj.output.below.priority = 0; + } + + bool value = test(io.col.oneEnable, one ^ io.col.oneInvert, io.col.twoEnable, two ^ io.col.twoInvert, io.col.mask); + bool array[] = {true, value, !value, false}; + output.above.colorEnable = array[io.col.aboveMask]; + output.below.colorEnable = array[io.col.belowMask]; +} + +auto PPU::Window::test(bool oneEnable, bool one, bool twoEnable, bool two, uint mask) -> bool { + if(!oneEnable) return two && twoEnable; + if(!twoEnable) return one; + if(mask == 0) return (one | two); + if(mask == 1) return (one & two); + return (one ^ two) == 3 - mask; +} + +auto PPU::Window::power() -> void { + io.bg1.oneEnable = random(); + io.bg1.oneInvert = random(); + io.bg1.twoEnable = random(); + io.bg1.twoInvert = random(); + io.bg1.mask = random(); + io.bg1.aboveEnable = random(); + io.bg1.belowEnable = random(); + + io.bg2.oneEnable = random(); + io.bg2.oneInvert = random(); + io.bg2.twoEnable = random(); + io.bg2.twoInvert = random(); + io.bg2.mask = random(); + io.bg2.aboveEnable = random(); + io.bg2.belowEnable = random(); + + io.bg3.oneEnable = random(); + io.bg3.oneInvert = random(); + io.bg3.twoEnable = random(); + io.bg3.twoInvert = random(); + io.bg3.mask = random(); + io.bg3.aboveEnable = random(); + io.bg3.belowEnable = random(); + + io.bg4.oneEnable = random(); + io.bg4.oneInvert = random(); + io.bg4.twoEnable = random(); + io.bg4.twoInvert = random(); + io.bg4.mask = random(); + io.bg4.aboveEnable = random(); + io.bg4.belowEnable = random(); + + io.obj.oneEnable = random(); + io.obj.oneInvert = random(); + io.obj.twoEnable = random(); + io.obj.twoInvert = random(); + io.obj.mask = random(); + io.obj.aboveEnable = random(); + io.obj.belowEnable = random(); + + io.col.oneEnable = random(); + io.col.oneInvert = random(); + io.col.twoEnable = random(); + io.col.twoInvert = random(); + io.col.mask = random(); + io.col.aboveMask = random(); + io.col.belowMask = random(); + + io.oneLeft = random(); + io.oneRight = random(); + io.twoLeft = random(); + io.twoRight = random(); + + output.above.colorEnable = 0; + output.below.colorEnable = 0; + + x = 0; +} diff --git a/sfc/ppu/window.hpp b/sfc/ppu/window.hpp new file mode 100644 index 0000000..ff3d845 --- /dev/null +++ b/sfc/ppu/window.hpp @@ -0,0 +1,47 @@ +struct Window { + auto scanline() -> void; + auto run() -> void; + auto test(bool oneEnable, bool one, bool twoEnable, bool two, uint mask) -> bool; + auto power() -> void; + + auto serialize(serializer&) -> void; + + struct IO { + struct Layer { + bool oneEnable; + bool oneInvert; + bool twoEnable; + bool twoInvert; + uint2 mask; + bool aboveEnable; + bool belowEnable; + } bg1, bg2, bg3, bg4, obj; + + struct Color { + bool oneEnable; + bool oneInvert; + bool twoEnable; + bool twoInvert; + uint2 mask; + uint2 aboveMask; + uint2 belowMask; + } col; + + uint8 oneLeft; + uint8 oneRight; + uint8 twoLeft; + uint8 twoRight; + } io; + + struct Output { + struct Pixel { + bool colorEnable; + } above, below; + } output; + + struct { + uint x; + }; + + friend class PPU; +}; diff --git a/sfc/sfc.hpp b/sfc/sfc.hpp new file mode 100644 index 0000000..9ecf56d --- /dev/null +++ b/sfc/sfc.hpp @@ -0,0 +1,150 @@ +#pragma once + +//license: GPLv3 +//started: 2004-10-14 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern "C" { + #include + #include +} + +namespace SuperFamicom { + #define platform Emulator::platform + namespace File = Emulator::File; + using Random = Emulator::Random; + using Cheat = Emulator::Cheat; + extern Random random; + extern Cheat cheat; + + struct Scheduler { + enum class Mode : uint { Run, Synchronize } mode; + enum class Event : uint { Frame, Synchronized, Desynchronized } event; + + cothread_t host = nullptr; + cothread_t active = nullptr; + bool desynchronized = false; + + auto enter() -> void { + host = co_active(); + co_switch(active); + } + + auto leave(Event event_) -> void { + event = event_; + active = co_active(); + co_switch(host); + } + + auto resume(cothread_t thread) -> void { + if(mode == Mode::Synchronize) desynchronized = true; + co_switch(thread); + } + + inline auto synchronizing() const -> bool { + return mode == Mode::Synchronize; + } + + inline auto synchronize() -> void { + if(mode == Mode::Synchronize) { + if(desynchronized) { + desynchronized = false; + leave(Event::Desynchronized); + } else { + leave(Event::Synchronized); + } + } + } + + inline auto desynchronize() -> void { + desynchronized = true; + } + }; + extern Scheduler scheduler; + + struct Thread { + enum : uint { Size = 4_KiB * sizeof(void*) }; + + auto create(auto (*entrypoint)() -> void, uint frequency_) -> void { + if(!thread) { + thread = co_create(Thread::Size, entrypoint); + } else { + thread = co_derive(thread, Thread::Size, entrypoint); + } + frequency = frequency_; + clock = 0; + } + + auto active() const -> bool { + return thread == co_active(); + } + + auto serialize(serializer& s) -> void { + s.integer(frequency); + s.integer(clock); + } + + auto serializeStack(serializer& s) -> void { + static uint8_t stack[Thread::Size]; + bool active = co_active() == thread; + + if(s.mode() == serializer::Size) { + s.array(stack, Thread::Size); + s.boolean(active); + } + + if(s.mode() == serializer::Load) { + s.array(stack, Thread::Size); + s.boolean(active); + memory::copy(thread, stack, Thread::Size); + if(active) scheduler.active = thread; + } + + if(s.mode() == serializer::Save) { + memory::copy(stack, thread, Thread::Size); + s.array(stack, Thread::Size); + s.boolean(active); + } + } + + cothread_t thread = nullptr; + uint32_t frequency = 0; + int64_t clock = 0; + }; + + struct Region { + static inline auto NTSC() -> bool; + static inline auto PAL() -> bool; + }; + + #include + #include + #include + + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + + #include + #include +} + +#include diff --git a/sfc/slot/bsmemory/bsmemory.cpp b/sfc/slot/bsmemory/bsmemory.cpp new file mode 100644 index 0000000..3adf075 --- /dev/null +++ b/sfc/slot/bsmemory/bsmemory.cpp @@ -0,0 +1,577 @@ +#include + +namespace SuperFamicom { + +BSMemory bsmemory; +#include "serialization.cpp" + +BSMemory::BSMemory() { + page.self = this; + uint blockID = 0; + for(auto& block : blocks) block.self = this, block.id = blockID++; + block.self = this; +} + +auto BSMemory::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto BSMemory::Enter() -> void { + while(true) { + scheduler.synchronize(); + bsmemory.main(); + } +} + +auto BSMemory::main() -> void { + if(ROM) return step(1'000'000); //1 second + + for(uint6 id : range(block.count())) { + if(block(id).erasing) return block(id).erase(); + block(id).status.ready = 1; + } + + compatible.status.ready = 1; + global.status.ready = 1; + step(10'000); //10 milliseconds +} + +auto BSMemory::step(uint clocks) -> void { + clock += clocks * (uint64_t)cpu.frequency; + synchronizeCPU(); +} + +auto BSMemory::load() -> bool { + if(ROM) return true; + + if(size() != 0x100000 && size() != 0x200000 && size() != 0x400000) { + memory.reset(); + return false; + } + + chip.vendor = 0x00'b0; //Sharp + if(size() == 0x100000) chip.device = 0x66'a8; //LH28F800SU + if(size() == 0x200000) chip.device = 0x66'88; //LH28F016SU + if(size() == 0x400000) chip.device = 0x66'88; //LH28F032SU (same device ID as LH28F016SU per datasheet) + chip.serial = 0x00'01'23'45'67'89ull; //serial# should be unique for every cartridge ... + + //page buffer values decay to random noise upon losing power to the flash chip + //the randomness is high entropy (at least compared to SNES SRAM/DRAM chips) + for(auto& byte : page.buffer[0]) byte = random(); + for(auto& byte : page.buffer[1]) byte = random(); + + for(auto& block : blocks) { + block.erased = 1; + block.locked = 1; + } + + if(auto fp = platform->open(pathID, "metadata.bml", File::Read, File::Optional)) { + auto document = BML::unserialize(fp->reads()); + if(auto node = document["flash/vendor"]) { + chip.vendor = node.natural(); + } + if(auto node = document["flash/device"]) { + chip.device = node.natural(); + } + if(auto node = document["flash/serial"]) { + chip.serial = node.natural(); + } + for(uint id : range(block.count())) { + if(auto node = document[{"flash/block(id=", id, ")"}]) { + if(auto erased = node["erased"]) { + block(id).erased = erased.natural(); + } + if(auto locked = node["locked"]) { + block(id).locked = locked.boolean(); + } + } + } + } + + return true; +} + +auto BSMemory::unload() -> void { + if(ROM) return memory.reset(); + + if(auto fp = platform->open(pathID, "metadata.bml", File::Write, File::Optional)) { + string manifest; + manifest.append("flash\n"); + manifest.append(" vendor: 0x", hex(chip.vendor, 4L), "\n"); + manifest.append(" device: 0x", hex(chip.device, 4L), "\n"); + manifest.append(" serial: 0x", hex(chip.serial, 12L), "\n"); + for(uint6 id : range(block.count())) { + manifest.append(" block\n"); + manifest.append(" id: ", id, "\n"); + manifest.append(" erased: ", (uint)block(id).erased, "\n"); + manifest.append(" locked: ", (bool)block(id).locked, "\n"); + } + fp->writes(manifest); + } + + memory.reset(); +} + +auto BSMemory::power() -> void { + create(Enter, 1'000'000); //microseconds + + for(auto& block : blocks) { + block.erasing = 0; + block.status = {}; + } + compatible.status = {}; + global.status = {}; + mode = Mode::Flash; + readyBusyMode = ReadyBusyMode::Disable; + queue.flush(); +} + +auto BSMemory::data() -> uint8* { + return memory.data(); +} + +auto BSMemory::size() const -> uint { + return memory.size(); +} + +auto BSMemory::read(uint address, uint8 data) -> uint8 { + if(!size()) return data; + if(ROM) return memory.read(bus.mirror(address, size())); + + if(mode == Mode::Chip) { + if(address == 0) return chip.vendor; //only appears once + if(address == 1) return chip.device; //only appears once + if((uint3)address == 2) return 0x63; //unknown constant: repeats every eight bytes + return 0x20; //unknown constant: fills in all remaining bytes + } + + if(mode == Mode::Page) { + return page.read(address); + } + + if(mode == Mode::CompatibleStatus) { + return compatible.status(); + } + + if(mode == Mode::ExtendedStatus) { + if((uint16)address == 0x0002) return block(address >> block.bitCount()).status(); + if((uint16)address == 0x0004) return global.status(); + return 0x00; //reserved: always zero + } + + return block(address >> block.bitCount()).read(address); //Mode::Flash +} + +auto BSMemory::write(uint address, uint8 data) -> void { + if(!size() || ROM) return; + queue.push(address, data); + + //write page to flash + if(queue.data(0) == 0x0c) { + if(queue.size() < 3) return; + uint16 count; //1 - 65536 + count = queue.data(!(queue.address(1) & 1) ? 1 : 2) << 0; + count |= queue.data(!(queue.address(1) & 1) ? 2 : 1) << 8; + uint address = queue.address(2); + do { + block(address >> block.bitCount()).write(address, page.read(address)); + address++; + } while(count--); + page.swap(); + mode = Mode::CompatibleStatus; + return queue.flush(); + } + + //write byte + if(queue.data(0) == 0x10) { + if(queue.size() < 2) return; + block(queue.address(1) >> block.bitCount()).write(queue.address(1), queue.data(1)); + mode = Mode::CompatibleStatus; + return queue.flush(); + } + + //erase block + if(queue.data(0) == 0x20) { + if(queue.size() < 2) return; + if(queue.data(1) != 0xd0) return failed(), queue.flush(); + block(queue.address(1) >> block.bitCount()).erase(); + mode = Mode::CompatibleStatus; + return queue.flush(); + } + + //LH28F800SUT-ZI specific? (undocumented / unavailable? for the LH28F800SU) + //write signature, identifier, serial# into current page buffer, then swap page buffers + if(queue.data(0) == 0x38) { + if(queue.size() < 2) return; + if(queue.data(1) != 0xd0) return failed(), queue.flush(); + page.write(0x00, 0x4d); //'M' (memory) + page.write(0x02, 0x50); //'P' (pack) + page.write(0x04, 0x04); //unknown constant (maybe block count? eg 1<<4 = 16 blocks) + page.write(0x06, 0x10 | (uint4)log2(size() >> 10)); //d0-d3 = size; d4-d7 = type (1) + page.write(0x08, chip.serial.byte(5)); //serial# (big endian; BCD format) + page.write(0x0a, chip.serial.byte(4)); //smallest observed value: + page.write(0x0c, chip.serial.byte(3)); // 0x00'00'10'62'62'39 + page.write(0x0e, chip.serial.byte(2)); //largest observed value: + page.write(0x10, chip.serial.byte(1)); // 0x00'91'90'70'31'03 + page.write(0x12, chip.serial.byte(0)); //most values are: 0x00'0x'xx'xx'xx'xx + page.swap(); + return queue.flush(); + } + + //write byte + if(queue.data(0) == 0x40) { + if(queue.size() < 2) return; + block(queue.address(1) >> block.bitCount()).write(queue.address(1), queue.data(1)); + mode = Mode::CompatibleStatus; + return queue.flush(); + } + + //clear status register + if(queue.data(0) == 0x50) { + for(uint6 id : range(block.count())) { + block(id).status.vppLow = 0; + block(id).status.failed = 0; + } + compatible.status.vppLow = 0; + compatible.status.writeFailed = 0; + compatible.status.eraseFailed = 0; + global.status.failed = 0; + return queue.flush(); + } + + //read compatible status register + if(queue.data(0) == 0x70) { + mode = Mode::CompatibleStatus; + return queue.flush(); + } + + //read extended status registers + if(queue.data(0) == 0x71) { + mode = Mode::ExtendedStatus; + return queue.flush(); + } + + //page buffer swap + if(queue.data(0) == 0x72) { + page.swap(); + return queue.flush(); + } + + //single load to page buffer + if(queue.data(0) == 0x74) { + if(queue.size() < 2) return; + page.write(queue.address(1), queue.data(1)); + return queue.flush(); + } + + //read page buffer + if(queue.data(0) == 0x75) { + mode = Mode::Page; + return queue.flush(); + } + + //lock block + if(queue.data(0) == 0x77) { + if(queue.size() < 2) return; + if(queue.data(1) != 0xd0) return failed(), queue.flush(); + block(queue.address(1) >> block.bitCount()).lock(); + return queue.flush(); + } + + //abort + //(unsupported) + if(queue.data(0) == 0x80) { + global.status.sleeping = 1; //abort seems to put the chip into sleep mode + return queue.flush(); + } + + //read chip identifiers + if(queue.data(0) == 0x90) { + mode = Mode::Chip; + return queue.flush(); + } + + //update ry/by mode + //(unsupported) + if(queue.data(0) == 0x96) { + if(queue.size() < 2) return; + if(queue.data(1) == 0x01) readyBusyMode = ReadyBusyMode::EnableToLevelMode; + if(queue.data(1) == 0x02) readyBusyMode = ReadyBusyMode::PulseOnWrite; + if(queue.data(1) == 0x03) readyBusyMode = ReadyBusyMode::PulseOnErase; + if(queue.data(1) == 0x04) readyBusyMode = ReadyBusyMode::Disable; + return queue.flush(); + } + + //upload lock status bits + if(queue.data(0) == 0x97) { + if(queue.size() < 2) return; + if(queue.data(1) != 0xd0) return failed(), queue.flush(); + for(uint6 id : range(block.count())) block(id).update(); + return queue.flush(); + } + + //upload device information (number of erase cycles per block) + if(queue.data(0) == 0x99) { + if(queue.size() < 2) return; + if(queue.data(1) != 0xd0) return failed(), queue.flush(); + page.write(0x06, 0x06); //unknown constant + page.write(0x07, 0x00); //unknown constant + for(uint6 id : range(block.count())) { + uint8 address; + address += (id >> 0 & 3) * 0x08; //verified for LH28F800SUT-ZI + address += (id >> 2 & 3) * 0x40; //verified for LH28F800SUT-ZI + address += (id >> 4 & 1) * 0x20; //guessed for LH28F016SU + address += (id >> 5 & 1) * 0x04; //guessed for LH28F032SU; will overwrite unknown constants + uint32 erased = 1 << 31 | block(id).erased; //unknown if d31 is set when erased == 0 + for(uint2 byte : range(4)) { + page.write(address + byte, erased >> byte * 8); //little endian + } + } + page.swap(); + return queue.flush(); + } + + //erase all blocks + if(queue.data(0) == 0xa7) { + if(queue.size() < 2) return; + if(queue.data(1) != 0xd0) return failed(), queue.flush(); + for(uint6 id : range(block.count())) block(id).erase(); + mode = Mode::CompatibleStatus; + return queue.flush(); + } + + //erase suspend/resume + //(unsupported) + if(queue.data(0) == 0xb0) { + if(queue.size() < 2) return; + if(queue.data(1) != 0xd0) return failed(), queue.flush(); + mode = Mode::CompatibleStatus; + return queue.flush(); + } + + //sequential load to page buffer + if(queue.data(0) == 0xe0) { + if(queue.size() < 4) return; //command length = 3 + count + uint16 count; //1 - 65536 + count = queue.data(1) << 0; //endian order not affected by queue.address(1).bit(0) + count |= queue.data(2) << 8; + page.write(queue.address(3), queue.data(3)); + if(count--) { + queue.history[1].data = count >> 0; + queue.history[2].data = count >> 8; + return queue.pop(); //hack to avoid needing a 65539-entry queue + } else { + return queue.flush(); + } + } + + //sleep + //(unsupported) + if(queue.data(0) == 0xf0) { + //it is currently unknown how to exit sleep mode; other than via chip reset + global.status.sleeping = 1; + return queue.flush(); + } + + //write word + if(queue.data(0) == 0xfb) { + if(queue.size() < 3) return; + uint16 value; + value = queue.data(!(queue.address(1) & 1) ? 1 : 2) << 0; + value |= queue.data(!(queue.address(1) & 1) ? 2 : 1) << 8; + //writes are always word-aligned: a0 toggles, rather than increments + block(queue.address(2) >> block.bitCount()).write(queue.address(2) ^ 0, value >> 0); + block(queue.address(2) >> block.bitCount()).write(queue.address(2) ^ 1, value >> 8); + mode = Mode::CompatibleStatus; + return queue.flush(); + } + + //read flash memory + if(queue.data(0) == 0xff) { + mode = Mode::Flash; + return queue.flush(); + } + + //unknown command + return queue.flush(); +} + +// + +auto BSMemory::failed() -> void { + compatible.status.writeFailed = 1; //datasheet specifies these are for write/erase failures + compatible.status.eraseFailed = 1; //yet all errors seem to set both of these bits ... + global.status.failed = 1; +} + +// + +auto BSMemory::Page::swap() -> void { + self->global.status.page ^= 1; +} + +auto BSMemory::Page::read(uint8 address) -> uint8 { + return buffer[self->global.status.page][address]; +} + +auto BSMemory::Page::write(uint8 address, uint8 data) -> void { + buffer[self->global.status.page][address] = data; +} + +// + +auto BSMemory::BlockInformation::bitCount() const -> uint { return 16; } +auto BSMemory::BlockInformation::byteCount() const -> uint { return 1 << bitCount(); } +auto BSMemory::BlockInformation::count() const -> uint { return self->size() >> bitCount(); } + +// + +auto BSMemory::Block::read(uint address) -> uint8 { + address &= byteCount() - 1; + return self->memory.read(id << bitCount() | address); +} + +auto BSMemory::Block::write(uint address, uint8 data) -> void { + if(!self->writable() && status.locked) { + status.failed = 1; + return self->failed(); + } + + //writes to flash can only clear bits + address &= byteCount() - 1; + data &= self->memory.read(id << bitCount() | address); + self->memory.write(id << bitCount() | address, data); +} + +auto BSMemory::Block::erase() -> void { + if(cpu.active()) { + //erase command runs even if the block is not currently writable + erasing = 1; + status.ready = 0; + self->compatible.status.ready = 0; + self->global.status.ready = 0; + return; + } + + self->step(300'000); //300 milliseconds are required to erase one block + erasing = 0; + + if(!self->writable() && status.locked) { + //does not set any failure bits when unsuccessful ... + return; + } + + for(uint address : range(byteCount())) { + self->memory.write(id << bitCount() | address, 0xff); + } + + erased++; + locked = 0; + status.locked = 0; +} + +auto BSMemory::Block::lock() -> void { + if(!self->writable()) { + //produces a failure result even if the page was already locked + status.failed = 1; + return self->failed(); + } + + locked = 1; + status.locked = 1; +} + +//at reset, the locked status bit is set +//this command refreshes the true locked status bit from the device +auto BSMemory::Block::update() -> void { + status.locked = locked; +} + +// + +auto BSMemory::Blocks::operator()(uint6 id) -> Block& { + return self->blocks[id & count() - 1]; +} + +// + +auto BSMemory::Block::Status::operator()() -> uint8 { + return ( //d0-d1 are reserved; always return zero + vppLow << 2 + | queueFull << 3 + | aborted << 4 + | failed << 5 + |!locked << 6 //note: technically the unlocked flag; so locked is inverted here + | ready << 7 + ); +} + +// + +auto BSMemory::Compatible::Status::operator()() -> uint8 { + return ( //d0-d2 are reserved; always return zero + vppLow << 3 + | writeFailed << 4 + | eraseFailed << 5 + | eraseSuspended << 6 + | ready << 7 + ); +} + +// + +auto BSMemory::Global::Status::operator()() -> uint8 { + return ( + page << 0 + | pageReady << 1 + | pageAvailable << 2 + | queueFull << 3 + | sleeping << 4 + | failed << 5 + | suspended << 6 + | ready << 7 + ); +} + +// + +auto BSMemory::Queue::flush() -> void { + history[0] = {}; + history[1] = {}; + history[2] = {}; + history[3] = {}; +} + +auto BSMemory::Queue::pop() -> void { + if(history[3].valid) { history[3] = {}; return; } + if(history[2].valid) { history[2] = {}; return; } + if(history[1].valid) { history[1] = {}; return; } + if(history[0].valid) { history[0] = {}; return; } +} + +auto BSMemory::Queue::push(uint24 address, uint8 data) -> void { + if(!history[0].valid) { history[0] = {true, address, data}; return; } + if(!history[1].valid) { history[1] = {true, address, data}; return; } + if(!history[2].valid) { history[2] = {true, address, data}; return; } + if(!history[3].valid) { history[3] = {true, address, data}; return; } +} + +auto BSMemory::Queue::size() -> uint { + if(history[3].valid) return 4; + if(history[2].valid) return 3; + if(history[1].valid) return 2; + if(history[0].valid) return 1; + return 0; +} + +auto BSMemory::Queue::address(uint index) -> uint24 { + if(index > 3 || !history[index].valid) return 0; + return history[index].address; +} + +auto BSMemory::Queue::data(uint index) -> uint8 { + if(index > 3 || !history[index].valid) return 0; + return history[index].data; +} + +} diff --git a/sfc/slot/bsmemory/bsmemory.hpp b/sfc/slot/bsmemory/bsmemory.hpp new file mode 100644 index 0000000..efa1273 --- /dev/null +++ b/sfc/slot/bsmemory/bsmemory.hpp @@ -0,0 +1,168 @@ +//MaskROMs supported: +// Sharp LH5S4TNI (MaskROM 512K x 8-bit) [BSMC-CR-01: BSMC-ZS5J-JPN, BSMC-YS5J-JPN] +// Sharp LH534VNF (MaskROM 512K x 8-bit) [BSMC-BR-01: BSMC-ZX3J-JPN] + +//Flash chips supported: (16-bit modes unsupported) +// Sharp LH28F800SUT-ZI (Flash 16 x 65536 x 8-bit) [BSMC-AF-01: BSMC-HM-JPN] +// Sharp LH28F016SU ??? (Flash 32 x 65536 x 8-bit) [unreleased: experimental] +// Sharp LH28F032SU ??? (Flash 64 x 65536 x 8-bit) [unreleased: experimental] + +//unsupported: +// Sharp LH28F400SU ??? (Flash 32 x 16384 x 8-bit) [unreleased] {vendor ID: 0x00'b0; device ID: 0x66'21} + +//notes: +//timing emulation is only present for block erase commands +//other commands generally complete so quickly that it's unnecessary (eg 70-120ns for writes) +//suspend, resume, abort, ready/busy modes are not supported + +struct BSMemory : Thread, Memory { + uint pathID = 0; + uint ROM = 1; + + auto writable() const { return pin.writable; } + auto writable(bool writable) { pin.writable = !ROM && writable; } + + //bsmemory.cpp + BSMemory(); + auto synchronizeCPU() -> void; + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + + auto load() -> bool; + auto unload() -> void; + auto power() -> void; + + auto data() -> uint8* override; + auto size() const -> uint override; + auto read(uint address, uint8 data) -> uint8 override; + auto write(uint address, uint8 data) -> void override; + + //serialization.cpp + auto serialize(serializer&) -> void; + + WritableMemory memory; + +private: + struct Pin { + uint1 writable; // => /WP + } pin; + + struct Chip { + uint16 vendor; + uint16 device; + uint48 serial; + } chip; + + struct Page { + BSMemory* self = nullptr; + + auto swap() -> void; + auto read(uint8 address) -> uint8; + auto write(uint8 address, uint8 data) -> void; + + uint8 buffer[2][256]; + } page; + + struct BlockInformation { + BSMemory* self = nullptr; + + inline auto bitCount() const -> uint; + inline auto byteCount() const -> uint; + inline auto count() const -> uint; + }; + + struct Block : BlockInformation { + auto read(uint address) -> uint8; + auto write(uint address, uint8 data) -> void; + auto erase() -> void; + auto lock() -> void; + auto update() -> void; + + uint4 id; + uint32 erased; + uint1 locked; + uint1 erasing; + + struct Status { + auto operator()() -> uint8; + + uint1 vppLow; + uint1 queueFull; + uint1 aborted; + uint1 failed; + uint1 locked = 1; + uint1 ready = 1; + } status; + } blocks[64]; //8mbit = 16; 16mbit = 32; 32mbit = 64 + + struct Blocks : BlockInformation { + auto operator()(uint6 id) -> Block&; + } block; + + struct Compatible { + struct Status { + auto operator()() -> uint8; + + uint1 vppLow; + uint1 writeFailed; + uint1 eraseFailed; + uint1 eraseSuspended; + uint1 ready = 1; + } status; + } compatible; + + struct Global { + struct Status { + auto operator()() -> uint8; + + uint1 page; + uint1 pageReady = 1; + uint1 pageAvailable = 1; + uint1 queueFull; + uint1 sleeping; + uint1 failed; + uint1 suspended; + uint1 ready = 1; + } status; + } global; + + struct Mode { enum : uint { + Flash, + Chip, + Page, + CompatibleStatus, + ExtendedStatus, + };}; + uint3 mode; + + struct ReadyBusyMode { enum : uint { + EnableToLevelMode, + PulseOnWrite, + PulseOnErase, + Disable, + };}; + uint2 readyBusyMode; + + struct Queue { + auto flush() -> void; + auto pop() -> void; + auto push(uint24 address, uint8 data) -> void; + auto size() -> uint; + auto address(uint index) -> uint24; + auto data(uint index) -> uint8; + + //serialization.cpp + auto serialize(serializer&) -> void; + + struct History { + uint1 valid; + uint24 address; + uint8 data; + } history[4]; + } queue; + + auto failed() -> void; +}; + +extern BSMemory bsmemory; diff --git a/sfc/slot/bsmemory/serialization.cpp b/sfc/slot/bsmemory/serialization.cpp new file mode 100644 index 0000000..70779e6 --- /dev/null +++ b/sfc/slot/bsmemory/serialization.cpp @@ -0,0 +1,67 @@ +auto BSMemory::serialize(serializer& s) -> void { + Thread::serialize(s); + if(ROM) return; + + s.array(memory.data(), memory.size()); + + s.integer(pin.writable); + + s.integer(chip.vendor); + s.integer(chip.device); + s.integer(chip.serial); + + s.array(page.buffer[0]); + s.array(page.buffer[1]); + + for(auto& block : blocks) { + s.integer(block.id); + s.integer(block.erased); + s.integer(block.locked); + s.integer(block.erasing); + s.integer(block.status.vppLow); + s.integer(block.status.queueFull); + s.integer(block.status.aborted); + s.integer(block.status.failed); + s.integer(block.status.locked); + s.integer(block.status.ready); + } + + s.integer(compatible.status.vppLow); + s.integer(compatible.status.writeFailed); + s.integer(compatible.status.eraseFailed); + s.integer(compatible.status.eraseSuspended); + s.integer(compatible.status.ready); + + s.integer(global.status.page); + s.integer(global.status.pageReady); + s.integer(global.status.pageAvailable); + s.integer(global.status.queueFull); + s.integer(global.status.sleeping); + s.integer(global.status.failed); + s.integer(global.status.suspended); + s.integer(global.status.ready); + + s.integer(mode); + + s.integer(readyBusyMode); + + queue.serialize(s); +} + +auto BSMemory::Queue::serialize(serializer& s) -> void { + s.integer(history[0].valid); + s.integer(history[0].address); + s.integer(history[0].data); + + s.integer(history[1].valid); + s.integer(history[1].address); + s.integer(history[1].data); + + s.integer(history[2].valid); + s.integer(history[2].address); + s.integer(history[2].data); + + s.integer(history[3].valid); + s.integer(history[3].address); + s.integer(history[3].data); +} diff --git a/sfc/slot/slot.cpp b/sfc/slot/slot.cpp new file mode 100644 index 0000000..0e1d4ab --- /dev/null +++ b/sfc/slot/slot.cpp @@ -0,0 +1,2 @@ +#include +#include diff --git a/sfc/slot/slot.hpp b/sfc/slot/slot.hpp new file mode 100644 index 0000000..1e28ccb --- /dev/null +++ b/sfc/slot/slot.hpp @@ -0,0 +1,2 @@ +#include +#include diff --git a/sfc/slot/sufamiturbo/serialization.cpp b/sfc/slot/sufamiturbo/serialization.cpp new file mode 100644 index 0000000..0f97d98 --- /dev/null +++ b/sfc/slot/sufamiturbo/serialization.cpp @@ -0,0 +1,3 @@ +auto SufamiTurboCartridge::serialize(serializer& s) -> void { + s.array(ram.data(), ram.size()); +} diff --git a/sfc/slot/sufamiturbo/sufamiturbo.cpp b/sfc/slot/sufamiturbo/sufamiturbo.cpp new file mode 100644 index 0000000..5c6fc05 --- /dev/null +++ b/sfc/slot/sufamiturbo/sufamiturbo.cpp @@ -0,0 +1,17 @@ +#include + +namespace SuperFamicom { + +#include "serialization.cpp" +SufamiTurboCartridge sufamiturboA; +SufamiTurboCartridge sufamiturboB; + +auto SufamiTurboCartridge::unload() -> void { + rom.reset(); + ram.reset(); +} + +auto SufamiTurboCartridge::power() -> void { +} + +} diff --git a/sfc/slot/sufamiturbo/sufamiturbo.hpp b/sfc/slot/sufamiturbo/sufamiturbo.hpp new file mode 100644 index 0000000..6f196bf --- /dev/null +++ b/sfc/slot/sufamiturbo/sufamiturbo.hpp @@ -0,0 +1,12 @@ +struct SufamiTurboCartridge { + auto unload() -> void; + auto power() -> void; + auto serialize(serializer&) -> void; + + uint pathID = 0; + ReadableMemory rom; + WritableMemory ram; +}; + +extern SufamiTurboCartridge sufamiturboA; +extern SufamiTurboCartridge sufamiturboB; diff --git a/sfc/smp/io.cpp b/sfc/smp/io.cpp new file mode 100644 index 0000000..ad1aea6 --- /dev/null +++ b/sfc/smp/io.cpp @@ -0,0 +1,182 @@ +auto SMP::portRead(uint2 port) const -> uint8 { + if(port == 0) return io.cpu0; + if(port == 1) return io.cpu1; + if(port == 2) return io.cpu2; + if(port == 3) return io.cpu3; + unreachable; +} + +auto SMP::portWrite(uint2 port, uint8 data) -> void { + if(port == 0) io.apu0 = data; + if(port == 1) io.apu1 = data; + if(port == 2) io.apu2 = data; + if(port == 3) io.apu3 = data; +} + +auto SMP::readIO(uint16 address) -> uint8 { + uint8 data; + + switch(address) { + case 0xf0: //TEST (write-only register) + return 0x00; + + case 0xf1: //CONTROL (write-only register) + return 0x00; + + case 0xf2: //DSPADDR + return io.dspAddr; + + case 0xf3: //DSPDATA + //0x80-0xff are read-only mirrors of 0x00-0x7f + return dsp.read(io.dspAddr & 0x7f); + + case 0xf4: //CPUIO0 + synchronizeCPU(); + return io.apu0; + + case 0xf5: //CPUIO1 + synchronizeCPU(); + return io.apu1; + + case 0xf6: //CPUIO2 + synchronizeCPU(); + return io.apu2; + + case 0xf7: //CPUIO3 + synchronizeCPU(); + return io.apu3; + + case 0xf8: //AUXIO4 + return io.aux4; + + case 0xf9: //AUXIO5 + return io.aux5; + + case 0xfa: //T0TARGET + case 0xfb: //T1TARGET + case 0xfc: //T2TARGET (write-only registers) + return 0x00; + + case 0xfd: //T0OUT (4-bit counter value) + data = timer0.stage3; + timer0.stage3 = 0; + return data; + + case 0xfe: //T1OUT (4-bit counter value) + data = timer1.stage3; + timer1.stage3 = 0; + return data; + + case 0xff: //T2OUT (4-bit counter value) + data = timer2.stage3; + timer2.stage3 = 0; + return data; + } + + return data; //unreachable +} + +auto SMP::writeIO(uint16 address, uint8 data) -> void { + switch(address) { + case 0xf0: //TEST + if(r.p.p) break; //writes only valid when P flag is clear + + io.timersDisable = data >> 0 & 1; + io.ramWritable = data >> 1 & 1; + io.ramDisable = data >> 2 & 1; + io.timersEnable = data >> 3 & 1; + io.externalWaitStates = data >> 4 & 3; + io.internalWaitStates = data >> 6 & 3; + + timer0.synchronizeStage1(); + timer1.synchronizeStage1(); + timer2.synchronizeStage1(); + break; + + case 0xf1: //CONTROL + //0->1 transistion resets timers + if(timer0.enable.raise(data & 0x01)) { + timer0.stage2 = 0; + timer0.stage3 = 0; + } + + if(timer1.enable.raise(data & 0x02)) { + timer1.stage2 = 0; + timer1.stage3 = 0; + } + + if(!timer2.enable.raise(data & 0x04)) { + timer2.stage2 = 0; + timer2.stage3 = 0; + } + + if(data & 0x10) { + synchronizeCPU(); + io.apu0 = 0x00; + io.apu1 = 0x00; + } + + if(data & 0x20) { + synchronizeCPU(); + io.apu2 = 0x00; + io.apu3 = 0x00; + } + + io.iplromEnable = bool(data & 0x80); + break; + + case 0xf2: //DSPADDR + io.dspAddr = data; + break; + + case 0xf3: //DSPDATA + if(io.dspAddr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f + dsp.write(io.dspAddr & 0x7f, data); + break; + + case 0xf4: //CPUIO0 + synchronizeCPU(); + io.cpu0 = data; + break; + + case 0xf5: //CPUIO1 + synchronizeCPU(); + io.cpu1 = data; + break; + + case 0xf6: //CPUIO2 + synchronizeCPU(); + io.cpu2 = data; + break; + + case 0xf7: //CPUIO3 + synchronizeCPU(); + io.cpu3 = data; + break; + + case 0xf8: //AUXIO4 + io.aux4 = data; + break; + + case 0xf9: //AUXIO5 + io.aux5 = 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; + } +} diff --git a/sfc/smp/memory.cpp b/sfc/smp/memory.cpp new file mode 100644 index 0000000..32af649 --- /dev/null +++ b/sfc/smp/memory.cpp @@ -0,0 +1,42 @@ +auto SMP::readRAM(uint16 address) -> uint8 { + if(address >= 0xffc0 && io.iplromEnable) return iplrom[address & 0x3f]; + if(io.ramDisable) return 0x5a; //0xff on mini-SNES + return dsp.apuram[address]; +} + +auto SMP::writeRAM(uint16 address, uint8 data) -> void { + //writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled + if(io.ramWritable && !io.ramDisable) dsp.apuram[address] = data; +} + +auto SMP::idle() -> void { + waitIdle(); +} + +auto SMP::read(uint16 address) -> uint8 { + //Kishin Douji Zenki - Tenchi Meidou requires bus hold delays on CPU I/O reads. + //smp_mem_access_times requires no bus hold delays on APU RAM reads. + if((address & 0xfffc) == 0x00f4) { + wait(address, 1); + uint8 data = readRAM(address); + if((address & 0xfff0) == 0x00f0) data = readIO(address); + wait(address, 1); + return data; + } else { + wait(address, 0); + uint8 data = readRAM(address); + if((address & 0xfff0) == 0x00f0) data = readIO(address); + return data; + } +} + +auto SMP::write(uint16 address, uint8 data) -> void { + wait(address); + writeRAM(address, data); //even IO writes affect underlying RAM + if((address & 0xfff0) == 0x00f0) writeIO(address, data); +} + +auto SMP::readDisassembler(uint16 address) -> uint8 { + if((address & 0xfff0) == 0x00f0) return 0x00; + return readRAM(address); +} diff --git a/sfc/smp/serialization.cpp b/sfc/smp/serialization.cpp new file mode 100644 index 0000000..caaec3a --- /dev/null +++ b/sfc/smp/serialization.cpp @@ -0,0 +1,55 @@ +auto SMP::serialize(serializer& s) -> void { + SPC700::serialize(s); + Thread::serialize(s); + + s.integer(io.clockCounter); + s.integer(io.dspCounter); + + s.integer(io.apu0); + s.integer(io.apu1); + s.integer(io.apu2); + s.integer(io.apu3); + + s.integer(io.timersDisable); + s.integer(io.ramWritable); + s.integer(io.ramDisable); + s.integer(io.timersEnable); + s.integer(io.externalWaitStates); + s.integer(io.internalWaitStates); + + s.integer(io.iplromEnable); + + s.integer(io.dspAddr); + + s.integer(io.cpu0); + s.integer(io.cpu1); + s.integer(io.cpu2); + s.integer(io.cpu3); + + s.integer(io.aux4); + s.integer(io.aux5); + + s.integer(timer0.stage0); + s.integer(timer0.stage1); + s.integer(timer0.stage2); + s.integer(timer0.stage3); + s.boolean(timer0.line); + s.boolean(timer0.enable); + s.integer(timer0.target); + + s.integer(timer1.stage0); + s.integer(timer1.stage1); + s.integer(timer1.stage2); + s.integer(timer1.stage3); + s.boolean(timer1.line); + s.boolean(timer1.enable); + s.integer(timer1.target); + + s.integer(timer2.stage0); + s.integer(timer2.stage1); + s.integer(timer2.stage2); + s.integer(timer2.stage3); + s.boolean(timer2.line); + s.boolean(timer2.enable); + s.integer(timer2.target); +} diff --git a/sfc/smp/smp.cpp b/sfc/smp/smp.cpp new file mode 100644 index 0000000..4002855 --- /dev/null +++ b/sfc/smp/smp.cpp @@ -0,0 +1,53 @@ +#include + +namespace SuperFamicom { + +SMP smp; +#include "memory.cpp" +#include "io.cpp" +#include "timing.cpp" +#include "serialization.cpp" + +auto SMP::synchronizeCPU() -> void { + if(clock >= 0) scheduler.resume(cpu.thread); +} + +auto SMP::synchronizeDSP() -> void { + while(dsp.clock < 0) dsp.main(); +} + +auto SMP::Enter() -> void { + while(true) { + scheduler.synchronize(); + smp.main(); + } +} + +auto SMP::main() -> void { + if(r.wait) return instructionWait(); + if(r.stop) return instructionStop(); + instruction(); +} + +auto SMP::load() -> bool { + if(auto fp = platform->open(ID::System, "ipl.rom", File::Read, File::Required)) { + fp->read(iplrom, 64); + return true; + } + return false; +} + +auto SMP::power(bool reset) -> void { + SPC700::power(); + create(Enter, system.apuFrequency() / 12.0); + + r.pc.byte.l = iplrom[62]; + r.pc.byte.h = iplrom[63]; + + io = {}; + timer0 = {}; + timer1 = {}; + timer2 = {}; +} + +} diff --git a/sfc/smp/smp.hpp b/sfc/smp/smp.hpp new file mode 100644 index 0000000..4b13dc6 --- /dev/null +++ b/sfc/smp/smp.hpp @@ -0,0 +1,100 @@ +//Sony CXP1100Q-1 + +struct SMP : Processor::SPC700, Thread { + inline auto synchronizing() const -> bool override { return scheduler.synchronizing(); } + + //io.cpp + auto portRead(uint2 port) const -> uint8; + auto portWrite(uint2 port, uint8 data) -> void; + + //smp.cpp + auto synchronizeCPU() -> void; + auto synchronizeDSP() -> void; + static auto Enter() -> void; + auto main() -> void; + auto load() -> bool; + auto power(bool reset) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + uint8 iplrom[64]; + +private: + struct IO { + //timing + uint clockCounter = 0; + uint dspCounter = 0; + + //external + uint8 apu0 = 0; + uint8 apu1 = 0; + uint8 apu2 = 0; + uint8 apu3 = 0; + + //$00f0 + uint1 timersDisable = 0; + uint1 ramWritable = 1; + uint1 ramDisable = 0; + uint1 timersEnable = 1; + uint2 externalWaitStates = 0; + uint2 internalWaitStates = 0; + + //$00f1 + uint1 iplromEnable = 1; + + //$00f2 + uint8 dspAddr = 0; + + //$00f4-00f7 + uint8 cpu0 = 0; + uint8 cpu1 = 0; + uint8 cpu2 = 0; + uint8 cpu3 = 0; + + //$00f8-00f9 + uint8 aux4 = 0; + uint8 aux5 = 0; + } io; + + //memory.cpp + inline auto readRAM(uint16 address) -> uint8; + inline auto writeRAM(uint16 address, uint8 data) -> void; + + auto idle() -> void override; + auto read(uint16 address) -> uint8 override; + auto write(uint16 address, uint8 data) -> void override; + + auto readDisassembler(uint16 address) -> uint8 override; + + //io.cpp + inline auto readIO(uint16 address) -> uint8; + inline auto writeIO(uint16 address, uint8 data) -> void; + + //timing.cpp + template + struct Timer { + uint8 stage0 = 0; + uint8 stage1 = 0; + uint8 stage2 = 0; + uint4 stage3 = 0; + boolean line = 0; + boolean enable = 0; + uint8 target = 0; + + auto step(uint clocks) -> void; + auto synchronizeStage1() -> void; + }; + + Timer<128> timer0; + Timer<128> timer1; + Timer< 16> timer2; + + inline auto wait(maybe address = nothing, bool half = false) -> void; + inline auto waitIdle(maybe address = nothing, bool half = false) -> void; + inline auto step(uint clocks) -> void; + inline auto stepIdle(uint clocks) -> void; + inline auto stepTimers(uint clocks) -> void; +}; + +extern SMP smp; diff --git a/sfc/smp/timing.cpp b/sfc/smp/timing.cpp new file mode 100644 index 0000000..4f70d56 --- /dev/null +++ b/sfc/smp/timing.cpp @@ -0,0 +1,78 @@ +//DSP clock (~24576khz) / 12 (~2048khz) is fed into the SMP +//from here, the wait states value is really a clock divider of {2, 4, 8, 16} +//due to an unknown hardware issue, clock dividers of 8 and 16 are glitchy +//the SMP ends up consuming 10 and 20 clocks per opcode cycle instead +//this causes unpredictable behavior on real hardware +//sometimes the SMP will run far slower than expected +//other times (and more likely), the SMP will deadlock until the system is reset +//the timers are not affected by this and advance by their expected values +auto SMP::wait(maybe addr, bool half) -> void { + static const uint cycleWaitStates[4] = {2, 4, 10, 20}; + static const uint timerWaitStates[4] = {2, 4, 8, 16}; + + uint waitStates = io.externalWaitStates; + if(!addr) waitStates = io.internalWaitStates; //idle cycles + else if((*addr & 0xfff0) == 0x00f0) waitStates = io.internalWaitStates; //IO registers + else if(*addr >= 0xffc0 && io.iplromEnable) waitStates = io.internalWaitStates; //IPLROM + + step(cycleWaitStates[waitStates] >> half); + stepTimers(timerWaitStates[waitStates] >> half); +} + +auto SMP::waitIdle(maybe addr, bool half) -> void { + static const uint cycleWaitStates[4] = {2, 4, 10, 20}; + static const uint timerWaitStates[4] = {2, 4, 8, 16}; + + uint waitStates = io.externalWaitStates; + if(!addr) waitStates = io.internalWaitStates; //idle cycles + else if((*addr & 0xfff0) == 0x00f0) waitStates = io.internalWaitStates; //IO registers + else if(*addr >= 0xffc0 && io.iplromEnable) waitStates = io.internalWaitStates; //IPLROM + + stepIdle(cycleWaitStates[waitStates] >> half); + stepTimers(timerWaitStates[waitStates] >> half); +} + +auto SMP::step(uint clocks) -> void { + clock += clocks * (uint64_t)cpu.frequency; + dsp.clock -= clocks; + synchronizeDSP(); + //forcefully sync SMP to CPU in case chips are not communicating + if(clock > 768 * 24 * (int64_t)24'000'000) synchronizeCPU(); +} + +auto SMP::stepIdle(uint clocks) -> void { + clock += clocks * (uint64_t)cpu.frequency; + dsp.clock -= clocks; +} + +auto SMP::stepTimers(uint clocks) -> void { + timer0.step(clocks); + timer1.step(clocks); + timer2.step(clocks); +} + +template auto SMP::Timer::step(uint clocks) -> void { + //stage 0 increment + stage0 += clocks; + if(stage0 < Frequency) return; + stage0 -= Frequency; + + //stage 1 increment + stage1 ^= 1; + synchronizeStage1(); +} + +template auto SMP::Timer::synchronizeStage1() -> void { + bool level = stage1; + if(!smp.io.timersEnable) level = false; + if(smp.io.timersDisable) level = false; + if(!line.lower(level)) return; //only pulse on 1->0 transition + + //stage 2 increment + if(!enable) return; + if(++stage2 != target) return; + + //stage 3 increment + stage2 = 0; + stage3++; +} diff --git a/sfc/system/serialization.cpp b/sfc/system/serialization.cpp new file mode 100644 index 0000000..75c0e5d --- /dev/null +++ b/sfc/system/serialization.cpp @@ -0,0 +1,119 @@ +auto System::serialize(bool synchronize) -> serializer { + //deterministic serialization (synchronize=false) is only possible with select libco methods + if(!co_serializable()) synchronize = true; + + if(!information.serializeSize[synchronize]) return {}; //should never occur + if(synchronize) runToSave(); + + uint signature = 0x31545342; + uint serializeSize = information.serializeSize[synchronize]; + char version[16] = {}; + char description[512] = {}; + memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size()); + + serializer s(serializeSize); + s.integer(signature); + s.integer(serializeSize); + s.array(version); + s.array(description); + s.boolean(synchronize); + s.boolean(hacks.fastPPU); + serializeAll(s, synchronize); + return s; +} + +auto System::unserialize(serializer& s) -> bool { + uint signature = 0; + uint serializeSize = 0; + char version[16] = {}; + char description[512] = {}; + bool synchronize = false; + bool fastPPU = false; + + s.integer(signature); + s.integer(serializeSize); + s.array(version); + s.array(description); + s.boolean(synchronize); + s.boolean(fastPPU); + + if(signature != 0x31545342) return false; + if(serializeSize != information.serializeSize[synchronize]) return false; + if(string{version} != Emulator::SerializerVersion) return false; + if(fastPPU != hacks.fastPPU) return false; + + if(synchronize) power(/* reset = */ false); + serializeAll(s, synchronize); + return true; +} + +//internal + +auto System::serializeAll(serializer& s, bool synchronize) -> void { + random.serialize(s); + cartridge.serialize(s); + cpu.serialize(s); + smp.serialize(s); + ppu.serialize(s); + dsp.serialize(s); + + if(cartridge.has.ICD) icd.serialize(s); + if(cartridge.has.MCC) mcc.serialize(s); + if(cartridge.has.DIP) dip.serialize(s); + if(cartridge.has.Event) event.serialize(s); + if(cartridge.has.SA1) sa1.serialize(s); + if(cartridge.has.SuperFX) superfx.serialize(s); + if(cartridge.has.ARMDSP) armdsp.serialize(s); + if(cartridge.has.HitachiDSP) hitachidsp.serialize(s); + if(cartridge.has.NECDSP) necdsp.serialize(s); + if(cartridge.has.EpsonRTC) epsonrtc.serialize(s); + if(cartridge.has.SharpRTC) sharprtc.serialize(s); + if(cartridge.has.SPC7110) spc7110.serialize(s); + if(cartridge.has.SDD1) sdd1.serialize(s); + if(cartridge.has.OBC1) obc1.serialize(s); + if(cartridge.has.MSU1) msu1.serialize(s); + + if(cartridge.has.Cx4) cx4.serialize(s); + if(cartridge.has.DSP1) dsp1.serialize(s); + if(cartridge.has.DSP2) dsp2.serialize(s); + if(cartridge.has.DSP4) dsp4.serialize(s); + if(cartridge.has.ST0010) st0010.serialize(s); + + if(cartridge.has.BSMemorySlot) bsmemory.serialize(s); + if(cartridge.has.SufamiTurboSlotA) sufamiturboA.serialize(s); + if(cartridge.has.SufamiTurboSlotB) sufamiturboB.serialize(s); + + controllerPort1.serialize(s); + controllerPort2.serialize(s); + expansionPort.serialize(s); + + if(!synchronize) { + cpu.serializeStack(s); + smp.serializeStack(s); + ppu.serializeStack(s); + for(auto coprocessor : cpu.coprocessors) { + coprocessor->serializeStack(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.) +auto System::serializeInit(bool synchronize) -> uint { + serializer s; + + uint signature = 0; + uint serializeSize = 0; + char version[16] = {}; + char description[512] = {}; + + s.integer(signature); + s.integer(serializeSize); + s.array(version); + s.array(description); + s.boolean(synchronize); + s.boolean(hacks.fastPPU); + serializeAll(s, synchronize); + return s.size(); +} diff --git a/sfc/system/system.cpp b/sfc/system/system.cpp new file mode 100644 index 0000000..27897f5 --- /dev/null +++ b/sfc/system/system.cpp @@ -0,0 +1,242 @@ +#include + +namespace SuperFamicom { + +System system; +Scheduler scheduler; +Random random; +Cheat cheat; +#include "serialization.cpp" + +auto System::run() -> void { + scheduler.mode = Scheduler::Mode::Run; + scheduler.enter(); + if(scheduler.event == Scheduler::Event::Frame) frameEvent(); +} + +auto System::runToSave() -> void { + auto method = configuration.system.serialization.method; + + //these games will periodically deadlock when using "Fast" synchronization + if(cartridge.headerTitle() == "Star Ocean") method = "Strict"; + if(cartridge.headerTitle() == "TALES OF PHANTASIA") method = "Strict"; + + //fallback in case of unrecognized method specified + if(method != "Fast" && method != "Strict") method = "Fast"; + + scheduler.mode = Scheduler::Mode::Synchronize; + if(method == "Fast") runToSaveFast(); + if(method == "Strict") runToSaveStrict(); + + scheduler.mode = Scheduler::Mode::Run; + scheduler.active = cpu.thread; +} + +auto System::runToSaveFast() -> void { + //run the emulator normally until the CPU thread naturally hits a synchronization point + while(true) { + scheduler.enter(); + if(scheduler.event == Scheduler::Event::Frame) frameEvent(); + if(scheduler.event == Scheduler::Event::Synchronized) { + if(scheduler.active != cpu.thread) continue; + break; + } + if(scheduler.event == Scheduler::Event::Desynchronized) continue; + } + + //ignore any desynchronization events to force all other threads to their synchronization points + auto synchronize = [&](cothread_t thread) -> void { + scheduler.active = thread; + while(true) { + scheduler.enter(); + if(scheduler.event == Scheduler::Event::Frame) frameEvent(); + if(scheduler.event == Scheduler::Event::Synchronized) break; + if(scheduler.event == Scheduler::Event::Desynchronized) continue; + } + }; + + synchronize(smp.thread); + synchronize(ppu.thread); + for(auto coprocessor : cpu.coprocessors) { + synchronize(coprocessor->thread); + } +} + +auto System::runToSaveStrict() -> void { + //run every thread until it cleanly hits a synchronization point + //if it fails, start resynchronizing every thread again + auto synchronize = [&](cothread_t thread) -> bool { + scheduler.active = thread; + while(true) { + scheduler.enter(); + if(scheduler.event == Scheduler::Event::Frame) frameEvent(); + if(scheduler.event == Scheduler::Event::Synchronized) break; + if(scheduler.event == Scheduler::Event::Desynchronized) return false; + } + return true; + }; + + while(true) { + //SMP thread is synchronized twice to ensure the CPU and SMP are closely aligned: + //this is extremely critical for Tales of Phantasia and Star Ocean. + if(!synchronize(smp.thread)) continue; + if(!synchronize(cpu.thread)) continue; + if(!synchronize(smp.thread)) continue; + if(!synchronize(ppu.thread)) continue; + + bool synchronized = true; + for(auto coprocessor : cpu.coprocessors) { + if(!synchronize(coprocessor->thread)) { synchronized = false; break; } + } + if(!synchronized) continue; + + break; + } +} + +auto System::frameEvent() -> void { + ppu.refresh(); + + //refresh all cheat codes once per frame + Memory::GlobalWriteEnable = true; + for(auto& code : cheat.codes) { + if(code.enable) { + bus.write(code.address, code.data); + } + } + Memory::GlobalWriteEnable = false; +} + +auto System::load(Emulator::Interface* interface) -> bool { + information = {}; + + bus.reset(); + if(!cpu.load()) return false; + if(!smp.load()) return false; + if(!ppu.load()) return false; + if(!dsp.load()) return false; + if(!cartridge.load()) return false; + + if(cartridge.region() == "NTSC") { + information.region = Region::NTSC; + information.cpuFrequency = Emulator::Constants::Colorburst::NTSC * 6.0; + } + if(cartridge.region() == "PAL") { + information.region = Region::PAL; + information.cpuFrequency = Emulator::Constants::Colorburst::PAL * 4.8; + } + + if(configuration.hacks.hotfixes) { + //due to poor programming, Rendering Ranger R2 will rarely lock up at 32040 * 768hz. + if(cartridge.headerTitle() == "RENDERING RANGER R2") { + information.apuFrequency = 32000.0 * 768.0; + } + } + + if(cartridge.has.ICD) { + if(!icd.load()) return false; + } + if(cartridge.has.BSMemorySlot) bsmemory.load(); + + this->interface = interface; + return information.loaded = true; +} + +auto System::save() -> void { + if(!loaded()) return; + + cartridge.save(); +} + +auto System::unload() -> void { + if(!loaded()) return; + + controllerPort1.unload(); + controllerPort2.unload(); + expansionPort.unload(); + + if(cartridge.has.ICD) icd.unload(); + if(cartridge.has.MCC) mcc.unload(); + if(cartridge.has.Event) event.unload(); + if(cartridge.has.SA1) sa1.unload(); + if(cartridge.has.SuperFX) superfx.unload(); + if(cartridge.has.HitachiDSP) hitachidsp.unload(); + if(cartridge.has.SPC7110) spc7110.unload(); + if(cartridge.has.SDD1) sdd1.unload(); + if(cartridge.has.OBC1) obc1.unload(); + if(cartridge.has.MSU1) msu1.unload(); + if(cartridge.has.BSMemorySlot) bsmemory.unload(); + if(cartridge.has.SufamiTurboSlotA) sufamiturboA.unload(); + if(cartridge.has.SufamiTurboSlotB) sufamiturboB.unload(); + + cartridge.unload(); + information.loaded = false; +} + +auto System::power(bool reset) -> void { + hacks.fastPPU = configuration.hacks.ppu.fast; + + Emulator::audio.reset(interface); + + random.entropy(Random::Entropy::Low); //fallback case + if(configuration.hacks.entropy == "None") random.entropy(Random::Entropy::None); + if(configuration.hacks.entropy == "Low" ) random.entropy(Random::Entropy::Low ); + if(configuration.hacks.entropy == "High") random.entropy(Random::Entropy::High); + + cpu.power(reset); + smp.power(reset); + dsp.power(reset); + ppu.power(reset); + + if(cartridge.has.ICD) icd.power(); + if(cartridge.has.MCC) mcc.power(); + if(cartridge.has.DIP) dip.power(); + if(cartridge.has.Event) event.power(); + if(cartridge.has.SA1) sa1.power(); + if(cartridge.has.SuperFX) superfx.power(); + if(cartridge.has.ARMDSP) armdsp.power(); + if(cartridge.has.HitachiDSP) hitachidsp.power(); + if(cartridge.has.NECDSP) necdsp.power(); + if(cartridge.has.EpsonRTC) epsonrtc.power(); + if(cartridge.has.SharpRTC) sharprtc.power(); + if(cartridge.has.SPC7110) spc7110.power(); + if(cartridge.has.SDD1) sdd1.power(); + if(cartridge.has.OBC1) obc1.power(); + if(cartridge.has.MSU1) msu1.power(); + if(cartridge.has.Cx4) cx4.power(); + if(cartridge.has.DSP1) dsp1.power(); + if(cartridge.has.DSP2) dsp2.power(); + if(cartridge.has.DSP4) dsp4.power(); + if(cartridge.has.ST0010) st0010.power(); + if(cartridge.has.BSMemorySlot) bsmemory.power(); + if(cartridge.has.SufamiTurboSlotA) sufamiturboA.power(); + if(cartridge.has.SufamiTurboSlotB) sufamiturboB.power(); + + if(cartridge.has.ICD) cpu.coprocessors.append(&icd); + if(cartridge.has.Event) cpu.coprocessors.append(&event); + if(cartridge.has.SA1) cpu.coprocessors.append(&sa1); + if(cartridge.has.SuperFX) cpu.coprocessors.append(&superfx); + if(cartridge.has.ARMDSP) cpu.coprocessors.append(&armdsp); + if(cartridge.has.HitachiDSP) cpu.coprocessors.append(&hitachidsp); + if(cartridge.has.NECDSP) cpu.coprocessors.append(&necdsp); + if(cartridge.has.EpsonRTC) cpu.coprocessors.append(&epsonrtc); + if(cartridge.has.SharpRTC) cpu.coprocessors.append(&sharprtc); + if(cartridge.has.SPC7110) cpu.coprocessors.append(&spc7110); + if(cartridge.has.MSU1) cpu.coprocessors.append(&msu1); + if(cartridge.has.BSMemorySlot) cpu.coprocessors.append(&bsmemory); + + scheduler.active = cpu.thread; + + controllerPort1.power(ID::Port::Controller1); + controllerPort2.power(ID::Port::Controller2); + expansionPort.power(); + + controllerPort1.connect(settings.controllerPort1); + controllerPort2.connect(settings.controllerPort2); + expansionPort.connect(settings.expansionPort); + + information.serializeSize[0] = serializeInit(0); + information.serializeSize[1] = serializeInit(1); +} + +} diff --git a/sfc/system/system.hpp b/sfc/system/system.hpp new file mode 100644 index 0000000..4642c1a --- /dev/null +++ b/sfc/system/system.hpp @@ -0,0 +1,54 @@ +struct System { + enum class Region : uint { NTSC, PAL }; + + inline auto loaded() const -> bool { return information.loaded; } + inline auto region() const -> Region { return information.region; } + inline auto cpuFrequency() const -> double { return information.cpuFrequency; } + inline auto apuFrequency() const -> double { return information.apuFrequency; } + + inline auto fastPPU() const -> bool { return hacks.fastPPU; } + + auto run() -> void; + auto runToSave() -> void; + auto runToSaveFast() -> void; + auto runToSaveStrict() -> void; + auto frameEvent() -> void; + + auto load(Emulator::Interface*) -> bool; + auto save() -> void; + auto unload() -> void; + auto power(bool reset) -> void; + + //serialization.cpp + auto serialize(bool synchronize) -> serializer; + auto unserialize(serializer&) -> bool; + + uint frameSkip = 0; + uint frameCounter = 0; + bool runAhead = 0; + +private: + Emulator::Interface* interface = nullptr; + + struct Information { + bool loaded = false; + Region region = Region::NTSC; + double cpuFrequency = Emulator::Constants::Colorburst::NTSC * 6.0; + double apuFrequency = 32040.0 * 768.0; + uint serializeSize[2] = {0, 0}; + } information; + + struct Hacks { + bool fastPPU = false; + } hacks; + + auto serializeAll(serializer&, bool synchronize) -> void; + auto serializeInit(bool synchronize) -> uint; + + friend class Cartridge; +}; + +extern System system; + +auto Region::NTSC() -> bool { return system.region() == System::Region::NTSC; } +auto Region::PAL() -> bool { return system.region() == System::Region::PAL; }