From aa7cf18989d60e01022129b34cec03a179a54567 Mon Sep 17 00:00:00 2001 From: Askot Date: Sat, 17 Sep 2016 20:43:24 -0700 Subject: [PATCH] -Too many to write --- .gitignore | 3 + Makefile.gc | 23 +- Makefile.wii | 10 +- hbc/meta.xml | 4 +- readme.txt | 41 +- source/fceugx.cpp | 123 +- source/fceugx.h | 27 +- source/fceultra/SConscript | 42 + source/fceultra/asm.cpp | 19 +- source/fceultra/auxlib.lua | 45 + source/fceultra/boards/09-034a.cpp | 36 +- source/fceultra/boards/112.cpp | 1 + source/fceultra/boards/12in1.cpp | 39 +- source/fceultra/boards/15.cpp | 1 + source/fceultra/boards/156.cpp | 1 + source/fceultra/boards/164.cpp | 3 + source/fceultra/boards/176.cpp | 26 +- source/fceultra/boards/177.cpp | 1 + source/fceultra/boards/178.cpp | 131 +- source/fceultra/boards/18.cpp | 1 + source/fceultra/boards/183.cpp | 35 +- source/fceultra/boards/186.cpp | 9 +- source/fceultra/boards/206.cpp | 7 +- source/fceultra/boards/208.cpp | 5 +- source/fceultra/boards/225.cpp | 2 +- source/fceultra/boards/232.cpp | 2 +- source/fceultra/boards/246.cpp | 1 + source/fceultra/boards/252.cpp | 1 + source/fceultra/boards/253.cpp | 22 +- source/fceultra/boards/28.cpp | 5 +- source/fceultra/boards/32.cpp | 1 + source/fceultra/boards/34.cpp | 1 + source/fceultra/boards/40.cpp | 1 + source/fceultra/boards/42.cpp | 1 + source/fceultra/boards/43.cpp | 26 +- source/fceultra/boards/50.cpp | 1 + source/fceultra/boards/65.cpp | 1 + source/fceultra/boards/67.cpp | 1 + source/fceultra/boards/68.cpp | 1 + source/fceultra/boards/69.cpp | 15 +- source/fceultra/boards/79.cpp | 1 + source/fceultra/boards/80.cpp | 1 + source/fceultra/boards/8157.cpp | 35 +- source/fceultra/boards/82.cpp | 1 + source/fceultra/boards/88.cpp | 3 + source/fceultra/boards/99.cpp | 1 + source/fceultra/boards/SConscript | 6 + source/fceultra/boards/__dummy_mapper.cpp | 2 +- source/fceultra/boards/addrlatch.cpp | 35 +- source/fceultra/boards/bandai.cpp | 205 +- source/fceultra/boards/coolboy.cpp | 108 + source/fceultra/boards/dance2000.cpp | 45 +- source/fceultra/boards/datalatch.cpp | 53 +- source/fceultra/boards/edu2000.cpp | 1 + source/fceultra/boards/emu2413.c | 2 +- source/fceultra/boards/famicombox.cpp | 2 +- source/fceultra/boards/ffe.cpp | 1 + source/fceultra/boards/inlnsf.cpp | 62 + source/fceultra/boards/ks7010.cpp | 85 + source/fceultra/boards/ks7012.cpp | 1 + source/fceultra/boards/ks7017.cpp | 1 + source/fceultra/boards/ks7037.cpp | 1 + source/fceultra/boards/lh32.cpp | 1 + source/fceultra/boards/lh53.cpp | 1 + source/fceultra/boards/mihunche.cpp | 68 + source/fceultra/boards/mmc1.cpp | 4 +- source/fceultra/boards/mmc2and4.cpp | 2 + source/fceultra/boards/mmc3.cpp | 126 +- source/fceultra/boards/mmc5.cpp | 321 +- source/fceultra/boards/n106.cpp | 2 +- source/fceultra/boards/onebus.cpp | 29 +- source/fceultra/boards/pec-586.cpp | 87 +- source/fceultra/boards/sb-2000.cpp | 195 + source/fceultra/boards/sc-127.cpp | 21 +- source/fceultra/boards/supervision.cpp | 58 +- source/fceultra/boards/t-262.cpp | 10 +- source/fceultra/boards/transformer.cpp | 1 + source/fceultra/boards/unrom512.cpp | 269 + source/fceultra/boards/vrc2and4.cpp | 2 + source/fceultra/boards/vrc3.cpp | 1 + .../boards/{konami-qtai.cpp => vrc5.cpp} | 451 +- source/fceultra/boards/vrc6.cpp | 7 +- source/fceultra/boards/vrc7.cpp | 15 +- source/fceultra/boards/yoko.cpp | 1 + source/fceultra/cart.cpp | 46 +- source/fceultra/cart.h | 11 +- source/fceultra/cheat.cpp | 13 +- source/fceultra/conddebug.cpp | 50 +- source/fceultra/conddebug.h | 4 +- source/fceultra/config.cpp | 63 +- source/fceultra/debug.cpp | 115 +- source/fceultra/debug.h | 30 +- source/fceultra/drawing.cpp | 18 +- source/fceultra/drawing.h | 4 +- source/fceultra/driver.h | 19 +- source/fceultra/emufile.cpp | 23 +- source/fceultra/emufile.h | 16 +- source/fceultra/fceu.cpp | 192 +- source/fceultra/fceu.h | 14 +- source/fceultra/fceulua.h | 91 + source/fceultra/fcoeffs.h | 2904 ++++---- source/fceultra/file.cpp | 78 +- source/fceultra/file.h | 5 +- source/fceultra/filter.cpp | 5 +- source/fceultra/fir/SConscript | 6 + source/fceultra/git.h | 20 +- source/fceultra/ines-correct.h | 67 +- source/fceultra/ines.cpp | 1523 +++-- source/fceultra/ines.h | 12 +- source/fceultra/input.cpp | 71 +- source/fceultra/input.h | 3 +- source/fceultra/input/SConscript | 6 + source/fceultra/input/fkb.cpp | 107 +- source/fceultra/input/fkb.h | 144 +- source/fceultra/input/pec586kb.cpp | 96 + source/fceultra/input/suborkb.cpp | 136 +- source/fceultra/input/suborkb.h | 196 +- source/fceultra/input/zapper.cpp | 27 +- source/fceultra/lua-engine.cpp | 6025 +++++++++++++++++ source/fceultra/lua/COPYRIGHT | 34 + source/fceultra/lua/HISTORY | 183 + source/fceultra/lua/README | 37 + source/fceultra/lua/SConscript | 8 + source/fceultra/lua/lua.vcproj | 366 + source/fceultra/lua/src/Makefile | 182 + source/fceultra/lua/src/lapi.c | 1087 +++ source/fceultra/lua/src/lapi.h | 16 + source/fceultra/lua/src/lauxlib.c | 652 ++ source/fceultra/lua/src/lauxlib.h | 174 + source/fceultra/lua/src/lbaselib.c | 653 ++ source/fceultra/lua/src/lcode.c | 839 +++ source/fceultra/lua/src/lcode.h | 76 + source/fceultra/lua/src/ldblib.c | 397 ++ source/fceultra/lua/src/ldebug.c | 638 ++ source/fceultra/lua/src/ldebug.h | 33 + source/fceultra/lua/src/ldo.c | 518 ++ source/fceultra/lua/src/ldo.h | 57 + source/fceultra/lua/src/ldump.c | 164 + source/fceultra/lua/src/lfunc.c | 174 + source/fceultra/lua/src/lfunc.h | 34 + source/fceultra/lua/src/lgc.c | 711 ++ source/fceultra/lua/src/lgc.h | 110 + source/fceultra/lua/src/linit.c | 38 + source/fceultra/lua/src/liolib.c | 553 ++ source/fceultra/lua/src/llex.c | 461 ++ source/fceultra/lua/src/llex.h | 81 + source/fceultra/lua/src/llimits.h | 128 + source/fceultra/lua/src/lmathlib.c | 263 + source/fceultra/lua/src/lmem.c | 86 + source/fceultra/lua/src/lmem.h | 49 + source/fceultra/lua/src/loadlib.c | 666 ++ source/fceultra/lua/src/lobject.c | 214 + source/fceultra/lua/src/lobject.h | 381 ++ source/fceultra/lua/src/lopcodes.c | 102 + source/fceultra/lua/src/lopcodes.h | 268 + source/fceultra/lua/src/loslib.c | 243 + source/fceultra/lua/src/lparser.c | 1339 ++++ source/fceultra/lua/src/lparser.h | 82 + source/fceultra/lua/src/lstate.c | 214 + source/fceultra/lua/src/lstate.h | 169 + source/fceultra/lua/src/lstring.c | 111 + source/fceultra/lua/src/lstring.h | 31 + source/fceultra/lua/src/lstrlib.c | 869 +++ source/fceultra/lua/src/ltable.c | 588 ++ source/fceultra/lua/src/ltable.h | 40 + source/fceultra/lua/src/ltablib.c | 287 + source/fceultra/lua/src/ltm.c | 75 + source/fceultra/lua/src/ltm.h | 54 + source/fceultra/lua/src/lua.c | 392 ++ source/fceultra/lua/src/lua.h | 388 ++ source/fceultra/lua/src/luac.c | 200 + source/fceultra/lua/src/luaconf.h | 763 +++ source/fceultra/lua/src/lualib.h | 53 + source/fceultra/lua/src/lundump.c | 227 + source/fceultra/lua/src/lundump.h | 36 + source/fceultra/lua/src/lvm.c | 763 +++ source/fceultra/lua/src/lvm.h | 36 + source/fceultra/lua/src/lzio.c | 82 + source/fceultra/lua/src/lzio.h | 67 + source/fceultra/lua/src/print.c | 227 + source/fceultra/movie.cpp | 131 +- source/fceultra/movie.h | 23 +- source/fceultra/netplay.cpp | 18 +- source/fceultra/nsf.cpp | 59 +- source/fceultra/oldmovie.cpp | 677 ++ source/fceultra/oldmovie.h | 30 + source/fceultra/palette.cpp | 41 +- source/fceultra/palettes/SConscript | 6 + source/fceultra/ppu.cpp | 2933 ++++---- source/fceultra/ppu.h | 4 +- source/fceultra/pputile.inc | 124 +- source/fceultra/sound.cpp | 185 +- source/fceultra/sound.h | 1 + source/fceultra/state.cpp | 191 +- source/fceultra/state.h | 4 +- source/fceultra/types-des.h | 458 ++ source/fceultra/types.h | 6 + source/fceultra/unif.cpp | 67 +- source/fceultra/unif.h | 5 + source/fceultra/utils/SConscript | 25 + source/fceultra/utils/backward.cpp | 33 + source/fceultra/utils/backward.hpp | 2196 ++++++ source/fceultra/utils/endian.h | 4 +- source/fceultra/utils/memory.cpp | 50 +- source/fceultra/utils/memory.h | 72 +- source/fceultra/utils/xstring.h | 22 +- source/fceultra/version.h | 4 +- source/fceultra/video.cpp | 29 +- source/fceultra/vsuni.cpp | 6 +- source/fceultra/wave.cpp | 6 +- source/fceultra/x6502.cpp | 12 +- source/fceultra/x6502.h | 2 +- source/fceustate.cpp | 19 + source/fceustate.h | 1 + source/filelist.h | 12 +- source/gcvideo.cpp | 522 +- source/gcvideo.h | 4 +- source/gui/gui.h | 11 + source/gui/gui_button.cpp | 22 +- source/gui/gui_filebrowser.cpp | 4 +- source/gui/gui_optionbrowser.cpp | 13 +- source/gui/gui_trigger.cpp | 41 +- source/gui/gui_window.cpp | 4 +- source/images/bg_game_selection.png | Bin 1528 -> 1432 bytes source/images/bg_game_selection_entry.png | Bin 268 -> 252 bytes source/images/bg_preview.png | Bin 0 -> 20416 bytes source/images/button_gamesave.png | Bin 549 -> 546 bytes source/images/button_gamesave_over.png | Bin 546 -> 12117 bytes source/images/button_palette.png | Bin 0 -> 1838 bytes source/images/button_palette_over.png | Bin 0 -> 1784 bytes source/images/button_prompt.png | Bin 1625 -> 1760 bytes source/images/button_prompt_over.png | Bin 1760 -> 1911 bytes source/images/icon_game_delete.png | Bin 0 -> 5892 bytes source/images/icon_settings_screenshot.png | Bin 0 -> 11719 bytes source/images/icon_settings_wiiupro.png | Bin 0 -> 10729 bytes source/menu.cpp | 311 +- source/menu.h | 1 + source/pad.cpp | 87 +- source/pad.h | 2 + source/preferences.cpp | 12 +- source/utils/vm/asm.h | 338 + source/utils/vm/dsihandler.s | 72 + source/utils/vm/vm.c | 367 + source/utils/vm/vm.h | 90 + source/vmalloc.cpp | 49 + source/vmalloc.h | 21 + update.xml | 3 +- 247 files changed, 36425 insertions(+), 5953 deletions(-) create mode 100644 .gitignore create mode 100644 source/fceultra/SConscript create mode 100644 source/fceultra/auxlib.lua create mode 100644 source/fceultra/boards/SConscript create mode 100644 source/fceultra/boards/coolboy.cpp create mode 100644 source/fceultra/boards/inlnsf.cpp create mode 100644 source/fceultra/boards/ks7010.cpp create mode 100644 source/fceultra/boards/mihunche.cpp create mode 100644 source/fceultra/boards/sb-2000.cpp create mode 100644 source/fceultra/boards/unrom512.cpp rename source/fceultra/boards/{konami-qtai.cpp => vrc5.cpp} (96%) create mode 100644 source/fceultra/fceulua.h create mode 100644 source/fceultra/fir/SConscript create mode 100644 source/fceultra/input/SConscript create mode 100644 source/fceultra/input/pec586kb.cpp create mode 100644 source/fceultra/lua-engine.cpp create mode 100644 source/fceultra/lua/COPYRIGHT create mode 100644 source/fceultra/lua/HISTORY create mode 100644 source/fceultra/lua/README create mode 100644 source/fceultra/lua/SConscript create mode 100644 source/fceultra/lua/lua.vcproj create mode 100644 source/fceultra/lua/src/Makefile create mode 100644 source/fceultra/lua/src/lapi.c create mode 100644 source/fceultra/lua/src/lapi.h create mode 100644 source/fceultra/lua/src/lauxlib.c create mode 100644 source/fceultra/lua/src/lauxlib.h create mode 100644 source/fceultra/lua/src/lbaselib.c create mode 100644 source/fceultra/lua/src/lcode.c create mode 100644 source/fceultra/lua/src/lcode.h create mode 100644 source/fceultra/lua/src/ldblib.c create mode 100644 source/fceultra/lua/src/ldebug.c create mode 100644 source/fceultra/lua/src/ldebug.h create mode 100644 source/fceultra/lua/src/ldo.c create mode 100644 source/fceultra/lua/src/ldo.h create mode 100644 source/fceultra/lua/src/ldump.c create mode 100644 source/fceultra/lua/src/lfunc.c create mode 100644 source/fceultra/lua/src/lfunc.h create mode 100644 source/fceultra/lua/src/lgc.c create mode 100644 source/fceultra/lua/src/lgc.h create mode 100644 source/fceultra/lua/src/linit.c create mode 100644 source/fceultra/lua/src/liolib.c create mode 100644 source/fceultra/lua/src/llex.c create mode 100644 source/fceultra/lua/src/llex.h create mode 100644 source/fceultra/lua/src/llimits.h create mode 100644 source/fceultra/lua/src/lmathlib.c create mode 100644 source/fceultra/lua/src/lmem.c create mode 100644 source/fceultra/lua/src/lmem.h create mode 100644 source/fceultra/lua/src/loadlib.c create mode 100644 source/fceultra/lua/src/lobject.c create mode 100644 source/fceultra/lua/src/lobject.h create mode 100644 source/fceultra/lua/src/lopcodes.c create mode 100644 source/fceultra/lua/src/lopcodes.h create mode 100644 source/fceultra/lua/src/loslib.c create mode 100644 source/fceultra/lua/src/lparser.c create mode 100644 source/fceultra/lua/src/lparser.h create mode 100644 source/fceultra/lua/src/lstate.c create mode 100644 source/fceultra/lua/src/lstate.h create mode 100644 source/fceultra/lua/src/lstring.c create mode 100644 source/fceultra/lua/src/lstring.h create mode 100644 source/fceultra/lua/src/lstrlib.c create mode 100644 source/fceultra/lua/src/ltable.c create mode 100644 source/fceultra/lua/src/ltable.h create mode 100644 source/fceultra/lua/src/ltablib.c create mode 100644 source/fceultra/lua/src/ltm.c create mode 100644 source/fceultra/lua/src/ltm.h create mode 100644 source/fceultra/lua/src/lua.c create mode 100644 source/fceultra/lua/src/lua.h create mode 100644 source/fceultra/lua/src/luac.c create mode 100644 source/fceultra/lua/src/luaconf.h create mode 100644 source/fceultra/lua/src/lualib.h create mode 100644 source/fceultra/lua/src/lundump.c create mode 100644 source/fceultra/lua/src/lundump.h create mode 100644 source/fceultra/lua/src/lvm.c create mode 100644 source/fceultra/lua/src/lvm.h create mode 100644 source/fceultra/lua/src/lzio.c create mode 100644 source/fceultra/lua/src/lzio.h create mode 100644 source/fceultra/lua/src/print.c create mode 100644 source/fceultra/oldmovie.cpp create mode 100644 source/fceultra/oldmovie.h create mode 100644 source/fceultra/palettes/SConscript create mode 100644 source/fceultra/types-des.h create mode 100644 source/fceultra/utils/SConscript create mode 100644 source/fceultra/utils/backward.cpp create mode 100644 source/fceultra/utils/backward.hpp create mode 100644 source/images/bg_preview.png create mode 100644 source/images/button_palette.png create mode 100644 source/images/button_palette_over.png create mode 100644 source/images/icon_game_delete.png create mode 100644 source/images/icon_settings_screenshot.png create mode 100644 source/images/icon_settings_wiiupro.png create mode 100644 source/utils/vm/asm.h create mode 100644 source/utils/vm/dsihandler.s create mode 100644 source/utils/vm/vm.c create mode 100644 source/utils/vm/vm.h create mode 100644 source/vmalloc.cpp create mode 100644 source/vmalloc.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a0c187 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/build_wii +/build_gc +/executables diff --git a/Makefile.gc b/Makefile.gc index 33f9bb9..a520276 100644 --- a/Makefile.gc +++ b/Makefile.gc @@ -19,26 +19,26 @@ TARGET := fceugx-gc TARGETDIR := executables BUILD := build_gc SOURCES := source source/images source/sounds source/fonts source/lang \ - source/gui source/utils source/utils/sz \ + source/gui source/utils source/utils/unzip source/utils/sz \ source/fceultra source/fceultra/boards source/fceultra/input \ - source/fceultra/utils source/fceultra/mbshare + source/fceultra/utils source/fceultra/mbshare source/utils/vm INCLUDES := source #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) -DNO_SOUND \ +CFLAGS = -g -O3 -LTO -Wall $(MACHDEP) $(INCLUDE) \ -DFRAMESKIP -DPSS_STYLE=1 -DPATH_MAX=1024 -DHAVE_ASPRINTF \ - -D_SZ_ONE_DIRECTORY -D_LZMA_IN_CB -D_LZMA_OUT_READ \ + -D_SZ_ONE_DIRECTORY -D_LZMA_IN_CB -D_LZMA_OUT_READ -DUSE_VM \ -fomit-frame-pointer \ -Wno-unused-parameter -Wno-strict-aliasing -Wno-write-strings CXXFLAGS = $(CFLAGS) -LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map +LDFLAGS = -g $(MACHDEP) -LTO -Wl,-Map,$(notdir $@).map #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- -LIBS := -lpng -lmxml -ltinysmb -lbba -lfat -liso9660 -lz -logc -lfreetype +LIBS := -lpng -lmxml -ltinysmb -lbba -lfat -liso9660 -lvorbisidec -lasnd -lz -logc -lfreetype #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing @@ -70,6 +70,7 @@ SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) TTFFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.ttf))) LANGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.lang))) PNGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.png))) +OGGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.ogg))) PCMFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pcm))) #--------------------------------------------------------------------------------- @@ -85,7 +86,7 @@ export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ $(sFILES:.s=.o) $(SFILES:.S=.o) \ $(TTFFILES:.ttf=.ttf.o) $(LANGFILES:.lang=.lang.o) \ $(PNGFILES:.png=.png.o) \ - $(PCMFILES:.pcm=.pcm.o) + $(OGGFILES:.ogg=.ogg.o) $(PCMFILES:.pcm=.pcm.o) #--------------------------------------------------------------------------------- # build a list of include paths @@ -136,7 +137,7 @@ $(OUTPUT).dol: $(OUTPUT).elf $(OUTPUT).elf: $(OFILES) #--------------------------------------------------------------------------------- -# This rule links in binary data with these extensions: ttf lang png pcm +# This rule links in binary data with these extensions: ttf lang png ogg pcm #--------------------------------------------------------------------------------- %.ttf.o : %.ttf @echo $(notdir $<) @@ -149,7 +150,11 @@ $(OUTPUT).elf: $(OFILES) %.png.o : %.png @echo $(notdir $<) $(bin2o) - + +%.ogg.o : %.ogg + @echo $(notdir $<) + $(bin2o) + %.pcm.o : %.pcm @echo $(notdir $<) $(bin2o) diff --git a/Makefile.wii b/Makefile.wii index cf304b8..000361c 100644 --- a/Makefile.wii +++ b/Makefile.wii @@ -16,8 +16,8 @@ include $(DEVKITPPC)/wii_rules # INCLUDES is a list of directories containing extra header files #--------------------------------------------------------------------------------- TARGET := fceugx-wii -TARGETDIR := executables -BUILD := build_wii +TARGETDIR := executables +BUILD := build_wii SOURCES := source source/images source/sounds source/fonts source/lang \ source/gui source/utils source/utils/sz source/utils/unzip \ source/fceultra source/fceultra/boards source/fceultra/input \ @@ -27,19 +27,19 @@ INCLUDES := source #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) \ +CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) -DNO_SOUND \ -DFRAMESKIP -DPSS_STYLE=1 -DPATH_MAX=1024 -DHAVE_ASPRINTF \ -D_SZ_ONE_DIRECTORY -D_LZMA_IN_CB -D_LZMA_OUT_READ \ -fomit-frame-pointer \ -Wno-unused-parameter -Wno-strict-aliasing -Wno-write-strings CXXFLAGS = $(CFLAGS) -LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map +LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,-wrap,wiiuse_register #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- LIBS := -ldi -liso9660 -lpng -lmxml \ - -lfat -lwiiuse -lz -lbte -lasnd -logc -lvorbisidec -lfreetype -ltinysmb + -lfat -lwiiuse -lwupc -lz -lbte -lasnd -logc -lvorbisidec -lfreetype -ltinysmb #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing diff --git a/hbc/meta.xml b/hbc/meta.xml index eb82691..426d5e0 100644 --- a/hbc/meta.xml +++ b/hbc/meta.xml @@ -1,8 +1,8 @@ FCE Ultra GX - Tantric - 3.3.4 + Tantric & Zopenko + 3.3.7 20130112 Nintendo Emulator A port of FCE Ultra to the Wii. diff --git a/readme.txt b/readme.txt index 7d1a321..a1829cb 100644 --- a/readme.txt +++ b/readme.txt @@ -12,7 +12,7 @@ Wii/GameCube. -=[ Features ]=- -* Wiimote, Nunchuk, Classic, and Gamecube controller support +* Wiimote, Nunchuk, Classic, Wii U Pro and Gamecube controller support * iNES, FDS, VS, UNIF, and NSF ROM support * 1-4 Player Support * Zapper support @@ -26,13 +26,50 @@ Wii/GameCube. * Cheat support (.CHT files and Game Genie) * Famicom 3D System support * IPS/UPS automatic patching support -* NES Compatibility Based on FCEUX 2.2.0+ (r2818) +* NES Compatibility Based on FCEUX 2.2.0+ (r2951) * Open Source! ח–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•Ĵ |0O×ĝo· UPDATE HISTORY ·oĝ×O0| `¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' +[3.3.7 - Apr 18, 2016] + +* Added both Firebrandx NES color palettes (thanks to SuperrSonic and Asho). +* Added Nestopia's RGB palette (thanks to SuperrSonic and ShadowOne333). +* Added a new window when selecting a color palette (in order to avoid cycling the color palettes one by one). +* Reverted FDS file in order to fix Disk System support (thanks to Burnt Lasagna) (Support was broken on ver 3.3.5 MOD). +* Added option to disable / enable the Virtual Memory messages on the settings menu. +* Removed the "Reset" and "Power On" messages when loading and reseting a game (Messages were added on ver 3.3.5 MOD). + +[3.3.6 - Apr 12, 2015] + +* Merged Emu_kidid's 3.3.5 mod version with Zopenko's 3.3.4 mod version. +* Added SuperrSonic's 3DS Virtual Console palette. +* Changed the savestate cursor box color (in order to match the emu's color design). + +[3.3.5 MOD - Apr 22, 2015] + +* Merged in changes from FCEUX (up to r2951) +* Added tueidj's TLB VM (w/ ARAM storage) for ROM and other data storage +* Enabled menu audio +* Less out of memory crashes +* Free memory displayed on in game menu + +[3.3.4 MOD - Apr 12, 2015] + +* Added Cebolleto's preview image support. +* Added FIX94's WiiUPro controller support. +* Added SuperrSonic's Wii Virtual Console Palette. +* Increase preview image size and reduce game list width. +* Added a background to the preview image. +* Added a Screenshot button (under the game settings options, the video scaling option must be set to default otherwise screenshot looks smaller and with black borders around it, also screenshot folder must already exist otherwise a folder error will popup). +* Added a "WiiuPro" button on the button mapping menu, the options is just for completeness, since the controller mappings are shared between the wiiupro and the classic controller. +* Fixed the inverted color button selection that was in some option Windows. +* On the cheat menu, increased the cheat name display size and added scrolling if the name is too long to display at once. +* Fixed cover image dimensions, now it displays screenshot and cover within the background border. +* Fixed screenshot option, it no longer creates an additional "dummy" file. + [3.3.4 - January 12, 2013] * Updated core to latest FCEUX (r2818) diff --git a/source/fceugx.cpp b/source/fceugx.cpp index b3cc1d7..3054953 100644 --- a/source/fceugx.cpp +++ b/source/fceugx.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,9 @@ #include "filelist.h" #include "gui/gui.h" #include "utils/FreeTypeGX.h" +#ifdef USE_VM + #include "vmalloc.h" +#endif #include "fceultra/types.h" @@ -49,6 +53,9 @@ void FCEUD_UpdateLeft(uint8 *XBuf, int32 *Buffer, int Count); void FCEUD_UpdateRight(uint8 *XBuf, int32 *Buffer, int Count); extern "C" { +#ifdef USE_VM + #include "utils/vm/vm.h" +#endif extern void __exception_setreload(int t); } @@ -91,6 +98,26 @@ static void ExitCleanup() void (*PSOReload) () = (void (*)()) 0x80001800; #endif +void ExitToWiiflow() +{ + ShutoffRumble(); + SavePrefs(SILENT); + if (romLoaded && !ConfigRequested && GCSettings.AutoSave == 1) + SaveRAMAuto(SILENT); + ExitCleanup(); + + if( !!*(u32*)0x80001800 ) + { + // Were we launched via HBC? (or via wiiflows stub replacement? :P) + exit(1); + } + else + { + // Wii channel support + SYS_ResetSystem( SYS_RETURNTOMENU, 0, 0 ); + } +} + void ExitApp() { #ifdef HW_RVL @@ -326,6 +353,10 @@ extern "C" { int main(int argc, char *argv[]) { + #ifdef USE_VM + VM_Init(ARAM_SIZE, MRAM_BACKING); // Setup Virtual Memory with the entire ARAM + #endif + #ifdef HW_RVL L2Enhance(); @@ -357,6 +388,7 @@ int main(int argc, char *argv[]) SYS_SetPowerCallback(ShutdownCB); SYS_SetResetCallback(ResetCB); + WUPC_Init(); WPAD_Init(); WPAD_SetPowerButtonCallback((WPADShutdownCallback)ShutdownCB); DI_Init(); @@ -379,13 +411,20 @@ int main(int argc, char *argv[]) DefaultSettings(); // Set defaults InitialiseAudio(); InitFreeType((u8*)font_ttf, font_ttf_size); // Initialize font system +#ifdef USE_VM + gameScreenPng = (u8 *)vm_malloc(512*1024); +#else gameScreenPng = (u8 *)malloc(512*1024); +#endif browserList = (BROWSERENTRY *)malloc(sizeof(BROWSERENTRY)*MAX_BROWSER_SIZE); InitGUIThreads(); // allocate memory to store rom +#ifdef USE_VM + nesrom = (unsigned char *)vm_malloc(1024*1024*4); // 4 MB should be plenty +#else nesrom = (unsigned char *)memalign(32,1024*1024*4); // 4 MB should be plenty - +#endif /*** Minimal Emulation Loop ***/ if (!FCEUI_Initialize()) ExitApp(); @@ -398,18 +437,86 @@ int main(int argc, char *argv[]) FCEUI_SetSoundQuality(1); // 0 - low, 1 - high, 2 - high (alt.) int currentTiming = 0; - while (1) // main loop - { - // go back to checking if devices were inserted/removed + bool autoboot = false; + if(argc > 3 && argv[1] != NULL && argv[2] != NULL && argv[3] != NULL) + { + autoboot = true; + ResetBrowser(); + LoadPrefs(); + if(strcasestr(argv[1], "sd:/") != NULL) + { + GCSettings.SaveMethod = DEVICE_SD; + GCSettings.LoadMethod = DEVICE_SD; + } + else + { + GCSettings.SaveMethod = DEVICE_USB; + GCSettings.LoadMethod = DEVICE_USB; + } + SavePrefs(SILENT); + selectLoadedFile = 1; + std::string dir(argv[1]); + dir.assign(&dir[dir.find_last_of(":") + 2]); + char arg_filename[1024]; + strncpy(arg_filename, argv[2], sizeof(arg_filename)); + strncpy(GCSettings.LoadFolder, dir.c_str(), sizeof(GCSettings.LoadFolder)); + OpenGameList(); + strncpy(GCSettings.Exit_Dol_File, argv[3], sizeof(GCSettings.Exit_Dol_File)); + if(argc > 5 && argv[4] != NULL && argv[5] != NULL) + { + sscanf(argv[4], "%08x", &GCSettings.Exit_Channel[0]); + sscanf(argv[5], "%08x", &GCSettings.Exit_Channel[1]); + } + else + { + GCSettings.Exit_Channel[0] = 0x00010008; + GCSettings.Exit_Channel[1] = 0x57494948; + } + if(argc > 6 && argv[6] != NULL) + strncpy(GCSettings.LoaderName, argv[6], sizeof(GCSettings.LoaderName)); + else + snprintf(GCSettings.LoaderName, sizeof(GCSettings.LoaderName), "WiiFlow"); + for(int i = 0; i < browser.numEntries; i++) + { + // Skip it + if (strcmp(browserList[i].filename, ".") == 0 || strcmp(browserList[i].filename, "..") == 0) + continue; + if(strcasestr(browserList[i].filename, arg_filename) != NULL) + { + browser.selIndex = i; + if(IsSz()) + { + BrowserLoadSz(); + browser.selIndex = 1; + } + break; + } + } + BrowserLoadFile(); + } + + while (1) // main loop + { + // go back to checking if devices were inserted/removed // since we're entering the menu - ResumeDeviceThread(); + ResumeDeviceThread(); SwitchAudioMode(1); - if(!romLoaded) - MainMenu(MENU_GAMESELECTION); + if(!autoboot) + { + if(!romLoaded) + MainMenu(MENU_GAMESELECTION); + else + MainMenu(MENU_GAME); + + ConfigRequested = 0; + ScreenshotRequested = 0; + } + else if(romLoaded && autoboot) + autoboot = false; else - MainMenu(MENU_GAME); + ExitApp(); if(currentTiming != GCSettings.timing) { diff --git a/source/fceugx.h b/source/fceugx.h index cf82282..ab9ae62 100644 --- a/source/fceugx.h +++ b/source/fceugx.h @@ -17,7 +17,7 @@ #include "fceultra/driver.h" #define APPNAME "FCE Ultra GX" -#define APPVERSION "3.3.4" +#define APPVERSION "3.3.8.x" #define APPFOLDER "fceugx" #define PREF_FILE_NAME "settings.xml" @@ -27,7 +27,8 @@ const char pathPrefix[9][8] = { "", "sd:/", "usb:/", "dvd:/", "smb:/", "carda:/", "cardb:/" }; -enum { +enum +{ DEVICE_AUTO, DEVICE_SD, DEVICE_USB, @@ -37,7 +38,8 @@ enum { DEVICE_SD_SLOTB }; -enum { +enum +{ FILE_RAM, FILE_STATE, FILE_ROM, @@ -56,7 +58,8 @@ enum const char ctrlName[6][20] = { "NES Controller", "NES Zapper", "NES Controllers (2)", "NES Controllers (4)" }; -enum { +enum +{ LANG_JAPANESE = 0, LANG_ENGLISH, LANG_GERMAN, @@ -74,17 +77,22 @@ enum { LANG_LENGTH }; -struct SGCSettings{ +struct SGCSettings +{ int AutoLoad; - int AutoSave; - int LoadMethod; // For ROMS: Auto, SD, DVD, USB, Network (SMB) + int AutoSave; + int LoadMethod; // For ROMS: Auto, SD, DVD, USB, Network (SMB) int SaveMethod; // For SRAM, Freeze, Prefs: Auto, SD, USB, SMB char LoadFolder[MAXPATHLEN]; // Path to game files char LastFileLoaded[MAXPATHLEN]; //Last file loaded filename char SaveFolder[MAXPATHLEN]; // Path to save files char CheatFolder[MAXPATHLEN]; // Path to cheat files char ScreenshotsFolder[MAXPATHLEN]; //Path to screenshots files - + + char Exit_Dol_File[MAXPATHLEN]; // Exit Path + char LoaderName[20]; // Menu Loader Name + u32 Exit_Channel[2]; // Exit Channel + char smbip[80]; char smbuser[20]; char smbpwd[20]; @@ -110,6 +118,7 @@ struct SGCSettings{ int SFXVolume; int Rumble; int language; + int DisplayVM; }; void ExitApp(); @@ -128,4 +137,4 @@ extern int fskipc; extern int turbomode; extern bool romLoaded; -#endif +#endif \ No newline at end of file diff --git a/source/fceultra/SConscript b/source/fceultra/SConscript new file mode 100644 index 0000000..4713e15 --- /dev/null +++ b/source/fceultra/SConscript @@ -0,0 +1,42 @@ +import glob +file_list = glob.glob('*.cpp') +file_list.remove('lua-engine.cpp') # use logic below for this + +subdirs = Split(""" +boards +drivers/common +fir +input +utils +""") +#palettes + +Import('env') +Export('env') + +if env['LUA']: + file_list.append('lua-engine.cpp') + if env['SYSTEM_LUA'] == 0: + subdirs.append('lua') + +if env['CREATE_AVI']: + subdirs.append('drivers/videolog') + + + +for dir in subdirs: + subdir_files = SConscript('%s/SConscript' % dir) + file_list.append(subdir_files) +if env['PLATFORM'] == 'win32': + platform_files = SConscript('drivers/win/SConscript') +else: + platform_files = SConscript('drivers/sdl/SConscript') +file_list.append(platform_files) + +print env['LINKFLAGS'] + +if env['PLATFORM'] == 'win32': + fceux = env.Program('fceux.exe', file_list) +else: + fceux = env.Program('fceux', file_list) +Return('fceux') diff --git a/source/fceultra/asm.cpp b/source/fceultra/asm.cpp index 176ccd7..8221155 100644 --- a/source/fceultra/asm.cpp +++ b/source/fceultra/asm.cpp @@ -1,15 +1,15 @@ /// \file /// \brief 6502 assembler and disassembler -#include -#include -#include #include "types.h" #include "utils/xstring.h" #include "debug.h" #include "asm.h" #include "x6502.h" +#include +#include +#include ///assembles the string to an instruction located at addr, storing opcodes in output buffer int Assemble(unsigned char *output, int addr, char *str) { //unsigned char opcode[3] = { 0,0,0 }; @@ -276,16 +276,23 @@ char *Disassemble(int addr, uint8 *opcode) { } #define indirectX(a) { \ (a) = (opcode[1]+RX)&0xFF; \ - (a) = GetMem((a)) | (GetMem((a)+1))<<8; \ + (a) = GetMem((a)) | (GetMem(((a)+1)&0xff))<<8; \ } #define indirectY(a) { \ - (a) = GetMem(opcode[1]) | (GetMem(opcode[1]+1))<<8; \ + (a) = GetMem(opcode[1]) | (GetMem((opcode[1]+1)&0xff))<<8; \ (a) += RY; \ } + #ifdef BRK_3BYTE_HACK + case 0x00: + sprintf(str,"BRK %02X %02X", opcode[1], opcode[2]); + break; + #else + case 0x00: strcpy(str,"BRK"); break; + #endif + //odd, 1-byte opcodes - case 0x00: strcpy(str,"BRK"); break; case 0x08: strcpy(str,"PHP"); break; case 0x0A: strcpy(str,"ASL"); break; case 0x18: strcpy(str,"CLC"); break; diff --git a/source/fceultra/auxlib.lua b/source/fceultra/auxlib.lua new file mode 100644 index 0000000..e3066fe --- /dev/null +++ b/source/fceultra/auxlib.lua @@ -0,0 +1,45 @@ +-- this includes the iup system +--local iuplua_open = package.loadlib("iuplua51.dll", "iuplua_open"); +--if(iuplua_open == nil) then require("libiuplua51"); end +--iuplua_open(); + +-- this includes the "special controls" of iup (dont change the order though) +--local iupcontrolslua_open = package.loadlib("iupluacontrols51.dll", "iupcontrolslua_open"); +--if(iupcontrolslua_open == nil) then require("libiupluacontrols51"); end +--iupcontrolslua_open(); +require("iuplua"); +--TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +--LUACALL_BEFOREEXIT use that instead of emu.OnClose below + +-- callback function to clean up our mess +-- this is called when the script exits (forced or natural) +-- you need to close all the open dialogs here or FCEUX crashes +--function emu.OnClose.iuplua() + -- gui.popup("OnClose!"); + --if(emu and emu.OnCloseIup ~= nil) then + -- emu.OnCloseIup(); + --end + --iup.Close(); +--end + + +-- this system allows you to open a number of dialogs without +-- having to bother about cleanup when the script exits +handles = {}; -- this table should hold the handle to all dialogs created in lua +dialogs = 0; -- should be incremented PRIOR to creating a new dialog + +-- called by the onclose event (above) +function OnCloseIup() + if (handles) then -- just in case the user was "smart" enough to clear this + local i = 1; + while (handles[i] ~= nil) do -- cycle through all handles, false handles are skipped, nil denotes the end + if (handles[i] and handles[i].destroy) then -- check for the existence of what we need + handles[i]:destroy(); -- close this dialog (:close() just hides it) + handles[i] = nil; + end; + i = i + 1; + end; + end; +end; + +emu.registerexit(OnCloseIup); diff --git a/source/fceultra/boards/09-034a.cpp b/source/fceultra/boards/09-034a.cpp index 4f5fd03..7847cd9 100644 --- a/source/fceultra/boards/09-034a.cpp +++ b/source/fceultra/boards/09-034a.cpp @@ -19,11 +19,13 @@ * * FDS Conversions * - * Super Mario Bros 2 J alt version is a BAD incomplete dump, should be mapper 43 + * Super Mario Bros 2j (Alt Full) is a BAD incomplete dump, should be mapper 43 * * Both Voleyball and Zanac by Whirlind Manu shares the same PCB, but with * some differences: Voleyball has 8K CHR ROM and 8K ROM at 6000K, Zanac * have 8K CHR RAM and banked 16K ROM mapper at 6000 as two 8K banks. +* + * Super Mario Bros 2j (Alt Small) uses additionally IRQ timer to drive framerate * * PCB for this mapper is "09-034A" */ @@ -31,9 +33,12 @@ #include "mapinc.h" static uint8 prg; +static uint32 IRQCount, IRQa; static SFORMAT StateRegs[] = { + { &IRQCount, 4, "IRQC" }, + { &IRQa, 4, "IRQA" }, { &prg, 1, "PRG" }, { 0 } }; @@ -44,16 +49,40 @@ static void Sync(void) { setchr8(0); } -static DECLFW(UNLSMB2JWrite) { +static DECLFW(UNLSMB2JWrite1) { prg = V & 1; Sync(); } +static DECLFW(UNLSMB2JWrite2) { + IRQa = V & 1; + IRQCount = 0; + X6502_IRQEnd(FCEU_IQEXT); +} + +static DECLFR(UNLSMB2JRead) { + return 0xFF; +} + static void UNLSMB2JPower(void) { prg = 0; Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x4027, 0x4027, UNLSMB2JWrite); + SetReadHandler(0x4042, 0x4055, UNLSMB2JRead); + SetWriteHandler(0x4068, 0x4068, UNLSMB2JWrite2); + SetWriteHandler(0x4027, 0x4027, UNLSMB2JWrite1); +} + +static void UNLSMB2JIRQHook(int a) { + if (IRQa) + { + if (IRQCount < 5750) // completely by guess + IRQCount += a; + else { + IRQa = 0; + X6502_IRQBegin(FCEU_IQEXT); + } + } } static void StateRestore(int version) { @@ -62,6 +91,7 @@ static void StateRestore(int version) { void UNLSMB2J_Init(CartInfo *info) { info->Power = UNLSMB2JPower; + MapIRQHook = UNLSMB2JIRQHook; GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); } diff --git a/source/fceultra/boards/112.cpp b/source/fceultra/boards/112.cpp index 6c184b1..077be0e 100644 --- a/source/fceultra/boards/112.cpp +++ b/source/fceultra/boards/112.cpp @@ -72,6 +72,7 @@ static void M112Power(void) { SetWriteHandler(0x4020, 0x5FFF, M112Write); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(8, 0x6000, WRAM); } static void StateRestore(int version) { diff --git a/source/fceultra/boards/12in1.cpp b/source/fceultra/boards/12in1.cpp index 15f6c07..add67cc 100644 --- a/source/fceultra/boards/12in1.cpp +++ b/source/fceultra/boards/12in1.cpp @@ -17,43 +17,45 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * 7-in-1 Darkwing Duck, Snake, MagicBlock (PCB marked as "12 in 1") + * 7-in-1 Darkwing Duck, Snake, MagicBlock (PCB marked as "12 in 1") + * 12-in-1 1991 New Star Co. Ltd. + * */ #include "mapinc.h" -static uint8 reg[4]; +static uint8 prgchr[2], ctrl; static SFORMAT StateRegs[] = { - { reg, 4, "REGS" }, + { prgchr, 2, "REGS" }, + { &ctrl, 1, "CTRL" }, { 0 } }; static void Sync(void) { - uint8 bank = (reg[3] & 3) << 3; - setchr4(0x0000, (reg[1] >> 3) | (bank << 2)); - setchr4(0x1000, (reg[2] >> 3) | (bank << 2)); - if (reg[3] & 8) { - setprg32(0x8000, ((reg[2] & 7) >> 1) | bank); + uint8 bank = (ctrl & 3) << 3; + setchr4(0x0000, (prgchr[0] >> 3) | (bank << 2)); + setchr4(0x1000, (prgchr[1] >> 3) | (bank << 2)); + if (ctrl & 8) { + setprg16(0x8000, bank | (prgchr[0] & 6) | 0); // actually, both 0 and 1 registers used, but they will switch each PA12 transition + setprg16(0xc000, bank | (prgchr[0] & 6) | 1); // if bits are different for both registers, so they must be programmed strongly the same! } else { - setprg16(0x8000, (reg[1] & 7) | bank); - setprg16(0xc000, 7 | bank); + setprg16(0x8000, bank | (prgchr[0] & 7)); + setprg16(0xc000, bank | 7 ); } - setmirror(((reg[3] & 4) >> 2) ^ 1); + setmirror(((ctrl & 4) >> 2) ^ 1); } static DECLFW(BMC12IN1Write) { - switch (A) { - case 0xafff: reg[0] = V; break; - case 0xbfff: reg[1] = V; break; - case 0xdfff: reg[2] = V; break; - case 0xefff: reg[3] = V; break; + switch (A & 0xE000) { + case 0xA000: prgchr[0] = V; Sync(); break; + case 0xC000: prgchr[1] = V; Sync(); break; + case 0xE000: ctrl = V & 0x0F; Sync(); break; } - Sync(); } static void BMC12IN1Power(void) { - reg[0] = reg[1] = reg[2] = reg[3] = 0; + prgchr[0] = prgchr[1] = ctrl = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, BMC12IN1Write); @@ -68,3 +70,4 @@ void BMC12IN1_Init(CartInfo *info) { GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); } + diff --git a/source/fceultra/boards/15.cpp b/source/fceultra/boards/15.cpp index 4aee608..8ea05bf 100644 --- a/source/fceultra/boards/15.cpp +++ b/source/fceultra/boards/15.cpp @@ -76,6 +76,7 @@ static void M15Power(void) { SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x8000, 0xFFFF, M15Write); SetReadHandler(0x8000, 0xFFFF, CartBR); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); Sync(); } diff --git a/source/fceultra/boards/156.cpp b/source/fceultra/boards/156.cpp index d682f30..6693962 100644 --- a/source/fceultra/boards/156.cpp +++ b/source/fceultra/boards/156.cpp @@ -86,6 +86,7 @@ static void M156Power(void) { SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0xC000, 0xCFFF, M156Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M156Close(void) { diff --git a/source/fceultra/boards/164.cpp b/source/fceultra/boards/164.cpp index 7cde0a3..aa859e3 100644 --- a/source/fceultra/boards/164.cpp +++ b/source/fceultra/boards/164.cpp @@ -102,6 +102,7 @@ static void Power(void) { SetWriteHandler(0x5000, 0x5FFF, Write); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); WSync(); } @@ -155,6 +156,7 @@ static void Power2(void) { SetWriteHandler(0x5000, 0x5FFF, Write2); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); WSync(); } @@ -206,6 +208,7 @@ static void Power3(void) { SetWriteHandler(0x5000, 0x5FFF, Write3); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); WSync(); } diff --git a/source/fceultra/boards/176.cpp b/source/fceultra/boards/176.cpp index 92700b8..f29ad08 100644 --- a/source/fceultra/boards/176.cpp +++ b/source/fceultra/boards/176.cpp @@ -47,7 +47,8 @@ static void Sync(void) } static DECLFW(M176Write_5001) -{ +{ + printf("%04X = $%02X\n",A,V); if(sbw) { prg[0] = V*4; @@ -59,13 +60,15 @@ static DECLFW(M176Write_5001) } static DECLFW(M176Write_5010) -{ +{ + printf("%04X = $%02X\n",A,V); if(V == 0x24) sbw = 1; Sync(); } static DECLFW(M176Write_5011) -{ +{ + printf("%04X = $%02X\n",A,V); V >>= 1; if(sbw) { @@ -78,7 +81,8 @@ static DECLFW(M176Write_5011) } static DECLFW(M176Write_5FF1) -{ +{ + printf("%04X = $%02X\n",A,V); V >>= 1; prg[0] = V*4; prg[1] = V*4+1; @@ -88,7 +92,8 @@ static DECLFW(M176Write_5FF1) } static DECLFW(M176Write_5FF2) -{ +{ + printf("%04X = $%02X\n",A,V); chr = V; Sync(); } @@ -106,15 +111,16 @@ static DECLFW(M176Write_WriteSRAM) static void M176Power(void) { - SetReadHandler(0x6000,0x7fff,CartBR); - SetWriteHandler(0x6000,0x7fff,M176Write_WriteSRAM); - SetReadHandler(0x8000,0xFFFF,CartBR); + SetReadHandler(0x6000,0x7fff,CartBR); + SetWriteHandler(0x6000,0x7fff,M176Write_WriteSRAM); + SetReadHandler(0x8000,0xFFFF,CartBR); SetWriteHandler(0xA001,0xA001,M176Write_A001); SetWriteHandler(0x5001,0x5001,M176Write_5001); SetWriteHandler(0x5010,0x5010,M176Write_5010); SetWriteHandler(0x5011,0x5011,M176Write_5011); - SetWriteHandler(0x5ff1,0x5ff1,M176Write_5FF1); - SetWriteHandler(0x5ff2,0x5ff2,M176Write_5FF2); + SetWriteHandler(0x5ff1,0x5ff1,M176Write_5FF1); + SetWriteHandler(0x5ff2,0x5ff2,M176Write_5FF2); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); we_sram = 0; sbw = 0; diff --git a/source/fceultra/boards/177.cpp b/source/fceultra/boards/177.cpp index 04fd9c8..0416060 100644 --- a/source/fceultra/boards/177.cpp +++ b/source/fceultra/boards/177.cpp @@ -50,6 +50,7 @@ static void M177Power(void) { SetWriteHandler(0x6000, 0x7fff, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M177Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M177Close(void) { diff --git a/source/fceultra/boards/178.cpp b/source/fceultra/boards/178.cpp index d359cd8..775fece 100644 --- a/source/fceultra/boards/178.cpp +++ b/source/fceultra/boards/178.cpp @@ -1,7 +1,7 @@ /* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2013 CaH4e3 * * 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 @@ -16,49 +16,134 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * DSOUNDV1/FL-TR8MA boards (32K WRAM, 8/16M), 178 mapper boards (8K WRAM, 4/8M) + * Various Education Cartridges + * */ #include "mapinc.h" static uint8 reg[4]; + static uint8 *WRAM = NULL; static uint32 WRAMSIZE; +// SND Registers +static uint8 pcm_enable = 0; +static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6; +static writefunc pcmwrite; + static SFORMAT StateRegs[] = { { reg, 4, "REGS" }, { 0 } }; -static void Sync(void) { - uint8 bank = (reg[2] & 3) << 3; - setmirror((reg[0] & 1) ^ 1); - setprg8r(0x10, 0x6000, 0); - setchr8(0); - if (reg[0] & 2) { - setprg16(0x8000, (reg[1] & 7) | bank); - setprg16(0xC000, ((~0) & 7) | bank); - } else { - setprg16(0x8000, (reg[1] & 6) | bank); - setprg16(0xC000, (reg[1] & 6) | bank | 1); +static int16 step_size[49] = { + 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, + 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, + 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, + 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 +}; //49 items +static int32 step_adj[16] = { -1, -1, -1, -1, 2, 5, 7, 9, -1, -1, -1, -1, 2, 5, 7, 9 }; + +//decode stuff +static int32 jedi_table[16 * 49]; +static int32 acc = 0; //ADPCM accumulator, initial condition must be 0 +static int32 decstep = 0; //ADPCM decoding step, initial condition must be 0 + +static void jedi_table_init() { + int step, nib; + + for (step = 0; step < 49; step++) { + for (nib = 0; nib < 16; nib++) { + int value = (2 * (nib & 0x07) + 1) * step_size[step] / 8; + jedi_table[step * 16 + nib] = ((nib & 0x08) != 0) ? -value : value; + } } } +static uint8 decode(uint8 code) { + acc += jedi_table[decstep + code]; + if ((acc & ~0x7ff) != 0) // acc is > 2047 + acc |= ~0xfff; + else acc &= 0xfff; + decstep += step_adj[code & 7] * 16; + if (decstep < 0) decstep = 0; + if (decstep > 48 * 16) decstep = 48 * 16; + return (acc >> 8) & 0xff; +} + +static void Sync(void) { + uint32 sbank = reg[1] & 0x7; + uint32 bbank = reg[2]; + setchr8(0); + setprg8r(0x10, 0x6000, reg[3] & 3); + if (reg[0] & 2) { // UNROM mode + setprg16(0x8000, (bbank << 3) | sbank); + if (reg[0] & 4) + setprg16(0xC000, (bbank << 3) | 6 | (reg[1] & 1)); + else + setprg16(0xC000, (bbank << 3) | 7); + } else { // NROM mode + uint32 bank = (bbank << 3) | sbank; + if (reg[0] & 4) { + setprg16(0x8000, bank); + setprg16(0xC000, bank); + } else + setprg32(0x8000, bank >> 1); + } + setmirror((reg[0] & 1) ^ 1); +} + static DECLFW(M178Write) { reg[A & 3] = V; +// FCEU_printf("cmd %04x:%02x\n", A, V); Sync(); } +static DECLFW(M178WriteSnd) { + if (A == 0x5800) { + if (V & 0xF0) { + pcm_enable = 1; +// pcmwrite(0x4011, (V & 0xF) << 3); + pcmwrite(0x4011, decode(V & 0xf)); + } else + pcm_enable = 0; + } else + FCEU_printf("misc %04x:%02x\n", A, V); +} + +static DECLFR(M178ReadSnd) { + if (A == 0x5800) + return (X.DB & 0xBF) | ((pcm_enable ^ 1) << 6); + else + return X.DB; +} + static void M178Power(void) { - reg[0] = 1; - reg[1] = 0; - reg[2] = 0; - reg[3] = 0; + reg[0] = reg[1] = reg[2] = reg[3] = 0; Sync(); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x4800, 0x4803, M178Write); + pcmwrite = GetWriteHandler(0x4011); + SetWriteHandler(0x4800, 0x4fff, M178Write); + SetWriteHandler(0x5800, 0x5fff, M178WriteSnd); + SetReadHandler(0x5800, 0x5fff, M178ReadSnd); + SetReadHandler(0x6000, 0x7fff, CartBR); + SetWriteHandler(0x6000, 0x7fff, CartBW); + SetReadHandler(0x8000, 0xffff, CartBR); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void M178SndClk(int a) { + if (pcm_enable) { + pcm_latch -= a; + if (pcm_latch <= 0) { + pcm_latch += pcm_clock; + pcm_enable = 0; + } + } } static void M178Close(void) { @@ -67,7 +152,6 @@ static void M178Close(void) { WRAM = NULL; } - static void StateRestore(int version) { Sync(); } @@ -76,8 +160,11 @@ void Mapper178_Init(CartInfo *info) { info->Power = M178Power; info->Close = M178Close; GameStateRestore = StateRestore; + MapIRQHook = M178SndClk; - WRAMSIZE = 8192; + jedi_table_init(); + + WRAMSIZE = 32768; WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); if (info->battery) { diff --git a/source/fceultra/boards/18.cpp b/source/fceultra/boards/18.cpp index dcec0dc..a9ac4b6 100644 --- a/source/fceultra/boards/18.cpp +++ b/source/fceultra/boards/18.cpp @@ -89,6 +89,7 @@ static void M18Power(void) { SetWriteHandler(0x8000, 0x9FFF, M18WritePrg); SetWriteHandler(0xA000, 0xDFFF, M18WriteChr); SetWriteHandler(0xE000, 0xFFFF, M18WriteIRQ); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M18IRQHook(int a) { diff --git a/source/fceultra/boards/183.cpp b/source/fceultra/boards/183.cpp index 7421abe..9ba8c2c 100644 --- a/source/fceultra/boards/183.cpp +++ b/source/fceultra/boards/183.cpp @@ -22,8 +22,7 @@ #include "mapinc.h" -static uint8 prg[4]; -static uint8 chr[8]; +static uint8 prg[4], chr[8], mirr; static uint8 IRQCount; static uint8 IRQPre; static uint8 IRQa; @@ -32,6 +31,7 @@ static SFORMAT StateRegs[] = { { prg, 4, "PRG" }, { chr, 8, "CHR" }, + { &mirr, 1, "MIRR" }, { &IRQCount, 1, "IRQC" }, { &IRQPre, 1, "IRQP" }, { &IRQa, 1, "IRQA" }, @@ -39,13 +39,22 @@ static SFORMAT StateRegs[] = }; static void SyncPrg(void) { - setprg8(0x6000, 0); + setprg8(0x6000, prg[3]); setprg8(0x8000, prg[0]); setprg8(0xA000, prg[1]); setprg8(0xC000, prg[2]); setprg8(0xE000, ~0); } +static void SyncMirr(void) { + switch (mirr) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } +} + static void SyncChr(void) { int i; for (i = 0; i < 8; i++) @@ -55,10 +64,14 @@ static void SyncChr(void) { static void StateRestore(int version) { SyncPrg(); SyncChr(); + SyncMirr(); } static DECLFW(M183Write) { - if (((A & 0xF80C) >= 0xB000) && ((A & 0xF80C) <= 0xE00C)) { + if ((A & 0xF800) == 0x6800) { + prg[3] = A & 0x3F; + SyncPrg(); + } else if (((A & 0xF80C) >= 0xB000) && ((A & 0xF80C) <= 0xE00C)) { int index = (((A >> 11) - 6) | (A >> 3)) & 7; chr[index] = (chr[index] & (0xF0 >> (A & 4))) | ((V & 0x0F) << (A & 4)); SyncChr(); @@ -66,14 +79,7 @@ static DECLFW(M183Write) { case 0x8800: prg[0] = V; SyncPrg(); break; case 0xA800: prg[1] = V; SyncPrg(); break; case 0xA000: prg[2] = V; SyncPrg(); break; - case 0x9800: - switch (V & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } - break; + case 0x9800: mirr = V & 3; SyncMirr(); break; case 0xF000: IRQCount = ((IRQCount & 0xF0) | (V & 0xF)); break; case 0xF004: IRQCount = ((IRQCount & 0x0F) | ((V & 0xF) << 4)); break; case 0xF008: IRQa = V; if (!V) IRQPre = 0; X6502_IRQEnd(FCEU_IQEXT); break; @@ -91,9 +97,8 @@ static void M183IRQCounter(void) { static void M183Power(void) { IRQPre = IRQCount = IRQa = 0; - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M183Write); - SetReadHandler(0x6000, 0x7FFF, CartBR); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0xFFFF, M183Write); SyncPrg(); SyncChr(); } diff --git a/source/fceultra/boards/186.cpp b/source/fceultra/boards/186.cpp index 21bcbd7..10902dc 100644 --- a/source/fceultra/boards/186.cpp +++ b/source/fceultra/boards/186.cpp @@ -22,14 +22,14 @@ #include "mapinc.h" -static uint8 SWRAM[2816]; +static uint8 SWRAM[3072]; static uint8 *WRAM = NULL; static uint8 regs[4]; static SFORMAT StateRegs[] = { { regs, 4, "DREG" }, - { SWRAM, 2816, "SWRM" }, + { SWRAM, 3072, "SWRM" }, { 0 } }; @@ -67,8 +67,9 @@ static void M186Power(void) { SetWriteHandler(0x6000, 0xFFFF, CartBW); SetReadHandler(0x4200, 0x43FF, M186Read); SetWriteHandler(0x4200, 0x43FF, M186Write); - SetReadHandler(0x4400, 0x4EFF, ASWRAM); - SetWriteHandler(0x4400, 0x4EFF, BSWRAM); + SetReadHandler(0x4400, 0x4FFF, ASWRAM); + SetWriteHandler(0x4400, 0x4FFF, BSWRAM); + FCEU_CheatAddRAM(32, 0x6000, WRAM); regs[0] = regs[1] = regs[2] = regs[3]; Sync(); } diff --git a/source/fceultra/boards/206.cpp b/source/fceultra/boards/206.cpp index b1bb0a1..d013a8f 100644 --- a/source/fceultra/boards/206.cpp +++ b/source/fceultra/boards/206.cpp @@ -38,6 +38,8 @@ static void Sync(void) { setchr1(0x1000 + (x << 10), DRegs[2 + x]); setprg8(0x8000, DRegs[6]); setprg8(0xa000, DRegs[7]); + setprg8(0xc000, ~1); + setprg8(0xe000, ~0); } static void StateRestore(int version) { @@ -60,10 +62,9 @@ static DECLFW(M206Write) { } static void M206Power(void) { - setprg8(0xc000, 0xE); - setprg8(0xe000, 0xF); cmd = 0; - memset(DRegs, 0, 8); + DRegs[6] = 0; + DRegs[7] = 1; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M206Write); diff --git a/source/fceultra/boards/208.cpp b/source/fceultra/boards/208.cpp index ffb3662..d581b1e 100644 --- a/source/fceultra/boards/208.cpp +++ b/source/fceultra/boards/208.cpp @@ -63,9 +63,10 @@ static DECLFR(M208ProtRead) { static void M208Power(void) { EXPREGS[5] = 3; GenMMC3Power(); - SetWriteHandler(0x4800, 0x4FFF, M208Write); + SetWriteHandler(0x4800, 0x4fff, M208Write); + SetWriteHandler(0x6800, 0x6fff, M208Write); SetWriteHandler(0x5000, 0x5fff, M208ProtWrite); - SetReadHandler(0x5800, 0x5FFF, M208ProtRead); + SetReadHandler(0x5800, 0x5fff, M208ProtRead); SetReadHandler(0x8000, 0xffff, CartBR); } diff --git a/source/fceultra/boards/225.cpp b/source/fceultra/boards/225.cpp index 9df7d51..fd008ea 100644 --- a/source/fceultra/boards/225.cpp +++ b/source/fceultra/boards/225.cpp @@ -39,7 +39,7 @@ static void Sync(void) { } else setprg32(0x8000, prg >> 1); setchr8(chr); - setmirror(mirr); + setmirror(mirr ^ 1); } static DECLFW(M225Write) { diff --git a/source/fceultra/boards/232.cpp b/source/fceultra/boards/232.cpp index 5f1df08..86bb0d0 100644 --- a/source/fceultra/boards/232.cpp +++ b/source/fceultra/boards/232.cpp @@ -30,7 +30,7 @@ static SFORMAT StateRegs[] = static void Sync(void) { // uint32 bbank = (bank & 0x18) >> 1; - uint32 bbank = ((bank & 0x10) >> 2) | (bank & 8); // some dumps have bbanks swapped, if swap commands, + uint32 bbank = ((bank & 0x10) >> 2) | (bank & 8); // some dumps have bbanks swapped, if swap commands, // then all roms can be played, but with some swapped // games in menu. if not, some dumps are unplayable // make hard dump for both cart types to check diff --git a/source/fceultra/boards/246.cpp b/source/fceultra/boards/246.cpp index 2c46acc..ec069de 100644 --- a/source/fceultra/boards/246.cpp +++ b/source/fceultra/boards/246.cpp @@ -54,6 +54,7 @@ static void M246Power(void) { SetReadHandler(0x6800, 0x6FFF, CartBR); SetWriteHandler(0x6800, 0x6FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M246Close(void) diff --git a/source/fceultra/boards/252.cpp b/source/fceultra/boards/252.cpp index 2c4b24b..9962e08 100644 --- a/source/fceultra/boards/252.cpp +++ b/source/fceultra/boards/252.cpp @@ -80,6 +80,7 @@ static void M252Power(void) { SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M252Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M252IRQ(int a) { diff --git a/source/fceultra/boards/253.cpp b/source/fceultra/boards/253.cpp index f7a64d0..3ed9bfe 100644 --- a/source/fceultra/boards/253.cpp +++ b/source/fceultra/boards/253.cpp @@ -50,13 +50,6 @@ static void Sync(void) { setprg8(0xe000, ~0); for (i = 0; i < 8; i++) { uint32 chr = chrlo[i] | (chrhi[i] << 8); - if (chrlo[i] == 0xc8) { - vlock = 0; - continue; - } else if (chrlo[i] == 0x88) { - vlock = 1; - continue; - } if (((chrlo[i] == 4) || (chrlo[i] == 5)) && !vlock) setchr1r(0x10, i << 10, chr & 1); else @@ -74,8 +67,15 @@ static DECLFW(M253Write) { if ((A >= 0xB000) && (A <= 0xE00C)) { uint8 ind = ((((A & 8) | (A >> 8)) >> 3) + 2) & 7; uint8 sar = A & 4; - chrlo[ind] = (chrlo[ind] & (0xF0 >> sar)) | ((V & 0x0F) << sar); - if (A & 4) + uint8 clo = (chrlo[ind] & (0xF0 >> sar)) | ((V & 0x0F) << sar); + chrlo[ind] = clo; + if (ind == 0) { + if (clo == 0xc8) + vlock = 0; + else if (clo == 0x88) + vlock = 1; + } + if (sar) chrhi[ind] = V >> 4; Sync(); } else @@ -85,16 +85,18 @@ static DECLFW(M253Write) { case 0x9400: mirr = V & 3; Sync(); break; case 0xF000: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0xF0; IRQLatch |= V & 0xF; break; case 0xF004: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0x0F; IRQLatch |= V << 4; break; - case 0xF008: X6502_IRQEnd(FCEU_IQEXT); IRQClock = 0; IRQCount = IRQLatch; IRQa = V & 2;break; + case 0xF008: X6502_IRQEnd(FCEU_IQEXT); IRQClock = 0; IRQCount = IRQLatch; IRQa = V & 2; break; } } static void M253Power(void) { + vlock = 0; Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M253Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M253Close(void) { diff --git a/source/fceultra/boards/28.cpp b/source/fceultra/boards/28.cpp index 6705330..c787b8c 100644 --- a/source/fceultra/boards/28.cpp +++ b/source/fceultra/boards/28.cpp @@ -129,8 +129,7 @@ static DECLFW(WriteEXP) { uint32 addr = A; uint8 value = V; - if (addr >= 05000) - reg = value & 0x81; + reg = value & 0x81; } static DECLFW(WritePRG) @@ -175,7 +174,7 @@ static void M28Power(void) prg_mask_16k = PRGsize[0] - 1; //EXP - SetWriteHandler(0x4020,0x5FFF,WriteEXP); + SetWriteHandler(0x5000,0x5FFF,WriteEXP); //PRG SetWriteHandler(0x8000,0xFFFF,WritePRG); diff --git a/source/fceultra/boards/32.cpp b/source/fceultra/boards/32.cpp index 0c34402..7dd91bb 100644 --- a/source/fceultra/boards/32.cpp +++ b/source/fceultra/boards/32.cpp @@ -75,6 +75,7 @@ static void M32Power(void) { SetWriteHandler(0x9000, 0x9FFF, M32Write1); SetWriteHandler(0xA000, 0xAFFF, M32Write2); SetWriteHandler(0xB000, 0xBFFF, M32Write3); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M32Close(void) diff --git a/source/fceultra/boards/34.cpp b/source/fceultra/boards/34.cpp index 71f1b30..5c27b00 100644 --- a/source/fceultra/boards/34.cpp +++ b/source/fceultra/boards/34.cpp @@ -66,6 +66,7 @@ static void M34Power(void) { SetWriteHandler(0x6000, 0x7ffc, CartBW); SetReadHandler(0x8000, 0xffff, CartBR); SetWriteHandler(0x7ffd, 0xffff, M34Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M34Close(void) { diff --git a/source/fceultra/boards/40.cpp b/source/fceultra/boards/40.cpp index 3400200..5cae497 100644 --- a/source/fceultra/boards/40.cpp +++ b/source/fceultra/boards/40.cpp @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel * * 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 diff --git a/source/fceultra/boards/42.cpp b/source/fceultra/boards/42.cpp index 6407bdd..8760857 100644 --- a/source/fceultra/boards/42.cpp +++ b/source/fceultra/boards/42.cpp @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel * * 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 diff --git a/source/fceultra/boards/43.cpp b/source/fceultra/boards/43.cpp index c720212..396f80e 100644 --- a/source/fceultra/boards/43.cpp +++ b/source/fceultra/boards/43.cpp @@ -16,13 +16,14 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * FDS Conversion + * */ -//ccording to nestopia, BTL_SMB2_C, otherwise known as UNL-SMB2J - #include "mapinc.h" -static uint8 reg; +static uint8 reg, swap; static uint32 IRQCount, IRQa; static SFORMAT StateRegs[] = @@ -30,31 +31,36 @@ static SFORMAT StateRegs[] = { &IRQCount, 4, "IRQC" }, { &IRQa, 4, "IRQA" }, { ®, 1, "REG" }, + { &swap, 1, "SWAP" }, { 0 } }; static void Sync(void) { - setprg4(0x5000, 16); // Only YS-612 advdnced version - setprg8(0x6000, 2); + setprg4(0x5000, 8 << 1); // Only YS-612 advanced version + setprg8(0x6000, swap?0:2); setprg8(0x8000, 1); setprg8(0xa000, 0); setprg8(0xc000, reg); - setprg8(0xe000, 9); + setprg8(0xe000, swap?8:9); // hard dump for mr.Mary is 128K, + // bank 9 is the last 2K ok bank 8 repeated 4 times, then till the end of 128K + // instead used bank A, containing some CHR data, ines rom have unused banks removed, + // and bank A moved to the bank 9 place for compatibility with other crappy dumps setchr8(0); } static DECLFW(M43Write) { // int transo[8]={4,3,4,4,4,7,5,6}; - int transo[8] = { 4, 3, 5, 3, 6, 3, 7, 3 }; // According to hardware tests + int transo[8] = { 4, 3, 5, 3, 6, 3, 7, 3 }; // According to hardware tests switch (A & 0xf1ff) { case 0x4022: reg = transo[V & 7]; Sync(); break; - case 0x8122: // hacked version - case 0x4122: IRQa = V & 1; X6502_IRQEnd(FCEU_IQEXT); IRQCount = 0; break; // original version + case 0x4120: swap = V & 1; Sync(); break; + case 0x8122: // hacked version + case 0x4122: IRQa = V & 1; X6502_IRQEnd(FCEU_IQEXT); IRQCount = 0; break; // original version } } static void M43Power(void) { - reg = 0; + reg = swap = 0; Sync(); SetReadHandler(0x5000, 0xffff, CartBR); SetWriteHandler(0x4020, 0xffff, M43Write); diff --git a/source/fceultra/boards/50.cpp b/source/fceultra/boards/50.cpp index a9ce08d..40a8e42 100644 --- a/source/fceultra/boards/50.cpp +++ b/source/fceultra/boards/50.cpp @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel * * 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 diff --git a/source/fceultra/boards/65.cpp b/source/fceultra/boards/65.cpp index fcdfddf..fbfd667 100644 --- a/source/fceultra/boards/65.cpp +++ b/source/fceultra/boards/65.cpp @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel * * 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 diff --git a/source/fceultra/boards/67.cpp b/source/fceultra/boards/67.cpp index 8c63bc9..4e29edb 100644 --- a/source/fceultra/boards/67.cpp +++ b/source/fceultra/boards/67.cpp @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel * * 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 diff --git a/source/fceultra/boards/68.cpp b/source/fceultra/boards/68.cpp index a38e567..710f443 100644 --- a/source/fceultra/boards/68.cpp +++ b/source/fceultra/boards/68.cpp @@ -134,6 +134,7 @@ static void M68Power(void) { SetWriteHandler(0xF000, 0xFFFF, M68WriteROM); SetWriteHandler(0x6000, 0x6000, M68WriteLo); SetWriteHandler(0x6001, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M68Close(void) { diff --git a/source/fceultra/boards/69.cpp b/source/fceultra/boards/69.cpp index 389e045..1baa629 100644 --- a/source/fceultra/boards/69.cpp +++ b/source/fceultra/boards/69.cpp @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel * * 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 @@ -74,7 +75,7 @@ static DECLFW(M69Write0) { } static DECLFW(M69Write1) { - switch(cmdreg) { + switch (cmdreg) { case 0x0: creg[0] = V; Sync(); break; case 0x1: creg[1] = V; Sync(); break; case 0x2: creg[2] = V; Sync(); break; @@ -87,10 +88,10 @@ static DECLFW(M69Write1) { case 0x9: preg[0] = V; Sync(); break; case 0xA: preg[1] = V; Sync(); break; case 0xB: preg[2] = V; Sync(); break; - case 0xC: mirr = V & 3; Sync(); break; + case 0xC: mirr = V & 3; Sync();break; case 0xD: IRQa = V; X6502_IRQEnd(FCEU_IQEXT); break; - case 0xE: IRQCount &= 0xFF00; IRQCount |= V; X6502_IRQEnd(FCEU_IQEXT); break; - case 0xF: IRQCount &= 0x00FF; IRQCount |= V << 8; X6502_IRQEnd(FCEU_IQEXT); break; + case 0xE: IRQCount &= 0xFF00; IRQCount |= V; break; + case 0xF: IRQCount &= 0x00FF; IRQCount |= V << 8; break; } } @@ -153,7 +154,7 @@ static void DoAYSQ(int x) { if (end <= start) return; CAYBC[x] = end; - if (amp) + if (amp && !(sreg[0x7] & (1 << x))) for (V = start; V < end; V++) { if (dcount[x]) Wave[V >> 4] += amp; @@ -231,10 +232,10 @@ static void M69Power(void) { SetWriteHandler(0xA000, 0xBFFF, M69Write1); SetWriteHandler(0xC000, 0xDFFF, M69SWrite0); SetWriteHandler(0xE000, 0xFFFF, M69SWrite1); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void M69Close(void) -{ +static void M69Close(void) { if (WRAM) FCEU_gfree(WRAM); WRAM = NULL; diff --git a/source/fceultra/boards/79.cpp b/source/fceultra/boards/79.cpp index 0aa35e2..14d9ac7 100644 --- a/source/fceultra/boards/79.cpp +++ b/source/fceultra/boards/79.cpp @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel * * 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 diff --git a/source/fceultra/boards/80.cpp b/source/fceultra/boards/80.cpp index f6f4ebe..b99132c 100644 --- a/source/fceultra/boards/80.cpp +++ b/source/fceultra/boards/80.cpp @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel * * 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 diff --git a/source/fceultra/boards/8157.cpp b/source/fceultra/boards/8157.cpp index aa3061e..287be08 100644 --- a/source/fceultra/boards/8157.cpp +++ b/source/fceultra/boards/8157.cpp @@ -16,30 +16,41 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * GG1 boards, similar to T-262, with no Data latch + * */ #include "mapinc.h" static uint16 cmdreg; -static uint8 invalid_data; +static uint8 reset; static SFORMAT StateRegs[] = { - { &invalid_data, 1, "INVD" }, + { &reset, 1, "REST" }, { &cmdreg, 2, "CREG" }, { 0 } }; static void Sync(void) { - setprg16r((cmdreg & 0x060) >> 5, 0x8000, (cmdreg & 0x01C) >> 2); - setprg16r((cmdreg & 0x060) >> 5, 0xC000, (cmdreg & 0x200) ? (~0) : 0); + uint32 base = ((cmdreg & 0x060) | ((cmdreg & 0x100) >> 1)) >> 2; + uint32 bank = (cmdreg & 0x01C) >> 2; + uint32 lbank = (cmdreg & 0x200) ? 7 : ((cmdreg & 0x80) ? bank : 0); + if (PRGptr[1]) { + setprg16r(base >> 3, 0x8000, bank); // for versions with split ROMs + setprg16r(base >> 3, 0xC000, lbank); + } else { + setprg16(0x8000, base | bank); + setprg16(0xC000, base | lbank); + } setmirror(((cmdreg & 2) >> 1) ^ 1); } static DECLFR(UNL8157Read) { - if (invalid_data && cmdreg & 0x100) - return 0xFF; - else - return CartBR(A); + if ((cmdreg & 0x100) && (PRGsize[0] < (1024 * 1024))) { + A = (A & 0xFFF0) + reset; + } + return CartBR(A); } static DECLFW(UNL8157Write) { @@ -51,14 +62,14 @@ static void UNL8157Power(void) { setchr8(0); SetWriteHandler(0x8000, 0xFFFF, UNL8157Write); SetReadHandler(0x8000, 0xFFFF, UNL8157Read); - cmdreg = 0x200; - invalid_data = 1; + cmdreg = reset = 0; Sync(); } static void UNL8157Reset(void) { - cmdreg = 0; - invalid_data ^= 1; + cmdreg = reset = 0; + reset++; + reset &= 0x1F; Sync(); } diff --git a/source/fceultra/boards/82.cpp b/source/fceultra/boards/82.cpp index 033e6ff..a1a68b6 100644 --- a/source/fceultra/boards/82.cpp +++ b/source/fceultra/boards/82.cpp @@ -68,6 +68,7 @@ static void M82Power(void) { SetReadHandler(0x6000, 0xffff, CartBR); SetWriteHandler(0x6000, 0x7fff, CartBW); SetWriteHandler(0x7ef0, 0x7efc, M82Write); // external WRAM might end at $73FF + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M82Close(void) { diff --git a/source/fceultra/boards/88.cpp b/source/fceultra/boards/88.cpp index c9ac31e..7341f25 100644 --- a/source/fceultra/boards/88.cpp +++ b/source/fceultra/boards/88.cpp @@ -56,6 +56,9 @@ static DECLFW(M88Write) { } static void M88Power(void) { + reg[0] = reg[1] = reg[2] = reg[3] = reg[4] = reg[5] = reg[6] = reg[7] = 0; + Sync(); + MSync(); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M88Write); } diff --git a/source/fceultra/boards/99.cpp b/source/fceultra/boards/99.cpp index caf5cff..b9df340 100644 --- a/source/fceultra/boards/99.cpp +++ b/source/fceultra/boards/99.cpp @@ -51,6 +51,7 @@ static void M99Power(void) { SetWriteHandler(0x4016, 0x4016, M99Write); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M99Close(void) diff --git a/source/fceultra/boards/SConscript b/source/fceultra/boards/SConscript new file mode 100644 index 0000000..f9afb2d --- /dev/null +++ b/source/fceultra/boards/SConscript @@ -0,0 +1,6 @@ +import glob +source_list = glob.glob('*.cpp')+glob.glob('*.c') + +for x in range(len(source_list)): + source_list[x] = 'boards/' + source_list[x] +Return('source_list') diff --git a/source/fceultra/boards/__dummy_mapper.cpp b/source/fceultra/boards/__dummy_mapper.cpp index 4a0eadf..505f916 100644 --- a/source/fceultra/boards/__dummy_mapper.cpp +++ b/source/fceultra/boards/__dummy_mapper.cpp @@ -1,7 +1,7 @@ /* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2013 CaH4e3 * * 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 diff --git a/source/fceultra/boards/addrlatch.cpp b/source/fceultra/boards/addrlatch.cpp index ae46300..dc0128e 100644 --- a/source/fceultra/boards/addrlatch.cpp +++ b/source/fceultra/boards/addrlatch.cpp @@ -44,6 +44,7 @@ static void LatchPower(void) { if (WRAM) { SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } else SetReadHandler(0x6000, 0xFFFF, defread); SetWriteHandler(addrreg0, addrreg1, LatchWrite); @@ -85,18 +86,6 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), readfunc func, uint16 AddExState(&latche, 2, 0, "LATC"); } -//------------------ UNLCC21 --------------------------- - -static void UNLCC21Sync(void) { - setprg32(0x8000, 0); - setchr8(latche & 1); - setmirror(MI_0 + ((latche & 2) >> 1)); -} - -void UNLCC21_Init(CartInfo *info) { - Latch_Init(info, UNLCC21Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0); -} - //------------------ BMCD1038 --------------------------- static void BMCD1038Sync(void) { @@ -248,7 +237,7 @@ void Mapper200_Init(CartInfo *info) { //------------------ Map 201 --------------------------- static void M201Sync(void) { - if(latche & 8) { + if (latche & 8) { setprg32(0x8000, latche & 3); setchr8(latche & 3); } else { @@ -303,14 +292,14 @@ static DECLFR(M212Read) { } static void M212Sync(void) { - if(latche & 0x4000) { + if (latche & 0x4000) { setprg32(0x8000, (latche >> 1) & 3); } else { setprg16(0x8000, latche & 7); setprg16(0xC000, latche & 7); } setchr8(latche & 7); - setmirror(((latche >> 3) & 1)^1); + setmirror(((latche >> 3) & 1) ^ 1); } void Mapper212_Init(CartInfo *info) { @@ -385,7 +374,7 @@ static void M227Sync(void) { } } - setmirror(((latche >> 1) & 1)^1); + setmirror(((latche >> 1) & 1) ^ 1); setchr8(0); setprg8r(0x10, 0x6000, 0); } @@ -398,13 +387,13 @@ void Mapper227_Init(CartInfo *info) { static void M229Sync(void) { setchr8(latche); - if(!(latche & 0x1e)) + if (!(latche & 0x1e)) setprg32(0x8000, 0); else { setprg16(0x8000, latche & 0x1F); setprg16(0xC000, latche & 0x1F); } - setmirror(((latche >> 5) & 1)^1); + setmirror(((latche >> 5) & 1) ^ 1); } void Mapper229_Init(CartInfo *info) { @@ -415,13 +404,13 @@ void Mapper229_Init(CartInfo *info) { static void M231Sync(void) { setchr8(0); - if(latche & 0x20) + if (latche & 0x20) setprg32(0x8000, (latche >> 1) & 0x0F); else { setprg16(0x8000, latche & 0x1E); setprg16(0xC000, latche & 0x1E); } - setmirror(((latche >> 7) & 1)^1); + setmirror(((latche >> 7) & 1) ^ 1); } void Mapper231_Init(CartInfo *info) { @@ -460,7 +449,7 @@ static void BMC810544CA1Sync(void) { uint32 bank = latche >> 7; if (latche & 0x40) setprg32(0x8000, bank); - else{ + else { setprg16(0x8000, (bank << 1) | ((latche >> 5) & 1)); setprg16(0xC000, (bank << 1) | ((latche >> 5) & 1)); } @@ -498,11 +487,11 @@ void BMCNTD03_Init(CartInfo *info) { static void BMCG146Sync(void) { setchr8(0); - if (latche & 0x800) { // UNROM mode + if (latche & 0x800) { // UNROM mode setprg16(0x8000, (latche & 0x1F) | (latche & ((latche & 0x40) >> 6))); setprg16(0xC000, (latche & 0x18) | 7); } else { - if (latche & 0x40) { // 16K mode + if (latche & 0x40) { // 16K mode setprg16(0x8000, latche & 0x1F); setprg16(0xC000, latche & 0x1F); } else { diff --git a/source/fceultra/boards/bandai.cpp b/source/fceultra/boards/bandai.cpp index b1dfebd..24043a9 100644 --- a/source/fceultra/boards/bandai.cpp +++ b/source/fceultra/boards/bandai.cpp @@ -22,14 +22,9 @@ * */ -//Famicom Jump 2 should get transformed to m153 -//All other games are not supporting EEPROM saving right now. -//We may need to distinguish between 16 and 159 in order to know the EEPROM configuration. -//Until then, we just return 0x00 from the EEPROM read - #include "mapinc.h" -static uint8 reg[16], is153; +static uint8 reg[16], is153, x24c02; static uint8 IRQa; static int16 IRQCount, IRQLatch; @@ -41,22 +36,133 @@ static SFORMAT StateRegs[] = { reg, 16, "REGS" }, { &IRQa, 1, "IRQA" }, { &IRQCount, 2, "IRQC" }, - { &IRQLatch, 2, "IRQL" }, // need for Famicom Jump II - Saikyou no 7 Nin (J) [!] + { &IRQLatch, 2, "IRQL" }, // need for Famicom Jump II - Saikyou no 7 Nin (J) [!] { 0 } }; -static void BandaiIRQHook(int a) { - if (IRQa) { - IRQCount -= a; - if (IRQCount < 0) { - X6502_IRQBegin(FCEU_IQEXT); - IRQa = 0; - IRQCount = -1; - } - } +// x24C0x interface + +#define X24C0X_STANDBY 0 +#define X24C0X_ADDRESS 1 +#define X24C0X_WORD 2 +#define X24C0X_READ 3 +#define X24C0X_WRITE 4 + +static uint8 x24c0x_data[256], x24c0x_state; +static uint8 x24c0x_addr, x24c0x_word, x24c0x_latch, x24c0x_bitcount; +static uint8 x24c0x_sda, x24c0x_scl, x24c0x_out, x24c0x_oe; + +static SFORMAT x24c0xStateRegs[] = +{ + { &x24c0x_addr, 1, "ADDR" }, + { &x24c0x_word, 1, "WORD" }, + { &x24c0x_latch, 1, "LATC" }, + { &x24c0x_bitcount, 1, "BITC" }, + { &x24c0x_sda, 1, "SDA" }, + { &x24c0x_scl, 1, "SCL" }, + { &x24c0x_out, 1, "OUT" }, + { &x24c0x_oe, 1, "OE" }, + { &x24c0x_state, 1, "STAT" }, + { 0 } +}; + +static void x24c0x_init() { + x24c0x_addr = x24c0x_word = x24c0x_latch = x24c0x_bitcount = x24c0x_sda = x24c0x_scl = x24c0x_oe = 0; + x24c0x_state = X24C0X_STANDBY; } -static void BandaiSync(void) { +static void x24c0x_write(uint8 data) { + uint8 sda = (data >> 6) & 1; + uint8 scl = (data >> 5) & 1; + x24c0x_oe = (data >> 7); + + if(x24c0x_scl && scl) { + if(x24c0x_sda && !sda) { // START + x24c0x_state = X24C0X_ADDRESS; + x24c0x_bitcount = 0; + x24c0x_addr = 0; + } else if(!x24c0x_sda && sda) { //STOP + x24c0x_state = X24C0X_STANDBY; + } + } else if(!x24c0x_scl && scl) { // RISING EDGE + switch(x24c0x_state) { + case X24C0X_ADDRESS: + if(x24c0x_bitcount < 7) { + x24c0x_addr <<= 1; + x24c0x_addr |= sda; + } else { + if(!x24c02) // X24C01 mode + x24c0x_word = x24c0x_addr; + if(sda) { // READ COMMAND + x24c0x_state = X24C0X_READ; + } else { // WRITE COMMAND + if(x24c02) // X24C02 mode + x24c0x_state = X24C0X_WORD; + else + x24c0x_state = X24C0X_WRITE; + } + } + x24c0x_bitcount++; + break; + case X24C0X_WORD: + if(x24c0x_bitcount == 8) { // ACK + x24c0x_word = 0; + x24c0x_out = 0; + } else { // WORD ADDRESS INPUT + x24c0x_word <<= 1; + x24c0x_word |= sda; + if(x24c0x_bitcount == 16) { // END OF ADDRESS INPUT + x24c0x_bitcount = 7; + x24c0x_state = X24C0X_WRITE; + } + } + x24c0x_bitcount++; + break; + case X24C0X_READ: + if (x24c0x_bitcount == 8) { // ACK + x24c0x_out = 0; + x24c0x_latch = x24c0x_data[x24c0x_word]; + x24c0x_bitcount = 0; + } else { // REAL OUTPUT + x24c0x_out = x24c0x_latch >> 7; + x24c0x_latch <<= 1; + x24c0x_bitcount++; + if(x24c0x_bitcount == 8) { + x24c0x_word++; + x24c0x_word &= 0xff; + } + } + break; + case X24C0X_WRITE: + if (x24c0x_bitcount == 8) { // ACK + x24c0x_out = 0; + x24c0x_latch = 0; + x24c0x_bitcount = 0; + } else { // REAL INPUT + x24c0x_latch <<= 1; + x24c0x_latch |= sda; + x24c0x_bitcount++; + if(x24c0x_bitcount == 8) { + x24c0x_data[x24c0x_word] = x24c0x_latch; + x24c0x_word++; + x24c0x_word &= 0xff; + } + } + break; + } + } + + x24c0x_sda = sda; + x24c0x_scl = scl; +} + +static uint8 x24c0x_read() { + return x24c0x_out << 4; +} + +// + +static void Sync(void) { if (is153) { int base = (reg[0] & 1) << 4; setchr8(0); @@ -80,41 +186,91 @@ static DECLFW(BandaiWrite) { A &= 0x0F; if (A < 0x0A) { reg[A & 0x0F] = V; - BandaiSync(); + Sync(); } else switch (A) { case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break; case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break; case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break; - case 0x0D: break; // Serial EEPROM control port + case 0x0D: x24c0x_write(V); break; } } +static DECLFR(BandaiRead) { + return (X.DB & 0xEF) | x24c0x_read(); +} + +static void BandaiIRQHook(int a) { + if (IRQa) { + IRQCount -= a; + if (IRQCount < 0) { + X6502_IRQBegin(FCEU_IQEXT); + IRQa = 0; + IRQCount = -1; + } + } +} + static void BandaiPower(void) { - BandaiSync(); + IRQa = 0; + x24c0x_init(); + Sync(); + SetReadHandler(0x6000, 0x7FFF, BandaiRead); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0xFFFF, BandaiWrite); } static void StateRestore(int version) { - BandaiSync(); + Sync(); } void Mapper16_Init(CartInfo *info) { + x24c02 = 1; is153 = 0; info->Power = BandaiPower; MapIRQHook = BandaiIRQHook; + + info->battery = 1; + info->SaveGame[0] = x24c0x_data; + info->SaveGameLen[0] = 256; + AddExState(x24c0x_data, 256, 0, "DATA"); + GameStateRestore = StateRestore; + AddExState(&x24c0xStateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0); } +void Mapper159_Init(CartInfo *info) { + x24c02 = 0; + is153 = 0; + info->Power = BandaiPower; + MapIRQHook = BandaiIRQHook; + + info->battery = 1; + info->SaveGame[0] = x24c0x_data; + info->SaveGameLen[0] = 128; + AddExState(x24c0x_data, 128, 0, "DATA"); + + GameStateRestore = StateRestore; + AddExState(&x24c0xStateRegs, ~0, 0, 0); + AddExState(&StateRegs, ~0, 0, 0); +} + +// Famicom jump 2: +// 0-7: Lower bit of data selects which 256KB PRG block is in use. +// This seems to be a hack on the developers' part, so I'll make emulation +// of it a hack(I think the current PRG block would depend on whatever the +// lowest bit of the CHR bank switching register that corresponds to the +// last CHR address read). + static void M153Power(void) { - BandaiSync(); + Sync(); setprg8r(0x10, 0x6000, 0); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, BandaiWrite); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } @@ -284,12 +440,13 @@ static DECLFR(BarcodeRead) { } static void M157Power(void) { + IRQa = 0; BarcodeData[0] = 0xFF; BarcodeReadPos = 0; BarcodeOut = 0; BarcodeCycleCount = 0; - BandaiSync(); + Sync(); SetWriteHandler(0x6000, 0xFFFF, BandaiWrite); SetReadHandler(0x6000, 0x7FFF, BarcodeRead); @@ -297,7 +454,7 @@ static void M157Power(void) { } void Mapper157_Init(CartInfo *info) { - is153 = 0; + is153 = 1; info->Power = M157Power; MapIRQHook = BarcodeIRQHook; diff --git a/source/fceultra/boards/coolboy.cpp b/source/fceultra/boards/coolboy.cpp new file mode 100644 index 0000000..4672553 --- /dev/null +++ b/source/fceultra/boards/coolboy.cpp @@ -0,0 +1,108 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2015 CaH4e3 + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * CoolBoy 400-in-1 FK23C-mimic mapper 16Mb/32Mb PROM + 128K/256K CHR RAM, optional SRAM, optional NTRAM + * only MMC3 mode + * + * 6000 (ġġ76x210) | 0ġÑ0 + * 6001 (ġġġ354ġġ) + * 6002 = 0 + * 6003 = 0 + * + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void COOLBOYCW(uint32 A, uint8 V) { + if(EXPREGS[3] & 0x10) + setchr8(EXPREGS[2] & 0xF); + else { + uint32 mask = 0xFF; + switch(EXPREGS[0] & 0xC0) { + case 0xC0: + mask = 0x7F; + break; + } + setchr1(A, V & mask); + } +} + +static void COOLBOYPW(uint32 A, uint8 V) { + uint32 mask, shift; + uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2); + switch(EXPREGS[0] & 0xC0) { + case 0x00: + mask = 0x3F; + break; + case 0x80: + mask = 0x1F; + break; + case 0xC0: + if(EXPREGS[3] & 0x10) { + mask = 0x01 | (EXPREGS[1] & 2); + } else { + mask = 0x0F; + } + break; + } + if(EXPREGS[3] & 0x10) + setprg8(A, (base << 4) | (V & mask) | ((EXPREGS[3] & (0x0E ^ (EXPREGS[1] & 2))) )); + else + setprg8(A, (base << 4) | (V & mask)); +} + +static DECLFW(COOLBOYWrite) { + if(A001B & 0x80) + CartBW(A,V); + else + if((EXPREGS[3] & 0x80) == 0) { + EXPREGS[A & 3] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2); + FCEU_printf("exp %02x %02x (base %03d)\n",A,V,base); + } +} + +static void COOLBOYReset(void) { + MMC3RegReset(); + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void COOLBOYPower(void) { + GenMMC3Power(); + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol + SetWriteHandler(0x6000, 0x6fff, COOLBOYWrite); +} + +void COOLBOY_Init(CartInfo *info) { + GenMMC3_Init(info, 512, 128, 8, 0); + pwrap = COOLBOYPW; + cwrap = COOLBOYCW; + info->Power = COOLBOYPower; + info->Reset = COOLBOYReset; + AddExState(EXPREGS, 4, 0, "EXPR"); +} + diff --git a/source/fceultra/boards/dance2000.cpp b/source/fceultra/boards/dance2000.cpp index 26448a4..37a6e1e 100644 --- a/source/fceultra/boards/dance2000.cpp +++ b/source/fceultra/boards/dance2000.cpp @@ -16,30 +16,29 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Dance 2000 12-in-1 - * */ #include "mapinc.h" -static uint8 prg, mirr, prgmode; +static uint8 prg, mode; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; +static uint32 lastnt = 0; static SFORMAT StateRegs[] = { { &prg, 1, "REGS" }, - { &mirr, 1, "MIRR" }, - { &prgmode, 1, "MIRR" }, + { &mode, 1, "MODE" }, + { &lastnt, 4, "LSNT" }, { 0 } }; static void Sync(void) { - setmirror(mirr); + setmirror((mode ^ 1) & 1); setprg8r(0x10, 0x6000, 0); - setchr8(0); - if (prgmode) + setchr4(0x0000, lastnt); + setchr4(0x1000, 1); + if (mode & 4) setprg32(0x8000, prg & 7); else { setprg16(0x8000, prg & 0x0f); @@ -48,11 +47,9 @@ static void Sync(void) { } static DECLFW(UNLD2000Write) { -// FCEU_printf("write %04x:%04x\n",A,V); switch (A) { case 0x5000: prg = V; Sync(); break; - case 0x5200: mirr = (V & 1) ^ 1; prgmode = V & 4; Sync(); break; -// default: FCEU_printf("write %04x:%04x\n",A,V); + case 0x5200: mode = V; if (mode & 4) Sync(); break; } } @@ -64,17 +61,28 @@ static DECLFR(UNLD2000Read) { } static void UNLD2000Power(void) { - prg = prgmode = 0; + prg = mode = 0; Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, UNLD2000Read); - SetWriteHandler(0x4020, 0x5FFF, UNLD2000Write); + SetWriteHandler(0x5000, 0x5FFF, UNLD2000Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void UNLAX5705IRQ(void) { - if (scanline > 174) setchr4(0x0000, 1); - else setchr4(0x0000, 0); +static void UNL2000Hook(uint32 A) { + if (mode & 2) { + if ((A & 0x3000) == 0x2000) { + uint32 curnt = A & 0x800; + if (curnt != lastnt) { + setchr4(0x0000, curnt >> 11); + lastnt = curnt; + } + } + } else { + lastnt = 0; + setchr4(0x0000, 0); + } } static void UNLD2000Close(void) { @@ -83,7 +91,6 @@ static void UNLD2000Close(void) { WRAM = NULL; } - static void StateRestore(int version) { Sync(); } @@ -91,7 +98,7 @@ static void StateRestore(int version) { void UNLD2000_Init(CartInfo *info) { info->Power = UNLD2000Power; info->Close = UNLD2000Close; - GameHBIRQHook = UNLAX5705IRQ; + PPU_hook = UNL2000Hook; GameStateRestore = StateRestore; WRAMSIZE = 8192; diff --git a/source/fceultra/boards/datalatch.cpp b/source/fceultra/boards/datalatch.cpp index 7f39add..62bf2b5 100644 --- a/source/fceultra/boards/datalatch.cpp +++ b/source/fceultra/boards/datalatch.cpp @@ -30,7 +30,7 @@ static void (*WSync)(void); static DECLFW(LatchWrite) { // FCEU_printf("bs %04x %02x\n",A,V); if (bus_conflict) - latche = V & CartBR(A); + latche = (V == CartBR(A)) ? V : 0; else latche = V; WSync(); @@ -42,6 +42,7 @@ static void LatchPower(void) { if (WRAM) { SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } else { SetReadHandler(0x8000, 0xFFFF, CartBR); } @@ -91,7 +92,7 @@ static DECLFW(NROMWrite) { #endif static void NROMPower(void) { - setprg8r(0x10, 0x6000, 0); // Famili BASIC (v3.0) need it (uses only 4KB), FP-BASIC uses 8KB + setprg8r(0x10, 0x6000, 0); // Famili BASIC (v3.0) need it (uses only 4KB), FP-BASIC uses 8KB setprg16(0x8000, 0); setprg16(0xC000, ~0); setchr8(0); @@ -100,7 +101,9 @@ static void NROMPower(void) { SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); - #ifdef DEBUG_MAPPER + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + +#ifdef DEBUG_MAPPER SetWriteHandler(0x4020, 0xFFFF, NROMWrite); #endif } @@ -122,14 +125,14 @@ void NROM_Init(CartInfo *info) { //------------------ Map 2 --------------------------- static void UNROMSync(void) { - static uint32 mirror_in_use = 0; - if (PRGsize[0] <= 128 * 1024) { - setprg16(0x8000, latche & 0x7); - if (latche & 8) mirror_in_use = 1; - if (mirror_in_use) - setmirror(((latche >> 3) & 1) ^ 1); // Higway Star Hacked mapper - } else - setprg16(0x8000, latche & 0xf); +// static uint32 mirror_in_use = 0; +// if (PRGsize[0] <= 128 * 1024) { +// setprg16(0x8000, latche & 0x7); +// if (latche & 8) mirror_in_use = 1; +// if (mirror_in_use) +// setmirror(((latche >> 3) & 1) ^ 1); // Higway Star Hacked mapper, disabled till new mapper defined +// } else + setprg16(0x8000, latche); setprg16(0xc000, ~0); setchr8(0); } @@ -143,7 +146,7 @@ void UNROM_Init(CartInfo *info) { static void CNROMSync(void) { setchr8(latche); setprg32(0x8000, 0); - setprg8r(0x10, 0x6000, 0); // Hayauchy IGO uses 2Kb or RAM + setprg8r(0x10, 0x6000, 0); // Hayauchy IGO uses 2Kb or RAM } void CNROM_Init(CartInfo *info) { @@ -159,7 +162,7 @@ static void ANROMSync() { } void ANROM_Init(CartInfo *info) { - Latch_Init(info, ANROMSync, 0, 0x8000, 0xFFFF, 0, 0); + Latch_Init(info, ANROMSync, 0, 0x4020, 0xFFFF, 0, 0); } //------------------ Map 8 --------------------------- @@ -201,6 +204,20 @@ void CPROM_Init(CartInfo *info) { Latch_Init(info, CPROMSync, 0, 0x8000, 0xFFFF, 0, 0); } +//------------------ Map 29 --------------------------- //Used by Glider, http://www.retrousb.com/product_info.php?cPath=30&products_id=58 + +static void M29Sync() { + setprg16(0x8000, (latche & 0x1C) >> 2); + setprg16(0xc000, ~0); + setchr8r(0, latche & 3); + setprg8r(0x10, 0x6000, 0); +} + +void Mapper29_Init(CartInfo *info) { + Latch_Init(info, M29Sync, 0, 0x8000, 0xFFFF, 1, 0); +} + + //------------------ Map 38 --------------------------- static void M38Sync(void) { @@ -215,7 +232,6 @@ void Mapper38_Init(CartInfo *info) { //------------------ Map 66 --------------------------- static void MHROMSync(void) { - setprg32(0x8000, latche >> 4); setchr8(latche & 0xF); } @@ -373,7 +389,7 @@ static void M152Sync() { setprg16(0x8000, (latche >> 4) & 7); setprg16(0xc000, ~0); setchr8(latche & 0xf); - setmirror(MI_0 + ((latche >> 7) & 1)); /* Saint Seiya...hmm. */ + setmirror(MI_0 + ((latche >> 7) & 1)); /* Saint Seiya...hmm. */ } void Mapper152_Init(CartInfo *info) { @@ -435,7 +451,10 @@ void Mapper240_Init(CartInfo *info) { static void M241Sync(void) { setchr8(0); setprg8r(0x10, 0x6000, 0); - setprg32(0x8000, latche); + if (latche & 0x80) + setprg32(0x8000, latche | 8); // no 241 actually, but why not afterall? + else + setprg32(0x8000, latche); } void Mapper241_Init(CartInfo *info) { @@ -452,7 +471,7 @@ void Mapper241_Init(CartInfo *info) { static void BMCA65ASSync(void) { if (latche & 0x40) setprg32(0x8000, (latche >> 1) & 0x0F); - else{ + else { setprg16(0x8000, ((latche & 0x30) >> 1) | (latche & 7)); setprg16(0xC000, ((latche & 0x30) >> 1) | 7); } diff --git a/source/fceultra/boards/edu2000.cpp b/source/fceultra/boards/edu2000.cpp index a872639..36f1ad1 100644 --- a/source/fceultra/boards/edu2000.cpp +++ b/source/fceultra/boards/edu2000.cpp @@ -48,6 +48,7 @@ static void UNLEDU2000Power(void) { SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0xFFFF, CartBW); SetWriteHandler(0x8000, 0xFFFF, UNLEDU2000HiWrite); + FCEU_CheatAddRAM(32, 0x6000, WRAM); reg = 0; Sync(); } diff --git a/source/fceultra/boards/emu2413.c b/source/fceultra/boards/emu2413.c index c7e6b16..240aeb0 100644 --- a/source/fceultra/boards/emu2413.c +++ b/source/fceultra/boards/emu2413.c @@ -335,7 +335,7 @@ static void makeDphaseARTable(void) { dphaseARTable[AR][Rks] = 0; /*EG_DP_WIDTH;*/ break; default: - dphaseARTable[AR][Rks] = rate_adjust((3 * (RL + 4) << (RM + 1))); + dphaseARTable[AR][Rks] = rate_adjust(3 * (RL + 4) << (RM + 1)); break; } } diff --git a/source/fceultra/boards/famicombox.cpp b/source/fceultra/boards/famicombox.cpp index 05c6a62..a47823f 100644 --- a/source/fceultra/boards/famicombox.cpp +++ b/source/fceultra/boards/famicombox.cpp @@ -79,6 +79,7 @@ static void SSSNROMPower(void) { SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void SSSNROMReset(void) { @@ -109,7 +110,6 @@ void SSSNROM_Init(CartInfo *info) { WRAMSIZE = 16384; WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); AddExState(&StateRegs, ~0, 0, 0); } diff --git a/source/fceultra/boards/ffe.cpp b/source/fceultra/boards/ffe.cpp index da35411..51e591e 100644 --- a/source/fceultra/boards/ffe.cpp +++ b/source/fceultra/boards/ffe.cpp @@ -102,6 +102,7 @@ static void FFEPower(void) { SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, FFEWriteLatch); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void FFEIRQHook(int a) { diff --git a/source/fceultra/boards/inlnsf.cpp b/source/fceultra/boards/inlnsf.cpp new file mode 100644 index 0000000..ccd0985 --- /dev/null +++ b/source/fceultra/boards/inlnsf.cpp @@ -0,0 +1,62 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mapinc.h" + +static uint8 regs[8]; + +static SFORMAT StateRegs[] = +{ + { regs, 8, "REGS" }, + { 0 } +}; + +static void Sync(void) { + for (int i=0; i < 8; ++i) + { + setprg4(0x8000 + (0x1000 * i), regs[i]); + } +} + +static DECLFW(M31Write) { + if (A >= 0x5000 && A <= 0x5FFF) + { + regs[A&7] = V; + Sync(); + } +} + +static void M31Power(void) { + setchr8(0); + regs[7] = 0xFF; + Sync(); + SetReadHandler(0x8000, 0xffff, CartBR); + SetWriteHandler(0x5000, 0x5fff, M31Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper31_Init(CartInfo *info) { + info->Power = M31Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/ks7010.cpp b/source/fceultra/boards/ks7010.cpp new file mode 100644 index 0000000..a4a9960 --- /dev/null +++ b/source/fceultra/boards/ks7010.cpp @@ -0,0 +1,85 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2007 CaH4e3 + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mapinc.h" + +static uint8 preg[4], creg, mirr; + +static SFORMAT StateRegs[] = +{ + { preg, 4, "PREG" }, + { &creg, 1, "CREG" }, + { &mirr, 1, "MIRR" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x6000, preg[0]); + setprg8(0x8000, 0xa); + setprg8(0xa000, 0xb); + setprg8(0xc000, 0x6); + setprg8(0xe000, 0x7); + setchr8(0x0c); + setmirror(mirr); +} + +static DECLFW(UNLKS7010Write) { + switch (A) { + case 0x4025: mirr = (((V >> 3) & 1) ^ 1); Sync(); break; + default: + FCEU_printf("bs %04x %02x\n",A,V); + break; + } +} + +static void UNLKS7010Reset(void) { + preg[0]++; + if(preg[0] == 0x10) { + preg[0] = 0; + preg[1]++; + if(preg[1] == 0x10) { + preg[1] = 0; + preg[2]++; + } + } + FCEU_printf("preg %02x %02x %02x\n",preg[0], preg[1], preg[2]); + Sync(); +} + +static void UNLKS7010Power(void) { + preg[0] = preg[1] = preg[2] = 0; + Sync(); + SetReadHandler(0x6000, 0x7fff, CartBR); + SetWriteHandler(0x6000, 0x7fff, CartBW); + SetReadHandler(0x8000, 0xffff, CartBR); + SetWriteHandler(0x4020, 0xffff, UNLKS7010Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void UNLKS7010_Init(CartInfo *info) { + info->Power = UNLKS7010Power; + info->Reset = UNLKS7010Reset; + + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/ks7012.cpp b/source/fceultra/boards/ks7012.cpp index feaa754..49def23 100644 --- a/source/fceultra/boards/ks7012.cpp +++ b/source/fceultra/boards/ks7012.cpp @@ -51,6 +51,7 @@ static void UNLKS7012Power(void) { SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, UNLKS7012Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void UNLKS7012Reset(void) { diff --git a/source/fceultra/boards/ks7017.cpp b/source/fceultra/boards/ks7017.cpp index 29c0203..3f119cf 100644 --- a/source/fceultra/boards/ks7017.cpp +++ b/source/fceultra/boards/ks7017.cpp @@ -87,6 +87,7 @@ static void UNLKS7017Power(void) { SetReadHandler(0x8000, 0xFFFF, CartBR); SetReadHandler(0x4030, 0x4030, FDSRead4030); SetWriteHandler(0x4020, 0x5FFF, UNLKS7017Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void UNLKS7017Close(void) { diff --git a/source/fceultra/boards/ks7037.cpp b/source/fceultra/boards/ks7037.cpp index efe43f2..232e758 100644 --- a/source/fceultra/boards/ks7037.cpp +++ b/source/fceultra/boards/ks7037.cpp @@ -82,6 +82,7 @@ static void LH10Power(void) { SetWriteHandler(0x8000, 0xBFFF, UNLKS7037Write); SetWriteHandler(0xC000, 0xDFFF, CartBW); SetWriteHandler(0xE000, 0xFFFF, UNLKS7037Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void Close(void) { diff --git a/source/fceultra/boards/lh32.cpp b/source/fceultra/boards/lh32.cpp index 2150aee..3983327 100644 --- a/source/fceultra/boards/lh32.cpp +++ b/source/fceultra/boards/lh32.cpp @@ -52,6 +52,7 @@ static void LH32Power(void) { SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0xC000, 0xDFFF, CartBW); SetWriteHandler(0x6000, 0x6000, LH32Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void LH32Close(void) { diff --git a/source/fceultra/boards/lh53.cpp b/source/fceultra/boards/lh53.cpp index 7626dca..7065b0c 100644 --- a/source/fceultra/boards/lh53.cpp +++ b/source/fceultra/boards/lh53.cpp @@ -80,6 +80,7 @@ static void LH53Power(void) { SetWriteHandler(0xB800, 0xD7FF, LH53RamWrite); SetWriteHandler(0xE000, 0xEFFF, LH53IRQaWrite); SetWriteHandler(0xF000, 0xFFFF, LH53Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void LH53Close(void) { diff --git a/source/fceultra/boards/mihunche.cpp b/source/fceultra/boards/mihunche.cpp new file mode 100644 index 0000000..c17478f --- /dev/null +++ b/source/fceultra/boards/mihunche.cpp @@ -0,0 +1,68 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2013 CaH4e3 + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mapinc.h" + +static uint16 latche; + +static SFORMAT StateRegs[] = +{ + { &latche, 2, "LATC" }, + { 0 } +}; + +static void Sync(void) { + setprg32(0x8000, 0); + if(CHRsize[0] == 8192) { + setchr4(0x0000, latche & 1); + setchr4(0x1000, latche & 1); + } else { + setchr8(latche & 1); // actually, my bad, overdumped roms, the real CHR size if 8K + } + setmirror(MI_0 + (latche & 1)); +} + +static DECLFW(UNLCC21Write1) { + latche = A; + Sync(); +} + +static DECLFW(UNLCC21Write2) { + latche = V; + Sync(); +} + +static void UNLCC21Power(void) { + latche = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8001, 0xFFFF, UNLCC21Write1); + SetWriteHandler(0x8000, 0x8000, UNLCC21Write2); // another one many-in-1 mapper, there is a lot of similar carts with little different wirings +} + +static void StateRestore(int version) { + Sync(); +} + +void UNLCC21_Init(CartInfo *info) { + info->Power = UNLCC21Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/mmc1.cpp b/source/fceultra/boards/mmc1.cpp index 17fab41..4631d6c 100644 --- a/source/fceultra/boards/mmc1.cpp +++ b/source/fceultra/boards/mmc1.cpp @@ -247,8 +247,8 @@ static void GenMMC1Power(void) { FCEU_CheatAddRAM(8, 0x6000, WRAM); if (mmc1opts & 4) FCEU_dwmemset(WRAM, 0, 8192) - else if (!(mmc1opts & 2)) - FCEU_dwmemset(WRAM, 0, 8192); + else if (!(mmc1opts & 2)) + FCEU_dwmemset(WRAM, 0, 8192); // wtf? } SetWriteHandler(0x8000, 0xFFFF, MMC1_write); SetReadHandler(0x8000, 0xFFFF, CartBR); diff --git a/source/fceultra/boards/mmc2and4.cpp b/source/fceultra/boards/mmc2and4.cpp index c962df9..5d9d73d 100644 --- a/source/fceultra/boards/mmc2and4.cpp +++ b/source/fceultra/boards/mmc2and4.cpp @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel * * 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 @@ -94,6 +95,7 @@ static void MMC2and4Power(void) { if (is10) { SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0xA000, 0xFFFF, MMC2and4Write); diff --git a/source/fceultra/boards/mmc3.cpp b/source/fceultra/boards/mmc3.cpp index dcf2f57..ebd2db4 100644 --- a/source/fceultra/boards/mmc3.cpp +++ b/source/fceultra/boards/mmc3.cpp @@ -28,12 +28,13 @@ #include "mmc3.h" uint8 MMC3_cmd; +uint8 kt_extra; uint8 *WRAM; uint32 WRAMSIZE; uint8 *CHRRAM; uint32 CHRRAMSIZE; uint8 DRegBuf[8]; -uint8 EXPREGS[8]; /* For bootleg games, mostly. */ +uint8 EXPREGS[8]; /* For bootleg games, mostly. */ uint8 A000B, A001B; uint8 mmc3opts = 0; @@ -79,7 +80,7 @@ void FixMMC3PRG(int V) { } else { pwrap(0x8000, DRegBuf[6]); pwrap(0xC000, ~1); - } + } pwrap(0xA000, DRegBuf[7]); pwrap(0xE000, ~0); } @@ -182,6 +183,17 @@ DECLFW(MMC3_IRQWrite) { } } +// KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support +DECLFW(KT008HackWrite) { +// FCEU_printf("%04x:%04x\n",A,V); + switch (A & 3) { + case 0: kt_extra = V; FixMMC3PRG(MMC3_cmd); break; + case 1: break; // unk + case 2: break; // unk + case 3: break; // unk + } +} + static void ClockMMC3Counter(void) { int count = IRQCount; if (!count || IRQReload) { @@ -216,11 +228,14 @@ void GenMMC3Restore(int version) { } static void GENCWRAP(uint32 A, uint8 V) { - setchr1(A, V); // Business Wars NEEDS THIS for 8K CHR-RAM + setchr1(A, V); // Business Wars NEEDS THIS for 8K CHR-RAM } static void GENPWRAP(uint32 A, uint8 V) { - setprg8(A, V & 0x7F); // [NJ102] Mo Dao Jie (C) has 1024Mb MMC3 BOARD, maybe something other will be broken +// [NJ102] Mo Dao Jie (C) has 1024Mb MMC3 BOARD, maybe something other will be broken +// also HengGe BBC-2x boards enables this mode as default board mode at boot up + setprg8(A, (V & 0x7F) | ((kt_extra & 4) << 4)); +// KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support } static void GENMWRAP(uint8 V) { @@ -246,6 +261,10 @@ void GenMMC3Power(void) { SetWriteHandler(0x8000, 0xBFFF, MMC3_CMDWrite); SetWriteHandler(0xC000, 0xFFFF, MMC3_IRQWrite); SetReadHandler(0x8000, 0xFFFF, CartBR); + +// KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support + SetWriteHandler(0x5000,0x5FFF, KT008HackWrite); + A001B = A000B = 0; setmirror(1); if (mmc3opts & 1) { @@ -254,7 +273,7 @@ void GenMMC3Power(void) { SetReadHandler(0x7000, 0x7FFF, MAWRAMMMC6); SetWriteHandler(0x7000, 0x7FFF, MBWRAMMMC6); } else { - FCEU_CheatAddRAM((WRAMSIZE & 0x1fff) >> 10, 0x6000, WRAM); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); SetWriteHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBW); SetReadHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBR); setprg8r(0x10, 0x6000, 0); @@ -299,17 +318,19 @@ void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery) { info->SaveGameLen[0] = WRAMSIZE; } +// KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support + AddExState(&kt_extra, 1, 0, "KTEX"); AddExState(MMC3_StateRegs, ~0, 0, 0); info->Power = GenMMC3Power; info->Reset = MMC3RegReset; info->Close = GenMMC3Close; - if (info->CRC32 == 0x5104833e) // Kick Master + if (info->CRC32 == 0x5104833e) // Kick Master GameHBIRQHook = MMC3_hb_KickMasterHack; - else if (info->CRC32 == 0x5a6860f1 || info->CRC32 == 0xae280e20) // Shougi Meikan '92/'93 + else if (info->CRC32 == 0x5a6860f1 || info->CRC32 == 0xae280e20)// Shougi Meikan '92/'93 GameHBIRQHook = MMC3_hb_KickMasterHack; - else if (info->CRC32 == 0xfcd772eb) // PAL Star Wars, similar problem as Kick Master. + else if (info->CRC32 == 0xfcd772eb) // PAL Star Wars, similar problem as Kick Master. GameHBIRQHook = MMC3_hb_PALStarWarsHack; else GameHBIRQHook = MMC3_hb; @@ -322,7 +343,7 @@ void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery) { // ---------------------------- Mapper 4 -------------------------------- -static int hackm4 = 0; /* For Karnov, maybe others. BLAH. Stupid iNES format.*/ +static int hackm4 = 0; /* For Karnov, maybe others. BLAH. Stupid iNES format.*/ static void M4Power(void) { GenMMC3Power(); @@ -353,10 +374,22 @@ static DECLFW(M12Write) { EXPREGS[1] = (V & 0x10) >> 4; } +static DECLFR(M12Read) { + return EXPREGS[2]; +} + static void M12Power(void) { EXPREGS[0] = EXPREGS[1] = 0; + EXPREGS[2] = 1; // chinese is default GenMMC3Power(); SetWriteHandler(0x4100, 0x5FFF, M12Write); + SetReadHandler(0x4100, 0x5FFF, M12Read); +} + +static void M12Reset(void) { + EXPREGS[0] = EXPREGS[1] = 0; + EXPREGS[2] ^= 1; + MMC3RegReset(); } void Mapper12_Init(CartInfo *info) { @@ -365,6 +398,7 @@ void Mapper12_Init(CartInfo *info) { isRevB = 0; info->Power = M12Power; + info->Reset = M12Reset; AddExState(EXPREGS, 2, 0, "EXPR"); } @@ -461,7 +495,7 @@ static void M45CW(uint32 A, uint8 V) { NV &= (1 << ((EXPREGS[2] & 7) + 1)) - 1; else if (EXPREGS[2]) - NV &= 0; // hack ;( don't know exactly how it should be + NV &= 0; // hack ;( don't know exactly how it should be NV |= EXPREGS[0] | ((EXPREGS[2] & 0xF0) << 4); setchr1(A, NV); } @@ -609,7 +643,7 @@ static void M52PW(uint32 A, uint8 V) { static void M52CW(uint32 A, uint8 V) { uint32 mask = 0xFF ^ ((EXPREGS[0] & 0x40) << 1); // uint32 bank = (((EXPREGS[0]>>3)&4)|((EXPREGS[0]>>1)&2)|((EXPREGS[0]>>6)&(EXPREGS[0]>>4)&1))<<7; - uint32 bank = (((EXPREGS[0] >> 4) & 2) | (EXPREGS[0] & 4) | ((EXPREGS[0] >> 6) & (EXPREGS[0] >> 4) & 1)) << 7; // actually 256K CHR banks index bits is inverted! + uint32 bank = (((EXPREGS[0] >> 4) & 2) | (EXPREGS[0] & 4) | ((EXPREGS[0] >> 6) & (EXPREGS[0] >> 4) & 1)) << 7; // actually 256K CHR banks index bits is inverted! setchr1(A, bank | (V & mask)); } @@ -659,7 +693,7 @@ void Mapper76_Init(CartInfo *info) { // ---------------------------- Mapper 74 ------------------------------- static void M74CW(uint32 A, uint8 V) { - if ((V == 8) || (V == 9)) //Di 4 Ci - Ji Qi Ren Dai Zhan (As).nes, Ji Jia Zhan Shi (As).nes + if ((V == 8) || (V == 9)) //Di 4 Ci - Ji Qi Ren Dai Zhan (As).nes, Ji Jia Zhan Shi (As).nes setchr1r(0x10, A, V); else setchr1r(0, A, V); @@ -735,7 +769,7 @@ void Mapper114_Init(CartInfo *info) { static void M115PW(uint32 A, uint8 V) { if (EXPREGS[0] & 0x80) { if (EXPREGS[0] & 0x20) - setprg32(0x8000, (EXPREGS[0] & 0x0F) >> 1); // real hardware tests, info 100% now lol + setprg32(0x8000, (EXPREGS[0] & 0x0F) >> 1); // real hardware tests, info 100% now lol else { setprg16(0x8000, (EXPREGS[0] & 0x0F)); setprg16(0xC000, (EXPREGS[0] & 0x0F)); @@ -749,8 +783,9 @@ static void M115CW(uint32 A, uint8 V) { } static DECLFW(M115Write) { - if (A == 0x5080) EXPREGS[2] = V; - if (A == 0x6000) + if (A == 0x5080) + EXPREGS[2] = V; // Extra prot hardware 2-in-1 mode + else if (A == 0x6000) EXPREGS[0] = V; else if (A == 0x6001) EXPREGS[1] = V; @@ -772,7 +807,7 @@ void Mapper115_Init(CartInfo *info) { cwrap = M115CW; pwrap = M115PW; info->Power = M115Power; - AddExState(EXPREGS, 2, 0, "EXPR"); + AddExState(EXPREGS, 3, 0, "EXPR"); } // ---------------------------- Mapper 118 ------------------------------ @@ -806,6 +841,7 @@ void Mapper119_Init(CartInfo *info) { CHRRAMSIZE = 8192; CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); } // ---------------------------- Mapper 134 ------------------------------ @@ -939,7 +975,7 @@ void Mapper192_Init(CartInfo *info) { // ---------------------------- Mapper 194 ------------------------------- static void M194CW(uint32 A, uint8 V) { - if (V <= 1) //Dai-2-Ji - Super Robot Taisen (As).nes + if (V <= 1) //Dai-2-Ji - Super Robot Taisen (As).nes setchr1r(0x10, A, V); else setchr1r(0, A, V); @@ -956,7 +992,7 @@ void Mapper194_Init(CartInfo *info) { // ---------------------------- Mapper 195 ------------------------------- static void M195CW(uint32 A, uint8 V) { - if (V <= 3) // Crystalis (c).nes, Captain Tsubasa Vol 2 - Super Striker (C) + if (V <= 3) // Crystalis (c).nes, Captain Tsubasa Vol 2 - Super Striker (C) setchr1r(0x10, A, V); else setchr1r(0, A, V); @@ -986,25 +1022,18 @@ void Mapper195_Init(CartInfo *info) { // game static void M196PW(uint32 A, uint8 V) { - if (EXPREGS[0]) // Tenchi o Kurau II - Shokatsu Koumei Den (J) (C).nes + if (EXPREGS[0]) setprg32(0x8000, EXPREGS[1]); else setprg8(A, V); -// setprg8(A,(V&3)|((V&8)>>1)|((V&4)<<1)); // Mali Splash Bomb } -//static void M196CW(uint32 A, uint8 V) -//{ -// setchr1(A,(V&0xDD)|((V&0x20)>>4)|((V&2)<<4)); -//} - static DECLFW(Mapper196Write) { if (A >= 0xC000) { A = (A & 0xFFFE) | ((A >> 2) & 1) | ((A >> 3) & 1); MMC3_IRQWrite(A, V); } else { A = (A & 0xFFFE) | ((A >> 2) & 1) | ((A >> 3) & 1) | ((A >> 1) & 1); -// A=(A&0xFFFE)|((A>>3)&1); // Mali Splash Bomb MMC3_CMDWrite(A, V); } } @@ -1025,10 +1054,44 @@ static void Mapper196Power(void) { void Mapper196_Init(CartInfo *info) { GenMMC3_Init(info, 128, 128, 0, 0); pwrap = M196PW; -// cwrap=M196CW; // Mali Splash Bomb info->Power = Mapper196Power; } +// ---------------------------- Mali Splash Bomb---------------------------- +// The same board as for 196 mapper games, but with additional data bit swap +// Also, it is impossible to work on the combined 196 mapper source with +// all data bits merged, because it's using one of them as 8000 reg... + +static void UNLMaliSBPW(uint32 A, uint8 V) { + setprg8(A, (V & 3) | ((V & 8) >> 1) | ((V & 4) << 1)); +} + +static void UNLMaliSBCW(uint32 A, uint8 V) { + setchr1(A, (V & 0xDD) | ((V & 0x20) >> 4) | ((V & 2) << 4)); +} + +static DECLFW(UNLMaliSBWrite) { + if (A >= 0xC000) { + A = (A & 0xFFFE) | ((A >> 2) & 1) | ((A >> 3) & 1); + MMC3_IRQWrite(A, V); + } else { + A = (A & 0xFFFE) | ((A >> 3) & 1); + MMC3_CMDWrite(A, V); + } +} + +static void UNLMaliSBPower(void) { + GenMMC3Power(); + SetWriteHandler(0x8000, 0xFFFF, UNLMaliSBWrite); +} + +void UNLMaliSB_Init(CartInfo *info) { + GenMMC3_Init(info, 128, 128, 0, 0); + pwrap = UNLMaliSBPW; + cwrap = UNLMaliSBCW; + info->Power = UNLMaliSBPower; +} + // ---------------------------- Mapper 197 ------------------------------- static void M197CW(uint32 A, uint8 V) { @@ -1048,7 +1111,7 @@ void Mapper197_Init(CartInfo *info) { // ---------------------------- Mapper 198 ------------------------------- static void M198PW(uint32 A, uint8 V) { - if (V >= 0x50) // Tenchi o Kurau II - Shokatsu Koumei Den (J) (C).nes + if (V >= 0x50) // Tenchi o Kurau II - Shokatsu Koumei Den (J) (C).nes setprg8(A, V & 0x4F); else setprg8(A, V); @@ -1100,7 +1163,7 @@ static void M205Reset(void) { static void M205Power(void) { GenMMC3Power(); SetWriteHandler(0x6000, 0x6fff, M205Write0); - SetWriteHandler(0x7000, 0x7fff, M205Write1); // OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein + SetWriteHandler(0x7000, 0x7fff, M205Write1); // OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein } void Mapper205_Init(CartInfo *info) { @@ -1115,7 +1178,7 @@ void Mapper205_Init(CartInfo *info) { // ---------------------------- Mapper 245 ------------------------------ static void M245CW(uint32 A, uint8 V) { - if (!UNIFchrrama) // Yong Zhe Dou E Long - Dragon Quest VI (As).nes NEEDS THIS for RAM cart + if (!UNIFchrrama) // Yong Zhe Dou E Long - Dragon Quest VI (As).nes NEEDS THIS for RAM cart setchr1(A, V & 7); EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); @@ -1144,7 +1207,7 @@ static void M249PW(uint32 A, uint8 V) { if (EXPREGS[0] & 0x2) { if (V < 0x20) V = (V & 1) | ((V >> 3) & 2) | ((V >> 1) & 4) | ((V << 2) & 8) | ((V << 2) & 0x10); - else{ + else { V -= 0x20; V = (V & 3) | ((V >> 1) & 4) | ((V >> 4) & 8) | ((V >> 2) & 0x10) | ((V << 3) & 0x20) | ((V << 2) & 0xC0); } @@ -1280,6 +1343,7 @@ void TQROM_Init(CartInfo *info) { CHRRAMSIZE = 8192; CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); } void HKROM_Init(CartInfo *info) { diff --git a/source/fceultra/boards/mmc5.cpp b/source/fceultra/boards/mmc5.cpp index 56a55aa..dcb32e4 100644 --- a/source/fceultra/boards/mmc5.cpp +++ b/source/fceultra/boards/mmc5.cpp @@ -88,12 +88,13 @@ static uint8 MMC5LineCounter; static uint8 mmc5psize, mmc5vsize; static uint8 mul[2]; +static uint32 WRAMSIZE = 0; static uint8 *WRAM = NULL; static uint8 *MMC5fill = NULL; static uint8 *ExRAM = NULL; -static uint8 MMC5WRAMsize; -static uint8 MMC5WRAMIndex[8]; +static uint8 MMC5WRAMsize; //configuration, not state +static uint8 MMC5WRAMIndex[8]; //configuration, not state static uint8 MMC5ROMWrProtect[4]; static uint8 MMC5MemIn[5]; @@ -137,7 +138,11 @@ static void mmc5_PPUWrite(uint32 A, uint8 V) { uint8 FASTCALL mmc5_PPURead(uint32 A) { if (A < 0x2000) { - if (ppuphase == PPUPHASE_BG) + if (ppuphase == PPUPHASE_BG + //zero 03-aug-2014 - added this to fix Uchuu Keibitai SDF. The game reads NT entries from CHR rom while PPU is disabled. + //obviously we have enormous numbers of bugs springing from our terrible emulation of ppu-disabled states, but this does the job for fixing this one + && (PPU[1] & 0x10) + ) return *MMC5BGVRAMADR(A); else return MMC5SPRVPage[(A) >> 10][(A)]; } else { @@ -145,51 +150,46 @@ uint8 FASTCALL mmc5_PPURead(uint32 A) { } } - - -// ELROM seems to have 8KB of RAM -// ETROM seems to have 16KB of WRAM -// EWROM seems to have 32KB of WRAM - cartdata MMC5CartList[] = { - { 0x9c18762b, 2 }, /* L'Empereur */ - { 0x26533405, 2 }, - { 0x6396b988, 2 }, - { 0xaca15643, 2 }, /* Uncharted Waters */ - { 0xfe3488d1, 2 }, /* Dai Koukai Jidai */ - { 0x15fe6d0f, 2 }, /* BKAC */ - { 0x39f2ce4b, 2 }, /* Suikoden */ - { 0x8ce478db, 2 }, /* Nobunaga's Ambition 2 */ - { 0xeee9a682, 2 }, - { 0xf9b4240f, 2 }, + { 0x6f4e4312, 4 }, /* Aoki Ookami to Shiroki Mejika - Genchou Hishi */ + { 0x15fe6d0f, 2 }, /* Bandit Kings of Ancient China */ + { 0x671f23a8, 0 }, /* Castlevania III - Dracula's Curse (E) */ + { 0xcd4e7430, 0 }, /* Castlevania III - Dracula's Curse (KC) */ + { 0xed2465be, 0 }, /* Castlevania III - Dracula's Curse (U) */ + { 0xfe3488d1, 2 }, /* Daikoukai Jidai */ + { 0x0ec6c023, 1 }, /* Gemfire */ + { 0x0afb395e, 0 }, /* Gun Sight */ { 0x1ced086f, 2 }, /* Ishin no Arashi */ - { 0xf540677b, 4 }, /* Nobunaga...Bushou Fuuun Roku */ - { 0x6f4e4312, 4 }, /* Aoki Ookami..Genchou */ - { 0xf011e490, 4 }, /* Romance of the 3 Kingdoms 2 */ - { 0x184c2124, 4 }, /* Sangokushi 2 */ - { 0xee8e6553, 4 }, + { 0x9cbadc25, 1 }, /* Just Breed */ + { 0x6396b988, 2 }, /* L'Empereur (J) */ + { 0x9c18762b, 2 }, /* L'Empereur (U) */ + { 0xb0480ae9, 0 }, /* Laser Invasion */ + { 0xb4735fac, 0 }, /* Metal Slader Glory */ + { 0xf540677b, 4 }, /* Nobunaga no Yabou - Bushou Fuuun Roku */ + { 0xeee9a682, 2 }, /* Nobunaga no Yabou - Sengoku Gunyuu Den (J) (PRG0) */ + { 0xf9b4240f, 2 }, /* Nobunaga no Yabou - Sengoku Gunyuu Den (J) (PRG1) */ + { 0x8ce478db, 2 }, /* Nobunaga's Ambition 2 */ + { 0xf011e490, 4 }, /* Romance of The Three Kingdoms II */ + { 0xbc80fb52, 1 }, /* Royal Blood */ + { 0x184c2124, 4 }, /* Sangokushi II (J) (PRG0) */ + { 0xee8e6553, 4 }, /* Sangokushi II (J) (PRG1) */ + { 0xd532e98f, 1 }, /* Shin 4 Nin Uchi Mahjong - Yakuman Tengoku */ + { 0x39f2ce4b, 2 }, /* Suikoden - Tenmei no Chikai */ + { 0xbb7f829a, 0 }, /* Uchuu Keibitai SDF */ + { 0xaca15643, 2 }, /* Uncharted Waters */ }; -#define MMC5_NOCARTS (sizeof(MMC5CartList) / sizeof(MMC5CartList[0])) +#define MMC5_NOCARTS (sizeof(MMC5CartList) / sizeof(MMC5CartList[0])) int DetectMMC5WRAMSize(uint32 crc32) { int x; for (x = 0; x < MMC5_NOCARTS; x++) { if (crc32 == MMC5CartList[x].crc32) { - FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n"); + if(MMC5CartList[x].size > 1) + FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n"); return(MMC5CartList[x].size * 8); } } - - //mbg 04-aug-08 - previously, this was returning 8KB - //but I changed it to return 64 because unlisted carts are probably homebrews, and they should probably use 64 (why not use it all?) - //ch4 10-dec-08 - then f***ng for what all this shit above? let's give em all this 64k shit! Damn - // homebrew must use it's own emulators or standart features. - //adelikat 20-dec-08 - reverting back to return 64, sounds like it was changed back to 8 simply on principle. FCEUX is all encompassing, and that include - //rom-hacking. We want it to be the best emulator for such purposes. So unless return 64 harms compatibility with anything else, I see now reason not to have it - //mbg 29-mar-09 - I should note that mmc5 is in principle capable of 64KB, even if no real carts ever supported it. - //This does not in principle break any games which share this mapper, and it should be OK for homebrew. - //if there are games which need 8KB instead of 64KB default then lets add them to the list return 64; } @@ -197,17 +197,11 @@ static void BuildWRAMSizeTable(void) { int x; for (x = 0; x < 8; x++) { switch (MMC5WRAMsize) { - case 0: MMC5WRAMIndex[x] = 255; break; //X,X,X,X,X,X,X,X - case 1: MMC5WRAMIndex[x] = (x > 3) ? 255 : 0; break; //0,0,0,0,X,X,X,X - case 2: MMC5WRAMIndex[x] = (x & 4) >> 2; break; //0,0,0,0,1,1,1,1 - case 4: MMC5WRAMIndex[x] = (x > 3) ? 255 : (x & 3); break; //0,1,2,3,X,X,X,X - case 8: MMC5WRAMIndex[x] = x; break; //0,1,2,3,4,5,6,7,8 - //mbg 8/6/08 - i added this to support 64KB of wram - //now, I have at least one example (laser invasion) which actually uses size 1 but isnt in the crc list - //so, whereas before my change on 8/4/08 we would have selected size 1, now we select size 8 - //this means that we could have just introduced an emulation bug, in case those games happened to - //address, say, page 3. with size 1 that would resolve to [0] but in size 8 it resolves to [3]. - //so, you know what to do if there are problems. + case 0: MMC5WRAMIndex[x] = 255; break; //X,X,X,X,X,X,X,X + case 1: MMC5WRAMIndex[x] = (x > 3) ? 255 : 0; break; //0,0,0,0,X,X,X,X + case 2: MMC5WRAMIndex[x] = (x & 4) >> 2; break; //0,0,0,0,1,1,1,1 + case 4: MMC5WRAMIndex[x] = (x > 3) ? 255 : (x & 3); break; //0,1,2,3,X,X,X,X + case 8: MMC5WRAMIndex[x] = x; break; //0,1,2,3,4,5,6,7 } } } @@ -277,10 +271,10 @@ static void MMC5CHRB(void) { } static void MMC5WRAM(uint32 A, uint32 V) { - //printf("%02x\n",V); V = MMC5WRAMIndex[V & 7]; if (V != 255) { setprg8r(0x10, A, V); + FCEU_CheatAddRAM(8, 0x6000, (WRAM + ((V * 8192) & (WRAMSIZE - 1)))); MMC5MemIn[(A - 0x6000) >> 13] = 1; } else MMC5MemIn[(A - 0x6000) >> 13] = 0; @@ -349,12 +343,31 @@ static void MMC5PRG(void) { } static DECLFW(Mapper5_write) { - if (A >= 0x5120 && A <= 0x5127) { - mmc5ABMode = 0; - CHRBanksA[A & 7] = V | ((MMC50x5130 & 0x3) << 8); //if we had a test case for this then we could test this, but it hasnt been verified - //CHRBanksA[A&7]=V; - MMC5CHRA(); - } else switch (A) { + switch (A) { + case 0x5100: + mmc5psize = V; + MMC5PRG(); + break; + case 0x5101: + mmc5vsize = V; + if (!mmc5ABMode) { + MMC5CHRB(); + MMC5CHRA(); + } else { + MMC5CHRA(); + MMC5CHRB(); + } + break; + case 0x5102: + WRAMMaskEnable[0] = V; + break; + case 0x5103: + WRAMMaskEnable[1] = V; + break; + case 0x5104: + CHRMode = V; + MMC5HackCHRMode = V & 3; + break; case 0x5105: { int x; @@ -369,53 +382,50 @@ static DECLFW(Mapper5_write) { NTAMirroring = V; break; } - case 0x5113: WRAMPage = V; MMC5WRAM(0x6000, V & 7); break; - case 0x5100: mmc5psize = V; MMC5PRG(); break; - case 0x5101: - mmc5vsize = V; - if (!mmc5ABMode) { - MMC5CHRB(); - MMC5CHRA(); - } else { - MMC5CHRA(); - MMC5CHRB(); + case 0x5106: + if (V != NTFill) + FCEU_dwmemset(MMC5fill, (V | (V << 8) | (V << 16) | (V << 24)), 0x3c0); + NTFill = V; + break; + case 0x5107: + if (V != ATFill) { + unsigned char moop = V | (V << 2) | (V << 4) | (V << 6); + FCEU_dwmemset(MMC5fill + 0x3c0, moop | (moop << 8) | (moop << 16) | (moop << 24), 0x40); } + ATFill = V; + break; + case 0x5113: + WRAMPage = V; + MMC5WRAM(0x6000, V & 7); break; case 0x5114: case 0x5115: case 0x5116: - case 0x5117: PRGBanks[A & 3] = V; MMC5PRG(); break; + case 0x5117: + PRGBanks[A & 3] = V; + MMC5PRG(); + break; + case 0x5120: + case 0x5121: + case 0x5122: + case 0x5123: + case 0x5124: + case 0x5125: + case 0x5126: + case 0x5127: + mmc5ABMode = 0; + CHRBanksA[A & 7] = V | ((MMC50x5130 & 0x3) << 8); + MMC5CHRA(); + break; case 0x5128: case 0x5129: case 0x512a: case 0x512b: mmc5ABMode = 1; - CHRBanksB[A & 3] = V; + CHRBanksB[A & 3] = V | ((MMC50x5130 & 0x3) << 8); MMC5CHRB(); break; - case 0x5102: WRAMMaskEnable[0] = V; break; - case 0x5103: WRAMMaskEnable[1] = V; break; - case 0x5104: CHRMode = V; MMC5HackCHRMode = V & 3; break; - case 0x5106: - if (V != NTFill) { - uint32 t; - t = V | (V << 8) | (V << 16) | (V << 24); - FCEU_dwmemset(MMC5fill, t, 0x3c0); - } - NTFill = V; - break; - case 0x5107: - if (V != ATFill) { - unsigned char moop; - uint32 t; - moop = V | (V << 2) | (V << 4) | (V << 6); - t = moop | (moop << 8) | (moop << 16) | (moop << 24); - FCEU_dwmemset(MMC5fill + 0x3c0, t, 0x40); - } - ATFill = V; - break; case 0x5130: MMC50x5130 = V; break; - case 0x5200: MMC5HackSPMode = V; break; case 0x5201: MMC5HackSPScroll = (V >> 3) & 0x1F; break; case 0x5202: MMC5HackSPPage = V & 0x3F; break; @@ -434,10 +444,11 @@ static DECLFR(MMC5_ReadROMRAM) { } static DECLFW(MMC5_WriteROMRAM) { - if (A >= 0x8000) - if (MMC5ROMWrProtect[(A - 0x8000) >> 13]) return; + if ((A >= 0x8000) && (MMC5ROMWrProtect[(A - 0x8000) >> 13])) + return; if (MMC5MemIn[(A - 0x6000) >> 13]) - if (((WRAMMaskEnable[0] & 3) | ((WRAMMaskEnable[1] & 3) << 2)) == 6) Page[A >> 11][A] = V; + if (((WRAMMaskEnable[0] & 3) | ((WRAMMaskEnable[1] & 3) << 2)) == 6) + Page[A >> 11][A] = V; } static DECLFW(MMC5_ExRAMWr) { @@ -446,17 +457,12 @@ static DECLFW(MMC5_ExRAMWr) { } static DECLFR(MMC5_ExRAMRd) { - // Not sure if this is correct, so I'll comment it out for now. -// if(MMC5HackCHRMode>=2) - return ExRAM[A & 0x3ff]; -// else -// return(X.DB); + return ExRAM[A & 0x3ff]; } static DECLFR(MMC5_read) { switch (A) { - case 0x5204: - { + case 0x5204: { uint8 x; X6502_IRQEnd(FCEU_IQEXT); x = MMC5IRQR; @@ -466,8 +472,10 @@ static DECLFR(MMC5_read) { MMC5IRQR &= 0x40; return x; } - case 0x5205: return(mul[0] * mul[1]); - case 0x5206: return((mul[0] * mul[1]) >> 8); + case 0x5205: + return(mul[0] * mul[1]); + case 0x5206: + return((mul[0] * mul[1]) >> 8); } return(X.DB); } @@ -492,38 +500,56 @@ void MMC5Synco(void) { MMC5CHRA(); MMC5CHRB(); } + + //in case the fill register changed, we need to overwrite the fill buffer + FCEU_dwmemset(MMC5fill, NTFill | (NTFill << 8) | (NTFill << 16) | (NTFill << 24), 0x3c0); { - uint32 t; - t = NTFill | (NTFill << 8) | (NTFill << 16) | (NTFill << 24); - FCEU_dwmemset(MMC5fill, t, 0x3c0); + unsigned char moop = ATFill | (ATFill << 2) | (ATFill << 4) | (ATFill << 6); + FCEU_dwmemset(MMC5fill + 0x3c0, moop | (moop << 8) | (moop << 16) | (moop << 24), 0x40); } - { - unsigned char moop; - uint32 t; - moop = ATFill | (ATFill << 2) | (ATFill << 4) | (ATFill << 6); - t = moop | (moop << 8) | (moop << 16) | (moop << 24); - FCEU_dwmemset(MMC5fill + 0x3c0, t, 0x40); - } - X6502_IRQEnd(FCEU_IQEXT); + MMC5HackCHRMode = CHRMode & 3; + + //zero 17-apr-2013 - why the heck should this happen here? anything in a `synco` should be depending on the state. + //im going to leave it commented out to see what happens + //X6502_IRQEnd(FCEU_IQEXT); } void MMC5_hb(int scanline) { - if (scanline == 240) { + //zero 24-jul-2014 - revised for newer understanding, to fix metal slader glory credits. see r7371 in bizhawk + + int sl = scanline + 1; + int ppuon = (PPU[1] & 0x18); + + if (!ppuon || sl >= 241) + { + // whenever rendering is off for any reason (vblank or forced disable + // the irq counter resets, as well as the inframe flag (easily verifiable from software) + MMC5IRQR &= ~0x40; + MMC5IRQR &= ~0x80; MMC5LineCounter = 0; - MMC5IRQR = 0x40; + X6502_IRQEnd(FCEU_IQEXT); return; } - if (MMC5LineCounter < 240) { - if (MMC5LineCounter == IRQScanline) { + + if (!(MMC5IRQR&0x40)) + { + MMC5IRQR |= 0x40; + MMC5IRQR &= ~0x80; + MMC5LineCounter = 0; + X6502_IRQEnd(FCEU_IQEXT); + } + else + { + MMC5LineCounter++; + if (MMC5LineCounter == IRQScanline) + { MMC5IRQR |= 0x80; if (IRQEnable & 0x80) X6502_IRQBegin(FCEU_IQEXT); } - MMC5LineCounter++; } - if (MMC5LineCounter == 240) - MMC5IRQR = 0; + } void MMC5_StateRestore(int version) { @@ -560,7 +586,7 @@ static void Do5PCM() { } static void Do5PCMHQ() { - uint32 V; //mbg merge 7/17/06 made uint32 + uint32 V; if (!(MMC5Sound.rawcontrol & 0x40) && MMC5Sound.raw) for (V = MMC5Sound.BC[2]; V < SOUNDTS; V++) WaveHi[V] += MMC5Sound.raw << 5; @@ -643,7 +669,7 @@ static void Do5SQ(int P) { static void Do5SQHQ(int P) { static int tal[4] = { 1, 2, 4, 6 }; - uint32 V; //mbg merge 7/17/06 made uint32 + uint32 V; int32 amp, rthresh, wl; wl = MMC5Sound.wl[P] + 1; @@ -726,8 +752,11 @@ void NSFMMC5_Init(void) { } void NSFMMC5_Close(void) { + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; FCEU_gfree(ExRAM); - ExRAM = 0; + ExRAM = NULL; } static void GenMMC5Reset(void) { @@ -759,7 +788,7 @@ static void GenMMC5Reset(void) { SetReadHandler(0x5205, 0x5206, MMC5_read); // GameHBIRQHook=MMC5_hb; - FCEU_CheatAddRAM(8, 0x6000, WRAM); +// FCEU_CheatAddRAM(8, 0x6000, WRAM); FCEU_CheatAddRAM(1, 0x5c00, ExRAM); } @@ -777,6 +806,15 @@ static SFORMAT MMC5_StateRegs[] = { { &NTFill, 1, "NTFL" }, { &ATFill, 1, "ATFL" }, + //zero 17-apr-2013 - added + { &MMC5IRQR, 1, "IRQR" }, + { &MMC5LineCounter, 1, "LCTR" }, + { &mmc5psize, 1, "PSIZ" }, + { &mmc5vsize, 1, "VSIZ" }, + { mul, 2, "MUL2" }, + { MMC5ROMWrProtect, 4, "WRPR" }, + { MMC5MemIn, 5, "MEMI" }, + { &MMC5Sound.wl[0], 2 | FCEUSTATE_RLSB, "SDW0" }, { &MMC5Sound.wl[1], 2 | FCEUSTATE_RLSB, "SDW1" }, { MMC5Sound.env, 2, "SDEV" }, @@ -784,6 +822,15 @@ static SFORMAT MMC5_StateRegs[] = { { &MMC5Sound.running, 1, "SDRU" }, { &MMC5Sound.raw, 1, "SDRW" }, { &MMC5Sound.rawcontrol, 1, "SDRC" }, + + //zero 17-apr-2013 - added + { &MMC5Sound.dcount[0], 4 | FCEUSTATE_RLSB, "DCT0" }, + { &MMC5Sound.dcount[1], 4 | FCEUSTATE_RLSB, "DCT1" }, + { &MMC5Sound.BC[0], 4 | FCEUSTATE_RLSB, "BC00" }, + { &MMC5Sound.BC[1], 4 | FCEUSTATE_RLSB, "BC01" }, + { &MMC5Sound.BC[2], 4 | FCEUSTATE_RLSB, "BC02" }, + { &MMC5Sound.vcount[0], 4 | FCEUSTATE_RLSB, "VCT0" }, + { &MMC5Sound.vcount[1], 4 | FCEUSTATE_RLSB, "VCT1" }, { 0 } }; @@ -797,13 +844,12 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) { MMC5fill = (uint8*)FCEU_gmalloc(1024); ExRAM = (uint8*)FCEU_gmalloc(1024); - AddExState(MMC5_StateRegs, ~0, 0, 0); - AddExState(WRAM, wsize * 1024, 0, "WRAM"); AddExState(ExRAM, 1024, 0, "ERAM"); AddExState(&MMC5HackSPMode, 1, 0, "SPLM"); AddExState(&MMC5HackSPScroll, 1, 0, "SPLS"); AddExState(&MMC5HackSPPage, 1, 0, "SPLP"); AddExState(&MMC50x5130, 1, 0, "5130"); + AddExState(MMC5_StateRegs, ~0, 0, 0); MMC5WRAMsize = wsize / 8; BuildWRAMSizeTable(); @@ -831,28 +877,27 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) { } void Mapper5_Init(CartInfo *info) { - GenMMC5_Init(info, DetectMMC5WRAMSize(info->CRC32), info->battery); + WRAMSIZE = DetectMMC5WRAMSize(info->CRC32); + GenMMC5_Init(info, WRAMSIZE, info->battery); } // ELROM seems to have 0KB of WRAM -// EKROM seems to have 8KB of WRAM -// ETROM seems to have 16KB of WRAM -// EWROM seems to have 32KB of WRAM - -// ETROM and EWROM are battery-backed, EKROM isn't. - -void ETROM_Init(CartInfo *info) { - GenMMC5_Init(info, 16, info->battery); -} +// EKROM seems to have 8KB of WRAM, battery-backed +// ETROM seems to have 16KB of WRAM, battery-backed +// EWROM seems to have 32KB of WRAM, battery-backed void ELROM_Init(CartInfo *info) { GenMMC5_Init(info, 0, 0); } -void EWROM_Init(CartInfo *info) { - GenMMC5_Init(info, 32, info->battery); -} - void EKROM_Init(CartInfo *info) { GenMMC5_Init(info, 8, info->battery); } + +void ETROM_Init(CartInfo *info) { + GenMMC5_Init(info, 16, info->battery); +} + +void EWROM_Init(CartInfo *info) { + GenMMC5_Init(info, 32, info->battery); +} diff --git a/source/fceultra/boards/n106.cpp b/source/fceultra/boards/n106.cpp index 591d2c6..71e189b 100644 --- a/source/fceultra/boards/n106.cpp +++ b/source/fceultra/boards/n106.cpp @@ -264,7 +264,7 @@ static void DoNamcoSoundHQ(void) { lengo = LengthCache[P]; duff2 = FetchDuff(P, envelope); - for (V = CVBC << 1; V < SOUNDTS << 1; V++) { + for (V = CVBC << 1; V < (int)SOUNDTS << 1; V++) { WaveHi[V >> 1] += duff2; if (!vco) { PlayIndex[P] += freq; diff --git a/source/fceultra/boards/onebus.cpp b/source/fceultra/boards/onebus.cpp index 96ce026..8b92fb2 100644 --- a/source/fceultra/boards/onebus.cpp +++ b/source/fceultra/boards/onebus.cpp @@ -32,17 +32,17 @@ static uint8 cpu410x[16], ppu201x[16], apu40xx[64]; // IRQ Registers static uint8 IRQCount, IRQa, IRQReload; -#define IRQLatch cpu410x[0x1] +#define IRQLatch cpu410x[0x1] // accc cccc, a = 0, AD12 switching, a = 1, HSYNC switching // MMC3 Registers -static uint8 inv_hack = 0; // some OneBus Systems have swapped PRG reg commans in MMC3 inplementation, - // trying to autodetect unusual behavior, due not to add a new mapper. -#define mmc3cmd cpu410x[0x5] -#define mirror cpu410x[0x6] +static uint8 inv_hack = 0; // some OneBus Systems have swapped PRG reg commans in MMC3 inplementation, + // trying to autodetect unusual behavior, due not to add a new mapper. +#define mmc3cmd cpu410x[0x5] // pcv- ----, p - program swap, c - video swap, v - internal VRAM enable +#define mirror cpu410x[0x6] // ---- ---m, m = 0 - H, m = 1 - V // APU Registers static uint8 pcm_enable = 0, pcm_irq = 0; -static int16 pcm_addr, pcm_size, pcm_latch, pcm_clock = 0xF6; +static int16 pcm_addr, pcm_size, pcm_latch, pcm_clock = 0xE1; static writefunc defapuwrite[64]; static readfunc defapuread[64]; @@ -113,7 +113,7 @@ static void CSync(void) { setchr1(0x1800 ^ cswap, block | (bank6 & mask)); setchr1(0x1c00 ^ cswap, block | (bank7 & mask)); - setmirror((mirror & 1) ^ 1); + setmirror(mirror & 1); } static void Sync(void) { @@ -124,7 +124,7 @@ static void Sync(void) { static DECLFW(UNLOneBusWriteCPU410X) { // FCEU_printf("CPU %04x:%04x\n",A,V); switch (A & 0xf) { - case 0x1: IRQLatch = V & 0xfe; break; + case 0x1: IRQLatch = V & 0xfe; break; // íċ ïî äàòàĝèòó case 0x2: IRQReload = 1; break; case 0x3: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; break; case 0x4: IRQa = 1; break; @@ -158,7 +158,7 @@ static DECLFW(UNLOneBusWriteMMC3) { } break; } - case 0xa000: mirror = V; CSync(); break; + case 0xa000: mirror = V ^ 1; CSync(); break; case 0xc000: IRQLatch = V & 0xfe; break; case 0xc001: IRQReload = 1; break; case 0xe000: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; break; @@ -180,17 +180,19 @@ static void UNLOneBusIRQHook(void) { } static DECLFW(UNLOneBusWriteAPU40XX) { -// FCEU_printf("APU %04x:%04x\n",A,V); +// if(((A & 0x3f)!=0x16) && ((apu40xx[0x30] & 0x10) || ((A & 0x3f)>0x17)))FCEU_printf("APU %04x:%04x\n",A,V); apu40xx[A & 0x3f] = V; switch (A & 0x3f) { case 0x12: if (apu40xx[0x30] & 0x10) { pcm_addr = V << 6; } + break; case 0x13: if (apu40xx[0x30] & 0x10) { pcm_size = (V << 4) + 1; } + break; case 0x15: if (apu40xx[0x30] & 0x10) { pcm_enable = V & 0x10; @@ -202,6 +204,7 @@ static DECLFW(UNLOneBusWriteAPU40XX) { pcm_latch = pcm_clock; V &= 0xef; } + break; } defapuwrite[A & 0x3f](A, V); } @@ -214,6 +217,7 @@ static DECLFR(UNLOneBusReadAPU40XX) { if (apu40xx[0x30] & 0x10) { result = (result & 0x7f) | pcm_irq; } + break; } return result; } @@ -229,7 +233,8 @@ static void UNLOneBusCpuHook(int a) { pcm_enable = 0; X6502_IRQBegin(FCEU_IQEXT); } else { - uint8 raw_pcm = ARead[pcm_addr](pcm_addr) >> 1; + uint16 addr = pcm_addr | ((apu40xx[0x30]^3) << 14); + uint8 raw_pcm = ARead[addr](addr) >> 1; defapuwrite[0x11](0x4011, raw_pcm); pcm_addr++; pcm_addr &= 0x7FFF; @@ -281,7 +286,7 @@ void UNLOneBus_Init(CartInfo *info) { info->Power = UNLOneBusPower; info->Reset = UNLOneBusReset; - if (((*(uint32*)&(info->MD5)) == 0x305fcdc3) || // PowerJoy Supermax Carts + if (((*(uint32*)&(info->MD5)) == 0x305fcdc3) || // PowerJoy Supermax Carts ((*(uint32*)&(info->MD5)) == 0x6abfce8e)) inv_hack = 0xf; diff --git a/source/fceultra/boards/pec-586.cpp b/source/fceultra/boards/pec-586.cpp index 44c504d..0eac60c 100644 --- a/source/fceultra/boards/pec-586.cpp +++ b/source/fceultra/boards/pec-586.cpp @@ -20,25 +20,27 @@ #include "mapinc.h" -static uint8 reg[7]; +static uint8 reg[8]; +static uint32 lastnt = 0; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; static SFORMAT StateRegs[] = { { reg, 2, "REG" }, + { &lastnt, 4, "LNT" }, { 0 } }; static uint8 bs_tbl[128] = { - 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, - 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, - 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, - 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, - 0x02, 0x12, 0x22, 0x32, 0x02, 0x12, 0x22, 0x32, 0x02, 0x12, 0x22, 0x32, 0x02, 0x12, 0x22, 0x32, - 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, - 0x02, 0x12, 0x22, 0x32, 0x02, 0x12, 0x22, 0x32, 0x02, 0x12, 0x22, 0x32, 0x00, 0x10, 0x20, 0x30, - 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, + 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, // 00 + 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, // 10 + 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, 0x03, 0x13, 0x23, 0x33, // 20 + 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, // 30 + 0x02, 0x12, 0x22, 0x32, 0x02, 0x12, 0x22, 0x32, 0x02, 0x12, 0x22, 0x32, 0x02, 0x12, 0x22, 0x32, // 40 + 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, 0x45, 0x67, // 50 + 0x02, 0x12, 0x22, 0x32, 0x02, 0x12, 0x22, 0x32, 0x02, 0x12, 0x22, 0x32, 0x00, 0x10, 0x20, 0x30, // 60 + 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, 0x47, 0x67, // 70 }; static uint8 br_tbl[16] = { @@ -46,48 +48,60 @@ static uint8 br_tbl[16] = { }; static void Sync(void) { -// setchr4(0x0000,(reg[0]&0x80) >> 7); -// setchr4(0x1000,(reg[0]&0x80) >> 7); setchr8(0); setprg8r(0x10, 0x6000, 0); - setprg16(0x8000, bs_tbl[reg[0] & 0x7f] >> 4); - setprg16(0xc000, bs_tbl[reg[0] & 0x7f] & 0xf); - setmirror(MI_V); + if(PRGsize[0] == 512 * 1024) { + if(reg[0] & 0x010) { + setprg32(0x8000, reg[0] & 7); + } else { + if(reg[0] & 0x40) + setprg8(0x8000, (reg[0] & 0x0F) | 0x20 | ((reg[0] & 0x20) >> 1)); + } + if((reg[0] & 0x18) == 0x18) + setmirror(MI_H); + else + setmirror(MI_V); + } else { + setprg16(0x8000, bs_tbl[reg[0] & 0x7f] >> 4); + setprg16(0xc000, bs_tbl[reg[0] & 0x7f] & 0xf); + setmirror(MI_V); + } } static DECLFW(UNLPEC586Write) { reg[(A & 0x700) >> 8] = V; - FCEU_printf("bs %04x %02x\n", A, V); + PEC586Hack = (reg[0] & 0x80) >> 7; +// FCEU_printf("bs %04x %02x\n", A, V); Sync(); } static DECLFR(UNLPEC586Read) { - FCEU_printf("read %04x\n", A); +// FCEU_printf("read %04x\n", A); return (X.DB & 0xD8) | br_tbl[reg[4] >> 4]; } -static void UNLPEC586Power(void) { - reg[0] = 0x0E; - Sync(); - setchr8(0); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x5000, 0x5fff, UNLPEC586Write); - SetReadHandler(0x5000, 0x5fff, UNLPEC586Read); +static DECLFR(UNLPEC586ReadHi) { + if((reg[0] & 0x10) || ((reg[0] & 0x40) && (A < 0xA000))) + return CartBR(A); + else + return PRGptr[0][((0x0107 | ((A >> 7) & 0x0F8)) << 10) | (A & 0x3FF)]; } -static void UNLPEC586IRQ(void) { -// if(reg[0]&0x80) - { - if (scanline == 128) { - setchr4(0x0000, 1); - setchr4(0x1000, 0); - } else { - setchr4(0x0000, 0); - setchr4(0x1000, 1); - } - } +static void UNLPEC586Power(void) { + if(PRGsize[0] == 512 * 1024) + reg[0] = 0x00; + else + reg[0] = 0x0E; + Sync(); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + if(PRGsize[0] == 512 * 1024) + SetReadHandler(0x8000, 0xFFFF, UNLPEC586ReadHi); + else + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x5000, 0x5fff, UNLPEC586Write); + SetReadHandler(0x5000, 0x5fff, UNLPEC586Read); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void UNLPEC586Close(void) { @@ -103,7 +117,6 @@ static void StateRestore(int version) { void UNLPEC586Init(CartInfo *info) { info->Power = UNLPEC586Power; info->Close = UNLPEC586Close; - GameHBIRQHook = UNLPEC586IRQ; GameStateRestore = StateRestore; WRAMSIZE = 8192; diff --git a/source/fceultra/boards/sb-2000.cpp b/source/fceultra/boards/sb-2000.cpp new file mode 100644 index 0000000..6a60b3f --- /dev/null +++ b/source/fceultra/boards/sb-2000.cpp @@ -0,0 +1,195 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2014 CaH4e3 + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mapinc.h" + +static uint8 preg[8]; +static uint8 IRQa; +static int16 IRQCount, IRQLatch; +static uint8 *WRAM = NULL; +static uint32 WRAMSIZE; +/* +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE; +*/ + +static SFORMAT StateRegs[] = +{ + { preg, 8, "PREG" }, + { &IRQa, 1, "IRQA" }, + { &IRQCount, 2, "IRQC" }, + { &IRQLatch, 2, "IRQL" }, + { 0 } +}; + +static void Sync(void) { + setchr8(0); + setprg8r(0x10, 0x6000, 0); + if(preg[0] & 0x80) + setprg4r(0x10,0x8000,preg[0] & 0x7f); + else + setprg4(0x8000,preg[0] & 0x7f); + if(preg[1] & 0x80) + setprg4r(0x10,0x9000,preg[1] & 0x7f); + else + setprg4(0x9000,preg[1] & 0x7f); + if(preg[2] & 0x80) + setprg4r(0x10,0xa000,preg[2] & 0x7f); + else + setprg4(0xa000,preg[2] & 0x7f); + if(preg[3] & 0x80) + setprg4r(0x10,0xb000,preg[3] & 0x7f); + else + setprg4(0xb000,preg[3] & 0x7f); +/* + if(preg[4] & 0x80) + setprg4r(0x10,0xc000,preg[4] & 0x7f); + else + setprg4(0xc000,preg[4] & 0x7f); + if(preg[5] & 0x80) + setprg4r(0x10,0xd000,preg[5] & 0x7f); + else + setprg4(0xd000,preg[5] & 0x7f); + if(preg[6] & 0x80) + setprg4r(0x10,0xe000,preg[6] & 0x7f); + else + setprg4(0xe000,preg[6] & 0x7f); + if(preg[7] & 0x80) + setprg4r(0x10,0xf000,preg[7] & 0x7f); + else + setprg4(0xf000,preg[7] & 0x7f); +*/ + setprg16(0xC000,1); +} + +static DECLFR(UNLSB2000Read) { + switch(A) { + case 0x4033: // IRQ flags + X6502_IRQEnd(FCEU_IQFCOUNT); + return 0xff; +// case 0x4204: // unk +// return 0xff; +// case 0x4205: // unk +// return 0xff; + default: + FCEU_printf("unk read: %04x\n",A); +// break; + return 0xff; // needed to prevent C4715 warning? + } +} + +static DECLFW(UNLSB2000Write) { + switch(A) { + case 0x4027: // PCM output + BWrite[0x4015](0x4015, 0x10); + BWrite[0x4011](0x4011, V >> 1); + break; + case 0x4032: // IRQ mask + IRQa &= ~V; +// X6502_IRQEnd(FCEU_IQEXT); + break; + case 0x4040: + case 0x4041: + case 0x4042: + case 0x4043: + case 0x4044: + case 0x4045: + case 0x4046: + case 0x4047: +// FCEU_printf("bank write: %04x:%02x\n",A,V); + preg[A&7] = V; + Sync(); + break; + default: +// FCEU_printf("unk write: %04x:%02x\n",A,V); + break; + } +} + +static void UNLSB2000Reset(void) { + preg[0] = 0; + preg[1] = 1; + preg[2] = 2; + preg[3] = 3; + preg[4] = 4; + preg[5] = 5; + preg[6] = 6; + preg[7] = 7; + IRQa = 0; +// BWrite[0x4017](0x4017,0xC0); +// BWrite[0x4015](0x4015,0x1F); +} + +static void UNLSB2000Power(void) { + UNLSB2000Reset(); + Sync(); + SetReadHandler(0x6000, 0x7fff, CartBR); + SetWriteHandler(0x6000, 0x7fff, CartBW); + SetReadHandler(0x8000, 0xffff, CartBR); + SetWriteHandler(0x8000, 0xbfff, CartBW); + SetWriteHandler(0x4020, 0x5fff, UNLSB2000Write); + SetReadHandler(0x4020, 0x5fff, UNLSB2000Read); +} + +static void UNLSB2000Close(void) +{ + if (WRAM) + FCEU_gfree(WRAM); +/* + if (CHRRAM) + FCEU_gfree(CHRRAM); +*/ + WRAM = /*CHRRAM = */NULL; +} +/* +static void UNLSB2000IRQHook() { + X6502_IRQBegin(FCEU_IQEXT); +} +*/ +static void StateRestore(int version) { + Sync(); +} + +void UNLSB2000_Init(CartInfo *info) { + info->Reset = UNLSB2000Reset; + info->Power = UNLSB2000Power; + info->Close = UNLSB2000Close; +// GameHBIRQHook = UNLSB2000IRQHook; + GameStateRestore = StateRestore; +/* + CHRRAMSIZE = 8192; + CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); +*/ + +// SetupCartCHRMapping(0, PRGptr[0], PRGsize[0], 0); + + WRAMSIZE = 512 * 1024; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/sc-127.cpp b/source/fceultra/boards/sc-127.cpp index ed466ca..2d2d968 100644 --- a/source/fceultra/boards/sc-127.cpp +++ b/source/fceultra/boards/sc-127.cpp @@ -31,16 +31,18 @@ static SFORMAT StateRegs[] = { { reg, 8, "REGS" }, { chr, 8, "CHRS" }, - { &IRQCount, 16, "IRQc" }, - { &IRQa, 16, "IRQa" }, + { &IRQCount, 2, "IRQc" }, + { &IRQa, 2, "IRQa" }, { 0 } }; static void Sync(void) { int i; + setprg8r(0x10, 0x6000, 0); setprg8(0x8000, reg[0]); setprg8(0xA000, reg[1]); setprg8(0xC000, reg[2]); + setprg8(0xE000, ~0); for (i = 0; i < 8; i++) setchr1(i << 10, chr[i]); setmirror(reg[3] ^ 1); @@ -67,20 +69,26 @@ static DECLFW(UNLSC127Write) { Sync(); } +static DECLFR(UNLSC127ProtRead) { + return 0x20; +} + static void UNLSC127Power(void) { + IRQCount = IRQa = 0; Sync(); - setprg8r(0x10, 0x6000, 0); - setprg8(0xE000, ~0); + SetReadHandler(0x5800, 0x5800, UNLSC127ProtRead); SetReadHandler(0x6000, 0x7fff, CartBR); SetWriteHandler(0x6000, 0x7fff, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, UNLSC127Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void UNLSC127IRQ(void) { if (IRQa) { - IRQCount--; - if (IRQCount == 0) { + if(IRQCount > 0) + IRQCount--; + if (!IRQCount) { X6502_IRQBegin(FCEU_IQEXT); IRQa = 0; } @@ -88,6 +96,7 @@ static void UNLSC127IRQ(void) { } static void UNLSC127Reset(void) { + IRQCount = IRQa = 0; } static void UNLSC127Close(void) { diff --git a/source/fceultra/boards/supervision.cpp b/source/fceultra/boards/supervision.cpp index 5dae765..46be8ed 100644 --- a/source/fceultra/boards/supervision.cpp +++ b/source/fceultra/boards/supervision.cpp @@ -21,45 +21,67 @@ #include "mapinc.h" static uint8 cmd0, cmd1; +static SFORMAT StateRegs[] = +{ + { &cmd0, 1, "L1" }, + { &cmd1, 1, "L2" }, + { 0 } +}; -static void DoSuper(void) { - setprg8r((cmd0 & 0xC) >> 2, 0x6000, ((cmd0 & 0x3) << 4) | 0xF); +static void Sync(void) { + setchr8(0); + if (PRGptr[1]) + setprg8r((cmd0 & 0xC) >> 2, 0x6000, ((cmd0 & 0x3) << 4) | 0xF); + else + setprg8(0x6000, (((cmd0 & 0xF) << 4) | 0xF) + 4); if (cmd0 & 0x10) { - setprg16r((cmd0 & 0xC) >> 2, 0x8000, ((cmd0 & 0x3) << 3) | (cmd1 & 7)); - setprg16r((cmd0 & 0xC) >> 2, 0xc000, ((cmd0 & 0x3) << 3) | 7); + if (PRGptr[1]) { + setprg16r((cmd0 & 0xC) >> 2, 0x8000, ((cmd0 & 0x3) << 3) | (cmd1 & 7)); + setprg16r((cmd0 & 0xC) >> 2, 0xc000, ((cmd0 & 0x3) << 3) | 7); + } else { + setprg16(0x8000, (((cmd0 & 0xF) << 3) | (cmd1 & 7)) + 2); + setprg16(0xc000, (((cmd0 & 0xF) << 3) | 7) + 2); + } } else - setprg32r(4, 0x8000, 0); + if (PRGptr[4]) + setprg32r(4, 0x8000, 0); + else + setprg32(0x8000, 0); setmirror(((cmd0 & 0x20) >> 5) ^ 1); } -static DECLFW(SuperWrite) { +static DECLFW(SuperWriteLo) { if (!(cmd0 & 0x10)) { cmd0 = V; - DoSuper(); + Sync(); } } -static DECLFW(SuperHi) { +static DECLFW(SuperWriteHi) { cmd1 = V; - DoSuper(); + Sync(); +} + +static void SuperPower(void) { + SetWriteHandler(0x6000, 0x7FFF, SuperWriteLo); + SetWriteHandler(0x8000, 0xFFFF, SuperWriteHi); + SetReadHandler(0x6000, 0xFFFF, CartBR); + cmd0 = cmd1 = 0; + Sync(); } static void SuperReset(void) { - SetWriteHandler(0x6000, 0x7FFF, SuperWrite); - SetWriteHandler(0x8000, 0xFFFF, SuperHi); - SetReadHandler(0x6000, 0xFFFF, CartBR); cmd0 = cmd1 = 0; - setprg32r(4, 0x8000, 0); - setchr8(0); + Sync(); } static void SuperRestore(int version) { - DoSuper(); + Sync(); } void Supervision16_Init(CartInfo *info) { - AddExState(&cmd0, 1, 0, "L1"); - AddExState(&cmd1, 1, 0, "L2"); - info->Power = SuperReset; + info->Power = SuperPower; + info->Reset = SuperReset; GameStateRestore = SuperRestore; + AddExState(&StateRegs, ~0, 0, 0); } diff --git a/source/fceultra/boards/t-262.cpp b/source/fceultra/boards/t-262.cpp index 0b41999..01b873b 100644 --- a/source/fceultra/boards/t-262.cpp +++ b/source/fceultra/boards/t-262.cpp @@ -20,26 +20,28 @@ #include "mapinc.h" -static uint8 bank, base, lock, mirr; +static uint8 bank, base, lock, mirr, mode; static SFORMAT StateRegs[] = { { &bank, 1, "BANK" }, { &base, 1, "BASE" }, { &lock, 1, "LOCK" }, { &mirr, 1, "MIRR" }, + { &mode, 1, "MODE" }, { 0 } }; static void Sync(void) { setchr8(0); setprg16(0x8000, base | bank); - setprg16(0xC000, base | 7); + setprg16(0xC000, base | (mode ? bank : 7)); setmirror(mirr); } static DECLFW(BMCT262Write) { if (!lock) { base = ((A & 0x60) >> 2) | ((A & 0x100) >> 3); + mode = A & 0x80; mirr = ((A & 2) >> 1) ^ 1; lock = (A & 0x2000) >> 13; } @@ -48,14 +50,14 @@ static DECLFW(BMCT262Write) { } static void BMCT262Power(void) { - lock = bank = base = 0; + lock = bank = base = mode = 0; Sync(); SetWriteHandler(0x8000, 0xFFFF, BMCT262Write); SetReadHandler(0x8000, 0xFFFF, CartBR); } static void BMCT262Reset(void) { - lock = bank = base = 0; + lock = bank = base = mode = 0; Sync(); } diff --git a/source/fceultra/boards/transformer.cpp b/source/fceultra/boards/transformer.cpp index 0f9c4a6..b125255 100644 --- a/source/fceultra/boards/transformer.cpp +++ b/source/fceultra/boards/transformer.cpp @@ -71,6 +71,7 @@ static void TransformerPower(void) { SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); MapIRQHook = TransformerIRQHook; } diff --git a/source/fceultra/boards/unrom512.cpp b/source/fceultra/boards/unrom512.cpp new file mode 100644 index 0000000..a52e0e6 --- /dev/null +++ b/source/fceultra/boards/unrom512.cpp @@ -0,0 +1,269 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2014 CaitSith2 + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Roms still using NES 1.0 format should be loaded as 32K CHR RAM. + * Roms defined under NES 2.0 should use the VRAM size field, defining 7, 8 or 9, based on how much VRAM should be present. + * UNIF doesn't have this problem, because unique board names can define this information. + * The UNIF names are UNROM-512-8K, UNROM-512-16K and UNROM-512-32K + * + * The battery flag in the NES header enables flash, Mirrror mode 2 Enables MI_0 and MI_1 mode. + * Known games to use this board are: + * Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled) + * Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled) + * Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space), + * it otherwise functions identically. +*/ + +#include "mapinc.h" +#include "../ines.h" + +static uint8 latche, latcheinit, bus_conflict, chrram_mask, software_id=false; +static uint16 latcha; +static uint8 *flashdata; +static uint32 *flash_write_count; +static uint8 *FlashPage[32]; +static uint32 *FlashWriteCountPage[32]; +static uint8 flashloaded = false; + +static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank; +static void (*WLSync)(void); +static void (*WHSync)(void); + +static INLINE void setfpageptr(int s, uint32 A, uint8 *p) { + uint32 AB = A >> 11; + int x; + + if (p) + for (x = (s >> 1) - 1; x >= 0; x--) { + FlashPage[AB + x] = p - A; + } + else + for (x = (s >> 1) - 1; x >= 0; x--) { + FlashPage[AB + x] = 0; + } +} + +void setfprg16(uint32 A, uint32 V) { + if (PRGsize[0] >= 16384) { + V &= PRGmask16[0]; + setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0); + } else { + uint32 VA = V << 3; + int x; + + for (x = 0; x < 8; x++) + setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0); + } +} + +void inc_flash_write_count(uint8 bank, uint32 A) +{ + flash_write_count[(bank*4) + ((A&0x3000)>>12)]++; + if(!flash_write_count[(bank*4) + ((A&0x3000)>>12)]) + flash_write_count[(bank*4) + ((A&0x3000)>>12)]++; +} + +uint32 GetFlashWriteCount(uint8 bank, uint32 A) +{ + return flash_write_count[(bank*4) + ((A&0x3000)>>12)]; +} + +static void StateRestore(int version) { + WHSync(); +} + +static DECLFW(UNROM512LLatchWrite) +{ + latche = V; + latcha = A; + WLSync(); +} + +static DECLFW(UNROM512HLatchWrite) +{ + if (bus_conflict) + latche = (V == CartBR(A)) ? V : 0; + else + latche = V; + latcha = A; + WHSync(); +} + +static DECLFR(UNROM512LatchRead) +{ + uint8 flash_id[3]={0xB5,0xB6,0xB7}; + if(software_id) + { + if(A&1) + return flash_id[ROM_size>>4]; + else + return 0xBF; + } + if(flash_save) + { + if(A < 0xC000) + { + if(GetFlashWriteCount(flash_bank,A)) + return FlashPage[A >> 11][A]; + } + else + { + if(GetFlashWriteCount(ROM_size-1,A)) + return FlashPage[A >> 11][A]; + } + } + return Page[A >> 11][A]; +} + +static void UNROM512LatchPower(void) { + latche = latcheinit; + WHSync(); + SetReadHandler(0x8000, 0xFFFF, UNROM512LatchRead); + if(!flash_save) + SetWriteHandler(0x8000, 0xFFFF, UNROM512HLatchWrite); + else + { + SetWriteHandler(0x8000,0xBFFF,UNROM512LLatchWrite); + SetWriteHandler(0xC000,0xFFFF,UNROM512HLatchWrite); + } +} + +static void UNROM512LatchClose(void) { + if(flash_write_count) + FCEU_gfree(flash_write_count); + if(flashdata) + FCEU_gfree(flashdata); + flash_write_count = NULL; + flashdata = NULL; +} + + +static void UNROM512LSync() { + int erase_a[5]={0x9555,0xAAAA,0x9555,0x9555,0xAAAA}; + int erase_d[5]={0xAA,0x55,0x80,0xAA,0x55}; + int erase_b[5]={1,0,1,1,0}; + + if(flash_mode==0) + { + if((latcha == erase_a[flash_state]) && (latche == erase_d[flash_state]) && (flash_bank == erase_b[flash_state])) + { + flash_state++; + if(flash_state == 5) + { + flash_mode=1; + } + } + else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0xA0)&&(flash_bank==1)) + { + flash_state++; + flash_mode=2; + } + else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0x90)&&(flash_bank==1)) + { + flash_state=0; + software_id=true; + } + else + { + if(latche==0xF0) + software_id=false; + flash_state=0; + } + } + else if(flash_mode==1) //Chip Erase or Sector Erase + { + if(latche==0x30) + { + inc_flash_write_count(flash_bank,latcha); + memset(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],0xFF,0x1000); + } + else if (latche==0x10) + { + for(int i=0;i<(ROM_size*4);i++) + inc_flash_write_count(i>>2,i<<12); + memset(flashdata,0xFF,ROM_size*0x4000); //Erasing the rom chip as instructed. Crash rate calulated to be 99.9% :) + } + flash_state=0; + flash_mode=0; + } + else if(flash_mode==2) //Byte Program + { + if(!GetFlashWriteCount(flash_bank,latcha)) + { + inc_flash_write_count(flash_bank,latcha); + memcpy(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],&Page[(latcha & 0xF000)>>11][latcha & 0xF000],0x1000); + } + FlashPage[latcha>>11][latcha]&=latche; + flash_state=0; + flash_mode=0; + } +} + +static void UNROM512HSync() +{ + flash_bank=latche&(ROM_size-1); + + setprg16(0x8000, flash_bank); + setprg16(0xc000, ~0); + setfprg16(0x8000, flash_bank); + setfprg16(0xC000, ~0); + setchr8r(0, (latche & chrram_mask) >> 5); + setmirror(MI_0+(latche>>7)); +} + +void UNROM512_Init(CartInfo *info) { + flash_state=0; + flash_bank=0; + flash_save=info->battery; + + if(info->vram_size == 8192) + chrram_mask = 0; + else if (info->vram_size == 16384) + chrram_mask = 0x20; + else + chrram_mask = 0x60; + + SetupCartMirroring(info->mirror,(info->mirror>=MI_0)?0:1,0); + bus_conflict = !info->battery; + latcheinit = 0; + WLSync = UNROM512LSync; + WHSync = UNROM512HSync; + info->Power = UNROM512LatchPower; + info->Close = UNROM512LatchClose; + GameStateRestore = StateRestore; + if(flash_save) + { + flashdata = (uint8*)FCEU_gmalloc(ROM_size*0x4000); + flash_write_count = (uint32*)FCEU_gmalloc(ROM_size*4*sizeof(uint32)); + info->SaveGame[0] = (uint8*)flash_write_count; + info->SaveGame[1] = flashdata; + info->SaveGameLen[0] = ROM_size*4*sizeof(uint32); + info->SaveGameLen[1] = ROM_size*0x4000; + AddExState(flash_write_count,ROM_size*4*sizeof(uint32),0,"FLASH_WRITE_COUNT"); + AddExState(flashdata,ROM_size*0x4000,0,"FLASH_DATA"); + AddExState(&flash_state,1,0,"FLASH_STATE"); + AddExState(&flash_mode,1,0,"FLASH_MODE"); + AddExState(&flash_bank,1,0,"FLASH_BANK"); + AddExState(&latcha,2,0,"LATA"); + } + AddExState(&latche, 1, 0, "LATC"); + AddExState(&bus_conflict, 1, 0, "BUSC"); +} \ No newline at end of file diff --git a/source/fceultra/boards/vrc2and4.cpp b/source/fceultra/boards/vrc2and4.cpp index 58e6d86..571e4a8 100644 --- a/source/fceultra/boards/vrc2and4.cpp +++ b/source/fceultra/boards/vrc2and4.cpp @@ -169,6 +169,7 @@ static void M23Power(void) { SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M23Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M25Power(void) { @@ -179,6 +180,7 @@ static void M25Power(void) { SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M22Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } void VRC24IRQHook(int a) { diff --git a/source/fceultra/boards/vrc3.cpp b/source/fceultra/boards/vrc3.cpp index 8369100..f6471ae 100644 --- a/source/fceultra/boards/vrc3.cpp +++ b/source/fceultra/boards/vrc3.cpp @@ -106,6 +106,7 @@ static void M73Power(void) { SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x8000, 0xFFFF, M73Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M73Close(void) diff --git a/source/fceultra/boards/konami-qtai.cpp b/source/fceultra/boards/vrc5.cpp similarity index 96% rename from source/fceultra/boards/konami-qtai.cpp rename to source/fceultra/boards/vrc5.cpp index 0b43937..43f7918 100644 --- a/source/fceultra/boards/konami-qtai.cpp +++ b/source/fceultra/boards/vrc5.cpp @@ -1,225 +1,226 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2005 CaH4e3 - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * VRC-5 (CAI Shogakko no Sansu) - * - */ - -#include "mapinc.h" - -static uint8 QTAINTRAM[2048]; -static writefunc old2007wrap; - -static uint16 CHRSIZE = 8192; -static uint16 WRAMSIZE = 8192 + 4096; -static uint8 *CHRRAM = NULL; -static uint8 *WRAM = NULL; - -static uint8 IRQa, K4IRQ; -static uint32 IRQLatch, IRQCount; - -static uint8 regs[16]; -//static uint8 test[8]; -static SFORMAT StateRegs[] = -{ - { &IRQCount, 1, "IRQC" }, - { &IRQLatch, 1, "IRQL" }, - { &IRQa, 1, "IRQA" }, - { &K4IRQ, 1, "KIRQ" }, - { regs, 16, "REGS" }, - { 0 } -}; - -static void chrSync(void) { - setchr4r(0x10, 0x0000, regs[5] & 1); - setchr4r(0x10, 0x1000, 0); -} - -static void Sync(void) { - chrSync(); -// if(regs[0xA]&0x10) -// { -/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0); - setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1); - setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2); - setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3); - setchr1r(0x10,0x1000,0); - setchr1r(0x10,0x1400,1); - setchr1r(0x10,0x1800,2); - setchr1r(0x10,0x1c00,3);*/ -/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0); - setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1); - setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2); - setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3); - setchr1r(0x10,0x1000,(((regs[5]&1)^1)<<2)+4); - setchr1r(0x10,0x1400,(((regs[5]&1)^1)<<2)+5); - setchr1r(0x10,0x1800,(((regs[5]&1)^1)<<2)+6); - setchr1r(0x10,0x1c00,(((regs[5]&1)^1)<<2)+7); -*/ -// } -// else -// { -/* - setchr1r(0x10,0x0000,(((regs[5]&1)^1)<<2)+0); - setchr1r(0x10,0x0400,(((regs[5]&1)^1)<<2)+1); - setchr1r(0x10,0x0800,(((regs[5]&1)^1)<<2)+2); - setchr1r(0x10,0x0c00,(((regs[5]&1)^1)<<2)+3); - setchr1r(0x10,0x1000,(((regs[5]&1))<<2)+4); - setchr1r(0x10,0x1400,(((regs[5]&1))<<2)+5); - setchr1r(0x10,0x1800,(((regs[5]&1))<<2)+6); - setchr1r(0x10,0x1c00,(((regs[5]&1))<<2)+7); -// } -//*/ -/* setchr1r(1,0x0000,test[0]); - setchr1r(1,0x0400,test[1]); - setchr1r(1,0x0800,test[2]); - setchr1r(1,0x0c00,test[3]); - setchr1r(1,0x1000,test[4]); - setchr1r(1,0x1400,test[5]); - setchr1r(1,0x1800,test[6]); - setchr1r(1,0x1c00,test[7]); -*/ - setprg4r(0x10, 0x6000, regs[0] & 1); - if (regs[2] >= 0x40) - setprg8r(1, 0x8000, (regs[2] - 0x40)); - else - setprg8r(0, 0x8000, (regs[2] & 0x3F)); - if (regs[3] >= 0x40) - setprg8r(1, 0xA000, (regs[3] - 0x40)); - else - setprg8r(0, 0xA000, (regs[3] & 0x3F)); - if (regs[4] >= 0x40) - setprg8r(1, 0xC000, (regs[4] - 0x40)); - else - setprg8r(0, 0xC000, (regs[4] & 0x3F)); - - setprg8r(1, 0xE000, ~0); - setmirror(MI_V); -} - -/*static DECLFW(TestWrite) -{ - test[A&7] = V; - Sync(); -}*/ - -static DECLFW(M190Write) { -// FCEU_printf("write %04x:%04x %d, %d\n",A,V,scanline,timestamp); - regs[(A & 0x0F00) >> 8] = V; - switch (A) { - case 0xd600: IRQLatch &= 0xFF00; IRQLatch |= V; break; - case 0xd700: IRQLatch &= 0x00FF; IRQLatch |= V << 8; break; - case 0xd900: IRQCount = IRQLatch; IRQa = V & 2; K4IRQ = V & 1; X6502_IRQEnd(FCEU_IQEXT); break; - case 0xd800: IRQa = K4IRQ; X6502_IRQEnd(FCEU_IQEXT); break; - } - Sync(); -} - -static DECLFR(M190Read) { -// FCEU_printf("read %04x:%04x %d, %d\n",A,regs[(A&0x0F00)>>8],scanline,timestamp); - return regs[(A & 0x0F00) >> 8] + regs[0x0B]; -} -static void VRC5IRQ(int a) { - if (IRQa) { - IRQCount += a; - if (IRQCount & 0x10000) { - X6502_IRQBegin(FCEU_IQEXT); - IRQCount = IRQLatch; - } - } -} - -//static void Mapper190_PPU(uint32 A) -//{ -// if(A<0x2000) -// setchr4r(0x10,0x1000,QTAINTRAM[A&0x1FFF]&1); -// else -// chrSync(); -//} - -static DECLFW(M1902007Wrap) { - if (A >= 0x2000) { - if (regs[0xA] & 1) - QTAINTRAM[A & 0x1FFF] = V; - else - old2007wrap(A, V); - } -} - - -static void M190Power(void) { -/* test[0]=0; - test[1]=1; - test[2]=2; - test[3]=3; - test[4]=4; - test[5]=5; - test[6]=6; - test[7]=7; -*/ - setprg4r(0x10, 0x7000, 2); - - old2007wrap = GetWriteHandler(0x2007); - SetWriteHandler(0x2007, 0x2007, M1902007Wrap); - - SetReadHandler(0x6000, 0xFFFF, CartBR); -// SetWriteHandler(0x5000,0x5007,TestWrite); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x8000, 0xFFFF, M190Write); - SetReadHandler(0xDC00, 0xDC00, M190Read); - SetReadHandler(0xDD00, 0xDD00, M190Read); - Sync(); -} - -static void M190Close(void) { - if (CHRRAM) - FCEU_gfree(CHRRAM); - CHRRAM = NULL; - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper190_Init(CartInfo *info) { - info->Power = M190Power; - info->Close = M190Close; - GameStateRestore = StateRestore; - - MapIRQHook = VRC5IRQ; -// PPU_hook=Mapper190_PPU; - - CHRRAM = (uint8*)FCEU_gmalloc(CHRSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRSIZE, 1); - AddExState(CHRRAM, CHRSIZE, 0, "CRAM"); - - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE - 4096; - } - - AddExState(&StateRegs, ~0, 0, 0); -} +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2005 CaH4e3 + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * VRC-5 (CAI Shogakko no Sansu) + * + */ + +#include "mapinc.h" + +static uint8 QTAINTRAM[2048]; +static writefunc old2007wrap; + +static uint16 CHRSIZE = 8192; +static uint16 WRAMSIZE = 8192 + 4096; +static uint8 *CHRRAM = NULL; +static uint8 *WRAM = NULL; + +static uint8 IRQa, K4IRQ; +static uint32 IRQLatch, IRQCount; + +static uint8 regs[16]; +//static uint8 test[8]; +static SFORMAT StateRegs[] = +{ + { &IRQCount, 1, "IRQC" }, + { &IRQLatch, 1, "IRQL" }, + { &IRQa, 1, "IRQA" }, + { &K4IRQ, 1, "KIRQ" }, + { regs, 16, "REGS" }, + { 0 } +}; + +static void chrSync(void) { + setchr4r(0x10, 0x0000, regs[5] & 1); + setchr4r(0x10, 0x1000, 0); +} + +static void Sync(void) { + chrSync(); +// if(regs[0xA]&0x10) +// { +/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0); + setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1); + setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2); + setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3); + setchr1r(0x10,0x1000,0); + setchr1r(0x10,0x1400,1); + setchr1r(0x10,0x1800,2); + setchr1r(0x10,0x1c00,3);*/ +/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0); + setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1); + setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2); + setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3); + setchr1r(0x10,0x1000,(((regs[5]&1)^1)<<2)+4); + setchr1r(0x10,0x1400,(((regs[5]&1)^1)<<2)+5); + setchr1r(0x10,0x1800,(((regs[5]&1)^1)<<2)+6); + setchr1r(0x10,0x1c00,(((regs[5]&1)^1)<<2)+7); +*/ +// } +// else +// { +/* + setchr1r(0x10,0x0000,(((regs[5]&1)^1)<<2)+0); + setchr1r(0x10,0x0400,(((regs[5]&1)^1)<<2)+1); + setchr1r(0x10,0x0800,(((regs[5]&1)^1)<<2)+2); + setchr1r(0x10,0x0c00,(((regs[5]&1)^1)<<2)+3); + setchr1r(0x10,0x1000,(((regs[5]&1))<<2)+4); + setchr1r(0x10,0x1400,(((regs[5]&1))<<2)+5); + setchr1r(0x10,0x1800,(((regs[5]&1))<<2)+6); + setchr1r(0x10,0x1c00,(((regs[5]&1))<<2)+7); +// } +//*/ +/* setchr1r(1,0x0000,test[0]); + setchr1r(1,0x0400,test[1]); + setchr1r(1,0x0800,test[2]); + setchr1r(1,0x0c00,test[3]); + setchr1r(1,0x1000,test[4]); + setchr1r(1,0x1400,test[5]); + setchr1r(1,0x1800,test[6]); + setchr1r(1,0x1c00,test[7]); +*/ + setprg4r(0x10, 0x6000, regs[0] & 1); + if (regs[2] >= 0x40) + setprg8r(1, 0x8000, (regs[2] - 0x40)); + else + setprg8r(0, 0x8000, (regs[2] & 0x3F)); + if (regs[3] >= 0x40) + setprg8r(1, 0xA000, (regs[3] - 0x40)); + else + setprg8r(0, 0xA000, (regs[3] & 0x3F)); + if (regs[4] >= 0x40) + setprg8r(1, 0xC000, (regs[4] - 0x40)); + else + setprg8r(0, 0xC000, (regs[4] & 0x3F)); + + setprg8r(1, 0xE000, ~0); + setmirror(MI_V); +} + +/*static DECLFW(TestWrite) +{ + test[A&7] = V; + Sync(); +}*/ + +static DECLFW(M190Write) { +// FCEU_printf("write %04x:%04x %d, %d\n",A,V,scanline,timestamp); + regs[(A & 0x0F00) >> 8] = V; + switch (A) { + case 0xd600: IRQLatch &= 0xFF00; IRQLatch |= V; break; + case 0xd700: IRQLatch &= 0x00FF; IRQLatch |= V << 8; break; + case 0xd900: IRQCount = IRQLatch; IRQa = V & 2; K4IRQ = V & 1; X6502_IRQEnd(FCEU_IQEXT); break; + case 0xd800: IRQa = K4IRQ; X6502_IRQEnd(FCEU_IQEXT); break; + } + Sync(); +} + +static DECLFR(M190Read) { +// FCEU_printf("read %04x:%04x %d, %d\n",A,regs[(A&0x0F00)>>8],scanline,timestamp); + return regs[(A & 0x0F00) >> 8] + regs[0x0B]; +} +static void VRC5IRQ(int a) { + if (IRQa) { + IRQCount += a; + if (IRQCount & 0x10000) { + X6502_IRQBegin(FCEU_IQEXT); + IRQCount = IRQLatch; + } + } +} + +//static void Mapper190_PPU(uint32 A) +//{ +// if(A<0x2000) +// setchr4r(0x10,0x1000,QTAINTRAM[A&0x1FFF]&1); +// else +// chrSync(); +//} + +static DECLFW(M1902007Wrap) { + if (A >= 0x2000) { + if (regs[0xA] & 1) + QTAINTRAM[A & 0x1FFF] = V; + else + old2007wrap(A, V); + } +} + + +static void M190Power(void) { +/* test[0]=0; + test[1]=1; + test[2]=2; + test[3]=3; + test[4]=4; + test[5]=5; + test[6]=6; + test[7]=7; +*/ + setprg4r(0x10, 0x7000, 2); + + old2007wrap = GetWriteHandler(0x2007); + SetWriteHandler(0x2007, 0x2007, M1902007Wrap); + + SetReadHandler(0x6000, 0xFFFF, CartBR); +// SetWriteHandler(0x5000,0x5007,TestWrite); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetWriteHandler(0x8000, 0xFFFF, M190Write); + SetReadHandler(0xDC00, 0xDC00, M190Read); + SetReadHandler(0xDD00, 0xDD00, M190Read); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + Sync(); +} + +static void M190Close(void) { + if (CHRRAM) + FCEU_gfree(CHRRAM); + CHRRAM = NULL; + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper190_Init(CartInfo *info) { + info->Power = M190Power; + info->Close = M190Close; + GameStateRestore = StateRestore; + + MapIRQHook = VRC5IRQ; +// PPU_hook=Mapper190_PPU; + + CHRRAM = (uint8*)FCEU_gmalloc(CHRSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRSIZE, 1); + AddExState(CHRRAM, CHRSIZE, 0, "CRAM"); + + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE - 4096; + } + + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/vrc6.cpp b/source/fceultra/boards/vrc6.cpp index 3cad0cc..43cd382 100644 --- a/source/fceultra/boards/vrc6.cpp +++ b/source/fceultra/boards/vrc6.cpp @@ -127,6 +127,7 @@ static void VRC6Power(void) { SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x8000, 0xFFFF, VRC6Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void VRC6IRQHook(int a) { @@ -245,11 +246,11 @@ static INLINE void DoSQVHQ(int x) { if (vpsg1[(x << 2) | 0x2] & 0x80) { if (vpsg1[x << 2] & 0x80) { - for (V = cvbc[x]; V < SOUNDTS; V++) + for (V = cvbc[x]; V < (int)SOUNDTS; V++) WaveHi[V] += amp; } else { int32 thresh = (vpsg1[x << 2] >> 4) & 7; - for (V = cvbc[x]; V < SOUNDTS; V++) { + for (V = cvbc[x]; V < (int)SOUNDTS; V++) { if (dcount[x] > thresh) WaveHi[V] += amp; vcount[x]--; @@ -277,7 +278,7 @@ static void DoSawVHQ(void) { int32 V; if (vpsg2[2] & 0x80) { - for (V = cvbc[2]; V < SOUNDTS; V++) { + for (V = cvbc[2]; V < (int)SOUNDTS; V++) { WaveHi[V] += (((phaseacc >> 3) & 0x1f) << 8) * 6 / 8; vcount[2]--; if (vcount[2] <= 0) { diff --git a/source/fceultra/boards/vrc7.cpp b/source/fceultra/boards/vrc7.cpp index 39154ef..e6b173a 100644 --- a/source/fceultra/boards/vrc7.cpp +++ b/source/fceultra/boards/vrc7.cpp @@ -26,6 +26,12 @@ static int32 IRQCount, CycleCount; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; +#include "emu2413.h" + +static int32 dwave = 0; +static OPLL *VRC7Sound = NULL; +static OPLL **VRC7Sound_saveptr = &VRC7Sound; + static SFORMAT StateRegs[] = { { &vrc7idx, 1, "VRCI" }, @@ -37,16 +43,12 @@ static SFORMAT StateRegs[] = { &IRQLatch, 1, "IRQL" }, { &IRQCount, 4, "IRQC" }, { &CycleCount, 4, "CYCC" }, - { 0 } + { (void**)VRC7Sound_saveptr, sizeof(*VRC7Sound) | FCEUSTATE_INDIRECT, "VRC7" }, + {0} }; // VRC7 Sound -#include "emu2413.h" - -static int32 dwave = 0; -static OPLL *VRC7Sound = NULL; - void DoVRC7Sound(void) { int32 z, a; if (FSettings.soundq >= 1) @@ -151,6 +153,7 @@ static void VRC7Power(void) { SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, VRC7Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void VRC7Close(void) diff --git a/source/fceultra/boards/yoko.cpp b/source/fceultra/boards/yoko.cpp index d2b4e05..f190548 100644 --- a/source/fceultra/boards/yoko.cpp +++ b/source/fceultra/boards/yoko.cpp @@ -174,6 +174,7 @@ static void M83Power(void) { SetWriteHandler(0x6000, 0x7fff, CartBW); // Pirate Dragon Ball Z Party [p1] used if for saves instead of seraial EEPROM SetReadHandler(0x8000, 0xffff, CartBR); SetWriteHandler(0x8000, 0xffff, M83Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void UNLYOKOReset(void) { diff --git a/source/fceultra/cart.cpp b/source/fceultra/cart.cpp index 6cbc227..8ebc00e 100644 --- a/source/fceultra/cart.cpp +++ b/source/fceultra/cart.cpp @@ -21,10 +21,6 @@ /// \file /// \brief This file contains all code for coordinating the mapping in of the address space external to the NES. -#include -#include -#include -#include #include "types.h" #include "fceu.h" #include "ppu.h" @@ -37,6 +33,11 @@ #include "utils/memory.h" +#include +#include +#include +#include + uint8 *Page[32], *VPage[8]; uint8 **VPageR = VPage; uint8 *VPageG[8]; @@ -46,8 +47,8 @@ uint8 *MMC5BGVPage[8]; static uint8 PRGIsRAM[32]; /* This page is/is not PRG RAM. */ /* 16 are (sort of) reserved for UNIF/iNES and 16 to map other stuff. */ -static int CHRram[32]; -static int PRGram[32]; +uint8 CHRram[32]; +uint8 PRGram[32]; uint8 *PRGptr[32]; uint8 *CHRptr[32]; @@ -343,40 +344,48 @@ static uint8 *GENIEROM=0; void FixGenieMap(void); -// Called when a game(file) is opened successfully. -void FCEU_OpenGenie(void) { +// Called when a game(file) is opened successfully. Returns TRUE on error. +bool FCEU_OpenGenie(void) +{ FILE *fp; int x; - if (!GENIEROM) { + if (!GENIEROM) + { char *fn; - if (!(GENIEROM = (uint8*)FCEU_malloc(4096 + 1024))) return; + if (!(GENIEROM = (uint8*)FCEU_malloc(4096 + 1024))) + return true; fn = strdup(FCEU_MakeFName(FCEUMKF_GGROM, 0, 0).c_str()); fp = FCEUD_UTF8fopen(fn, "rb"); - if (!fp) { - FCEU_PrintError("Error opening Game Genie ROM image!"); + if (!fp) + { + FCEU_PrintError("Error opening Game Genie ROM image!\nIt should be named \"gg.rom\"!"); free(GENIEROM); GENIEROM = 0; - return; + return true; } - if (fread(GENIEROM, 1, 16, fp) != 16) { + if (fread(GENIEROM, 1, 16, fp) != 16) + { grerr: FCEU_PrintError("Error reading from Game Genie ROM image!"); free(GENIEROM); GENIEROM = 0; fclose(fp); - return; + return true; } - if (GENIEROM[0] == 0x4E) { /* iNES ROM image */ + if (GENIEROM[0] == 0x4E) + { + /* iNES ROM image */ if (fread(GENIEROM, 1, 4096, fp) != 4096) goto grerr; if (fseek(fp, 16384 - 4096, SEEK_CUR)) goto grerr; if (fread(GENIEROM + 4096, 1, 256, fp) != 256) goto grerr; - } else { + } else + { if (fread(GENIEROM + 16, 1, 4352 - 16, fp) != (4352 - 16)) goto grerr; } @@ -384,10 +393,13 @@ void FCEU_OpenGenie(void) { /* Workaround for the FCE Ultra CHR page size only being 1KB */ for (x = 0; x < 4; x++) + { memcpy(GENIEROM + 4096 + (x << 8), GENIEROM + 4096, 256); + } } geniestage = 1; + return false; } /* Called when a game is closed. */ diff --git a/source/fceultra/cart.h b/source/fceultra/cart.h index 92d5365..9d3b0b8 100644 --- a/source/fceultra/cart.h +++ b/source/fceultra/cart.h @@ -13,6 +13,12 @@ typedef struct { // that are not really MMC3 but are // set to mapper 4. int battery; // Presence of an actual battery. + int ines2; + int submapper; // Submappers as defined by NES 2.0 + int wram_size; + int battery_wram_size; + int vram_size; + int battery_vram_size; uint8 MD5[16]; uint32 CRC32; // Should be set by the iNES/UNIF loading // code, used by mapper/board code, maybe @@ -34,6 +40,9 @@ DECLFR(CartBROB); DECLFR(CartBR); DECLFW(CartBW); +extern uint8 PRGram[32]; +extern uint8 CHRram[32]; + extern uint8 *PRGptr[32]; extern uint8 *CHRptr[32]; @@ -86,6 +95,6 @@ extern int geniestage; void FCEU_GeniePower(void); -void FCEU_OpenGenie(void); +bool FCEU_OpenGenie(void); void FCEU_CloseGenie(void); void FCEU_KillGenie(void); diff --git a/source/fceultra/cheat.cpp b/source/fceultra/cheat.cpp index 5037869..a938076 100644 --- a/source/fceultra/cheat.cpp +++ b/source/fceultra/cheat.cpp @@ -18,11 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include -#include -#include -#include #include "types.h" #include "x6502.h" @@ -33,6 +28,12 @@ #include "driver.h" #include "utils/memory.h" +#include +#include +#include +#include +#include + using namespace std; static uint8 *CheatRPtrs[64]; @@ -152,6 +153,8 @@ void FCEU_PowerCheats() numsubcheats=0; /* Quick hack to prevent setting of ancient read addresses. */ RebuildSubCheats(); } + +int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type); static void CheatMemErr(void) { FCEUD_PrintError("Error allocating memory for cheat data."); diff --git a/source/fceultra/conddebug.cpp b/source/fceultra/conddebug.cpp index 51116ef..af2099c 100644 --- a/source/fceultra/conddebug.cpp +++ b/source/fceultra/conddebug.cpp @@ -37,18 +37,21 @@ * Register -> 'A' | 'X' | 'Y' | 'P' * Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V' * PC Bank -> 'K' +* Data Bank -> 'T' */ -#include -#include -#include -#include -#include - -#include "conddebug.h" #include "types.h" +#include "conddebug.h" #include "utils/memory.h" +#include +#include +#include +#include +#include + +// hack: this address is used by 'T' condition +uint16 addressOfTheLastAccessedData = 0; // Next non-whitespace character in string char next; @@ -137,12 +140,18 @@ int isRegister(char c) return c == 'A' || c == 'X' || c == 'Y' || c == 'P'; } -// Determines if a character is for bank -int isBank(char c) +// Determines if a character is for PC bank +int isPCBank(char c) { return c == 'K'; } +// Determines if a character is for Data bank +int isDataBank(char c) +{ + return c == 'T'; +} + // Reads a hexadecimal number from str int getNumber(unsigned int* number, const char** str) { @@ -229,16 +238,33 @@ Condition* Primitive(const char** str, Condition* c) return c; } - else if (isBank(next)) /* PC Bank */ + else if (isPCBank(next)) /* PC Bank */ { if (c->type1 == TYPE_NO) { - c->type1 = TYPE_BANK; + c->type1 = TYPE_PC_BANK; c->value1 = next; } else { - c->type2 = TYPE_BANK; + c->type2 = TYPE_PC_BANK; + c->value2 = next; + } + + scan(str); + + return c; + } + else if (isDataBank(next)) /* Data Bank */ + { + if (c->type1 == TYPE_NO) + { + c->type1 = TYPE_DATA_BANK; + c->value1 = next; + } + else + { + c->type2 = TYPE_DATA_BANK; c->value2 = next; } diff --git a/source/fceultra/conddebug.h b/source/fceultra/conddebug.h index 02a3b50..92ea633 100644 --- a/source/fceultra/conddebug.h +++ b/source/fceultra/conddebug.h @@ -26,7 +26,8 @@ #define TYPE_FLAG 2 #define TYPE_NUM 3 #define TYPE_ADDR 4 -#define TYPE_BANK 5 +#define TYPE_PC_BANK 5 +#define TYPE_DATA_BANK 6 #define OP_NO 0 #define OP_EQ 1 @@ -42,6 +43,7 @@ #define OP_OR 11 #define OP_AND 12 +extern uint16 addressOfTheLastAccessedData; //mbg merge 7/18/06 turned into sane c++ struct Condition { diff --git a/source/fceultra/config.cpp b/source/fceultra/config.cpp index 642062f..de66a1e 100644 --- a/source/fceultra/config.cpp +++ b/source/fceultra/config.cpp @@ -1,48 +1,47 @@ /// \file /// \brief Contains methods related to the build configuration -#include -#include -#include - #include "types.h" #include "version.h" #include "fceu.h" #include "driver.h" #include "utils/memory.h" +#include +#include +#include + static char *aboutString = 0; -///returns a string suitable for use in an aboutbox +// returns a string suitable for use in an aboutbox char *FCEUI_GetAboutString() { const char *aboutTemplate = - FCEU_NAME_AND_VERSION "\n\n\ -Administrators:\n\ -zeromus, adelikat, AnS\n\n\ -Current Contributors:\n\ -punkrockguy318 (Lukas Sabota)\n\ -Plombo (Bryan Cain)\n\ -qeed, QFox, Shinydoofy, ugetab\n\ -CaH4e3, gocha, Acmlm, DWEdit\n\ -\n\ -FCEUX 2.0:\n\ -mz, nitsujrehtona, Lukas Sabota,\n\ -SP, Ugly Joe\n\ -\n\ -Previous versions:\n\ -FCE - Bero\n\ -FCEU - Xodnizel\n\ -FCEU XD - Bbitmaster & Parasyte\n\ -FCEU XD SP - Sebastian Porst\n\ -FCEU MM - CaH4e3\n\ -FCEU TAS - blip & nitsuja\n\ -FCEU TAS+ - Luke Gustafson\n\ -\n\ -FCEUX is dedicated to the fallen heroes\n\ -of NES emulation. In Memoriam --\n\ -ugetab\n\ -\n\ -"__TIME__" "__DATE__"\n"; + FCEU_NAME_AND_VERSION "\n\n" + "Administrators:\n" + "zeromus, adelikat, AnS\n\n" + "Current Contributors:\n" + "punkrockguy318 (Lukas Sabota)\n" + "CaH4e3, gocha, xhainingx, feos\n" + "\n" + "FCEUX 2.0:\n" + "mz, nitsujrehtona, SP, Ugly Joe,\n" + "Plombo, qeed, QFox, Shinydoofy\n" + "ugetab, Acmlm, DWEdit\n" + "\n" + "Previous versions:\n" + "FCE - Bero\n" + "FCEU - Xodnizel\n" + "FCEU XD - Bbitmaster & Parasyte\n" + "FCEU XD SP - Sebastian Porst\n" + "FCEU MM - CaH4e3\n" + "FCEU TAS - blip & nitsuja\n" + "FCEU TAS+ - Luke Gustafson\n" + "\n" + "FCEUX is dedicated to the fallen heroes\n" + "of NES emulation. In Memoriam --\n" + "ugetab\n" + "\n" + __TIME__ " " __DATE__ "\n"; if(aboutString) return aboutString; diff --git a/source/fceultra/debug.cpp b/source/fceultra/debug.cpp index d367196..7d26682 100644 --- a/source/fceultra/debug.cpp +++ b/source/fceultra/debug.cpp @@ -1,9 +1,5 @@ /// \file /// \brief Implements core debugging facilities - -#include -#include - #include "types.h" #include "x6502.h" #include "fceu.h" @@ -15,6 +11,10 @@ #include "x6502abbrev.h" +#include +#include + +unsigned int debuggerPageSize = 14; int vblankScanLines = 0; //Used to calculate scanlines 240-261 (vblank) int vblankPixel = 0; //Used to calculate the pixels in vblank @@ -232,12 +232,12 @@ int getBank(int offs) if (GameInfo && GameInfo->type==GIT_NSF) return addr != -1 ? addr / 0x1000 : -1; - return addr != -1 ? addr / 0x4000 : -1; + return addr != -1 ? addr / (1< 0xFFFF))return -1; + if((A < 0x6000) || (A > 0xFFFF))return -1; result = &Page[A>>11][A]-PRGptr[0]; if((result > (int)(PRGsize[0])) || (result < 0))return -1; else return result+16; //16 bytes for the header remember @@ -263,7 +263,7 @@ uint8 *GetNesCHRPointer(int A){ } uint8 GetMem(uint16 A) { - if ((A >= 0x2000) && (A < 0x4000)) { + if ((A >= 0x2000) && (A < 0x4000)) // PPU regs and their mirrors switch (A&7) { case 0: return PPU[0]; case 1: return PPU[1]; @@ -271,16 +271,32 @@ uint8 GetMem(uint16 A) { case 3: return PPU[3]; case 4: return SPRAM[PPU[3]]; case 5: return XOffset; - case 6: return RefreshAddr&0xFF; + case 6: return FCEUPPU_PeekAddress() & 0xFF; case 7: return VRAMBuffer; } - } else if ((A >= 0x4000) && (A < 0x5000)) return 0xFF; // AnS: changed the range, so MMC5 ExRAM can be watched in the Hexeditor - if (GameInfo) return ARead[A](A); //adelikat: 11/17/09: Prevent crash if this is called with no game loaded. + // feos: added more registers + else if ((A >= 0x4000) && (A < 0x4010)) + return PSG[A&15]; + else if ((A >= 0x4010) && (A < 0x4018)) + switch(A&7) { + case 0: return DMCFormat; + case 1: return RawDALatch; + case 2: return DMCAddressLatch; + case 3: return DMCSizeLatch; + case 4: return SpriteDMA; + case 5: return EnabledChannels; + case 6: return RawReg4016; + case 7: return IRQFrameMode; + } + else if ((A >= 0x4018) && (A < 0x5000)) // AnS: changed the range, so MMC5 ExRAM can be watched in the Hexeditor + return 0xFF; + if (GameInfo) //adelikat: 11/17/09: Prevent crash if this is called with no game loaded. + return ARead[A](A); else return 0; } uint8 GetPPUMem(uint8 A) { - uint16 tmp=RefreshAddr&0x3FFF; + uint16 tmp = FCEUPPU_PeekAddress() & 0x3FFF; if (tmp<0x2000) return VPage[tmp>>10][tmp]; if (tmp>=0x3F00) return PALRAM[tmp&0x1F]; @@ -313,7 +329,8 @@ int evaluate(Condition* c) switch(c->type1) { case TYPE_ADDR: value1 = GetMem(value1); break; - case TYPE_BANK: value1 = getBank(_PC); break; + case TYPE_PC_BANK: value1 = getBank(_PC); break; + case TYPE_DATA_BANK: value1 = getBank(addressOfTheLastAccessedData); break; } f = value1; @@ -337,7 +354,8 @@ int evaluate(Condition* c) switch(c->type2) { case TYPE_ADDR: value2 = GetMem(value2); break; - case TYPE_BANK: value2 = getBank(_PC); break; + case TYPE_PC_BANK: value2 = getBank(_PC); break; + case TYPE_DATA_BANK: value2 = getBank(addressOfTheLastAccessedData); break; } switch (c->op) @@ -370,6 +388,7 @@ int condition(watchpointinfo* wp) volatile int codecount, datacount, undefinedcount; unsigned char *cdloggerdata; +unsigned int cdloggerdataSize = 0; static int indirectnext; int debug_loggingCD; @@ -402,7 +421,8 @@ void LogCDData(uint8 *opcode, uint16 A, int size) { for (i = 0; i < size; i++) { if(cdloggerdata[j+i] & 1)continue; //this has been logged so skip cdloggerdata[j+i] |= 1; - cdloggerdata[j+i] |=((_PC+i)>>11)&0x0c; + cdloggerdata[j+i] |= ((_PC + i) >> 11) & 0x0c; + cdloggerdata[j+i] |= ((_PC & 0x8000) >> 8) ^ 0x80; // 19/07/14 used last reserved bit, if bit 7 is 1, then code is running from lowe area (6000) if(indirectnext)cdloggerdata[j+i] |= 0x10; codecount++; if(!(cdloggerdata[j+i] & 2))undefinedcount--; @@ -439,15 +459,16 @@ int u; //deleteme int skipdebug; //deleteme int numWPs; +bool break_asap = false; // for CPU cycles and Instructions counters -unsigned long int total_cycles_base = 0; -unsigned long int delta_cycles_base = 0; +uint64 total_cycles_base = 0; +uint64 delta_cycles_base = 0; bool break_on_cycles = false; -unsigned long int break_cycles_limit = 0; -unsigned long int total_instructions = 0; -unsigned long int delta_instructions = 0; +uint64 break_cycles_limit = 0; +uint64 total_instructions = 0; +uint64 delta_instructions = 0; bool break_on_instructions = false; -unsigned long int break_instructions_limit = 0; +uint64 break_instructions_limit = 0; static DebuggerState dbgstate; @@ -455,12 +476,20 @@ DebuggerState &FCEUI_Debugger() { return dbgstate; } void ResetDebugStatisticsCounters() { - total_cycles_base = delta_cycles_base = timestampbase + timestamp; + ResetCyclesCounter(); + ResetInstructionsCounter(); +} +void ResetCyclesCounter() +{ + total_cycles_base = delta_cycles_base = timestampbase + (uint64)timestamp; +} +void ResetInstructionsCounter() +{ total_instructions = delta_instructions = 0; } void ResetDebugStatisticsDeltaCounters() { - delta_cycles_base = timestampbase + timestamp; + delta_cycles_base = timestampbase + (uint64)timestamp; delta_instructions = 0; } void IncrementInstructionsCounters() @@ -469,12 +498,13 @@ void IncrementInstructionsCounters() delta_instructions++; } -void BreakHit(int bp_num, bool force = false) +void BreakHit(int bp_num, bool force) { - if(!force) { - + if(!force) + { //check to see whether we fall in any forbid zone - for (int i = 0; i < numWPs; i++) { + for (int i = 0; i < numWPs; i++) + { watchpointinfo& wp = watchpoint[i]; if(!(wp.flags & WP_F) || !(wp.flags & WP_E)) continue; @@ -509,7 +539,13 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { uint8 stackop=0; uint8 stackopstartaddr,stackopendaddr; - if (break_on_cycles && (timestampbase + timestamp - total_cycles_base > break_cycles_limit)) + if (break_asap) + { + break_asap = false; + BreakHit(BREAK_TYPE_LUA, true); + } + + if (break_on_cycles && ((timestampbase + (uint64)timestamp - total_cycles_base) > break_cycles_limit)) BreakHit(BREAK_TYPE_CYCLES_EXCEED, true); if (break_on_instructions && (total_instructions > break_instructions_limit)) BreakHit(BREAK_TYPE_INSTRUCTIONS_EXCEED, true); @@ -588,13 +624,14 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { // PPU Mem breaks if ((watchpoint[i].flags & brk_type) && ((A >= 0x2000) && (A < 0x4000)) && ((A&7) == 7)) { + const uint32 PPUAddr = FCEUPPU_PeekAddress(); if (watchpoint[i].endaddress) { - if ((watchpoint[i].address <= RefreshAddr) && (watchpoint[i].endaddress >= RefreshAddr)) + if ((watchpoint[i].address <= PPUAddr) && (watchpoint[i].endaddress >= PPUAddr)) BreakHit(i); } else { - if (watchpoint[i].address == RefreshAddr) + if (watchpoint[i].address == PPUAddr) BreakHit(i); } } @@ -715,19 +752,12 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { } //bbit edited: this is the end of the inserted code -int debug_tracing; - void DebugCycle() { uint8 opcode[3] = {0}; - uint16 A = 0; + uint16 A = 0, tmp; int size; -#ifdef WIN32 - // since this function is called once for every instruction, we can use it for keeping statistics - IncrementInstructionsCounters(); -#endif - if (scanline == 240) { vblankScanLines = (PAL?int((double)timestamp / ((double)341 / (double)3.2)):timestamp / 114); //114 approximates the number of timestamps per scanline during vblank. Approx 2508. NTSC: (341 / 3.0) PAL: (341 / 3.2). Uses (3.? * cpu_cycles) / 341.0, and assumes 1 cpu cycle. @@ -760,19 +790,22 @@ void DebugCycle() { case 0: break; case 1: - A = (opcode[1] + _X) & 0xFF; - A = GetMem(A) | (GetMem(A + 1) << 8); + tmp = (opcode[1] + _X) & 0xFF; + A = GetMem(tmp); + tmp = (opcode[1] + _X + 1) & 0xFF; + A |= (GetMem(tmp) << 8); break; case 2: A = opcode[1]; break; case 3: A = opcode[1] | (opcode[2] << 8); break; - case 4: A = (GetMem(opcode[1]) | (GetMem(opcode[1]+1) << 8)) + _Y; break; + case 4: A = (GetMem(opcode[1]) | (GetMem((opcode[1] + 1) & 0xFF) << 8)) + _Y; break; case 5: A = opcode[1] + _X; break; case 6: A = (opcode[1] | (opcode[2] << 8)) + _Y; break; case 7: A = (opcode[1] | (opcode[2] << 8)) + _X; break; case 8: A = opcode[1] + _Y; break; } + addressOfTheLastAccessedData = A; - if (numWPs || dbgstate.step || dbgstate.runline || dbgstate.stepout || watchpoint[64].flags || dbgstate.badopbreak || break_on_cycles || break_on_instructions) + if (numWPs || dbgstate.step || dbgstate.runline || dbgstate.stepout || watchpoint[64].flags || dbgstate.badopbreak || break_on_cycles || break_on_instructions || break_asap) breakpoint(opcode, A, size); if(debug_loggingCD) diff --git a/source/fceultra/debug.h b/source/fceultra/debug.h index 5c4296f..bd5472a 100644 --- a/source/fceultra/debug.h +++ b/source/fceultra/debug.h @@ -20,6 +20,7 @@ #define BREAK_TYPE_BADOP -2 #define BREAK_TYPE_CYCLES_EXCEED -3 #define BREAK_TYPE_INSTRUCTIONS_EXCEED -4 +#define BREAK_TYPE_LUA -5 //opbrktype is used to grab the breakpoint type that each instruction will cause. //WP_X is not used because ALL opcodes will have the execute bit set. @@ -76,6 +77,7 @@ void LogCDVectors(int which); void LogCDData(uint8 *opcode, uint16 A, int size); extern volatile int codecount, datacount, undefinedcount; extern unsigned char *cdloggerdata; +extern unsigned int cdloggerdataSize; extern int debug_loggingCD; static INLINE void FCEUI_SetLoggingCD(int val) { debug_loggingCD = val; } @@ -93,12 +95,28 @@ static INLINE int FCEUI_GetLoggingCD() { return debug_loggingCD; } extern int iaPC; extern uint32 iapoffset; //mbg merge 7/18/06 changed from int void DebugCycle(); +void BreakHit(int bp_num, bool force = false); + +extern bool break_asap; +extern uint64 total_cycles_base; +extern uint64 delta_cycles_base; +extern bool break_on_cycles; +extern uint64 break_cycles_limit; +extern uint64 total_instructions; +extern uint64 delta_instructions; +extern bool break_on_instructions; +extern uint64 break_instructions_limit; +extern void ResetDebugStatisticsCounters(); +extern void ResetCyclesCounter(); +extern void ResetInstructionsCounter(); +extern void ResetDebugStatisticsDeltaCounters(); +extern void IncrementInstructionsCounters(); //------------- //internal variables that debuggers will want access to extern uint8 *vnapage[4],*VPage[8]; extern uint8 PPU[4],PALRAM[0x20],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset; -extern uint32 RefreshAddr; +extern uint32 FCEUPPU_PeekAddress(); extern int debug_loggingCD; extern int numWPs; @@ -130,6 +148,16 @@ public: extern NSF_HEADER NSFHeader; +extern uint8 PSG[0x10]; +extern uint8 DMCFormat; +extern uint8 RawDALatch; +extern uint8 DMCAddressLatch; +extern uint8 DMCSizeLatch; +extern uint8 EnabledChannels; +extern uint8 SpriteDMA; +extern uint8 RawReg4016; +extern uint8 IRQFrameMode; + ///retrieves the core's DebuggerState DebuggerState &FCEUI_Debugger(); diff --git a/source/fceultra/drawing.cpp b/source/fceultra/drawing.cpp index f73ca2b..2d64fd8 100644 --- a/source/fceultra/drawing.cpp +++ b/source/fceultra/drawing.cpp @@ -7,7 +7,7 @@ static uint8 Font6x7[792] = { - 6, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, // 0x20 - Spacebar 3, 64, 64, 64, 64, 64, 0, 64, 5, 80, 80, 80, 0, 0, 0, 0, 6, 80, 80,248, 80,248, 80, 80, @@ -23,7 +23,7 @@ static uint8 Font6x7[792] = 5, 0, 0, 0,240, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 64, 5, 16, 16, 32, 32, 32, 64, 64, - 6,112,136,136,136,136,136,112, //0 + 6,112,136,136,136,136,136,112, // 0x30 - 0 6, 32, 96, 32, 32, 32, 32, 32, 6,112,136, 8, 48, 64,128,248, 6,112,136, 8, 48, 8,136,112, @@ -38,9 +38,9 @@ static uint8 Font6x7[792] = 4, 0, 32, 64,128, 64, 32, 0, 5, 0, 0,240, 0,240, 0, 0, 4, 0,128, 64, 32, 64,128, 0, - 5,112,136, 8, 16, 32, 0, 32, - 6,112,136,136,184,176,128,112, - 6,112,136,136,248,136,136,136, //A + 6,112,136, 8, 16, 32, 0, 32, // 0x3F - ? + 6,112,136,136,184,176,128,112, // 0x40 - @ + 6,112,136,136,248,136,136,136, // 0x41 - A 6,240,136,136,240,136,136,240, 6,112,136,128,128,128,136,112, 6,224,144,136,136,136,144,224, @@ -72,7 +72,7 @@ static uint8 Font6x7[792] = 4, 64,160, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0,248, 3,128, 64, 0, 0, 0, 0, 0, - 5, 0, 0, 96, 16,112,144,112, //a + 5, 0, 0, 96, 16,112,144,112, // 0x61 - a 5,128,128,224,144,144,144,224, 5, 0, 0,112,128,128,128,112, 5, 16, 16,112,144,144,144,112, @@ -402,10 +402,10 @@ static int JoedCharWidth(uint8 ch) char target[64][256]; -void DrawTextTransWH(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor, int max_w, int max_h, int border) +void DrawTextTransWH(uint8 *dest, int width, uint8 *textmsg, uint8 fgcolor, int max_w, int max_h, int border) { - unsigned int beginx=2, x=beginx; - unsigned int y=2; + int beginx=2, x=beginx; + int y=2; memset(target, 0, 64 * 256); diff --git a/source/fceultra/drawing.h b/source/fceultra/drawing.h index 8e87649..9ec8e50 100644 --- a/source/fceultra/drawing.h +++ b/source/fceultra/drawing.h @@ -1,8 +1,6 @@ -#include - void DrawTextLineBG(uint8 *dest); void DrawMessage(bool beforeMovie); void FCEU_DrawRecordingStatus(uint8* XBuf); void FCEU_DrawNumberRow(uint8 *XBuf, int *nstatus, int cur); void DrawTextTrans(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor); -void DrawTextTransWH(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor, int max_w, int max_h, int border); +void DrawTextTransWH(uint8 *dest, int width, uint8 *textmsg, uint8 fgcolor, int max_w, int max_h, int border); diff --git a/source/fceultra/driver.h b/source/fceultra/driver.h index 47d9018..db12067 100644 --- a/source/fceultra/driver.h +++ b/source/fceultra/driver.h @@ -1,14 +1,14 @@ #ifndef __DRIVER_H_ #define __DRIVER_H_ -#include -#include -#include - #include "types.h" #include "git.h" #include "file.h" +#include +#include +#include + FILE *FCEUD_UTF8fopen(const char *fn, const char *mode); inline FILE *FCEUD_UTF8fopen(const std::string &n, const char *mode) { return FCEUD_UTF8fopen(n.c_str(),mode); } EMUFILE_FILE* FCEUD_UTF8_fstream(const char *n, const char *m); @@ -120,6 +120,10 @@ void FCEUI_SetGameGenie(bool a); //Set video system a=0 NTSC, a=1 PAL void FCEUI_SetVidSystem(int a); +//Set variables for NTSC(0) / PAL(1) / Dendy(2) +//Dendy has PAL framerate and resolution, but ~NTSC timings, and has 50 dummy scanlines to force 50 fps +void FCEUI_SetRegion(int region); + //Convenience function; returns currently emulated video system(0=NTSC, 1=PAL). int FCEUI_GetCurrentVidSystem(int *slstart, int *slend); @@ -161,8 +165,8 @@ int FCEUI_SelectState(int, int); extern void FCEUI_SelectStateNext(int); //"fname" overrides the default save state filename code if non-NULL. -void FCEUI_SaveState(const char *fname); -void FCEUI_LoadState(const char *fname); +void FCEUI_SaveState(const char *fname, bool display_message=true); +void FCEUI_LoadState(const char *fname, bool display_message=true); void FCEUD_SaveStateAs(void); void FCEUD_LoadStateFrom(void); @@ -229,7 +233,6 @@ void FCEUI_GetIVectors(uint16 *reset, uint16 *irq, uint16 *nmi); uint32 FCEUI_CRC32(uint32 crc, uint8 *buf, uint32 len); -void FCEUI_ToggleTileView(void); void FCEUI_SetLowPass(int q); void FCEUI_NSFSetVis(int mode); @@ -336,7 +339,7 @@ enum EFCEUI FCEUI_STOPMOVIE, FCEUI_RECORDMOVIE, FCEUI_PLAYMOVIE, FCEUI_OPENGAME, FCEUI_CLOSEGAME, FCEUI_TASEDITOR, - FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK + FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN }; //checks whether an EFCEUI is valid right now diff --git a/source/fceultra/emufile.cpp b/source/fceultra/emufile.cpp index 0c32590..5102f2c 100644 --- a/source/fceultra/emufile.cpp +++ b/source/fceultra/emufile.cpp @@ -21,6 +21,7 @@ THE SOFTWARE. */ #include "emufile.h" +#include "utils/xstring.h" #include @@ -59,6 +60,24 @@ size_t EMUFILE_MEMORY::_fread(const void *ptr, size_t bytes){ return todo; } +void EMUFILE_FILE::open(const char* fname, const char* mode) +{ + fp = fopen(fname,mode); + if(!fp) + { +#ifdef _MSC_VER + std::wstring wfname = mbstowcs((std::string)fname); + std::wstring wfmode = mbstowcs((std::string)mode); + fp = _wfopen(wfname.c_str(),wfmode.c_str()); +#endif + if(!fp) + failbit = true; + } + this->fname = fname; + strcpy(this->mode,mode); +} + + void EMUFILE_FILE::truncate(s32 length) { ::fflush(fp); @@ -229,7 +248,7 @@ size_t EMUFILE::read8le(u8* val) u8 EMUFILE::read8le() { - u8 temp; + u8 temp = 0; fread(&temp,1); return temp; } @@ -256,4 +275,4 @@ size_t EMUFILE::readdouble(double* val) size_t ret = read64le(&temp); *val = u64_to_double(temp); return ret; -} \ No newline at end of file +} diff --git a/source/fceultra/emufile.h b/source/fceultra/emufile.h index 6b1c462..4d7d702 100644 --- a/source/fceultra/emufile.h +++ b/source/fceultra/emufile.h @@ -25,23 +25,23 @@ THE SOFTWARE. #ifndef EMUFILE_H #define EMUFILE_H -#include -#include -#include -#include -#include -#include -#include #ifdef GEKKO #include #endif - #include "emufile_types.h" #ifdef _MSC_VER #include #endif +#include +#include +#include +#include +#include +#include +#include + class EMUFILE { protected: bool failbit; diff --git a/source/fceultra/fceu.cpp b/source/fceultra/fceu.cpp index 3576631..dcad5eb 100644 --- a/source/fceultra/fceu.cpp +++ b/source/fceultra/fceu.cpp @@ -18,12 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include -#include -#include -#include -#include #include "types.h" #include "x6502.h" #include "fceu.h" @@ -49,14 +43,15 @@ #include "file.h" #include "vsuni.h" #include "ines.h" - #ifdef WIN32 #include "drivers/win/pref.h" +#include "utils/xstring.h" +extern void CDLoggerROMClosed(); +extern void CDLoggerROMChanged(); extern void ResetDebugStatisticsCounters(); extern void SetMainWindowText(); - -extern bool TaseditorIsRecording(); +extern bool isTaseditorRecording(); extern int32 fps_scale; extern int32 fps_scale_unpaused; @@ -64,9 +59,6 @@ extern int32 fps_scale_frameadvance; extern void RefreshThrottleFPS(); #endif -#include -#include - #ifdef _S9XLUA_H #include "fceulua.h" #endif @@ -74,6 +66,7 @@ extern void RefreshThrottleFPS(); //TODO - we really need some kind of global platform-specific options api #ifdef WIN32 #include "drivers/win/main.h" +#include "drivers/win/memview.h" #include "drivers/win/cheat.h" #include "drivers/win/texthook.h" #include "drivers/win/ram_search.h" @@ -88,6 +81,16 @@ extern void RefreshThrottleFPS(); #endif #endif +#include +#include +#include + +#include +#include +#include +#include +#include + using namespace std; int AFon = 1, AFoff = 1, AutoFireOffset = 0; //For keeping track of autofire settings @@ -97,17 +100,24 @@ bool AutoSS = false; //Flagged true when the first auto-savestate is made bool movieSubtitles = true; //Toggle for displaying movie subtitles bool DebuggerWasUpdated = false; //To prevent the debugger from updating things without being updated. bool AutoResumePlay = false; -char rom_name_when_closing_emulator[129] = {0}; +char romNameWhenClosingEmulator[2048] = {0}; +int dendy = 0; FCEUGI::FCEUGI() - : filename(0) - , archiveFilename(0) { + : filename(0), + archiveFilename(0) { //printf("%08x",opsize); // WTF?! } FCEUGI::~FCEUGI() { - if (filename) delete filename; - if (archiveFilename) delete archiveFilename; + if (filename) { + free(filename); + filename = NULL; + } + if (archiveFilename) { + delete archiveFilename; + archiveFilename = NULL; + } } bool CheckFileExists(const char* filename) { @@ -143,18 +153,17 @@ static void FCEU_CloseGame(void) { if (GameInfo) { - if (AutoResumePlay && (GameInfo->type != GIT_NSF)) + if (AutoResumePlay) { // save "-resume" savestate - FCEUSS_Save(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str()); + FCEUSS_Save(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str(), false); } #ifdef WIN32 extern char LoadedRomFName[2048]; - if (storePreferences(LoadedRomFName)) - { + if (storePreferences(mass_replace(LoadedRomFName, "|", ".").c_str())) FCEUD_PrintError("Couldn't store debugging data"); - } + CDLoggerROMClosed(); #endif if (FCEUnetplay) { @@ -163,7 +172,7 @@ static void FCEU_CloseGame(void) if (GameInfo->name) { free(GameInfo->name); - GameInfo->name = 0; + GameInfo->name = NULL; } if (GameInfo->type != GIT_NSF) { @@ -264,8 +273,8 @@ void FlushGenieRW(void) { } free(AReadG); free(BWriteG); - AReadG = 0; - BWriteG = 0; + AReadG = NULL; + BWriteG = NULL; RWWrap = 0; } } @@ -276,8 +285,10 @@ readfunc GetReadHandler(int32 a) { else return ARead[a]; } + void SetReadHandler(int32 start, int32 end, readfunc func) { int32 x; + if (!func) func = ANull; @@ -329,6 +340,7 @@ static void AllocBuffers() { static void FreeBuffers() { FCEU_free(RAM); + RAM = NULL; } //------ @@ -361,15 +373,16 @@ void ResetGameLoaded(void) { if (GameInfo) FCEU_CloseGame(); EmulationPaused = 0; //mbg 5/8/08 - loading games while paused was bad news. maybe this fixes it GameStateRestore = 0; - PPU_hook = 0; - GameHBIRQHook = 0; - FFCEUX_PPURead = 0; - FFCEUX_PPUWrite = 0; + PPU_hook = NULL; + GameHBIRQHook = NULL; + FFCEUX_PPURead = NULL; + FFCEUX_PPUWrite = NULL; if (GameExpSound.Kill) GameExpSound.Kill(); memset(&GameExpSound, 0, sizeof(GameExpSound)); - MapIRQHook = 0; + MapIRQHook = NULL; MMC5Hack = 0; + PEC586Hack = 0; PAL &= 1; pale = 0; } @@ -387,8 +400,7 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen //---------- //attempt to open the files FCEUFILE *fp; - - FCEU_printf("Loading %s...\n\n", name); + char fullname[2048]; // this name contains both archive name and ROM file name const char* romextensions[] = { "nes", "fds", 0 }; fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions); @@ -398,16 +410,21 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen if (!silent) FCEU_PrintError("Error opening \"%s\"!", name); return 0; + } else if (fp->archiveFilename != "") + { + strcpy(fullname, fp->archiveFilename.c_str()); + strcat(fullname, "|"); + strcat(fullname, fp->filename.c_str()); + } else + { + strcpy(fullname, name); } - GetFileBase(fp->filename.c_str()); - //--------- - //file opened ok. start loading. - + FCEU_printf("Loading %s...\n\n", fullname); + GetFileBase(fp->filename.c_str()); ResetGameLoaded(); - - //reset parameters so theyre cleared just in case a format's loader doesnt know to do the clearing + //reset parameters so they're cleared just in case a format's loader doesn't know to do the clearing MasterRomInfoParams = TMasterRomInfoParams(); if (!AutosaveStatus) @@ -420,7 +437,8 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen memset(GameInfo, 0, sizeof(FCEUGI)); GameInfo->filename = strdup(fp->filename.c_str()); - if (fp->archiveFilename != "") GameInfo->archiveFilename = strdup(fp->archiveFilename.c_str()); + if (fp->archiveFilename != "") + GameInfo->archiveFilename = strdup(fp->archiveFilename.c_str()); GameInfo->archiveCount = fp->archiveCount; GameInfo->soundchan = 0; @@ -436,13 +454,13 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen bool FCEUXLoad(const char *name, FCEUFILE * fp); /*if(FCEUXLoad(name,fp)) goto endlseq;*/ - if (iNESLoad(name, fp, OverwriteVidMode)) + if (iNESLoad(fullname, fp, OverwriteVidMode)) goto endlseq; - if (NSFLoad(name, fp)) + if (NSFLoad(fullname, fp)) goto endlseq; - if (UNIFLoad(name, fp)) + if (UNIFLoad(fullname, fp)) goto endlseq; - if (FDSLoad(name, fp)) + if (FDSLoad(fullname, fp)) goto endlseq; if (!silent) @@ -463,7 +481,7 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen extern char LoadedRomFName[2048]; extern int loadDebugDataFailed; - if ((loadDebugDataFailed = loadPreferences(LoadedRomFName))) + if ((loadDebugDataFailed = loadPreferences(mass_replace(LoadedRomFName, "|", ".").c_str()))) if (!silent) FCEU_printf("Couldn't load debugging data.\n"); @@ -473,8 +491,18 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen FCEU_ResetVidSys(); if (GameInfo->type != GIT_NSF) + { if (FSettings.GameGenie) - FCEU_OpenGenie(); + { + if (FCEU_OpenGenie()) + { + FCEUI_SetGameGenie(false); +#ifdef WIN32 + genie = 0; +#endif + } + } + } PowerNES(); if (GameInfo->type != GIT_NSF) @@ -486,21 +514,24 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen if (GameInfo->type != GIT_NSF) FCEU_LoadGameCheats(0); -#if defined (WIN32) || defined (WIN64) - DoDebuggerDataReload(); // Reloads data without reopening window -#endif - - if (AutoResumePlay && (GameInfo->type != GIT_NSF)) + if (AutoResumePlay) { // load "-resume" savestate - if (FCEUSS_Load(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str())) + if (FCEUSS_Load(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str(), false)) FCEU_DispMessage("Old play session resumed.", 0); - else - FCEU_DispMessage("", 0); } ResetScreenshotsCounter(); +#if defined (WIN32) || defined (WIN64) + DoDebuggerDataReload(); // Reloads data without reopening window + CDLoggerROMChanged(); + if (hMemView) UpdateColorTable(); + if (hCheat) UpdateCheatsAdded(); + if (FrozenAddressCount) + FCEU_DispMessage("%d cheats active", 0, FrozenAddressCount); +#endif + return GameInfo; } @@ -735,7 +766,7 @@ void ResetNES(void) { extern uint8 *XBackBuf; memset(XBackBuf, 0, 256 * 256); - FCEU_DispMessage("Reset", 0); + //FCEU_DispMessage("Reset", 0); } void FCEU_MemoryRand(uint8 *ptr, uint32 size) { @@ -782,8 +813,8 @@ void PowerNES(void) { SetReadHandler(0, 0x7FF, ARAML); SetWriteHandler(0, 0x7FF, BRAML); - SetReadHandler(0x800, 0x1FFF, ARAMH); // Part of a little - SetWriteHandler(0x800, 0x1FFF, BRAMH); //hack for a small speed boost. + SetReadHandler(0x800, 0x1FFF, ARAMH); // Part of a little + SetWriteHandler(0x800, 0x1FFF, BRAMH); //hack for a small speed boost. InitializeInput(); FCEUSND_Power(); @@ -806,7 +837,7 @@ void PowerNES(void) { #endif FCEU_PowerCheats(); LagCounterReset(); - // clear back baffer + // clear back buffer extern uint8 *XBackBuf; memset(XBackBuf, 0, 256 * 256); @@ -814,7 +845,7 @@ void PowerNES(void) { Update_RAM_Search(); // Update_RAM_Watch() is also called. #endif - FCEU_DispMessage("Power on", 0); + //FCEU_DispMessage("Power on", 0); } void FCEU_ResetVidSys(void) { @@ -822,13 +853,15 @@ void FCEU_ResetVidSys(void) { if (GameInfo->vidsys == GIV_NTSC) w = 0; - else if (GameInfo->vidsys == GIV_PAL) + else if (GameInfo->vidsys == GIV_PAL) { w = 1; - else + dendy = 0; + } else w = FSettings.PAL; PAL = w ? 1 : 0; - FCEUPPU_SetVideoSystem(w); + + FCEUPPU_SetVideoSystem(w || dendy); SetSoundVariables(); } @@ -867,7 +900,7 @@ void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall) { FSettings.UsrLastSLine[0] = ntscl; FSettings.UsrFirstSLine[1] = palf; FSettings.UsrLastSLine[1] = pall; - if (PAL) { + if (PAL || dendy) { FSettings.FirstSLine = FSettings.UsrFirstSLine[1]; FSettings.LastSLine = FSettings.UsrLastSLine[1]; } else { @@ -892,6 +925,30 @@ int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) { *slend = FSettings.LastSLine; return(PAL); } +/* +// TODO: make use on SDL +void FCEUI_SetRegion(int region) { + switch (region) { + case 0: // NTSC + pal_emulation = 0; + dendy = 0; + break; + case 1: // PAL + pal_emulation = 1; + dendy = 0; + break; + case 2: // Dendy + pal_emulation = 0; + dendy = 1; + break; + } + FCEUI_SetVidSystem(pal_emulation); + RefreshThrottleFPS(); +#ifdef WIN32 + UpdateCheckedMenuItems(); + PushCurrentVideoSettings(); +#endif +}*/ //Enable or disable Game Genie option. void FCEUI_SetGameGenie(bool a) { @@ -905,7 +962,7 @@ void FCEUI_SetGameGenie(bool a) { //} int32 FCEUI_GetDesiredFPS(void) { - if (PAL) + if (PAL || dendy) return(838977920); // ~50.007 else return(1008307711); // ~60.1 @@ -958,14 +1015,15 @@ void UpdateAutosave(void) { AutosaveCounter = 0; AutosaveIndex = (AutosaveIndex + 1) % AutosaveQty; f = strdup(FCEU_MakeFName(FCEUMKF_AUTOSTATE, AutosaveIndex, 0).c_str()); - FCEUSS_Save(f); + FCEUSS_Save(f, false); AutoSS = true; //Flag that an auto-savestate was made free(f); + f = NULL; AutosaveStatus[AutosaveIndex] = 1; } } -void FCEUI_Autosave(void) { +void FCEUI_RewindToLastAutosave(void) { if (!EnableAutosave || !AutoSS) return; @@ -974,6 +1032,7 @@ void FCEUI_Autosave(void) { f = strdup(FCEU_MakeFName(FCEUMKF_AUTOSTATE, AutosaveIndex, 0).c_str()); FCEUSS_Load(f); free(f); + f = NULL; //Set pointer to previous available slot if (AutosaveStatus[(AutosaveIndex + AutosaveQty - 1) % AutosaveQty] == 1) { @@ -1031,10 +1090,11 @@ bool FCEU_IsValidUI(EFCEUI ui) { case FCEUI_POWER: case FCEUI_EJECT_DISK: case FCEUI_SWITCH_DISK: + case FCEUI_INSERT_COIN: if (!GameInfo) return false; if (FCEUMOV_Mode(MOVIEMODE_RECORD)) return true; #ifdef WIN32 - if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR) && TaseditorIsRecording()) return true; + if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR) && isTaseditorRecording()) return true; #endif if (!FCEUMOV_Mode(MOVIEMODE_INACTIVE)) return false; break; diff --git a/source/fceultra/fceu.h b/source/fceultra/fceu.h index eef643b..743492c 100644 --- a/source/fceultra/fceu.h +++ b/source/fceultra/fceu.h @@ -1,12 +1,14 @@ #ifndef _FCEUH #define _FCEUH +#include "types.h" + extern int fceuindbg; extern int newppu; void ResetGameLoaded(void); extern bool AutoResumePlay; -extern char rom_name_when_closing_emulator[]; +extern char romNameWhenClosingEmulator[]; #define DECLFR(x) uint8 x (uint32 A) #define DECLFW(x) void x (uint32 A, uint8 V) @@ -29,7 +31,7 @@ void PowerNES(void); void SetAutoFireOffset(int offset); void SetAutoFirePattern(int onframes, int offframes); void AutoFire(void); -void FCEUI_Autosave(void); +void FCEUI_RewindToLastAutosave(void); //mbg 7/23/06 char *FCEUI_GetAboutString(); @@ -37,7 +39,7 @@ char *FCEUI_GetAboutString(); extern uint64 timestampbase; extern uint32 MMC5HackVROMMask; extern uint8 *MMC5HackExNTARAMPtr; -extern int MMC5Hack; +extern int MMC5Hack, PEC586Hack; extern uint8 *MMC5HackVROMPTR; extern uint8 MMC5HackCHRMode; extern uint8 MMC5HackSPMode; @@ -72,6 +74,7 @@ extern FCEUGI *GameInfo; extern int GameAttributes; extern uint8 PAL; +extern int dendy; //#include "driver.h" @@ -125,6 +128,11 @@ void FCEU_PutImage(void); void FCEU_PutImageDummy(void); #endif +#ifdef WIN32 +extern void UpdateCheckedMenuItems(); +extern void PushCurrentVideoSettings(); +#endif + extern uint8 Exit; extern uint8 pale; extern uint8 vsdip; diff --git a/source/fceultra/fceulua.h b/source/fceultra/fceulua.h new file mode 100644 index 0000000..4a0933d --- /dev/null +++ b/source/fceultra/fceulua.h @@ -0,0 +1,91 @@ +#ifdef _S9XLUA_H +#ifndef _FCEULUA_H +#define _FCEULUA_H + +enum LuaCallID +{ + LUACALL_BEFOREEMULATION, + LUACALL_AFTEREMULATION, + LUACALL_BEFOREEXIT, + LUACALL_BEFORESAVE, + LUACALL_AFTERLOAD, + LUACALL_TASEDITOR_AUTO, + LUACALL_TASEDITOR_MANUAL, + + LUACALL_COUNT +}; +extern void CallRegisteredLuaFunctions(LuaCallID calltype); + +enum LuaMemHookType +{ + LUAMEMHOOK_WRITE, + LUAMEMHOOK_READ, + LUAMEMHOOK_EXEC, + LUAMEMHOOK_WRITE_SUB, + LUAMEMHOOK_READ_SUB, + LUAMEMHOOK_EXEC_SUB, + + LUAMEMHOOK_COUNT +}; +void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType); + +struct LuaSaveData +{ + LuaSaveData() { recordList = 0; } + ~LuaSaveData() { ClearRecords(); } + + struct Record + { + unsigned int key; // crc32 + unsigned int size; // size of data + unsigned char* data; + Record* next; + }; + + Record* recordList; + + void SaveRecord(struct lua_State* L, unsigned int key); // saves Lua stack into a record and pops it + void LoadRecord(struct lua_State* L, unsigned int key, unsigned int itemsToLoad) const; // pushes a record's data onto the Lua stack + void SaveRecordPartial(struct lua_State* L, unsigned int key, int idx); // saves part of the Lua stack (at the given index) into a record and does NOT pop anything + + void ExportRecords(void* file) const; // writes all records to an already-open file + void ImportRecords(void* file); // reads records from an already-open file + void ClearRecords(); // deletes all record data + +private: + // disallowed, it's dangerous to call this + // (because the memory the destructor deletes isn't refcounted and shouldn't need to be copied) + // so pass LuaSaveDatas by reference and this should never get called + LuaSaveData(const LuaSaveData& copy) {} +}; + +#define LUA_DATARECORDKEY 42 + +void CallRegisteredLuaSaveFunctions(int savestateNumber, LuaSaveData& saveData); +void CallRegisteredLuaLoadFunctions(int savestateNumber, const LuaSaveData& saveData); + +// Just forward function declarations + +void FCEU_LuaFrameBoundary(); +int FCEU_LoadLuaCode(const char *filename, const char *arg=NULL); +void FCEU_ReloadLuaCode(); +void FCEU_LuaStop(); +int FCEU_LuaRunning(); + +uint8 FCEU_LuaReadJoypad(int,uint8); // HACK - Function needs controller input +int FCEU_LuaSpeed(); +int FCEU_LuaFrameskip(); +int FCEU_LuaRerecordCountSkip(); + +void FCEU_LuaGui(uint8 *XBuf); +void FCEU_LuaUpdatePalette(); + +struct lua_State* FCEU_GetLuaState(); +char* FCEU_GetLuaScriptName(); + +// And some interesting REVERSE declarations! +char *FCEU_GetFreezeFilename(int slot); + + +#endif +#endif diff --git a/source/fceultra/fcoeffs.h b/source/fceultra/fcoeffs.h index 0ab65a3..2d7fa51 100644 --- a/source/fceultra/fcoeffs.h +++ b/source/fceultra/fcoeffs.h @@ -48,248 +48,248 @@ Coefficients: */ static const int32 C96000NTSC[NCOEFFS/2]= { -/*0*/ 65536*16* -5.9950991853042605E-6 -/*1*/, 65536*16* -3.0394382502604395E-6 -/*2*/, 65536*16* -3.728403434239284E-6 -/*3*/, 65536*16* -4.460351826790638E-6 -/*4*/, 65536*16* -5.2164320385801135E-6 -/*5*/, 65536*16* -5.9787071016806234E-6 -/*6*/, 65536*16* -6.716463411023574E-6 -/*7*/, 65536*16* -7.408551386580002E-6 -/*8*/, 65536*16* -8.023491429829738E-6 -/*9*/, 65536*16* -8.531232892238868E-6 -/*10*/, 65536*16* -8.878741512154837E-6 -/*11*/, 65536*16* -9.046773382992595E-6 -/*12*/, 65536*16* -8.993971214348702E-6 -/*13*/, 65536*16* -8.66944931521744E-6 -/*14*/, 65536*16* -8.049348524459474E-6 -/*15*/, 65536*16* -7.083238646482467E-6 -/*16*/, 65536*16* -5.746762349938464E-6 -/*17*/, 65536*16* -4.005753681691657E-6 -/*18*/, 65536*16* -1.838018035195733E-6 -/*19*/, 65536*16* 7.763983938828864E-7 -/*20*/, 65536*16* 3.842232025916005E-6 -/*21*/, 65536*16* 7.361161707034959E-6 -/*22*/, 65536*16* 1.1325948767988128E-5 -/*23*/, 65536*16* 1.5711486406341978E-5 -/*24*/, 65536*16* 2.0488201424957098E-5 -/*25*/, 65536*16* 2.5608402660083142E-5 -/*26*/, 65536*16* 3.101231858515874E-5 -/*27*/, 65536*16* 3.6630654060842745E-5 -/*28*/, 65536*16* 4.2375439803123404E-5 -/*29*/, 65536*16* 4.815060832963289E-5 -/*30*/, 65536*16* 5.384626411548906E-5 -/*31*/, 65536*16* 5.934549587237094E-5 -/*32*/, 65536*16* 6.451785679907682E-5 -/*33*/, 65536*16* 6.923065879553487E-5 -/*34*/, 65536*16* 7.334304650233838E-5 -/*35*/, 65536*16* 7.671308820252635E-5 -/*36*/, 65536*16* 7.920112989696133E-5 -/*37*/, 65536*16* 8.066793124218096E-5 -/*38*/, 65536*16* 8.098382483962539E-5 -/*39*/, 65536*16* 8.002921154479775E-5 -/*40*/, 65536*16* 7.769789869215064E-5 -/*41*/, 65536*16* 7.390152475899438E-5 -/*42*/, 65536*16* 6.857231550142758E-5 -/*43*/, 65536*16* 6.16673817460573E-5 -/*44*/, 65536*16* 5.3169767940001464E-5 -/*45*/, 65536*16* 4.309495398773014E-5 -/*46*/, 65536*16* 3.148737405995964E-5 -/*47*/, 65536*16* 1.8428415219696232E-5 -/*48*/, 65536*16* 4.0337781533928895E-6 -/*49*/, 65536*16* -1.154525373085283E-5 -/*50*/, 65536*16* -2.8120750949316567E-5 -/*51*/, 65536*16* -4.5470242422149815E-5 -/*52*/, 65536*16* -6.333736379615692E-5 -/*53*/, 65536*16* -8.143489509942166E-5 -/*54*/, 65536*16* -9.94475640226242E-5 -/*55*/, 65536*16* -1.1703729468742291E-4 -/*56*/, 65536*16* -1.3384679191408508E-4 -/*57*/, 65536*16* -1.4950548598267213E-4 -/*58*/, 65536*16* -1.6363792959068823E-4 -/*59*/, 65536*16* -1.7586732627086947E-4 -/*60*/, 65536*16* -1.858264971517669E-4 -/*61*/, 65536*16* -1.9316312487547242E-4 -/*62*/, 65536*16* -1.975494021862538E-4 -/*63*/, 65536*16* -1.9868977868165154E-4 -/*64*/, 65536*16* -1.963293865814053E-4 -/*65*/, 65536*16* -1.9026146175876417E-4 -/*66*/, 65536*16* -1.803352078962109E-4 -/*67*/, 65536*16* -1.66463443436789E-4 -/*68*/, 65536*16* -1.4862710934868261E-4 -/*69*/, 65536*16* -1.2688200452566298E-4 -/*70*/, 65536*16* -1.0136212853169677E-4 -/*71*/, 65536*16* -7.228199463954364E-5 -/*72*/, 65536*16* -3.9939461621236575E-5 -/*73*/, 65536*16* -4.7134932934724E-6 -/*74*/, 65536*16* 3.2936215273699675E-5 -/*75*/, 65536*16* 7.247384833064696E-5 -/*76*/, 65536*16* 1.1329187082792405E-4 -/*77*/, 65536*16* 1.5471948843725746E-4 -/*78*/, 65536*16* 1.9603027714808286E-4 -/*79*/, 65536*16* 2.364532958813608E-4 -/*80*/, 65536*16* 2.751853212246927E-4 -/*81*/, 65536*16* 3.114033208188799E-4 -/*82*/, 65536*16* 3.442804841775461E-4 -/*83*/, 65536*16* 3.7300098840546946E-4 -/*84*/, 65536*16* 3.967764136715296E-4 -/*85*/, 65536*16* 4.148631617351676E-4 -/*86*/, 65536*16* 4.265789297533608E-4 -/*87*/, 65536*16* 4.3132002526188114E-4 -/*88*/, 65536*16* 4.2857701618443636E-4 -/*89*/, 65536*16* 4.179510914969621E-4 -/*90*/, 65536*16* 3.991670037587729E-4 -/*91*/, 65536*16* 3.720870989970653E-4 -/*92*/, 65536*16* 3.367209236003282E-4 -/*93*/, 65536*16* 2.932338231303312E-4 -/*94*/, 65536*16* 2.419533571940393E-4 -/*95*/, 65536*16* 1.8337169647749448E-4 -/*96*/, 65536*16* 1.1814612711310299E-4 -/*97*/, 65536*16* 4.709567952563025E-5 -/*98*/, 65536*16* -2.880519351052945E-5 -/*99*/, 65536*16* -1.08436462295612E-4 -/*100*/, 65536*16* -1.905455293630124E-4 -/*101*/, 65536*16* -2.7376362665015007E-4 -/*102*/, 65536*16* -3.566259161939277E-4 -/*103*/, 65536*16* -4.375928024937683E-4 -/*104*/, 65536*16* -5.150762555847844E-4 -/*105*/, 65536*16* -5.874662774920191E-4 -/*106*/, 65536*16* -6.531605887419429E-4 -/*107*/, 65536*16* -7.105951946653638E-4 -/*108*/, 65536*16* -7.582757639600853E-4 -/*109*/, 65536*16* -7.948096207059845E-4 -/*110*/, 65536*16* -8.189373133065186E-4 -/*111*/, 65536*16* -8.295634640890689E-4 -/*112*/, 65536*16* -8.257854455404298E-4 -/*113*/, 65536*16* -8.069208861135825E-4 -/*114*/, 65536*16* -7.725316214556066E-4 -/*115*/, 65536*16* -7.224442067331338E-4 -/*116*/, 65536*16* -6.567673177902021E-4 -/*117*/, 65536*16* -5.759031970767677E-4 -/*118*/, 65536*16* -4.8055576975832975E-4 -/*119*/, 65536*16* -3.7173219275304865E-4 -/*120*/, 65536*16* -2.507394811359122E-4 -/*121*/, 65536*16* -1.191747608775131E-4 -/*122*/, 65536*16* 2.1089774143064154E-5 -/*123*/, 65536*16* 1.6792832047168277E-4 -/*124*/, 65536*16* 3.189887341095747E-4 -/*125*/, 65536*16* 4.7172479984555337E-4 -/*126*/, 65536*16* 6.234346495766704E-4 -/*127*/, 65536*16* 7.713029674040095E-4 -/*128*/, 65536*16* 9.124478381058291E-4 -/*129*/, 65536*16* 0.0010439713492973299 -/*130*/, 65536*16* 0.0011630121060354824 -/*131*/, 65536*16* 0.0012668003330792172 -/*132*/, 65536*16* 0.0013527131638668246 -/*133*/, 65536*16* 0.0014183305230994348 -/*134*/, 65536*16* 0.0014614889365474647 -/*135*/, 65536*16* 0.0014803340336415063 -/*136*/, 65536*16* 0.0014733688575452508 -/*137*/, 65536*16* 0.001439498243826639 -/*138*/, 65536*16* 0.0013780680098511918 -/*139*/, 65536*16* 0.0012888970057146566 -/*140*/, 65536*16* 0.0011723026532406624 -/*141*/, 65536*16* 0.0010291180003947405 -/*142*/, 65536*16* 8.607001658653358E-4 -/*143*/, 65536*16* 6.689295599970792E-4 -/*144*/, 65536*16* 4.5619928199453885E-4 -/*145*/, 65536*16* 2.253948582736753E-4 -/*146*/, 65536*16* -2.0136349562764177E-5 -/*147*/, 65536*16* -2.766248035657636E-4 -/*148*/, 65536*16* -5.399290507797791E-4 -/*149*/, 65536*16* -8.055939397996815E-4 -/*150*/, 65536*16* -0.0010689177291287714 -/*151*/, 65536*16* -0.0013250265370767429 -/*152*/, 65536*16* -0.0015689549600474482 -/*153*/, 65536*16* -0.0017957322527663085 -/*154*/, 65536*16* -0.002000472024117418 -/*155*/, 65536*16* -0.0021784645223266222 -/*156*/, 65536*16* -0.0023252695222818146 -/*157*/, 65536*16* -0.0024368087083972345 -/*158*/, 65536*16* -0.002509455241851095 -/*159*/, 65536*16* -0.0025401189567937766 -/*160*/, 65536*16* -0.0025263261450844377 -/*161*/, 65536*16* -0.0024662908754217406 -/*162*/, 65536*16* -0.002358977944127433 -/*163*/, 65536*16* -0.002204154401342649 -/*164*/, 65536*16* -0.002002429343138771 -/*165*/, 65536*16* -0.0017552803385372808 -/*166*/, 65536*16* -0.0014650656045065488 -/*167*/, 65536*16* -0.001135021049166992 -/*168*/, 65536*16* -7.692415547098649E-4 -/*169*/, 65536*16* -3.7264671522013244E-4 -/*170*/, 65536*16* 4.906989195928291E-5 -/*171*/, 65536*16* 4.895067103339711E-4 -/*172*/, 65536*16* 9.416355837269647E-4 -/*173*/, 65536*16* 0.001397897684142057 -/*174*/, 65536*16* 0.0018503121614766558 -/*175*/, 65536*16* 0.002290597319733804 -/*176*/, 65536*16* 0.0027103015920374113 -/*177*/, 65536*16* 0.0031009433327120863 -/*178*/, 65536*16* 0.0034541565687980116 -/*179*/, 65536*16* 0.0037618412630103333 -/*180*/, 65536*16* 0.004016315066649496 -/*181*/, 65536*16* 0.004210464374744574 -/*182*/, 65536*16* 0.004337892288164658 -/*183*/, 65536*16* 0.004393060165490985 -/*184*/, 65536*16* 0.004371421226297046 -/*185*/, 65536*16* 0.004269542847715132 -/*186*/, 65536*16* 0.00408521543517564 -/*187*/, 65536*16* 0.0038175457430583526 -/*188*/, 65536*16* 0.00346703221076496 -/*189*/, 65536*16* 0.0030356209846777236 -/*190*/, 65536*16* 0.002526740400739804 -/*191*/, 65536*16* 0.0019453134428630866 -/*192*/, 65536*16* 0.0012977462825954304 -/*193*/, 65536*16* 5.918933555500828E-4 -/*194*/, 65536*16* -1.6300197379338156E-4 -/*195*/, 65536*16* -9.563908629597664E-4 -/*196*/, 65536*16* -0.0017765255338228524 -/*197*/, 65536*16* -0.0026105886000394158 -/*198*/, 65536*16* -0.003444843158936217 -/*199*/, 65536*16* -0.004264802433556331 -/*200*/, 65536*16* -0.00505541655658742 -/*201*/, 65536*16* -0.005801274223045036 -/*202*/, 65536*16* -0.0064868164183708756 -/*203*/, 65536*16* -0.007096559102022994 -/*204*/, 65536*16* -0.007615322236172286 -/*205*/, 65536*16* -0.008028460796606074 -/*206*/, 65536*16* -0.008322095341268461 -/*207*/, 65536*16* -0.008483337773170242 -/*208*/, 65536*16* -0.008500509194641638 -/*209*/, 65536*16* -0.008363346317351387 -/*210*/, 65536*16* -0.008063192746297233 -/*211*/, 65536*16* -0.007593172286363423 -/*212*/, 65536*16* -0.0069483408893122045 -/*213*/, 65536*16* -0.006125814985695579 -/*214*/, 65536*16* -0.005124873148956596 -/*215*/, 65536*16* -0.003947029569132915 -/*216*/, 65536*16* -0.002596077508306772 -/*217*/, 65536*16* -0.0010781012650798818 -/*218*/, 65536*16* 5.985434770618447E-4 -/*219*/, 65536*16* 0.0024232820773754 -/*220*/, 65536*16* 0.004383405101533075 -/*221*/, 65536*16* 0.006464184070028333 -/*222*/, 65536*16* 0.008649017282842432 -/*223*/, 65536*16* 0.010919604285452066 -/*224*/, 65536*16* 0.013256146772932903 -/*225*/, 65536*16* 0.015637573164024095 -/*226*/, 65536*16* 0.018041784432073237 -/*227*/, 65536*16* 0.020445917198990023 -/*228*/, 65536*16* 0.022826621253151515 -/*229*/, 65536*16* 0.025160347111354456 -/*230*/, 65536*16* 0.02742363969736895 -/*231*/, 65536*16* 0.02959343430076011 -/*232*/, 65536*16* 0.03164735012116834 -/*233*/, 65536*16* 0.03356397767681876 -/*234*/, 65536*16* 0.035323155364389396 -/*235*/, 65536*16* 0.03690623176571385 -/*236*/, 65536*16* 0.03829630932788767 -/*237*/, 65536*16* 0.03947846623700253 -/*238*/, 65536*16* 0.040439953107911 -/*239*/, 65536*16* 0.0411703612762271 -/*240*/, 65536*16* 0.04166176091370756 -/*241*/, 65536*16* 0.041908806136461134 +/*0*/ static_cast(65536*16* -5.9950991853042605E-6) +/*1*/, static_cast(65536*16* -3.0394382502604395E-6) +/*2*/, static_cast(65536*16* -3.728403434239284E-6) +/*3*/, static_cast(65536*16* -4.460351826790638E-6) +/*4*/, static_cast(65536*16* -5.2164320385801135E-6) +/*5*/, static_cast(65536*16* -5.9787071016806234E-6) +/*6*/, static_cast(65536*16* -6.716463411023574E-6) +/*7*/, static_cast(65536*16* -7.408551386580002E-6) +/*8*/, static_cast(65536*16* -8.023491429829738E-6) +/*9*/, static_cast(65536*16* -8.531232892238868E-6) +/*10*/, static_cast(65536*16* -8.878741512154837E-6) +/*11*/, static_cast(65536*16* -9.046773382992595E-6) +/*12*/, static_cast(65536*16* -8.993971214348702E-6) +/*13*/, static_cast(65536*16* -8.66944931521744E-6) +/*14*/, static_cast(65536*16* -8.049348524459474E-6) +/*15*/, static_cast(65536*16* -7.083238646482467E-6) +/*16*/, static_cast(65536*16* -5.746762349938464E-6) +/*17*/, static_cast(65536*16* -4.005753681691657E-6) +/*18*/, static_cast(65536*16* -1.838018035195733E-6) +/*19*/, static_cast(65536*16* 7.763983938828864E-7) +/*20*/, static_cast(65536*16* 3.842232025916005E-6) +/*21*/, static_cast(65536*16* 7.361161707034959E-6) +/*22*/, static_cast(65536*16* 1.1325948767988128E-5) +/*23*/, static_cast(65536*16* 1.5711486406341978E-5) +/*24*/, static_cast(65536*16* 2.0488201424957098E-5) +/*25*/, static_cast(65536*16* 2.5608402660083142E-5) +/*26*/, static_cast(65536*16* 3.101231858515874E-5) +/*27*/, static_cast(65536*16* 3.6630654060842745E-5) +/*28*/, static_cast(65536*16* 4.2375439803123404E-5) +/*29*/, static_cast(65536*16* 4.815060832963289E-5) +/*30*/, static_cast(65536*16* 5.384626411548906E-5) +/*31*/, static_cast(65536*16* 5.934549587237094E-5) +/*32*/, static_cast(65536*16* 6.451785679907682E-5) +/*33*/, static_cast(65536*16* 6.923065879553487E-5) +/*34*/, static_cast(65536*16* 7.334304650233838E-5) +/*35*/, static_cast(65536*16* 7.671308820252635E-5) +/*36*/, static_cast(65536*16* 7.920112989696133E-5) +/*37*/, static_cast(65536*16* 8.066793124218096E-5) +/*38*/, static_cast(65536*16* 8.098382483962539E-5) +/*39*/, static_cast(65536*16* 8.002921154479775E-5) +/*40*/, static_cast(65536*16* 7.769789869215064E-5) +/*41*/, static_cast(65536*16* 7.390152475899438E-5) +/*42*/, static_cast(65536*16* 6.857231550142758E-5) +/*43*/, static_cast(65536*16* 6.16673817460573E-5) +/*44*/, static_cast(65536*16* 5.3169767940001464E-5) +/*45*/, static_cast(65536*16* 4.309495398773014E-5) +/*46*/, static_cast(65536*16* 3.148737405995964E-5) +/*47*/, static_cast(65536*16* 1.8428415219696232E-5) +/*48*/, static_cast(65536*16* 4.0337781533928895E-6) +/*49*/, static_cast(65536*16* -1.154525373085283E-5) +/*50*/, static_cast(65536*16* -2.8120750949316567E-5) +/*51*/, static_cast(65536*16* -4.5470242422149815E-5) +/*52*/, static_cast(65536*16* -6.333736379615692E-5) +/*53*/, static_cast(65536*16* -8.143489509942166E-5) +/*54*/, static_cast(65536*16* -9.94475640226242E-5) +/*55*/, static_cast(65536*16* -1.1703729468742291E-4) +/*56*/, static_cast(65536*16* -1.3384679191408508E-4) +/*57*/, static_cast(65536*16* -1.4950548598267213E-4) +/*58*/, static_cast(65536*16* -1.6363792959068823E-4) +/*59*/, static_cast(65536*16* -1.7586732627086947E-4) +/*60*/, static_cast(65536*16* -1.858264971517669E-4) +/*61*/, static_cast(65536*16* -1.9316312487547242E-4) +/*62*/, static_cast(65536*16* -1.975494021862538E-4) +/*63*/, static_cast(65536*16* -1.9868977868165154E-4) +/*64*/, static_cast(65536*16* -1.963293865814053E-4) +/*65*/, static_cast(65536*16* -1.9026146175876417E-4) +/*66*/, static_cast(65536*16* -1.803352078962109E-4) +/*67*/, static_cast(65536*16* -1.66463443436789E-4) +/*68*/, static_cast(65536*16* -1.4862710934868261E-4) +/*69*/, static_cast(65536*16* -1.2688200452566298E-4) +/*70*/, static_cast(65536*16* -1.0136212853169677E-4) +/*71*/, static_cast(65536*16* -7.228199463954364E-5) +/*72*/, static_cast(65536*16* -3.9939461621236575E-5) +/*73*/, static_cast(65536*16* -4.7134932934724E-6) +/*74*/, static_cast(65536*16* 3.2936215273699675E-5) +/*75*/, static_cast(65536*16* 7.247384833064696E-5) +/*76*/, static_cast(65536*16* 1.1329187082792405E-4) +/*77*/, static_cast(65536*16* 1.5471948843725746E-4) +/*78*/, static_cast(65536*16* 1.9603027714808286E-4) +/*79*/, static_cast(65536*16* 2.364532958813608E-4) +/*80*/, static_cast(65536*16* 2.751853212246927E-4) +/*81*/, static_cast(65536*16* 3.114033208188799E-4) +/*82*/, static_cast(65536*16* 3.442804841775461E-4) +/*83*/, static_cast(65536*16* 3.7300098840546946E-4) +/*84*/, static_cast(65536*16* 3.967764136715296E-4) +/*85*/, static_cast(65536*16* 4.148631617351676E-4) +/*86*/, static_cast(65536*16* 4.265789297533608E-4) +/*87*/, static_cast(65536*16* 4.3132002526188114E-4) +/*88*/, static_cast(65536*16* 4.2857701618443636E-4) +/*89*/, static_cast(65536*16* 4.179510914969621E-4) +/*90*/, static_cast(65536*16* 3.991670037587729E-4) +/*91*/, static_cast(65536*16* 3.720870989970653E-4) +/*92*/, static_cast(65536*16* 3.367209236003282E-4) +/*93*/, static_cast(65536*16* 2.932338231303312E-4) +/*94*/, static_cast(65536*16* 2.419533571940393E-4) +/*95*/, static_cast(65536*16* 1.8337169647749448E-4) +/*96*/, static_cast(65536*16* 1.1814612711310299E-4) +/*97*/, static_cast(65536*16* 4.709567952563025E-5) +/*98*/, static_cast(65536*16* -2.880519351052945E-5) +/*99*/, static_cast(65536*16* -1.08436462295612E-4) +/*100*/, static_cast(65536*16* -1.905455293630124E-4) +/*101*/, static_cast(65536*16* -2.7376362665015007E-4) +/*102*/, static_cast(65536*16* -3.566259161939277E-4) +/*103*/, static_cast(65536*16* -4.375928024937683E-4) +/*104*/, static_cast(65536*16* -5.150762555847844E-4) +/*105*/, static_cast(65536*16* -5.874662774920191E-4) +/*106*/, static_cast(65536*16* -6.531605887419429E-4) +/*107*/, static_cast(65536*16* -7.105951946653638E-4) +/*108*/, static_cast(65536*16* -7.582757639600853E-4) +/*109*/, static_cast(65536*16* -7.948096207059845E-4) +/*110*/, static_cast(65536*16* -8.189373133065186E-4) +/*111*/, static_cast(65536*16* -8.295634640890689E-4) +/*112*/, static_cast(65536*16* -8.257854455404298E-4) +/*113*/, static_cast(65536*16* -8.069208861135825E-4) +/*114*/, static_cast(65536*16* -7.725316214556066E-4) +/*115*/, static_cast(65536*16* -7.224442067331338E-4) +/*116*/, static_cast(65536*16* -6.567673177902021E-4) +/*117*/, static_cast(65536*16* -5.759031970767677E-4) +/*118*/, static_cast(65536*16* -4.8055576975832975E-4) +/*119*/, static_cast(65536*16* -3.7173219275304865E-4) +/*120*/, static_cast(65536*16* -2.507394811359122E-4) +/*121*/, static_cast(65536*16* -1.191747608775131E-4) +/*122*/, static_cast(65536*16* 2.1089774143064154E-5) +/*123*/, static_cast(65536*16* 1.6792832047168277E-4) +/*124*/, static_cast(65536*16* 3.189887341095747E-4) +/*125*/, static_cast(65536*16* 4.7172479984555337E-4) +/*126*/, static_cast(65536*16* 6.234346495766704E-4) +/*127*/, static_cast(65536*16* 7.713029674040095E-4) +/*128*/, static_cast(65536*16* 9.124478381058291E-4) +/*129*/, static_cast(65536*16* 0.0010439713492973299) +/*130*/, static_cast(65536*16* 0.0011630121060354824) +/*131*/, static_cast(65536*16* 0.0012668003330792172) +/*132*/, static_cast(65536*16* 0.0013527131638668246) +/*133*/, static_cast(65536*16* 0.0014183305230994348) +/*134*/, static_cast(65536*16* 0.0014614889365474647) +/*135*/, static_cast(65536*16* 0.0014803340336415063) +/*136*/, static_cast(65536*16* 0.0014733688575452508) +/*137*/, static_cast(65536*16* 0.001439498243826639) +/*138*/, static_cast(65536*16* 0.0013780680098511918) +/*139*/, static_cast(65536*16* 0.0012888970057146566) +/*140*/, static_cast(65536*16* 0.0011723026532406624) +/*141*/, static_cast(65536*16* 0.0010291180003947405) +/*142*/, static_cast(65536*16* 8.607001658653358E-4) +/*143*/, static_cast(65536*16* 6.689295599970792E-4) +/*144*/, static_cast(65536*16* 4.5619928199453885E-4) +/*145*/, static_cast(65536*16* 2.253948582736753E-4) +/*146*/, static_cast(65536*16* -2.0136349562764177E-5) +/*147*/, static_cast(65536*16* -2.766248035657636E-4) +/*148*/, static_cast(65536*16* -5.399290507797791E-4) +/*149*/, static_cast(65536*16* -8.055939397996815E-4) +/*150*/, static_cast(65536*16* -0.0010689177291287714) +/*151*/, static_cast(65536*16* -0.0013250265370767429) +/*152*/, static_cast(65536*16* -0.0015689549600474482) +/*153*/, static_cast(65536*16* -0.0017957322527663085) +/*154*/, static_cast(65536*16* -0.002000472024117418) +/*155*/, static_cast(65536*16* -0.0021784645223266222) +/*156*/, static_cast(65536*16* -0.0023252695222818146) +/*157*/, static_cast(65536*16* -0.0024368087083972345) +/*158*/, static_cast(65536*16* -0.002509455241851095) +/*159*/, static_cast(65536*16* -0.0025401189567937766) +/*160*/, static_cast(65536*16* -0.0025263261450844377) +/*161*/, static_cast(65536*16* -0.0024662908754217406) +/*162*/, static_cast(65536*16* -0.002358977944127433) +/*163*/, static_cast(65536*16* -0.002204154401342649) +/*164*/, static_cast(65536*16* -0.002002429343138771) +/*165*/, static_cast(65536*16* -0.0017552803385372808) +/*166*/, static_cast(65536*16* -0.0014650656045065488) +/*167*/, static_cast(65536*16* -0.001135021049166992) +/*168*/, static_cast(65536*16* -7.692415547098649E-4) +/*169*/, static_cast(65536*16* -3.7264671522013244E-4) +/*170*/, static_cast(65536*16* 4.906989195928291E-5) +/*171*/, static_cast(65536*16* 4.895067103339711E-4) +/*172*/, static_cast(65536*16* 9.416355837269647E-4) +/*173*/, static_cast(65536*16* 0.001397897684142057) +/*174*/, static_cast(65536*16* 0.0018503121614766558) +/*175*/, static_cast(65536*16* 0.002290597319733804) +/*176*/, static_cast(65536*16* 0.0027103015920374113) +/*177*/, static_cast(65536*16* 0.0031009433327120863) +/*178*/, static_cast(65536*16* 0.0034541565687980116) +/*179*/, static_cast(65536*16* 0.0037618412630103333) +/*180*/, static_cast(65536*16* 0.004016315066649496) +/*181*/, static_cast(65536*16* 0.004210464374744574) +/*182*/, static_cast(65536*16* 0.004337892288164658) +/*183*/, static_cast(65536*16* 0.004393060165490985) +/*184*/, static_cast(65536*16* 0.004371421226297046) +/*185*/, static_cast(65536*16* 0.004269542847715132) +/*186*/, static_cast(65536*16* 0.00408521543517564) +/*187*/, static_cast(65536*16* 0.0038175457430583526) +/*188*/, static_cast(65536*16* 0.00346703221076496) +/*189*/, static_cast(65536*16* 0.0030356209846777236) +/*190*/, static_cast(65536*16* 0.002526740400739804) +/*191*/, static_cast(65536*16* 0.0019453134428630866) +/*192*/, static_cast(65536*16* 0.0012977462825954304) +/*193*/, static_cast(65536*16* 5.918933555500828E-4) +/*194*/, static_cast(65536*16* -1.6300197379338156E-4) +/*195*/, static_cast(65536*16* -9.563908629597664E-4) +/*196*/, static_cast(65536*16* -0.0017765255338228524) +/*197*/, static_cast(65536*16* -0.0026105886000394158) +/*198*/, static_cast(65536*16* -0.003444843158936217) +/*199*/, static_cast(65536*16* -0.004264802433556331) +/*200*/, static_cast(65536*16* -0.00505541655658742) +/*201*/, static_cast(65536*16* -0.005801274223045036) +/*202*/, static_cast(65536*16* -0.0064868164183708756) +/*203*/, static_cast(65536*16* -0.007096559102022994) +/*204*/, static_cast(65536*16* -0.007615322236172286) +/*205*/, static_cast(65536*16* -0.008028460796606074) +/*206*/, static_cast(65536*16* -0.008322095341268461) +/*207*/, static_cast(65536*16* -0.008483337773170242) +/*208*/, static_cast(65536*16* -0.008500509194641638) +/*209*/, static_cast(65536*16* -0.008363346317351387) +/*210*/, static_cast(65536*16* -0.008063192746297233) +/*211*/, static_cast(65536*16* -0.007593172286363423) +/*212*/, static_cast(65536*16* -0.0069483408893122045) +/*213*/, static_cast(65536*16* -0.006125814985695579) +/*214*/, static_cast(65536*16* -0.005124873148956596) +/*215*/, static_cast(65536*16* -0.003947029569132915) +/*216*/, static_cast(65536*16* -0.002596077508306772) +/*217*/, static_cast(65536*16* -0.0010781012650798818) +/*218*/, static_cast(65536*16* 5.985434770618447E-4) +/*219*/, static_cast(65536*16* 0.0024232820773754) +/*220*/, static_cast(65536*16* 0.004383405101533075) +/*221*/, static_cast(65536*16* 0.006464184070028333) +/*222*/, static_cast(65536*16* 0.008649017282842432) +/*223*/, static_cast(65536*16* 0.010919604285452066) +/*224*/, static_cast(65536*16* 0.013256146772932903) +/*225*/, static_cast(65536*16* 0.015637573164024095) +/*226*/, static_cast(65536*16* 0.018041784432073237) +/*227*/, static_cast(65536*16* 0.020445917198990023) +/*228*/, static_cast(65536*16* 0.022826621253151515) +/*229*/, static_cast(65536*16* 0.025160347111354456) +/*230*/, static_cast(65536*16* 0.02742363969736895) +/*231*/, static_cast(65536*16* 0.02959343430076011) +/*232*/, static_cast(65536*16* 0.03164735012116834) +/*233*/, static_cast(65536*16* 0.03356397767681876) +/*234*/, static_cast(65536*16* 0.035323155364389396) +/*235*/, static_cast(65536*16* 0.03690623176571385) +/*236*/, static_cast(65536*16* 0.03829630932788767) +/*237*/, static_cast(65536*16* 0.03947846623700253) +/*238*/, static_cast(65536*16* 0.040439953107911) +/*239*/, static_cast(65536*16* 0.0411703612762271) +/*240*/, static_cast(65536*16* 0.04166176091370756) +/*241*/, static_cast(65536*16* 0.041908806136461134) }; /* @@ -307,248 +307,248 @@ Coefficients: static const int32 C96000PAL[NCOEFFS/2]= { -/*0*/ 65536*16* 3.850781559466991E-7 -/*1*/, 65536*16* -1.280019401722687E-6 -/*2*/, 65536*16* -1.3004583488088965E-6 -/*3*/, 65536*16* -1.7523167437749452E-6 -/*4*/, 65536*16* -2.410249470764872E-6 -/*5*/, 65536*16* -3.2346426554155092E-6 -/*6*/, 65536*16* -4.227271662321092E-6 -/*7*/, 65536*16* -5.3971678027414914E-6 -/*8*/, 65536*16* -6.753444785567694E-6 -/*9*/, 65536*16* -8.302128790766257E-6 -/*10*/, 65536*16* -1.0045896006160685E-5 -/*11*/, 65536*16* -1.1982368218542129E-5 -/*12*/, 65536*16* -1.4104296519058353E-5 -/*13*/, 65536*16* -1.6397945806910793E-5 -/*14*/, 65536*16* -1.8843550708827064E-5 -/*15*/, 65536*16* -2.1413952016264175E-5 -/*16*/, 65536*16* -2.407540699773165E-5 -/*17*/, 65536*16* -2.6786418491045868E-5 -/*18*/, 65536*16* -2.949883620881563E-5 -/*19*/, 65536*16* -3.215685693993941E-5 -/*20*/, 65536*16* -3.4698621200866915E-5 -/*21*/, 65536*16* -3.7055635055088747E-5 -/*22*/, 65536*16* -3.915516367387583E-5 -/*23*/, 65536*16* -4.092005046973106E-5 -/*24*/, 65536*16* -4.227173792151256E-5 -/*25*/, 65536*16* -4.313002076491602E-5 -/*26*/, 65536*16* -4.3416606424857764E-5 -/*27*/, 65536*16* -4.3054793786740716E-5 -/*28*/, 65536*16* -4.1974462257106624E-5 -/*29*/, 65536*16* -4.011236719136458E-5 -/*30*/, 65536*16* -3.7415159397597796E-5 -/*31*/, 65536*16* -3.3846213818414235E-5 -/*32*/, 65536*16* -2.9372757531099172E-5 -/*33*/, 65536*16* -2.3989695934591954E-5 -/*34*/, 65536*16* -1.7705989252101064E-5 -/*35*/, 65536*16* -1.0551320217411096E-5 -/*36*/, 65536*16* -2.5775325043216536E-6 -/*37*/, 65536*16* 6.139645766572715E-6 -/*38*/, 65536*16* 1.5501423038008354E-5 -/*39*/, 65536*16* 2.5384753820737575E-5 -/*40*/, 65536*16* 3.5643398684518664E-5 -/*41*/, 65536*16* 4.6108393091574726E-5 -/*42*/, 65536*16* 5.659011526249589E-5 -/*43*/, 65536*16* 6.68803323899828E-5 -/*44*/, 65536*16* 7.675537622878941E-5 -/*45*/, 65536*16* 8.597960059720824E-5 -/*46*/, 65536*16* 9.430960279897814E-5 -/*47*/, 65536*16* 1.0149893801465577E-4 -/*48*/, 65536*16* 1.0730328189856642E-4 -/*49*/, 65536*16* 1.1148622997923174E-4 -/*50*/, 65536*16* 1.1382511217545132E-4 -/*51*/, 65536*16* 1.141174295909343E-4 -/*52*/, 65536*16* 1.1218671460549208E-4 -/*53*/, 65536*16* 1.078890398041802E-4 -/*54*/, 65536*16* 1.0111839925160891E-4 -/*55*/, 65536*16* 9.181292532691402E-5 -/*56*/, 65536*16* 7.995923739813694E-5 -/*57*/, 65536*16* 6.559772591687974E-5 -/*58*/, 65536*16* 4.882471526869663E-5 -/*59*/, 65536*16* 2.9795861807919456E-5 -/*60*/, 65536*16* 8.727003235393024E-6 -/*61*/, 65536*16* -1.4106777294769694E-5 -/*62*/, 65536*16* -3.836880959229582E-5 -/*63*/, 65536*16* -6.366921149307032E-5 -/*64*/, 65536*16* -8.956481187350594E-5 -/*65*/, 65536*16* -1.1556632861786434E-4 -/*66*/, 65536*16* -1.411455941949306E-4 -/*67*/, 65536*16* -1.657445386231986E-4 -/*68*/, 65536*16* -1.8878427001863077E-4 -/*69*/, 65536*16* -2.0967688285495866E-4 -/*70*/, 65536*16* -2.2783715638612827E-4 -/*71*/, 65536*16* -2.4269587549180196E-4 -/*72*/, 65536*16* -2.5371305459897316E-4 -/*73*/, 65536*16* -2.603919787720978E-4 -/*74*/, 65536*16* -2.6229284265917287E-4 -/*75*/, 65536*16* -2.59046413963889E-4 -/*76*/, 65536*16* -2.503668396740634E-4 -/*77*/, 65536*16* -2.3606367328604213E-4 -/*78*/, 65536*16* -2.160524966650091E-4 -/*79*/, 65536*16* -1.903639226156617E-4 -/*80*/, 65536*16* -1.59150691014015E-4 -/*81*/, 65536*16* -1.2269241610349266E-4 -/*82*/, 65536*16* -8.139812226735764E-5 -/*83*/, 65536*16* -3.5805772732231955E-5 -/*84*/, 65536*16* 1.3420603339835859E-5 -/*85*/, 65536*16* 6.549742374431074E-5 -/*86*/, 65536*16* 1.1953033076822495E-4 -/*87*/, 65536*16* 1.745269622757623E-4 -/*88*/, 65536*16* 2.2941123586808386E-4 -/*89*/, 65536*16* 2.830419125977025E-4 -/*90*/, 65536*16* 3.3423267917052983E-4 -/*91*/, 65536*16* 3.81774499172079E-4 -/*92*/, 65536*16* 4.244616654237554E-4 -/*93*/, 65536*16* 4.611154134679936E-4 -/*94*/, 65536*16* 4.906128810250551E-4 -/*95*/, 65536*16* 5.119138315653597E-4 -/*96*/, 65536*16* 5.240878477917174E-4 -/*97*/, 65536*16* 5.263406012974186E-4 -/*98*/, 65536*16* 5.180395272684202E-4 -/*99*/, 65536*16* 4.987363674123535E-4 -/*100*/, 65536*16* 4.681879119879578E-4 -/*101*/, 65536*16* 4.263728836819278E-4 -/*102*/, 65536*16* 3.735054898141368E-4 -/*103*/, 65536*16* 3.1004425441119956E-4 -/*104*/, 65536*16* 2.3669640454159868E-4 -/*105*/, 65536*16* 1.5441686754990788E-4 -/*106*/, 65536*16* 6.440207419421148E-5 -/*107*/, 65536*16* -3.192198333335273E-5 -/*108*/, 65536*16* -1.3291717686663037E-4 -/*109*/, 65536*16* -2.3675627296534203E-4 -/*110*/, 65536*16* -3.414512496033162E-4 -/*111*/, 65536*16* -4.4488659997924806E-4 -/*112*/, 65536*16* -5.44857304239037E-4 -/*113*/, 65536*16* -6.391106241040588E-4 -/*114*/, 65536*16* -7.253914361418537E-4 -/*115*/, 65536*16* -8.0148962040363E-4 -/*116*/, 65536*16* -8.652895191393541E-4 -/*117*/, 65536*16* -9.148193159968953E-4 -/*118*/, 65536*16* -9.483009583169883E-4 -/*119*/, 65536*16* -9.64197392644944E-4 -/*120*/, 65536*16* -9.612579850877552E-4 -/*121*/, 65536*16* -9.385600118624972E-4 -/*122*/, 65536*16* -8.955444281498081E-4 -/*123*/, 65536*16* -8.320477398703453E-4 -/*124*/, 65536*16* -7.483247067952744E-4 -/*125*/, 65536*16* -6.450648142040654E-4 -/*126*/, 65536*16* -5.234000259248345E-4 -/*127*/, 65536*16* -3.8490357943433983E-4 -/*128*/, 65536*16* -2.3157879639504726E-4 -/*129*/, 65536*16* -6.583909529283622E-5 -/*130*/, 65536*16* 1.0952239530879758E-4 -/*131*/, 65536*16* 2.9137227027685464E-4 -/*132*/, 65536*16* 4.76285797012954E-4 -/*133*/, 65536*16* 6.606041066674581E-4 -/*134*/, 65536*16* 8.404993785845289E-4 -/*135*/, 65536*16* 0.0010120465600366754 -/*136*/, 65536*16* 0.00117130077980147 -/*137*/, 65536*16* 0.0013143787565297594 -/*138*/, 65536*16* 0.0014375429397231808 -/*139*/, 65536*16* 0.0015372865339524395 -/*140*/, 65536*16* 0.0016104178085955662 -/*141*/, 65536*16* 0.0016541417860661317 -/*142*/, 65536*16* 0.0016661374441763997 -/*143*/, 65536*16* 0.0016446287155235182 -/*144*/, 65536*16* 0.0015884472759871292 -/*145*/, 65536*16* 0.0014970858621845143 -/*146*/, 65536*16* 0.0013707399310406382 -/*147*/, 65536*16* 0.0012103371052757787 -/*148*/, 65536*16* 0.0010175519857289184 -/*149*/, 65536*16* 7.94807053668863E-4 -/*150*/, 65536*16* 5.452573395422002E-4 -/*151*/, 65536*16* 2.727594075846488E-4 -/*152*/, 65536*16* -1.8175144027827955E-5 -/*153*/, 65536*16* -3.2244298920455907E-4 -/*154*/, 65536*16* -6.344261333752713E-4 -/*155*/, 65536*16* -9.480839637356165E-4 -/*156*/, 65536*16* -0.001257058056943197 -/*157*/, 65536*16* -0.001554788246611654 -/*158*/, 65536*16* -0.001834637661184569 -/*159*/, 65536*16* -0.0020900256934556468 -/*160*/, 65536*16* -0.0023145651572872143 -/*161*/, 65536*16* -0.0025022020560114683 -/*162*/, 65536*16* -0.002647354498854991 -/*163*/, 65536*16* -0.002745048447695108 -/*164*/, 65536*16* -0.0027910469441460657 -/*165*/, 65536*16* -0.002781970255972488 -/*166*/, 65536*16* -0.0027154038464012363 -/*167*/, 65536*16* -0.002589991713387623 -/*168*/, 65536*16* -0.0024055123883779776 -/*169*/, 65536*16* -0.0021629354924022053 -/*170*/, 65536*16* -0.0018644567566629092 -/*171*/, 65536*16* -0.0015135100031795994 -/*172*/, 65536*16* -0.0011147548631940517 -/*173*/, 65536*16* -6.740394224166433E-4 -/*174*/, 65536*16* -1.9833762845333352E-4 -/*175*/, 65536*16* 3.043386309556266E-4 -/*176*/, 65536*16* 8.250516255359581E-4 -/*177*/, 65536*16* 0.0013540734762851313 -/*178*/, 65536*16* 0.0018810427835111666 -/*179*/, 65536*16* 0.002395141352428365 -/*180*/, 65536*16* 0.002885286937512414 -/*181*/, 65536*16* 0.0033403397957704442 -/*182*/, 65536*16* 0.003749319662913449 -/*183*/, 65536*16* 0.00410162844368435 -/*184*/, 65536*16* 0.00438727601255591 -/*185*/, 65536*16* 0.004597103692808949 -/*186*/, 65536*16* 0.004723001540295747 -/*187*/, 65536*16* 0.004758115147888017 -/*188*/, 65536*16* 0.0046970379302800494 -/*189*/, 65536*16* 0.0045359837766146575 -/*190*/, 65536*16* 0.004272937350956345 -/*191*/, 65536*16* 0.003907777448988567 -/*192*/, 65536*16* 0.0034423707924944227 -/*193*/, 65536*16* 0.0028806330094231125 -/*194*/, 65536*16* 0.0022285548928660825 -/*195*/, 65536*16* 0.0014941919971143964 -/*196*/, 65536*16* 6.876167025638233E-4 -/*197*/, 65536*16* -1.7916781098860902E-4 -/*198*/, 65536*16* -0.001092351250031068 -/*199*/, 65536*16* -0.002036476651580642 -/*200*/, 65536*16* -0.002994635788760751 -/*201*/, 65536*16* -0.003948697212655613 -/*202*/, 65536*16* -0.004879563858611486 -/*203*/, 65536*16* -0.005767456511229176 -/*204*/, 65536*16* -0.006592218979894068 -/*205*/, 65536*16* -0.007333640031607341 -/*206*/, 65536*16* -0.007971787269457032 -/*207*/, 65536*16* -0.008487346947516187 -/*208*/, 65536*16* -0.008861964740105959 -/*209*/, 65536*16* -0.009078580419089913 -/*210*/, 65536*16* -0.009121751784315056 -/*211*/, 65536*16* -0.008977961157199062 -/*212*/, 65536*16* -0.008635898786325313 -/*213*/, 65536*16* -0.008086718339557295 -/*214*/, 65536*16* -0.007324258683042848 -/*215*/, 65536*16* -0.0063452279676933475 -/*216*/, 65536*16* -0.005149346015761238 -/*217*/, 65536*16* -0.0037394415039958702 -/*218*/, 65536*16* -0.0021215012056140783 -/*219*/, 65536*16* -3.046703636518387E-4 -/*220*/, 65536*16* 0.0016987979320526618 -/*221*/, 65536*16* 0.0038736435001752246 -/*222*/, 65536*16* 0.006201749792159754 -/*223*/, 65536*16* 0.00866234250983842 -/*224*/, 65536*16* 0.011232233932071251 -/*225*/, 65536*16* 0.013886109426908738 -/*226*/, 65536*16* 0.016596852190097027 -/*227*/, 65536*16* 0.01933590131308301 -/*228*/, 65536*16* 0.022073637826085922 -/*229*/, 65536*16* 0.024779792715016697 -/*230*/, 65536*16* 0.027423870545765342 -/*231*/, 65536*16* 0.029975581949125456 -/*232*/, 65536*16* 0.03240527801144671 -/*233*/, 65536*16* 0.034684379593278115 -/*234*/, 65536*16* 0.03678579448103684 -/*235*/, 65536*16* 0.03868431571442653 -/*236*/, 65536*16* 0.04035699420925718 -/*237*/, 65536*16* 0.041783479941480954 -/*238*/, 65536*16* 0.04294632536294341 -/*239*/, 65536*16* 0.043831247006285705 -/*240*/, 65536*16* 0.044427339714649856 -/*241*/, 65536*16* 0.04472724072106236 +/*0*/ static_cast(65536*16* 3.850781559466991E-7) +/*1*/, static_cast(65536*16* -1.280019401722687E-6) +/*2*/, static_cast(65536*16* -1.3004583488088965E-6) +/*3*/, static_cast(65536*16* -1.7523167437749452E-6) +/*4*/, static_cast(65536*16* -2.410249470764872E-6) +/*5*/, static_cast(65536*16* -3.2346426554155092E-6) +/*6*/, static_cast(65536*16* -4.227271662321092E-6) +/*7*/, static_cast(65536*16* -5.3971678027414914E-6) +/*8*/, static_cast(65536*16* -6.753444785567694E-6) +/*9*/, static_cast(65536*16* -8.302128790766257E-6) +/*10*/, static_cast(65536*16* -1.0045896006160685E-5) +/*11*/, static_cast(65536*16* -1.1982368218542129E-5) +/*12*/, static_cast(65536*16* -1.4104296519058353E-5) +/*13*/, static_cast(65536*16* -1.6397945806910793E-5) +/*14*/, static_cast(65536*16* -1.8843550708827064E-5) +/*15*/, static_cast(65536*16* -2.1413952016264175E-5) +/*16*/, static_cast(65536*16* -2.407540699773165E-5) +/*17*/, static_cast(65536*16* -2.6786418491045868E-5) +/*18*/, static_cast(65536*16* -2.949883620881563E-5) +/*19*/, static_cast(65536*16* -3.215685693993941E-5) +/*20*/, static_cast(65536*16* -3.4698621200866915E-5) +/*21*/, static_cast(65536*16* -3.7055635055088747E-5) +/*22*/, static_cast(65536*16* -3.915516367387583E-5) +/*23*/, static_cast(65536*16* -4.092005046973106E-5) +/*24*/, static_cast(65536*16* -4.227173792151256E-5) +/*25*/, static_cast(65536*16* -4.313002076491602E-5) +/*26*/, static_cast(65536*16* -4.3416606424857764E-5) +/*27*/, static_cast(65536*16* -4.3054793786740716E-5) +/*28*/, static_cast(65536*16* -4.1974462257106624E-5) +/*29*/, static_cast(65536*16* -4.011236719136458E-5) +/*30*/, static_cast(65536*16* -3.7415159397597796E-5) +/*31*/, static_cast(65536*16* -3.3846213818414235E-5) +/*32*/, static_cast(65536*16* -2.9372757531099172E-5) +/*33*/, static_cast(65536*16* -2.3989695934591954E-5) +/*34*/, static_cast(65536*16* -1.7705989252101064E-5) +/*35*/, static_cast(65536*16* -1.0551320217411096E-5) +/*36*/, static_cast(65536*16* -2.5775325043216536E-6) +/*37*/, static_cast(65536*16* 6.139645766572715E-6) +/*38*/, static_cast(65536*16* 1.5501423038008354E-5) +/*39*/, static_cast(65536*16* 2.5384753820737575E-5) +/*40*/, static_cast(65536*16* 3.5643398684518664E-5) +/*41*/, static_cast(65536*16* 4.6108393091574726E-5) +/*42*/, static_cast(65536*16* 5.659011526249589E-5) +/*43*/, static_cast(65536*16* 6.68803323899828E-5) +/*44*/, static_cast(65536*16* 7.675537622878941E-5) +/*45*/, static_cast(65536*16* 8.597960059720824E-5) +/*46*/, static_cast(65536*16* 9.430960279897814E-5) +/*47*/, static_cast(65536*16* 1.0149893801465577E-4) +/*48*/, static_cast(65536*16* 1.0730328189856642E-4) +/*49*/, static_cast(65536*16* 1.1148622997923174E-4) +/*50*/, static_cast(65536*16* 1.1382511217545132E-4) +/*51*/, static_cast(65536*16* 1.141174295909343E-4) +/*52*/, static_cast(65536*16* 1.1218671460549208E-4) +/*53*/, static_cast(65536*16* 1.078890398041802E-4) +/*54*/, static_cast(65536*16* 1.0111839925160891E-4) +/*55*/, static_cast(65536*16* 9.181292532691402E-5) +/*56*/, static_cast(65536*16* 7.995923739813694E-5) +/*57*/, static_cast(65536*16* 6.559772591687974E-5) +/*58*/, static_cast(65536*16* 4.882471526869663E-5) +/*59*/, static_cast(65536*16* 2.9795861807919456E-5) +/*60*/, static_cast(65536*16* 8.727003235393024E-6) +/*61*/, static_cast(65536*16* -1.4106777294769694E-5) +/*62*/, static_cast(65536*16* -3.836880959229582E-5) +/*63*/, static_cast(65536*16* -6.366921149307032E-5) +/*64*/, static_cast(65536*16* -8.956481187350594E-5) +/*65*/, static_cast(65536*16* -1.1556632861786434E-4) +/*66*/, static_cast(65536*16* -1.411455941949306E-4) +/*67*/, static_cast(65536*16* -1.657445386231986E-4) +/*68*/, static_cast(65536*16* -1.8878427001863077E-4) +/*69*/, static_cast(65536*16* -2.0967688285495866E-4) +/*70*/, static_cast(65536*16* -2.2783715638612827E-4) +/*71*/, static_cast(65536*16* -2.4269587549180196E-4) +/*72*/, static_cast(65536*16* -2.5371305459897316E-4) +/*73*/, static_cast(65536*16* -2.603919787720978E-4) +/*74*/, static_cast(65536*16* -2.6229284265917287E-4) +/*75*/, static_cast(65536*16* -2.59046413963889E-4) +/*76*/, static_cast(65536*16* -2.503668396740634E-4) +/*77*/, static_cast(65536*16* -2.3606367328604213E-4) +/*78*/, static_cast(65536*16* -2.160524966650091E-4) +/*79*/, static_cast(65536*16* -1.903639226156617E-4) +/*80*/, static_cast(65536*16* -1.59150691014015E-4) +/*81*/, static_cast(65536*16* -1.2269241610349266E-4) +/*82*/, static_cast(65536*16* -8.139812226735764E-5) +/*83*/, static_cast(65536*16* -3.5805772732231955E-5) +/*84*/, static_cast(65536*16* 1.3420603339835859E-5) +/*85*/, static_cast(65536*16* 6.549742374431074E-5) +/*86*/, static_cast(65536*16* 1.1953033076822495E-4) +/*87*/, static_cast(65536*16* 1.745269622757623E-4) +/*88*/, static_cast(65536*16* 2.2941123586808386E-4) +/*89*/, static_cast(65536*16* 2.830419125977025E-4) +/*90*/, static_cast(65536*16* 3.3423267917052983E-4) +/*91*/, static_cast(65536*16* 3.81774499172079E-4) +/*92*/, static_cast(65536*16* 4.244616654237554E-4) +/*93*/, static_cast(65536*16* 4.611154134679936E-4) +/*94*/, static_cast(65536*16* 4.906128810250551E-4) +/*95*/, static_cast(65536*16* 5.119138315653597E-4) +/*96*/, static_cast(65536*16* 5.240878477917174E-4) +/*97*/, static_cast(65536*16* 5.263406012974186E-4) +/*98*/, static_cast(65536*16* 5.180395272684202E-4) +/*99*/, static_cast(65536*16* 4.987363674123535E-4) +/*100*/, static_cast(65536*16* 4.681879119879578E-4) +/*101*/, static_cast(65536*16* 4.263728836819278E-4) +/*102*/, static_cast(65536*16* 3.735054898141368E-4) +/*103*/, static_cast(65536*16* 3.1004425441119956E-4) +/*104*/, static_cast(65536*16* 2.3669640454159868E-4) +/*105*/, static_cast(65536*16* 1.5441686754990788E-4) +/*106*/, static_cast(65536*16* 6.440207419421148E-5) +/*107*/, static_cast(65536*16* -3.192198333335273E-5) +/*108*/, static_cast(65536*16* -1.3291717686663037E-4) +/*109*/, static_cast(65536*16* -2.3675627296534203E-4) +/*110*/, static_cast(65536*16* -3.414512496033162E-4) +/*111*/, static_cast(65536*16* -4.4488659997924806E-4) +/*112*/, static_cast(65536*16* -5.44857304239037E-4) +/*113*/, static_cast(65536*16* -6.391106241040588E-4) +/*114*/, static_cast(65536*16* -7.253914361418537E-4) +/*115*/, static_cast(65536*16* -8.0148962040363E-4) +/*116*/, static_cast(65536*16* -8.652895191393541E-4) +/*117*/, static_cast(65536*16* -9.148193159968953E-4) +/*118*/, static_cast(65536*16* -9.483009583169883E-4) +/*119*/, static_cast(65536*16* -9.64197392644944E-4) +/*120*/, static_cast(65536*16* -9.612579850877552E-4) +/*121*/, static_cast(65536*16* -9.385600118624972E-4) +/*122*/, static_cast(65536*16* -8.955444281498081E-4) +/*123*/, static_cast(65536*16* -8.320477398703453E-4) +/*124*/, static_cast(65536*16* -7.483247067952744E-4) +/*125*/, static_cast(65536*16* -6.450648142040654E-4) +/*126*/, static_cast(65536*16* -5.234000259248345E-4) +/*127*/, static_cast(65536*16* -3.8490357943433983E-4) +/*128*/, static_cast(65536*16* -2.3157879639504726E-4) +/*129*/, static_cast(65536*16* -6.583909529283622E-5) +/*130*/, static_cast(65536*16* 1.0952239530879758E-4) +/*131*/, static_cast(65536*16* 2.9137227027685464E-4) +/*132*/, static_cast(65536*16* 4.76285797012954E-4) +/*133*/, static_cast(65536*16* 6.606041066674581E-4) +/*134*/, static_cast(65536*16* 8.404993785845289E-4) +/*135*/, static_cast(65536*16* 0.0010120465600366754) +/*136*/, static_cast(65536*16* 0.00117130077980147) +/*137*/, static_cast(65536*16* 0.0013143787565297594) +/*138*/, static_cast(65536*16* 0.0014375429397231808) +/*139*/, static_cast(65536*16* 0.0015372865339524395) +/*140*/, static_cast(65536*16* 0.0016104178085955662) +/*141*/, static_cast(65536*16* 0.0016541417860661317) +/*142*/, static_cast(65536*16* 0.0016661374441763997) +/*143*/, static_cast(65536*16* 0.0016446287155235182) +/*144*/, static_cast(65536*16* 0.0015884472759871292) +/*145*/, static_cast(65536*16* 0.0014970858621845143) +/*146*/, static_cast(65536*16* 0.0013707399310406382) +/*147*/, static_cast(65536*16* 0.0012103371052757787) +/*148*/, static_cast(65536*16* 0.0010175519857289184) +/*149*/, static_cast(65536*16* 7.94807053668863E-4) +/*150*/, static_cast(65536*16* 5.452573395422002E-4) +/*151*/, static_cast(65536*16* 2.727594075846488E-4) +/*152*/, static_cast(65536*16* -1.8175144027827955E-5) +/*153*/, static_cast(65536*16* -3.2244298920455907E-4) +/*154*/, static_cast(65536*16* -6.344261333752713E-4) +/*155*/, static_cast(65536*16* -9.480839637356165E-4) +/*156*/, static_cast(65536*16* -0.001257058056943197) +/*157*/, static_cast(65536*16* -0.001554788246611654) +/*158*/, static_cast(65536*16* -0.001834637661184569) +/*159*/, static_cast(65536*16* -0.0020900256934556468) +/*160*/, static_cast(65536*16* -0.0023145651572872143) +/*161*/, static_cast(65536*16* -0.0025022020560114683) +/*162*/, static_cast(65536*16* -0.002647354498854991) +/*163*/, static_cast(65536*16* -0.002745048447695108) +/*164*/, static_cast(65536*16* -0.0027910469441460657) +/*165*/, static_cast(65536*16* -0.002781970255972488) +/*166*/, static_cast(65536*16* -0.0027154038464012363) +/*167*/, static_cast(65536*16* -0.002589991713387623) +/*168*/, static_cast(65536*16* -0.0024055123883779776) +/*169*/, static_cast(65536*16* -0.0021629354924022053) +/*170*/, static_cast(65536*16* -0.0018644567566629092) +/*171*/, static_cast(65536*16* -0.0015135100031795994) +/*172*/, static_cast(65536*16* -0.0011147548631940517) +/*173*/, static_cast(65536*16* -6.740394224166433E-4) +/*174*/, static_cast(65536*16* -1.9833762845333352E-4) +/*175*/, static_cast(65536*16* 3.043386309556266E-4) +/*176*/, static_cast(65536*16* 8.250516255359581E-4) +/*177*/, static_cast(65536*16* 0.0013540734762851313) +/*178*/, static_cast(65536*16* 0.0018810427835111666) +/*179*/, static_cast(65536*16* 0.002395141352428365) +/*180*/, static_cast(65536*16* 0.002885286937512414) +/*181*/, static_cast(65536*16* 0.0033403397957704442) +/*182*/, static_cast(65536*16* 0.003749319662913449) +/*183*/, static_cast(65536*16* 0.00410162844368435) +/*184*/, static_cast(65536*16* 0.00438727601255591) +/*185*/, static_cast(65536*16* 0.004597103692808949) +/*186*/, static_cast(65536*16* 0.004723001540295747) +/*187*/, static_cast(65536*16* 0.004758115147888017) +/*188*/, static_cast(65536*16* 0.0046970379302800494) +/*189*/, static_cast(65536*16* 0.0045359837766146575) +/*190*/, static_cast(65536*16* 0.004272937350956345) +/*191*/, static_cast(65536*16* 0.003907777448988567) +/*192*/, static_cast(65536*16* 0.0034423707924944227) +/*193*/, static_cast(65536*16* 0.0028806330094231125) +/*194*/, static_cast(65536*16* 0.0022285548928660825) +/*195*/, static_cast(65536*16* 0.0014941919971143964) +/*196*/, static_cast(65536*16* 6.876167025638233E-4) +/*197*/, static_cast(65536*16* -1.7916781098860902E-4) +/*198*/, static_cast(65536*16* -0.001092351250031068) +/*199*/, static_cast(65536*16* -0.002036476651580642) +/*200*/, static_cast(65536*16* -0.002994635788760751) +/*201*/, static_cast(65536*16* -0.003948697212655613) +/*202*/, static_cast(65536*16* -0.004879563858611486) +/*203*/, static_cast(65536*16* -0.005767456511229176) +/*204*/, static_cast(65536*16* -0.006592218979894068) +/*205*/, static_cast(65536*16* -0.007333640031607341) +/*206*/, static_cast(65536*16* -0.007971787269457032) +/*207*/, static_cast(65536*16* -0.008487346947516187) +/*208*/, static_cast(65536*16* -0.008861964740105959) +/*209*/, static_cast(65536*16* -0.009078580419089913) +/*210*/, static_cast(65536*16* -0.009121751784315056) +/*211*/, static_cast(65536*16* -0.008977961157199062) +/*212*/, static_cast(65536*16* -0.008635898786325313) +/*213*/, static_cast(65536*16* -0.008086718339557295) +/*214*/, static_cast(65536*16* -0.007324258683042848) +/*215*/, static_cast(65536*16* -0.0063452279676933475) +/*216*/, static_cast(65536*16* -0.005149346015761238) +/*217*/, static_cast(65536*16* -0.0037394415039958702) +/*218*/, static_cast(65536*16* -0.0021215012056140783) +/*219*/, static_cast(65536*16* -3.046703636518387E-4) +/*220*/, static_cast(65536*16* 0.0016987979320526618) +/*221*/, static_cast(65536*16* 0.0038736435001752246) +/*222*/, static_cast(65536*16* 0.006201749792159754) +/*223*/, static_cast(65536*16* 0.00866234250983842) +/*224*/, static_cast(65536*16* 0.011232233932071251) +/*225*/, static_cast(65536*16* 0.013886109426908738) +/*226*/, static_cast(65536*16* 0.016596852190097027) +/*227*/, static_cast(65536*16* 0.01933590131308301) +/*228*/, static_cast(65536*16* 0.022073637826085922) +/*229*/, static_cast(65536*16* 0.024779792715016697) +/*230*/, static_cast(65536*16* 0.027423870545765342) +/*231*/, static_cast(65536*16* 0.029975581949125456) +/*232*/, static_cast(65536*16* 0.03240527801144671) +/*233*/, static_cast(65536*16* 0.034684379593278115) +/*234*/, static_cast(65536*16* 0.03678579448103684) +/*235*/, static_cast(65536*16* 0.03868431571442653) +/*236*/, static_cast(65536*16* 0.04035699420925718) +/*237*/, static_cast(65536*16* 0.041783479941480954) +/*238*/, static_cast(65536*16* 0.04294632536294341) +/*239*/, static_cast(65536*16* 0.043831247006285705) +/*240*/, static_cast(65536*16* 0.044427339714649856) +/*241*/, static_cast(65536*16* 0.04472724072106236) }; /* @@ -563,248 +563,248 @@ Stopband attenuation: 60.0 dB */ static const int32 C48000NTSC[NCOEFFS/2]= { -/*0*/ 65536*16* -1.2211019733097893E-4 -/*1*/ , 65536*16* 5.374660789759626E-4 -/*2*/ , 65536*16* 1.9882723274804067E-4 -/*3*/ , 65536*16* 1.3631041618360223E-4 -/*4*/ , 65536*16* 1.3153691128499229E-4 -/*5*/ , 65536*16* 1.3886281724158703E-4 -/*6*/ , 65536*16* 1.4887278966773673E-4 -/*7*/ , 65536*16* 1.5943890243162037E-4 -/*8*/ , 65536*16* 1.7020639605259616E-4 -/*9*/ , 65536*16* 1.809192079749018E-4 -/*10*/ , 65536*16* 1.9162093203709557E-4 -/*11*/ , 65536*16* 2.02127312351196E-4 -/*12*/ , 65536*16* 2.1249848894399555E-4 -/*13*/ , 65536*16* 2.2254095363111247E-4 -/*14*/ , 65536*16* 2.323202963851337E-4 -/*15*/ , 65536*16* 2.4163344759163413E-4 -/*16*/ , 65536*16* 2.505472122265602E-4 -/*17*/ , 65536*16* 2.5885306226458603E-4 -/*18*/ , 65536*16* 2.6660828860384193E-4 -/*19*/ , 65536*16* 2.736061193417779E-4 -/*20*/ , 65536*16* 2.79907587492226E-4 -/*21*/ , 65536*16* 2.852884076207648E-4 -/*22*/ , 65536*16* 2.898305905338908E-4 -/*23*/ , 65536*16* 2.93305922863925E-4 -/*24*/ , 65536*16* 2.958004341042564E-4 -/*25*/ , 65536*16* 2.9706939623100196E-4 -/*26*/ , 65536*16* 2.972508466837626E-4 -/*27*/ , 65536*16* 2.960684730022295E-4 -/*28*/ , 65536*16* 2.937123123731801E-4 -/*29*/ , 65536*16* 2.898634667442807E-4 -/*30*/ , 65536*16* 2.8478700978604426E-4 -/*31*/ , 65536*16* 2.7808505097364714E-4 -/*32*/ , 65536*16* 2.7016032300539216E-4 -/*33*/ , 65536*16* 2.6042025835357706E-4 -/*34*/ , 65536*16* 2.496053090718662E-4 -/*35*/ , 65536*16* 2.3660011363209167E-4 -/*36*/ , 65536*16* 2.228827056917728E-4 -/*37*/ , 65536*16* 2.0662381151599093E-4 -/*38*/ , 65536*16* 1.8946729340692708E-4 -/*39*/ , 65536*16* 1.707894290302382E-4 -/*40*/ , 65536*16* 1.4964075656329285E-4 -/*41*/ , 65536*16* 1.2806315562352013E-4 -/*42*/ , 65536*16* 1.0470129333132878E-4 -/*43*/ , 65536*16* 7.952742687952367E-5 -/*44*/ , 65536*16* 5.3080519892589936E-5 -/*45*/ , 65536*16* 2.5960680465529317E-5 -/*46*/ , 65536*16* -2.5651586484338896E-6 -/*47*/ , 65536*16* -3.248840068536756E-5 -/*48*/ , 65536*16* -6.374045088088799E-5 -/*49*/ , 65536*16* -9.575401529845337E-5 -/*50*/ , 65536*16* -1.2853435644071695E-4 -/*51*/ , 65536*16* -1.6188456243132127E-4 -/*52*/ , 65536*16* -1.9591394048834482E-4 -/*53*/ , 65536*16* -2.3037663947407175E-4 -/*54*/ , 65536*16* -2.6523734278928246E-4 -/*55*/ , 65536*16* -3.0020331327926296E-4 -/*56*/ , 65536*16* -3.352268879856044E-4 -/*57*/ , 65536*16* -3.700260022275662E-4 -/*58*/ , 65536*16* -4.045571559416333E-4 -/*59*/ , 65536*16* -4.38534577720557E-4 -/*60*/ , 65536*16* -4.718927645081437E-4 -/*61*/ , 65536*16* -5.043317033789757E-4 -/*62*/ , 65536*16* -5.357994753678582E-4 -/*63*/ , 65536*16* -5.659671580788766E-4 -/*64*/ , 65536*16* -5.947897013020397E-4 -/*65*/ , 65536*16* -6.219384666963997E-4 -/*66*/ , 65536*16* -6.473787936195385E-4 -/*67*/ , 65536*16* -6.707514595741775E-4 -/*68*/ , 65536*16* -6.920680579893526E-4 -/*69*/ , 65536*16* -7.109402066802999E-4 -/*70*/ , 65536*16* -7.274298271538291E-4 -/*71*/ , 65536*16* -7.411375648954899E-4 -/*72*/ , 65536*16* -7.520788343347275E-4 -/*73*/ , 65536*16* -7.600510659768832E-4 -/*74*/ , 65536*16* -7.647430899316486E-4 -/*75*/ , 65536*16* -7.664294191482773E-4 -/*76*/ , 65536*16* -7.644147173692687E-4 -/*77*/ , 65536*16* -7.590920613362674E-4 -/*78*/ , 65536*16* -7.501459543641885E-4 -/*79*/ , 65536*16* -7.373621082253133E-4 -/*80*/ , 65536*16* -7.208964561671388E-4 -/*81*/ , 65536*16* -7.006901755632023E-4 -/*82*/ , 65536*16* -6.764591748580997E-4 -/*83*/ , 65536*16* -6.483697284795448E-4 -/*84*/ , 65536*16* -6.164929718400197E-4 -/*85*/ , 65536*16* -5.806918766677904E-4 -/*86*/ , 65536*16* -5.409344735839229E-4 -/*87*/ , 65536*16* -4.97405373620265E-4 -/*88*/ , 65536*16* -4.502086002815554E-4 -/*89*/ , 65536*16* -3.9932330033988294E-4 -/*90*/ , 65536*16* -3.448028565721092E-4 -/*91*/ , 65536*16* -2.8685420307046736E-4 -/*92*/ , 65536*16* -2.256958038579715E-4 -/*93*/ , 65536*16* -1.615040528190604E-4 -/*94*/ , 65536*16* -9.438524808984473E-5 -/*95*/ , 65536*16* -2.4519303584370608E-5 -/*96*/ , 65536*16* 4.786961616483501E-5 -/*97*/ , 65536*16* 1.2248011782462745E-4 -/*98*/ , 65536*16* 1.990534978611127E-4 -/*99*/ , 65536*16* 2.7728245405517893E-4 -/*100*/ , 65536*16* 3.5690342407690407E-4 -/*101*/ , 65536*16* 4.376002679601721E-4 -/*102*/ , 65536*16* 5.19047629492113E-4 -/*103*/ , 65536*16* 6.008846564336277E-4 -/*104*/ , 65536*16* 6.827617063818499E-4 -/*105*/ , 65536*16* 7.643160551093983E-4 -/*106*/ , 65536*16* 8.451272011819538E-4 -/*107*/ , 65536*16* 9.248890776355356E-4 -/*108*/ , 65536*16* 0.001003072355955673 -/*109*/ , 65536*16* 0.0010794672777372975 -/*110*/ , 65536*16* 0.0011534276232606116 -/*111*/ , 65536*16* 0.0012247823207262698 -/*112*/ , 65536*16* 0.0012929541324917778 -/*113*/ , 65536*16* 0.001357585199795128 -/*114*/ , 65536*16* 0.001418338397346014 -/*115*/ , 65536*16* 0.0014746734285279383 -/*116*/ , 65536*16* 0.0015262884930771822 -/*117*/ , 65536*16* 0.0015728226550844923 -/*118*/ , 65536*16* 0.00161379655898045 -/*119*/ , 65536*16* 0.001648915948444658 -/*120*/ , 65536*16* 0.0016778840108713717 -/*121*/ , 65536*16* 0.0017002560629258679 -/*122*/ , 65536*16* 0.0017157641984855009 -/*123*/ , 65536*16* 0.0017241805985007432 -/*124*/ , 65536*16* 0.001725182645995729 -/*125*/ , 65536*16* 0.0017184841648036691 -/*126*/ , 65536*16* 0.0017039216808435336 -/*127*/ , 65536*16* 0.001681334520841587 -/*128*/ , 65536*16* 0.0016504918660173195 -/*129*/ , 65536*16* 0.0016112687597971862 -/*130*/ , 65536*16* 0.0015636063248128528 -/*131*/ , 65536*16* 0.0015074624593932396 -/*132*/ , 65536*16* 0.0014427699009003175 -/*133*/ , 65536*16* 0.001369527394628539 -/*134*/ , 65536*16* 0.0012878043567412672 -/*135*/ , 65536*16* 0.0011977101442406943 -/*136*/ , 65536*16* 0.0010993686954177168 -/*137*/ , 65536*16* 9.928872878864818E-4 -/*138*/ , 65536*16* 8.784941174786496E-4 -/*139*/ , 65536*16* 7.564288883294911E-4 -/*140*/ , 65536*16* 6.270372159510238E-4 -/*141*/ , 65536*16* 4.905983779660314E-4 -/*142*/ , 65536*16* 3.4754116793679786E-4 -/*143*/ , 65536*16* 1.9816162887093084E-4 -/*144*/ , 65536*16* 4.300342678121075E-5 -/*145*/ , 65536*16* -1.1751370467978956E-4 -/*146*/ , 65536*16* -2.8280605795854083E-4 -/*147*/ , 65536*16* -4.523173545514795E-4 -/*148*/ , 65536*16* -6.255041797790695E-4 -/*149*/ , 65536*16* -8.016355996557292E-4 -/*150*/ , 65536*16* -9.801573426762404E-4 -/*151*/ , 65536*16* -0.0011602954820678437 -/*152*/ , 65536*16* -0.001341343986206184 -/*153*/ , 65536*16* -0.001522571621631356 -/*154*/ , 65536*16* -0.001703172768158951 -/*155*/ , 65536*16* -0.0018823360844618293 -/*156*/ , 65536*16* -0.00205930337901632 -/*157*/ , 65536*16* -0.0022331579230920632 -/*158*/ , 65536*16* -0.002403069015327 -/*159*/ , 65536*16* -0.0025682175666884455 -/*160*/ , 65536*16* -0.002727682820990084 -/*161*/ , 65536*16* -0.002880584481539458 -/*162*/ , 65536*16* -0.003026077683940661 -/*163*/ , 65536*16* -0.00316326704154516 -/*164*/ , 65536*16* -0.003291235176827385 -/*165*/ , 65536*16* -0.0034091436232751705 -/*166*/ , 65536*16* -0.0035161624262765347 -/*167*/ , 65536*16* -0.00361139707788214 -/*168*/ , 65536*16* -0.0036940241232429707 -/*169*/ , 65536*16* -0.003763249197925811 -/*170*/ , 65536*16* -0.0038183138554794805 -/*171*/ , 65536*16* -0.003858413648517434 -/*172*/ , 65536*16* -0.0038828565696081884 -/*173*/ , 65536*16* -0.0038909308779192654 -/*174*/ , 65536*16* -0.0038820231307916493 -/*175*/ , 65536*16* -0.0038554750792844325 -/*176*/ , 65536*16* -0.003810737282493679 -/*177*/ , 65536*16* -0.003747262375484652 -/*178*/ , 65536*16* -0.0036646285078894706 -/*179*/ , 65536*16* -0.0035623728689170597 -/*180*/ , 65536*16* -0.0034401218523635543 -/*181*/ , 65536*16* -0.003297594128579178 -/*182*/ , 65536*16* -0.0031344918897463427 -/*183*/ , 65536*16* -0.0029506999116335536 -/*184*/ , 65536*16* -0.002746012743503227 -/*185*/ , 65536*16* -0.0025204082871514897 -/*186*/ , 65536*16* -0.0022738407863853822 -/*187*/ , 65536*16* -0.0020063873037173175 -/*188*/ , 65536*16* -0.0017182175415557032 -/*189*/ , 65536*16* -0.0014095092681882975 -/*190*/ , 65536*16* -0.0010805220633352567 -/*191*/ , 65536*16* -7.316077716348434E-4 -/*192*/ , 65536*16* -3.631468249678417E-4 -/*193*/ , 65536*16* 2.438177178474359E-5 -/*194*/ , 65536*16* 4.3040711526763105E-4 -/*195*/ , 65536*16* 8.543758511240976E-4 -/*196*/ , 65536*16* 0.0012955688715509065 -/*197*/ , 65536*16* 0.0017532574138845757 -/*198*/ , 65536*16* 0.0022266720975588176 -/*199*/ , 65536*16* 0.0027149312534676365 -/*200*/ , 65536*16* 0.003217102703811305 -/*201*/ , 65536*16* 0.0037322302087511496 -/*202*/ , 65536*16* 0.004259307964559864 -/*203*/ , 65536*16* 0.004797205731205993 -/*204*/ , 65536*16* 0.00534482556712745 -/*205*/ , 65536*16* 0.00590099232932727 -/*206*/ , 65536*16* 0.0064644836497811 -/*207*/ , 65536*16* 0.007034017389280477 -/*208*/ , 65536*16* 0.007608353016621833 -/*209*/ , 65536*16* 0.008186157965561618 -/*210*/ , 65536*16* 0.008766068964147668 -/*211*/ , 65536*16* 0.009346716260147759 -/*212*/ , 65536*16* 0.009926718862388615 -/*213*/ , 65536*16* 0.010504681043184161 -/*214*/ , 65536*16* 0.01107917387309342 -/*215*/ , 65536*16* 0.011648797102049465 -/*216*/ , 65536*16* 0.012212089485935572 -/*217*/ , 65536*16* 0.012767702033610684 -/*218*/ , 65536*16* 0.01331416222058608 -/*219*/ , 65536*16* 0.013850107485964188 -/*220*/ , 65536*16* 0.01437415626494087 -/*221*/ , 65536*16* 0.01488494484218882 -/*222*/ , 65536*16* 0.015381157046388828 -/*223*/ , 65536*16* 0.015861470914555698 -/*224*/ , 65536*16* 0.016324639468324405 -/*225*/ , 65536*16* 0.01676942738258265 -/*226*/ , 65536*16* 0.017194657140859698 -/*227*/ , 65536*16* 0.01759919326505855 -/*228*/ , 65536*16* 0.01798195744932672 -/*229*/ , 65536*16* 0.018341882104229386 -/*230*/ , 65536*16* 0.018678046774501487 -/*231*/ , 65536*16* 0.018989525183852277 -/*232*/ , 65536*16* 0.019275463483745325 -/*233*/ , 65536*16* 0.019535099985330217 -/*234*/ , 65536*16* 0.019767681230128092 -/*235*/ , 65536*16* 0.019972616359274192 -/*236*/ , 65536*16* 0.02014933369102741 -/*237*/ , 65536*16* 0.020297350637687013 -/*238*/ , 65536*16* 0.020416241350314838 -/*239*/ , 65536*16* 0.020505719050281913 -/*240*/ , 65536*16* 0.020565502954380747 -/*241*/ , 65536*16* 0.02059542406883178 +/*0*/ static_cast( 65536*16* -1.2211019733097893E-4) +/*1*/ , static_cast(65536*16* 5.374660789759626E-4) +/*2*/ , static_cast(65536*16* 1.9882723274804067E-4) +/*3*/ , static_cast(65536*16* 1.3631041618360223E-4) +/*4*/ , static_cast(65536*16* 1.3153691128499229E-4) +/*5*/ , static_cast(65536*16* 1.3886281724158703E-4) +/*6*/ , static_cast(65536*16* 1.4887278966773673E-4) +/*7*/ , static_cast(65536*16* 1.5943890243162037E-4) +/*8*/ , static_cast(65536*16* 1.7020639605259616E-4) +/*9*/ , static_cast(65536*16* 1.809192079749018E-4) +/*10*/ , static_cast(65536*16* 1.9162093203709557E-4) +/*11*/ , static_cast(65536*16* 2.02127312351196E-4) +/*12*/ , static_cast(65536*16* 2.1249848894399555E-4) +/*13*/ , static_cast(65536*16* 2.2254095363111247E-4) +/*14*/ , static_cast(65536*16* 2.323202963851337E-4) +/*15*/ , static_cast(65536*16* 2.4163344759163413E-4) +/*16*/ , static_cast(65536*16* 2.505472122265602E-4) +/*17*/ , static_cast(65536*16* 2.5885306226458603E-4) +/*18*/ , static_cast(65536*16* 2.6660828860384193E-4) +/*19*/ , static_cast(65536*16* 2.736061193417779E-4) +/*20*/ , static_cast(65536*16* 2.79907587492226E-4) +/*21*/ , static_cast(65536*16* 2.852884076207648E-4) +/*22*/ , static_cast(65536*16* 2.898305905338908E-4) +/*23*/ , static_cast(65536*16* 2.93305922863925E-4) +/*24*/ , static_cast(65536*16* 2.958004341042564E-4) +/*25*/ , static_cast(65536*16* 2.9706939623100196E-4) +/*26*/ , static_cast(65536*16* 2.972508466837626E-4) +/*27*/ , static_cast(65536*16* 2.960684730022295E-4) +/*28*/ , static_cast(65536*16* 2.937123123731801E-4) +/*29*/ , static_cast(65536*16* 2.898634667442807E-4) +/*30*/ , static_cast(65536*16* 2.8478700978604426E-4) +/*31*/ , static_cast(65536*16* 2.7808505097364714E-4) +/*32*/ , static_cast(65536*16* 2.7016032300539216E-4) +/*33*/ , static_cast(65536*16* 2.6042025835357706E-4) +/*34*/ , static_cast(65536*16* 2.496053090718662E-4) +/*35*/ , static_cast(65536*16* 2.3660011363209167E-4) +/*36*/ , static_cast(65536*16* 2.228827056917728E-4) +/*37*/ , static_cast(65536*16* 2.0662381151599093E-4) +/*38*/ , static_cast(65536*16* 1.8946729340692708E-4) +/*39*/ , static_cast(65536*16* 1.707894290302382E-4) +/*40*/ , static_cast(65536*16* 1.4964075656329285E-4) +/*41*/ , static_cast(65536*16* 1.2806315562352013E-4) +/*42*/ , static_cast(65536*16* 1.0470129333132878E-4) +/*43*/ , static_cast(65536*16* 7.952742687952367E-5) +/*44*/ , static_cast(65536*16* 5.3080519892589936E-5) +/*45*/ , static_cast(65536*16* 2.5960680465529317E-5) +/*46*/ , static_cast(65536*16* -2.5651586484338896E-6) +/*47*/ , static_cast(65536*16* -3.248840068536756E-5) +/*48*/ , static_cast(65536*16* -6.374045088088799E-5) +/*49*/ , static_cast(65536*16* -9.575401529845337E-5) +/*50*/ , static_cast(65536*16* -1.2853435644071695E-4) +/*51*/ , static_cast(65536*16* -1.6188456243132127E-4) +/*52*/ , static_cast(65536*16* -1.9591394048834482E-4) +/*53*/ , static_cast(65536*16* -2.3037663947407175E-4) +/*54*/ , static_cast(65536*16* -2.6523734278928246E-4) +/*55*/ , static_cast(65536*16* -3.0020331327926296E-4) +/*56*/ , static_cast(65536*16* -3.352268879856044E-4) +/*57*/ , static_cast(65536*16* -3.700260022275662E-4) +/*58*/ , static_cast(65536*16* -4.045571559416333E-4) +/*59*/ , static_cast(65536*16* -4.38534577720557E-4) +/*60*/ , static_cast(65536*16* -4.718927645081437E-4) +/*61*/ , static_cast(65536*16* -5.043317033789757E-4) +/*62*/ , static_cast(65536*16* -5.357994753678582E-4) +/*63*/ , static_cast(65536*16* -5.659671580788766E-4) +/*64*/ , static_cast(65536*16* -5.947897013020397E-4) +/*65*/ , static_cast(65536*16* -6.219384666963997E-4) +/*66*/ , static_cast(65536*16* -6.473787936195385E-4) +/*67*/ , static_cast(65536*16* -6.707514595741775E-4) +/*68*/ , static_cast(65536*16* -6.920680579893526E-4) +/*69*/ , static_cast(65536*16* -7.109402066802999E-4) +/*70*/ , static_cast(65536*16* -7.274298271538291E-4) +/*71*/ , static_cast(65536*16* -7.411375648954899E-4) +/*72*/ , static_cast(65536*16* -7.520788343347275E-4) +/*73*/ , static_cast(65536*16* -7.600510659768832E-4) +/*74*/ , static_cast(65536*16* -7.647430899316486E-4) +/*75*/ , static_cast(65536*16* -7.664294191482773E-4) +/*76*/ , static_cast(65536*16* -7.644147173692687E-4) +/*77*/ , static_cast(65536*16* -7.590920613362674E-4) +/*78*/ , static_cast(65536*16* -7.501459543641885E-4) +/*79*/ , static_cast(65536*16* -7.373621082253133E-4) +/*80*/ , static_cast(65536*16* -7.208964561671388E-4) +/*81*/ , static_cast(65536*16* -7.006901755632023E-4) +/*82*/ , static_cast(65536*16* -6.764591748580997E-4) +/*83*/ , static_cast(65536*16* -6.483697284795448E-4) +/*84*/ , static_cast(65536*16* -6.164929718400197E-4) +/*85*/ , static_cast(65536*16* -5.806918766677904E-4) +/*86*/ , static_cast(65536*16* -5.409344735839229E-4) +/*87*/ , static_cast(65536*16* -4.97405373620265E-4) +/*88*/ , static_cast(65536*16* -4.502086002815554E-4) +/*89*/ , static_cast(65536*16* -3.9932330033988294E-4) +/*90*/ , static_cast(65536*16* -3.448028565721092E-4) +/*91*/ , static_cast(65536*16* -2.8685420307046736E-4) +/*92*/ , static_cast(65536*16* -2.256958038579715E-4) +/*93*/ , static_cast(65536*16* -1.615040528190604E-4) +/*94*/ , static_cast(65536*16* -9.438524808984473E-5) +/*95*/ , static_cast(65536*16* -2.4519303584370608E-5) +/*96*/ , static_cast(65536*16* 4.786961616483501E-5) +/*97*/ , static_cast(65536*16* 1.2248011782462745E-4) +/*98*/ , static_cast(65536*16* 1.990534978611127E-4) +/*99*/ , static_cast(65536*16* 2.7728245405517893E-4) +/*100*/ , static_cast(65536*16* 3.5690342407690407E-4) +/*101*/ , static_cast(65536*16* 4.376002679601721E-4) +/*102*/ , static_cast(65536*16* 5.19047629492113E-4) +/*103*/ , static_cast(65536*16* 6.008846564336277E-4) +/*104*/ , static_cast(65536*16* 6.827617063818499E-4) +/*105*/ , static_cast(65536*16* 7.643160551093983E-4) +/*106*/ , static_cast(65536*16* 8.451272011819538E-4) +/*107*/ , static_cast(65536*16* 9.248890776355356E-4) +/*108*/ , static_cast(65536*16* 0.001003072355955673) +/*109*/ , static_cast(65536*16* 0.0010794672777372975) +/*110*/ , static_cast(65536*16* 0.0011534276232606116) +/*111*/ , static_cast(65536*16* 0.0012247823207262698) +/*112*/ , static_cast(65536*16* 0.0012929541324917778) +/*113*/ , static_cast(65536*16* 0.001357585199795128) +/*114*/ , static_cast(65536*16* 0.001418338397346014) +/*115*/ , static_cast(65536*16* 0.0014746734285279383) +/*116*/ , static_cast(65536*16* 0.0015262884930771822) +/*117*/ , static_cast(65536*16* 0.0015728226550844923) +/*118*/ , static_cast(65536*16* 0.00161379655898045) +/*119*/ , static_cast(65536*16* 0.001648915948444658) +/*120*/ , static_cast(65536*16* 0.0016778840108713717) +/*121*/ , static_cast(65536*16* 0.0017002560629258679) +/*122*/ , static_cast(65536*16* 0.0017157641984855009) +/*123*/ , static_cast(65536*16* 0.0017241805985007432) +/*124*/ , static_cast(65536*16* 0.001725182645995729) +/*125*/ , static_cast(65536*16* 0.0017184841648036691) +/*126*/ , static_cast(65536*16* 0.0017039216808435336) +/*127*/ , static_cast(65536*16* 0.001681334520841587) +/*128*/ , static_cast(65536*16* 0.0016504918660173195) +/*129*/ , static_cast(65536*16* 0.0016112687597971862) +/*130*/ , static_cast(65536*16* 0.0015636063248128528) +/*131*/ , static_cast(65536*16* 0.0015074624593932396) +/*132*/ , static_cast(65536*16* 0.0014427699009003175) +/*133*/ , static_cast(65536*16* 0.001369527394628539) +/*134*/ , static_cast(65536*16* 0.0012878043567412672) +/*135*/ , static_cast(65536*16* 0.0011977101442406943) +/*136*/ , static_cast(65536*16* 0.0010993686954177168) +/*137*/ , static_cast(65536*16* 9.928872878864818E-4) +/*138*/ , static_cast(65536*16* 8.784941174786496E-4) +/*139*/ , static_cast(65536*16* 7.564288883294911E-4) +/*140*/ , static_cast(65536*16* 6.270372159510238E-4) +/*141*/ , static_cast(65536*16* 4.905983779660314E-4) +/*142*/ , static_cast(65536*16* 3.4754116793679786E-4) +/*143*/ , static_cast(65536*16* 1.9816162887093084E-4) +/*144*/ , static_cast(65536*16* 4.300342678121075E-5) +/*145*/ , static_cast(65536*16* -1.1751370467978956E-4) +/*146*/ , static_cast(65536*16* -2.8280605795854083E-4) +/*147*/ , static_cast(65536*16* -4.523173545514795E-4) +/*148*/ , static_cast(65536*16* -6.255041797790695E-4) +/*149*/ , static_cast(65536*16* -8.016355996557292E-4) +/*150*/ , static_cast(65536*16* -9.801573426762404E-4) +/*151*/ , static_cast(65536*16* -0.0011602954820678437) +/*152*/ , static_cast(65536*16* -0.001341343986206184) +/*153*/ , static_cast(65536*16* -0.001522571621631356) +/*154*/ , static_cast(65536*16* -0.001703172768158951) +/*155*/ , static_cast(65536*16* -0.0018823360844618293) +/*156*/ , static_cast(65536*16* -0.00205930337901632) +/*157*/ , static_cast(65536*16* -0.0022331579230920632) +/*158*/ , static_cast(65536*16* -0.002403069015327) +/*159*/ , static_cast(65536*16* -0.0025682175666884455) +/*160*/ , static_cast(65536*16* -0.002727682820990084) +/*161*/ , static_cast(65536*16* -0.002880584481539458) +/*162*/ , static_cast(65536*16* -0.003026077683940661) +/*163*/ , static_cast(65536*16* -0.00316326704154516) +/*164*/ , static_cast(65536*16* -0.003291235176827385) +/*165*/ , static_cast(65536*16* -0.0034091436232751705) +/*166*/ , static_cast(65536*16* -0.0035161624262765347) +/*167*/ , static_cast(65536*16* -0.00361139707788214) +/*168*/ , static_cast(65536*16* -0.0036940241232429707) +/*169*/ , static_cast(65536*16* -0.003763249197925811) +/*170*/ , static_cast(65536*16* -0.0038183138554794805) +/*171*/ , static_cast(65536*16* -0.003858413648517434) +/*172*/ , static_cast(65536*16* -0.0038828565696081884) +/*173*/ , static_cast(65536*16* -0.0038909308779192654) +/*174*/ , static_cast(65536*16* -0.0038820231307916493) +/*175*/ , static_cast(65536*16* -0.0038554750792844325) +/*176*/ , static_cast(65536*16* -0.003810737282493679) +/*177*/ , static_cast(65536*16* -0.003747262375484652) +/*178*/ , static_cast(65536*16* -0.0036646285078894706) +/*179*/ , static_cast(65536*16* -0.0035623728689170597) +/*180*/ , static_cast(65536*16* -0.0034401218523635543) +/*181*/ , static_cast(65536*16* -0.003297594128579178) +/*182*/ , static_cast(65536*16* -0.0031344918897463427) +/*183*/ , static_cast(65536*16* -0.0029506999116335536) +/*184*/ , static_cast(65536*16* -0.002746012743503227) +/*185*/ , static_cast(65536*16* -0.0025204082871514897) +/*186*/ , static_cast(65536*16* -0.0022738407863853822) +/*187*/ , static_cast(65536*16* -0.0020063873037173175) +/*188*/ , static_cast(65536*16* -0.0017182175415557032) +/*189*/ , static_cast(65536*16* -0.0014095092681882975) +/*190*/ , static_cast(65536*16* -0.0010805220633352567) +/*191*/ , static_cast(65536*16* -7.316077716348434E-4) +/*192*/ , static_cast(65536*16* -3.631468249678417E-4) +/*193*/ , static_cast(65536*16* 2.438177178474359E-5) +/*194*/ , static_cast(65536*16* 4.3040711526763105E-4) +/*195*/ , static_cast(65536*16* 8.543758511240976E-4) +/*196*/ , static_cast(65536*16* 0.0012955688715509065) +/*197*/ , static_cast(65536*16* 0.0017532574138845757) +/*198*/ , static_cast(65536*16* 0.0022266720975588176) +/*199*/ , static_cast(65536*16* 0.0027149312534676365) +/*200*/ , static_cast(65536*16* 0.003217102703811305) +/*201*/ , static_cast(65536*16* 0.0037322302087511496) +/*202*/ , static_cast(65536*16* 0.004259307964559864) +/*203*/ , static_cast(65536*16* 0.004797205731205993) +/*204*/ , static_cast(65536*16* 0.00534482556712745) +/*205*/ , static_cast(65536*16* 0.00590099232932727) +/*206*/ , static_cast(65536*16* 0.0064644836497811) +/*207*/ , static_cast(65536*16* 0.007034017389280477) +/*208*/ , static_cast(65536*16* 0.007608353016621833) +/*209*/ , static_cast(65536*16* 0.008186157965561618) +/*210*/ , static_cast(65536*16* 0.008766068964147668) +/*211*/ , static_cast(65536*16* 0.009346716260147759) +/*212*/ , static_cast(65536*16* 0.009926718862388615) +/*213*/ , static_cast(65536*16* 0.010504681043184161) +/*214*/ , static_cast(65536*16* 0.01107917387309342) +/*215*/ , static_cast(65536*16* 0.011648797102049465) +/*216*/ , static_cast(65536*16* 0.012212089485935572) +/*217*/ , static_cast(65536*16* 0.012767702033610684) +/*218*/ , static_cast(65536*16* 0.01331416222058608) +/*219*/ , static_cast(65536*16* 0.013850107485964188) +/*220*/ , static_cast(65536*16* 0.01437415626494087) +/*221*/ , static_cast(65536*16* 0.01488494484218882) +/*222*/ , static_cast(65536*16* 0.015381157046388828) +/*223*/ , static_cast(65536*16* 0.015861470914555698) +/*224*/ , static_cast(65536*16* 0.016324639468324405) +/*225*/ , static_cast(65536*16* 0.01676942738258265) +/*226*/ , static_cast(65536*16* 0.017194657140859698) +/*227*/ , static_cast(65536*16* 0.01759919326505855) +/*228*/ , static_cast(65536*16* 0.01798195744932672) +/*229*/ , static_cast(65536*16* 0.018341882104229386) +/*230*/ , static_cast(65536*16* 0.018678046774501487) +/*231*/ , static_cast(65536*16* 0.018989525183852277) +/*232*/ , static_cast(65536*16* 0.019275463483745325) +/*233*/ , static_cast(65536*16* 0.019535099985330217) +/*234*/ , static_cast(65536*16* 0.019767681230128092) +/*235*/ , static_cast(65536*16* 0.019972616359274192) +/*236*/ , static_cast(65536*16* 0.02014933369102741) +/*237*/ , static_cast(65536*16* 0.020297350637687013) +/*238*/ , static_cast(65536*16* 0.020416241350314838) +/*239*/ , static_cast(65536*16* 0.020505719050281913) +/*240*/ , static_cast(65536*16* 0.020565502954380747) +/*241*/ , static_cast(65536*16* 0.02059542406883178) }; @@ -824,248 +824,248 @@ Coefficients: static const int32 C44100NTSC[NCOEFFS/2]= { -/*0*/ 65536 *16 * 2.7250584077004043E-4 -/*1*/, 65536 *16 * -5.6651407794062126E-5 -/*2*/, 65536 *16 * -5.387595203270082E-5 -/*3*/, 65536 *16 * -5.3104114528112036E-5 -/*4*/, 65536 *16 * -5.3927905431407917E-5 -/*5*/, 65536 *16 * -5.624810531844495E-5 -/*6*/, 65536 *16 * -5.9753966587005594E-5 -/*7*/, 65536 *16 * -6.443298022976466E-5 -/*8*/, 65536 *16 * -7.002861393823279E-5 -/*9*/, 65536 *16 * -7.658937335809571E-5 -/*10*/, 65536 *16 * -8.388337472693157E-5 -/*11*/, 65536 *16 * -9.20081628039712E-5 -/*12*/, 65536 *16 * -1.007311169050114E-4 -/*13*/, 65536 *16 * -1.1019992230503533E-4 -/*14*/, 65536 *16 * -1.2014773803429516E-4 -/*15*/, 65536 *16 * -1.3080398984366903E-4 -/*16*/, 65536 *16 * -1.4175865072457003E-4 -/*17*/, 65536 *16 * -1.536527853404198E-4 -/*18*/, 65536 *16 * -1.6517054562524376E-4 -/*19*/, 65536 *16 * -1.7797585116596963E-4 -/*20*/, 65536 *16 * -1.909845496405445E-4 -/*21*/, 65536 *16 * -2.0389566936141008E-4 -/*22*/, 65536 *16 * -2.1726846302640957E-4 -/*23*/, 65536 *16 * -2.310008165840215E-4 -/*24*/, 65536 *16 * -2.4506881863360544E-4 -/*25*/, 65536 *16 * -2.5926465655995895E-4 -/*26*/, 65536 *16 * -2.735381275272462E-4 -/*27*/, 65536 *16 * -2.878190904612406E-4 -/*28*/, 65536 *16 * -3.0209388781875723E-4 -/*29*/, 65536 *16 * -3.163448868528516E-4 -/*30*/, 65536 *16 * -3.30514980542584E-4 -/*31*/, 65536 *16 * -3.4458721564408845E-4 -/*32*/, 65536 *16 * -3.5843761692424506E-4 -/*33*/, 65536 *16 * -3.720823326733447E-4 -/*34*/, 65536 *16 * -3.8529611278848583E-4 -/*35*/, 65536 *16 * -3.982435971141635E-4 -/*36*/, 65536 *16 * -4.1054225307421383E-4 -/*37*/, 65536 *16 * -4.223385042208698E-4 -/*38*/, 65536 *16 * -4.3363210365443626E-4 -/*39*/, 65536 *16 * -4.440451096331875E-4 -/*40*/, 65536 *16 * -4.537334227294333E-4 -/*41*/, 65536 *16 * -4.6260960194346025E-4 -/*42*/, 65536 *16 * -4.706224417116799E-4 -/*43*/, 65536 *16 * -4.776010427698281E-4 -/*44*/, 65536 *16 * -4.8350610346281614E-4 -/*45*/, 65536 *16 * -4.8826489934975626E-4 -/*46*/, 65536 *16 * -4.918511387810396E-4 -/*47*/, 65536 *16 * -4.941839548845786E-4 -/*48*/, 65536 *16 * -4.95186572618022E-4 -/*49*/, 65536 *16 * -4.947817087436606E-4 -/*50*/, 65536 *16 * -4.928828353341973E-4 -/*51*/, 65536 *16 * -4.894676199661217E-4 -/*52*/, 65536 *16 * -4.8443244774343773E-4 -/*53*/, 65536 *16 * -4.778002134883142E-4 -/*54*/, 65536 *16 * -4.694896704084311E-4 -/*55*/, 65536 *16 * -4.593928438902496E-4 -/*56*/, 65536 *16 * -4.4763586771533415E-4 -/*57*/, 65536 *16 * -4.3399559196764174E-4 -/*58*/, 65536 *16 * -4.185187519793231E-4 -/*59*/, 65536 *16 * -4.0118338859945383E-4 -/*60*/, 65536 *16 * -3.820043675631783E-4 -/*61*/, 65536 *16 * -3.6090543967085524E-4 -/*62*/, 65536 *16 * -3.379128204177913E-4 -/*63*/, 65536 *16 * -3.130247503897743E-4 -/*64*/, 65536 *16 * -2.8628759491904673E-4 -/*65*/, 65536 *16 * -2.5769205396918157E-4 -/*66*/, 65536 *16 * -2.2726228845123853E-4 -/*67*/, 65536 *16 * -1.9501222414998665E-4 -/*68*/, 65536 *16 * -1.609903786128509E-4 -/*69*/, 65536 *16 * -1.2525258280646142E-4 -/*70*/, 65536 *16 * -8.786088130641809E-5 -/*71*/, 65536 *16 * -4.885883411475722E-5 -/*72*/, 65536 *16 * -8.373566315346232E-6 -/*73*/, 65536 *16 * 3.362843819360238E-5 -/*74*/, 65536 *16 * 7.69302822233031E-5 -/*75*/, 65536 *16 * 1.2151249228835434E-4 -/*76*/, 65536 *16 * 1.6724878315058612E-4 -/*77*/, 65536 *16 * 2.1402171363813576E-4 -/*78*/, 65536 *16 * 2.6167305946436103E-4 -/*79*/, 65536 *16 * 3.10122854445744E-4 -/*80*/, 65536 *16 * 3.5921866691687363E-4 -/*81*/, 65536 *16 * 4.0882826181233784E-4 -/*82*/, 65536 *16 * 4.5876834733749337E-4 -/*83*/, 65536 *16 * 5.089048509923103E-4 -/*84*/, 65536 *16 * 5.590621717784201E-4 -/*85*/, 65536 *16 * 6.090870406928206E-4 -/*86*/, 65536 *16 * 6.587768488216395E-4 -/*87*/, 65536 *16 * 7.079653533691067E-4 -/*88*/, 65536 *16 * 7.56434905175643E-4 -/*89*/, 65536 *16 * 8.040537989021466E-4 -/*90*/, 65536 *16 * 8.505576158388297E-4 -/*91*/, 65536 *16 * 8.958345533585908E-4 -/*92*/, 65536 *16 * 9.396170235698547E-4 -/*93*/, 65536 *16 * 9.817197600520506E-4 -/*94*/, 65536 *16 * 0.0010219440113723856 -/*95*/, 65536 *16 * 0.0010600976395277468 -/*96*/, 65536 *16 * 0.0010959465933076378 -/*97*/, 65536 *16 * 0.0011293213059753442 -/*98*/, 65536 *16 * 0.001160012212002378 -/*99*/, 65536 *16 * 0.0011878334518393636 -/*100*/, 65536 *16 * 0.0012125633172564833 -/*101*/, 65536 *16 * 0.0012340340153475305 -/*102*/, 65536 *16 * 0.0012520523486154733 -/*103*/, 65536 *16 * 0.001266464375255462 -/*104*/, 65536 *16 * 0.001277070934117742 -/*105*/, 65536 *16 * 0.0012837351142488396 -/*106*/, 65536 *16 * 0.0012862625405968798 -/*107*/, 65536 *16 * 0.0012845614834936406 -/*108*/, 65536 *16 * 0.0012784420593778636 -/*109*/, 65536 *16 * 0.0012678178114382621 -/*110*/, 65536 *16 * 0.0012525556826375537 -/*111*/, 65536 *16 * 0.0012325473943852084 -/*112*/, 65536 *16 * 0.0012077126268838676 -/*113*/, 65536 *16 * 0.0011779966448355029 -/*114*/, 65536 *16 * 0.0011433146771737655 -/*115*/, 65536 *16 * 0.0011036347058885887 -/*116*/, 65536 *16 * 0.0010589202139950945 -/*117*/, 65536 *16 * 0.0010091683044254098 -/*118*/, 65536 *16 * 9.543624468571229E-4 -/*119*/, 65536 *16 * 8.945398819399117E-4 -/*120*/, 65536 *16 * 8.297313883125644E-4 -/*121*/, 65536 *16 * 7.600155199968718E-4 -/*122*/, 65536 *16 * 6.854405952299358E-4 -/*123*/, 65536 *16 * 6.061236114458317E-4 -/*124*/, 65536 *16 * 5.221478191516476E-4 -/*125*/, 65536 *16 * 4.336813620599164E-4 -/*126*/, 65536 *16 * 3.408549526515998E-4 -/*127*/, 65536 *16 * 2.438450825114285E-4 -/*128*/, 65536 *16 * 1.428494911857926E-4 -/*129*/, 65536 *16 * 3.8067640594361634E-5 -/*130*/, 65536 *16 * -7.027035111775681E-5 -/*131*/, 65536 *16 * -1.818984143827126E-4 -/*132*/, 65536 *16 * -2.9656343184630157E-4 -/*133*/, 65536 *16 * -4.1397802421901906E-4 -/*134*/, 65536 *16 * -5.33838500742085E-4 -/*135*/, 65536 *16 * -6.558110253978588E-4 -/*136*/, 65536 *16 * -7.795655816897978E-4 -/*137*/, 65536 *16 * -9.047371821667003E-4 -/*138*/, 65536 *16 * -0.001030961345825847 -/*139*/, 65536 *16 * -0.0011578367988084777 -/*140*/, 65536 *16 * -0.0012849810572319298 -/*141*/, 65536 *16 * -0.0014119662266064482 -/*142*/, 65536 *16 * -0.0015383759515758101 -/*143*/, 65536 *16 * -0.001663756794188296 -/*144*/, 65536 *16 * -0.0017876541594460456 -/*145*/, 65536 *16 * -0.001909621722046808 -/*146*/, 65536 *16 * -0.0020291786719378088 -/*147*/, 65536 *16 * -0.002145855089743562 -/*148*/, 65536 *16 * -0.002259171910476534 -/*149*/, 65536 *16 * -0.0023686314802222655 -/*150*/, 65536 *16 * -0.002473745572697707 -/*151*/, 65536 *16 * -0.0025740277587192853 -/*152*/, 65536 *16 * -0.0026689831666099955 -/*153*/, 65536 *16 * -0.0027581124255643377 -/*154*/, 65536 *16 * -0.0028409282136656177 -/*155*/, 65536 *16 * -0.0029169432593640367 -/*156*/, 65536 *16 * -0.002985680612410139 -/*157*/, 65536 *16 * -0.003046658228485494 -/*158*/, 65536 *16 * -0.003099414222252269 -/*159*/, 65536 *16 * -0.0031434902530511595 -/*160*/, 65536 *16 * -0.003178436798255356 -/*161*/, 65536 *16 * -0.0032038260756887147 -/*162*/, 65536 *16 * -0.003219225355080285 -/*163*/, 65536 *16 * -0.0032242502222488744 -/*164*/, 65536 *16 * -0.003218506103318342 -/*165*/, 65536 *16 * -0.003201625222636992 -/*166*/, 65536 *16 * -0.003173259488065382 -/*167*/, 65536 *16 * -0.0031330803817718332 -/*168*/, 65536 *16 * -0.0030807779128908526 -/*169*/, 65536 *16 * -0.0030160821637947783 -/*170*/, 65536 *16 * -0.0029387362752889335 -/*171*/, 65536 *16 * -0.002848510131379585 -/*172*/, 65536 *16 * -0.0027451998188029363 -/*173*/, 65536 *16 * -0.00262863682904045 -/*174*/, 65536 *16 * -0.0024986780420415064 -/*175*/, 65536 *16 * -0.0023552114528323513 -/*176*/, 65536 *16 * -0.0021981491527779964 -/*177*/, 65536 *16 * -0.0020274504745732714 -/*178*/, 65536 *16 * -0.0018430877753141852 -/*179*/, 65536 *16 * -0.0016450910502005863 -/*180*/, 65536 *16 * -0.0014334955802048866 -/*181*/, 65536 *16 * -0.0012083983821827642 -/*182*/, 65536 *16 * -9.699135443572468E-4 -/*183*/, 65536 *16 * -7.181935207475589E-4 -/*184*/, 65536 *16 * -4.534224887286362E-4 -/*185*/, 65536 *16 * -1.758311300125605E-4 -/*186*/, 65536 *16 * 1.1433027008948132E-4 -/*187*/, 65536 *16 * 4.1675921199616097E-4 -/*188*/, 65536 *16 * 7.311320710094336E-4 -/*189*/, 65536 *16 * 0.0010570872458505827 -/*190*/, 65536 *16 * 0.0013942372682560795 -/*191*/, 65536 *16 * 0.001742148094642797 -/*192*/, 65536 *16 * 0.002100362793433286 -/*193*/, 65536 *16 * 0.0024683818857210646 -/*194*/, 65536 *16 * 0.002845695057494279 -/*195*/, 65536 *16 * 0.0032317385772924275 -/*196*/, 65536 *16 * 0.0036259433326630884 -/*197*/, 65536 *16 * 0.0040276894120370626 -/*198*/, 65536 *16 * 0.004436353627556968 -/*199*/, 65536 *16 * 0.004851271439526238 -/*200*/, 65536 *16 * 0.005271762758295799 -/*201*/, 65536 *16 * 0.005697120565601845 -/*202*/, 65536 *16 * 0.006126626859240469 -/*203*/, 65536 *16 * 0.006559527746778011 -/*204*/, 65536 *16 * 0.0069950693344747504 -/*205*/, 65536 *16 * 0.007432470090915211 -/*206*/, 65536 *16 * 0.007870944336430185 -/*207*/, 65536 *16 * 0.008309688701943495 -/*208*/, 65536 *16 * 0.008747898549370043 -/*209*/, 65536 *16 * 0.009184747205291654 -/*210*/, 65536 *16 * 0.009619414724898365 -/*211*/, 65536 *16 * 0.010051063453485451 -/*212*/, 65536 *16 * 0.010478876316671397 -/*213*/, 65536 *16 * 0.010902016899039163 -/*214*/, 65536 *16 * 0.011319665474466693 -/*215*/, 65536 *16 * 0.011730992134403782 -/*216*/, 65536 *16 * 0.012135186113163639 -/*217*/, 65536 *16 * 0.01253143889871197 -/*218*/, 65536 *16 * 0.012918956981226547 -/*219*/, 65536 *16 * 0.013296952886747157 -/*220*/, 65536 *16 * 0.013664665893392403 -/*221*/, 65536 *16 * 0.014021339353548561 -/*222*/, 65536 *16 * 0.014366244972764902 -/*223*/, 65536 *16 * 0.014698670942210527 -/*224*/, 65536 *16 * 0.015017930945351435 -/*225*/, 65536 *16 * 0.015323359168800435 -/*226*/, 65536 *16 * 0.015614322198635518 -/*227*/, 65536 *16 * 0.015890204972590742 -/*228*/, 65536 *16 * 0.016150433344740527 -/*229*/, 65536 *16 * 0.01639445378257351 -/*230*/, 65536 *16 * 0.016621758349582072 -/*231*/, 65536 *16 * 0.01683186471138077 -/*232*/, 65536 *16 * 0.01702432745775747 -/*233*/, 65536 *16 * 0.017198732908190056 -/*234*/, 65536 *16 * 0.017354710361561963 -/*235*/, 65536 *16 * 0.017491928210652433 -/*236*/, 65536 *16 * 0.017610096156964024 -/*237*/, 65536 *16 * 0.017708958417438553 -/*238*/, 65536 *16 * 0.017788304726419644 -/*239*/, 65536 *16 * 0.01784796484627723 -/*240*/, 65536 *16 * 0.017887808513528385 -/*241*/, 65536 *16 * 0.01790775243433271 +/*0*/ static_cast(65536 *16 * 2.7250584077004043E-4) +/*1*/, static_cast(65536 *16 * -5.6651407794062126E-5) +/*2*/, static_cast(65536 *16 * -5.387595203270082E-5) +/*3*/, static_cast(65536 *16 * -5.3104114528112036E-5) +/*4*/, static_cast(65536 *16 * -5.3927905431407917E-5) +/*5*/, static_cast(65536 *16 * -5.624810531844495E-5) +/*6*/, static_cast(65536 *16 * -5.9753966587005594E-5) +/*7*/, static_cast(65536 *16 * -6.443298022976466E-5) +/*8*/, static_cast(65536 *16 * -7.002861393823279E-5) +/*9*/, static_cast(65536 *16 * -7.658937335809571E-5) +/*10*/, static_cast(65536 *16 * -8.388337472693157E-5) +/*11*/, static_cast(65536 *16 * -9.20081628039712E-5) +/*12*/, static_cast(65536 *16 * -1.007311169050114E-4) +/*13*/, static_cast(65536 *16 * -1.1019992230503533E-4) +/*14*/, static_cast(65536 *16 * -1.2014773803429516E-4) +/*15*/, static_cast(65536 *16 * -1.3080398984366903E-4) +/*16*/, static_cast(65536 *16 * -1.4175865072457003E-4) +/*17*/, static_cast(65536 *16 * -1.536527853404198E-4) +/*18*/, static_cast(65536 *16 * -1.6517054562524376E-4) +/*19*/, static_cast(65536 *16 * -1.7797585116596963E-4) +/*20*/, static_cast(65536 *16 * -1.909845496405445E-4) +/*21*/, static_cast(65536 *16 * -2.0389566936141008E-4) +/*22*/, static_cast(65536 *16 * -2.1726846302640957E-4) +/*23*/, static_cast(65536 *16 * -2.310008165840215E-4) +/*24*/, static_cast(65536 *16 * -2.4506881863360544E-4) +/*25*/, static_cast(65536 *16 * -2.5926465655995895E-4) +/*26*/, static_cast(65536 *16 * -2.735381275272462E-4) +/*27*/, static_cast(65536 *16 * -2.878190904612406E-4) +/*28*/, static_cast(65536 *16 * -3.0209388781875723E-4) +/*29*/, static_cast(65536 *16 * -3.163448868528516E-4) +/*30*/, static_cast(65536 *16 * -3.30514980542584E-4) +/*31*/, static_cast(65536 *16 * -3.4458721564408845E-4) +/*32*/, static_cast(65536 *16 * -3.5843761692424506E-4) +/*33*/, static_cast(65536 *16 * -3.720823326733447E-4) +/*34*/, static_cast(65536 *16 * -3.8529611278848583E-4) +/*35*/, static_cast(65536 *16 * -3.982435971141635E-4) +/*36*/, static_cast(65536 *16 * -4.1054225307421383E-4) +/*37*/, static_cast(65536 *16 * -4.223385042208698E-4) +/*38*/, static_cast(65536 *16 * -4.3363210365443626E-4) +/*39*/, static_cast(65536 *16 * -4.440451096331875E-4) +/*40*/, static_cast(65536 *16 * -4.537334227294333E-4) +/*41*/, static_cast(65536 *16 * -4.6260960194346025E-4) +/*42*/, static_cast(65536 *16 * -4.706224417116799E-4) +/*43*/, static_cast(65536 *16 * -4.776010427698281E-4) +/*44*/, static_cast(65536 *16 * -4.8350610346281614E-4) +/*45*/, static_cast(65536 *16 * -4.8826489934975626E-4) +/*46*/, static_cast(65536 *16 * -4.918511387810396E-4) +/*47*/, static_cast(65536 *16 * -4.941839548845786E-4) +/*48*/, static_cast(65536 *16 * -4.95186572618022E-4) +/*49*/, static_cast(65536 *16 * -4.947817087436606E-4) +/*50*/, static_cast(65536 *16 * -4.928828353341973E-4) +/*51*/, static_cast(65536 *16 * -4.894676199661217E-4) +/*52*/, static_cast(65536 *16 * -4.8443244774343773E-4) +/*53*/, static_cast(65536 *16 * -4.778002134883142E-4) +/*54*/, static_cast(65536 *16 * -4.694896704084311E-4) +/*55*/, static_cast(65536 *16 * -4.593928438902496E-4) +/*56*/, static_cast(65536 *16 * -4.4763586771533415E-4) +/*57*/, static_cast(65536 *16 * -4.3399559196764174E-4) +/*58*/, static_cast(65536 *16 * -4.185187519793231E-4) +/*59*/, static_cast(65536 *16 * -4.0118338859945383E-4) +/*60*/, static_cast(65536 *16 * -3.820043675631783E-4) +/*61*/, static_cast(65536 *16 * -3.6090543967085524E-4) +/*62*/, static_cast(65536 *16 * -3.379128204177913E-4) +/*63*/, static_cast(65536 *16 * -3.130247503897743E-4) +/*64*/, static_cast(65536 *16 * -2.8628759491904673E-4) +/*65*/, static_cast(65536 *16 * -2.5769205396918157E-4) +/*66*/, static_cast(65536 *16 * -2.2726228845123853E-4) +/*67*/, static_cast(65536 *16 * -1.9501222414998665E-4) +/*68*/, static_cast(65536 *16 * -1.609903786128509E-4) +/*69*/, static_cast(65536 *16 * -1.2525258280646142E-4) +/*70*/, static_cast(65536 *16 * -8.786088130641809E-5) +/*71*/, static_cast(65536 *16 * -4.885883411475722E-5) +/*72*/, static_cast(65536 *16 * -8.373566315346232E-6) +/*73*/, static_cast(65536 *16 * 3.362843819360238E-5) +/*74*/, static_cast(65536 *16 * 7.69302822233031E-5) +/*75*/, static_cast(65536 *16 * 1.2151249228835434E-4) +/*76*/, static_cast(65536 *16 * 1.6724878315058612E-4) +/*77*/, static_cast(65536 *16 * 2.1402171363813576E-4) +/*78*/, static_cast(65536 *16 * 2.6167305946436103E-4) +/*79*/, static_cast(65536 *16 * 3.10122854445744E-4) +/*80*/, static_cast(65536 *16 * 3.5921866691687363E-4) +/*81*/, static_cast(65536 *16 * 4.0882826181233784E-4) +/*82*/, static_cast(65536 *16 * 4.5876834733749337E-4) +/*83*/, static_cast(65536 *16 * 5.089048509923103E-4) +/*84*/, static_cast(65536 *16 * 5.590621717784201E-4) +/*85*/, static_cast(65536 *16 * 6.090870406928206E-4) +/*86*/, static_cast(65536 *16 * 6.587768488216395E-4) +/*87*/, static_cast(65536 *16 * 7.079653533691067E-4) +/*88*/, static_cast(65536 *16 * 7.56434905175643E-4) +/*89*/, static_cast(65536 *16 * 8.040537989021466E-4) +/*90*/, static_cast(65536 *16 * 8.505576158388297E-4) +/*91*/, static_cast(65536 *16 * 8.958345533585908E-4) +/*92*/, static_cast(65536 *16 * 9.396170235698547E-4) +/*93*/, static_cast(65536 *16 * 9.817197600520506E-4) +/*94*/, static_cast(65536 *16 * 0.0010219440113723856) +/*95*/, static_cast(65536 *16 * 0.0010600976395277468) +/*96*/, static_cast(65536 *16 * 0.0010959465933076378) +/*97*/, static_cast(65536 *16 * 0.0011293213059753442) +/*98*/, static_cast(65536 *16 * 0.001160012212002378) +/*99*/, static_cast(65536 *16 * 0.0011878334518393636) +/*100*/, static_cast(65536 *16 * 0.0012125633172564833) +/*101*/, static_cast(65536 *16 * 0.0012340340153475305) +/*102*/, static_cast(65536 *16 * 0.0012520523486154733) +/*103*/, static_cast(65536 *16 * 0.001266464375255462) +/*104*/, static_cast(65536 *16 * 0.001277070934117742) +/*105*/, static_cast(65536 *16 * 0.0012837351142488396) +/*106*/, static_cast(65536 *16 * 0.0012862625405968798) +/*107*/, static_cast(65536 *16 * 0.0012845614834936406) +/*108*/, static_cast(65536 *16 * 0.0012784420593778636) +/*109*/, static_cast(65536 *16 * 0.0012678178114382621) +/*110*/, static_cast(65536 *16 * 0.0012525556826375537) +/*111*/, static_cast(65536 *16 * 0.0012325473943852084) +/*112*/, static_cast(65536 *16 * 0.0012077126268838676) +/*113*/, static_cast(65536 *16 * 0.0011779966448355029) +/*114*/, static_cast(65536 *16 * 0.0011433146771737655) +/*115*/, static_cast(65536 *16 * 0.0011036347058885887) +/*116*/, static_cast(65536 *16 * 0.0010589202139950945) +/*117*/, static_cast(65536 *16 * 0.0010091683044254098) +/*118*/, static_cast(65536 *16 * 9.543624468571229E-4) +/*119*/, static_cast(65536 *16 * 8.945398819399117E-4) +/*120*/, static_cast(65536 *16 * 8.297313883125644E-4) +/*121*/, static_cast(65536 *16 * 7.600155199968718E-4) +/*122*/, static_cast(65536 *16 * 6.854405952299358E-4) +/*123*/, static_cast(65536 *16 * 6.061236114458317E-4) +/*124*/, static_cast(65536 *16 * 5.221478191516476E-4) +/*125*/, static_cast(65536 *16 * 4.336813620599164E-4) +/*126*/, static_cast(65536 *16 * 3.408549526515998E-4) +/*127*/, static_cast(65536 *16 * 2.438450825114285E-4) +/*128*/, static_cast(65536 *16 * 1.428494911857926E-4) +/*129*/, static_cast(65536 *16 * 3.8067640594361634E-5) +/*130*/, static_cast(65536 *16 * -7.027035111775681E-5) +/*131*/, static_cast(65536 *16 * -1.818984143827126E-4) +/*132*/, static_cast(65536 *16 * -2.9656343184630157E-4) +/*133*/, static_cast(65536 *16 * -4.1397802421901906E-4) +/*134*/, static_cast(65536 *16 * -5.33838500742085E-4) +/*135*/, static_cast(65536 *16 * -6.558110253978588E-4) +/*136*/, static_cast(65536 *16 * -7.795655816897978E-4) +/*137*/, static_cast(65536 *16 * -9.047371821667003E-4) +/*138*/, static_cast(65536 *16 * -0.001030961345825847) +/*139*/, static_cast(65536 *16 * -0.0011578367988084777) +/*140*/, static_cast(65536 *16 * -0.0012849810572319298) +/*141*/, static_cast(65536 *16 * -0.0014119662266064482) +/*142*/, static_cast(65536 *16 * -0.0015383759515758101) +/*143*/, static_cast(65536 *16 * -0.001663756794188296) +/*144*/, static_cast(65536 *16 * -0.0017876541594460456) +/*145*/, static_cast(65536 *16 * -0.001909621722046808) +/*146*/, static_cast(65536 *16 * -0.0020291786719378088) +/*147*/, static_cast(65536 *16 * -0.002145855089743562) +/*148*/, static_cast(65536 *16 * -0.002259171910476534) +/*149*/, static_cast(65536 *16 * -0.0023686314802222655) +/*150*/, static_cast(65536 *16 * -0.002473745572697707) +/*151*/, static_cast(65536 *16 * -0.0025740277587192853) +/*152*/, static_cast(65536 *16 * -0.0026689831666099955) +/*153*/, static_cast(65536 *16 * -0.0027581124255643377) +/*154*/, static_cast(65536 *16 * -0.0028409282136656177) +/*155*/, static_cast(65536 *16 * -0.0029169432593640367) +/*156*/, static_cast(65536 *16 * -0.002985680612410139) +/*157*/, static_cast(65536 *16 * -0.003046658228485494) +/*158*/, static_cast(65536 *16 * -0.003099414222252269) +/*159*/, static_cast(65536 *16 * -0.0031434902530511595) +/*160*/, static_cast(65536 *16 * -0.003178436798255356) +/*161*/, static_cast(65536 *16 * -0.0032038260756887147) +/*162*/, static_cast(65536 *16 * -0.003219225355080285) +/*163*/, static_cast(65536 *16 * -0.0032242502222488744) +/*164*/, static_cast(65536 *16 * -0.003218506103318342) +/*165*/, static_cast(65536 *16 * -0.003201625222636992) +/*166*/, static_cast(65536 *16 * -0.003173259488065382) +/*167*/, static_cast(65536 *16 * -0.0031330803817718332) +/*168*/, static_cast(65536 *16 * -0.0030807779128908526) +/*169*/, static_cast(65536 *16 * -0.0030160821637947783) +/*170*/, static_cast(65536 *16 * -0.0029387362752889335) +/*171*/, static_cast(65536 *16 * -0.002848510131379585) +/*172*/, static_cast(65536 *16 * -0.0027451998188029363) +/*173*/, static_cast(65536 *16 * -0.00262863682904045) +/*174*/, static_cast(65536 *16 * -0.0024986780420415064) +/*175*/, static_cast(65536 *16 * -0.0023552114528323513) +/*176*/, static_cast(65536 *16 * -0.0021981491527779964) +/*177*/, static_cast(65536 *16 * -0.0020274504745732714) +/*178*/, static_cast(65536 *16 * -0.0018430877753141852) +/*179*/, static_cast(65536 *16 * -0.0016450910502005863) +/*180*/, static_cast(65536 *16 * -0.0014334955802048866) +/*181*/, static_cast(65536 *16 * -0.0012083983821827642) +/*182*/, static_cast(65536 *16 * -9.699135443572468E-4) +/*183*/, static_cast(65536 *16 * -7.181935207475589E-4) +/*184*/, static_cast(65536 *16 * -4.534224887286362E-4) +/*185*/, static_cast(65536 *16 * -1.758311300125605E-4) +/*186*/, static_cast(65536 *16 * 1.1433027008948132E-4) +/*187*/, static_cast(65536 *16 * 4.1675921199616097E-4) +/*188*/, static_cast(65536 *16 * 7.311320710094336E-4) +/*189*/, static_cast(65536 *16 * 0.0010570872458505827) +/*190*/, static_cast(65536 *16 * 0.0013942372682560795) +/*191*/, static_cast(65536 *16 * 0.001742148094642797) +/*192*/, static_cast(65536 *16 * 0.002100362793433286) +/*193*/, static_cast(65536 *16 * 0.0024683818857210646) +/*194*/, static_cast(65536 *16 * 0.002845695057494279) +/*195*/, static_cast(65536 *16 * 0.0032317385772924275) +/*196*/, static_cast(65536 *16 * 0.0036259433326630884) +/*197*/, static_cast(65536 *16 * 0.0040276894120370626) +/*198*/, static_cast(65536 *16 * 0.004436353627556968) +/*199*/, static_cast(65536 *16 * 0.004851271439526238) +/*200*/, static_cast(65536 *16 * 0.005271762758295799) +/*201*/, static_cast(65536 *16 * 0.005697120565601845) +/*202*/, static_cast(65536 *16 * 0.006126626859240469) +/*203*/, static_cast(65536 *16 * 0.006559527746778011) +/*204*/, static_cast(65536 *16 * 0.0069950693344747504) +/*205*/, static_cast(65536 *16 * 0.007432470090915211) +/*206*/, static_cast(65536 *16 * 0.007870944336430185) +/*207*/, static_cast(65536 *16 * 0.008309688701943495) +/*208*/, static_cast(65536 *16 * 0.008747898549370043) +/*209*/, static_cast(65536 *16 * 0.009184747205291654) +/*210*/, static_cast(65536 *16 * 0.009619414724898365) +/*211*/, static_cast(65536 *16 * 0.010051063453485451) +/*212*/, static_cast(65536 *16 * 0.010478876316671397) +/*213*/, static_cast(65536 *16 * 0.010902016899039163) +/*214*/, static_cast(65536 *16 * 0.011319665474466693) +/*215*/, static_cast(65536 *16 * 0.011730992134403782) +/*216*/, static_cast(65536 *16 * 0.012135186113163639) +/*217*/, static_cast(65536 *16 * 0.01253143889871197) +/*218*/, static_cast(65536 *16 * 0.012918956981226547) +/*219*/, static_cast(65536 *16 * 0.013296952886747157) +/*220*/, static_cast(65536 *16 * 0.013664665893392403) +/*221*/, static_cast(65536 *16 * 0.014021339353548561) +/*222*/, static_cast(65536 *16 * 0.014366244972764902) +/*223*/, static_cast(65536 *16 * 0.014698670942210527) +/*224*/, static_cast(65536 *16 * 0.015017930945351435) +/*225*/, static_cast(65536 *16 * 0.015323359168800435) +/*226*/, static_cast(65536 *16 * 0.015614322198635518) +/*227*/, static_cast(65536 *16 * 0.015890204972590742) +/*228*/, static_cast(65536 *16 * 0.016150433344740527) +/*229*/, static_cast(65536 *16 * 0.01639445378257351) +/*230*/, static_cast(65536 *16 * 0.016621758349582072) +/*231*/, static_cast(65536 *16 * 0.01683186471138077) +/*232*/, static_cast(65536 *16 * 0.01702432745775747) +/*233*/, static_cast(65536 *16 * 0.017198732908190056) +/*234*/, static_cast(65536 *16 * 0.017354710361561963) +/*235*/, static_cast(65536 *16 * 0.017491928210652433) +/*236*/, static_cast(65536 *16 * 0.017610096156964024) +/*237*/, static_cast(65536 *16 * 0.017708958417438553) +/*238*/, static_cast(65536 *16 * 0.017788304726419644) +/*239*/, static_cast(65536 *16 * 0.01784796484627723) +/*240*/, static_cast(65536 *16 * 0.017887808513528385) +/*241*/, static_cast(65536 *16 * 0.01790775243433271) }; /* 48000 PAL @@ -1082,248 +1082,248 @@ Coefficients: */ static const int32 C48000PAL[NCOEFFS/2]= { -/*0*/ 65536 *16 * -4.8720337170268194E-4 -/*1*/, 65536 *16 * 7.629902642634879E-7 -/*2*/, 65536 *16 * 2.1378369687164975E-6 -/*3*/, 65536 *16 * 4.2506426520122444E-6 -/*4*/, 65536 *16 * 7.369889860416342E-6 -/*5*/, 65536 *16 * 1.1216062943011637E-5 -/*6*/, 65536 *16 * 1.6073843505677063E-5 -/*7*/, 65536 *16 * 2.1633099120040373E-5 -/*8*/, 65536 *16 * 2.8206508485377597E-5 -/*9*/, 65536 *16 * 3.543629776593455E-5 -/*10*/, 65536 *16 * 4.368764327716006E-5 -/*11*/, 65536 *16 * 5.2518982409171E-5 -/*12*/, 65536 *16 * 6.239757141317561E-5 -/*13*/, 65536 *16 * 7.27096511997309E-5 -/*14*/, 65536 *16 * 8.417180660805913E-5 -/*15*/, 65536 *16 * 9.556951705928003E-5 -/*16*/, 65536 *16 * 1.0902571193097876E-4 -/*17*/, 65536 *16 * 1.227237340685471E-4 -/*18*/, 65536 *16 * 1.3608963828565135E-4 -/*19*/, 65536 *16 * 1.5074291732163737E-4 -/*20*/, 65536 *16 * 1.654957671774518E-4 -/*21*/, 65536 *16 * 1.8094544537755017E-4 -/*22*/, 65536 *16 * 1.9650254639058925E-4 -/*23*/, 65536 *16 * 2.124977005396817E-4 -/*24*/, 65536 *16 * 2.2850169154416925E-4 -/*25*/, 65536 *16 * 2.447269340662641E-4 -/*26*/, 65536 *16 * 2.60813097374866E-4 -/*27*/, 65536 *16 * 2.769089011403406E-4 -/*28*/, 65536 *16 * 2.926838284872595E-4 -/*29*/, 65536 *16 * 3.082587328683191E-4 -/*30*/, 65536 *16 * 3.233018169377691E-4 -/*31*/, 65536 *16 * 3.379664790017549E-4 -/*32*/, 65536 *16 * 3.520147829064225E-4 -/*33*/, 65536 *16 * 3.6489502104188965E-4 -/*34*/, 65536 *16 * 3.771837837785839E-4 -/*35*/, 65536 *16 * 3.8841744550992556E-4 -/*36*/, 65536 *16 * 3.985152578693797E-4 -/*37*/, 65536 *16 * 4.0737410559796126E-4 -/*38*/, 65536 *16 * 4.1485052511765913E-4 -/*39*/, 65536 *16 * 4.2087321591616255E-4 -/*40*/, 65536 *16 * 4.252880030529943E-4 -/*41*/, 65536 *16 * 4.2804175098790727E-4 -/*42*/, 65536 *16 * 4.289792011350111E-4 -/*43*/, 65536 *16 * 4.280677040429387E-4 -/*44*/, 65536 *16 * 4.251526022872329E-4 -/*45*/, 65536 *16 * 4.202312572840644E-4 -/*46*/, 65536 *16 * 4.1313629237647344E-4 -/*47*/, 65536 *16 * 4.0393669855985745E-4 -/*48*/, 65536 *16 * 3.9229544134295797E-4 -/*49*/, 65536 *16 * 3.785081882385653E-4 -/*50*/, 65536 *16 * 3.624387298611128E-4 -/*51*/, 65536 *16 * 3.439609793120755E-4 -/*52*/, 65536 *16 * 3.2317107312926493E-4 -/*53*/, 65536 *16 * 3.0001522643985015E-4 -/*54*/, 65536 *16 * 2.7456037312211196E-4 -/*55*/, 65536 *16 * 2.468022375847908E-4 -/*56*/, 65536 *16 * 2.1682011116032351E-4 -/*57*/, 65536 *16 * 1.846463359087917E-4 -/*58*/, 65536 *16 * 1.5038519581308458E-4 -/*59*/, 65536 *16 * 1.1409999503195986E-4 -/*60*/, 65536 *16 * 7.592602477010921E-5 -/*61*/, 65536 *16 * 3.594949037485983E-5 -/*62*/, 65536 *16 * -5.654205953473915E-6 -/*63*/, 65536 *16 * -4.8796158887641113E-5 -/*64*/, 65536 *16 * -9.324450907374415E-5 -/*65*/, 65536 *16 * -1.3875102646747199E-4 -/*66*/, 65536 *16 * -1.853099936736042E-4 -/*67*/, 65536 *16 * -2.3256519878196182E-4 -/*68*/, 65536 *16 * -2.803629983423417E-4 -/*69*/, 65536 *16 * -3.284299717573991E-4 -/*70*/, 65536 *16 * -3.7655572805983734E-4 -/*71*/, 65536 *16 * -4.244648731259925E-4 -/*72*/, 65536 *16 * -4.7191652130487173E-4 -/*73*/, 65536 *16 * -5.18626812434502E-4 -/*74*/, 65536 *16 * -5.64334322901072E-4 -/*75*/, 65536 *16 * -6.087503654593899E-4 -/*76*/, 65536 *16 * -6.515995849807032E-4 -/*77*/, 65536 *16 * -6.925935510204477E-4 -/*78*/, 65536 *16 * -7.314432865833455E-4 -/*79*/, 65536 *16 * -7.678735923848921E-4 -/*80*/, 65536 *16 * -8.015359919770463E-4 -/*81*/, 65536 *16 * -8.322768680565776E-4 -/*82*/, 65536 *16 * -8.597539203190856E-4 -/*83*/, 65536 *16 * -8.836879776280238E-4 -/*84*/, 65536 *16 * -9.038629010388075E-4 -/*85*/, 65536 *16 * -9.200080217158554E-4 -/*86*/, 65536 *16 * -9.319235257639778E-4 -/*87*/, 65536 *16 * -9.393690949611698E-4 -/*88*/, 65536 *16 * -9.421725179420662E-4 -/*89*/, 65536 *16 * -9.401299048871544E-4 -/*90*/, 65536 *16 * -9.33106896645869E-4 -/*91*/, 65536 *16 * -9.209400636174311E-4 -/*92*/, 65536 *16 * -9.035401279622776E-4 -/*93*/, 65536 *16 * -8.807854817776823E-4 -/*94*/, 65536 *16 * -8.526430615286829E-4 -/*95*/, 65536 *16 * -8.190296190822509E-4 -/*96*/, 65536 *16 * -7.799980167439345E-4 -/*97*/, 65536 *16 * -7.355478199155667E-4 -/*98*/, 65536 *16 * -6.8567697874281E-4 -/*99*/, 65536 *16 * -6.305240657493408E-4 -/*100*/, 65536 *16 * -5.701694385732142E-4 -/*101*/, 65536 *16 * -5.047740591296687E-4 -/*102*/, 65536 *16 * -4.344980221283718E-4 -/*103*/, 65536 *16 * -3.595556715693896E-4 -/*104*/, 65536 *16 * -2.8017864491759883E-4 -/*105*/, 65536 *16 * -1.9664106446578853E-4 -/*106*/, 65536 *16 * -1.0924056590418239E-4 -/*107*/, 65536 *16 * -1.831009861307028E-5 -/*108*/, 65536 *16 * 7.579029921420169E-5 -/*109*/, 65536 *16 * 1.726696848384902E-4 -/*110*/, 65536 *16 * 2.719067221880469E-4 -/*111*/, 65536 *16 * 3.7305728261123155E-4 -/*112*/, 65536 *16 * 4.7562651195605295E-4 -/*113*/, 65536 *16 * 5.791888527128953E-4 -/*114*/, 65536 *16 * 6.831673135667645E-4 -/*115*/, 65536 *16 * 7.870493762901182E-4 -/*116*/, 65536 *16 * 8.902822670362451E-4 -/*117*/, 65536 *16 * 9.923024258505538E-4 -/*118*/, 65536 *16 * 0.0010925350458368308 -/*119*/, 65536 *16 * 0.0011903898503065698 -/*120*/, 65536 *16 * 0.0012852771482304163 -/*121*/, 65536 *16 * 0.0013765956662458894 -/*122*/, 65536 *16 * 0.001463753120426749 -/*123*/, 65536 *16 * 0.001546148019165285 -/*124*/, 65536 *16 * 0.0016231971391851225 -/*125*/, 65536 *16 * 0.0016943089588603764 -/*126*/, 65536 *16 * 0.0017589264521182184 -/*127*/, 65536 *16 * 0.001816477825843157 -/*128*/, 65536 *16 * 0.001866465750234791 -/*129*/, 65536 *16 * 0.001908351881851273 -/*130*/, 65536 *16 * 0.0019416355874888774 -/*131*/, 65536 *16 * 0.0019658912100497094 -/*132*/, 65536 *16 * 0.0019806705540431754 -/*133*/, 65536 *16 * 0.001985602463070219 -/*134*/, 65536 *16 * 0.0019803173347810094 -/*135*/, 65536 *16 * 0.001964518487218229 -/*136*/, 65536 *16 * 0.00193792749109128 -/*137*/, 65536 *16 * 0.0019003361153152295 -/*138*/, 65536 *16 * 0.0018515636696845045 -/*139*/, 65536 *16 * 0.0017915008584460717 -/*140*/, 65536 *16 * 0.0017200735452676211 -/*141*/, 65536 *16 * 0.0016372830430278298 -/*142*/, 65536 *16 * 0.0015431709906056357 -/*143*/, 65536 *16 * 0.0014378573929982352 -/*144*/, 65536 *16 * 0.0013215084987890104 -/*145*/, 65536 *16 * 0.001194328283068528 -/*146*/, 65536 *16 * 0.0010566468386934231 -/*147*/, 65536 *16 * 9.088002025373218E-4 -/*148*/, 65536 *16 * 7.512135584215806E-4 -/*149*/, 65536 *16 * 5.843621536328689E-4 -/*150*/, 65536 *16 * 4.087894375795271E-4 -/*151*/, 65536 *16 * 2.2510227575334467E-4 -/*152*/, 65536 *16 * 3.396239791846655E-5 -/*153*/, 65536 *16 * -1.6390294871759475E-4 -/*154*/, 65536 *16 * -3.6771789280231503E-4 -/*155*/, 65536 *16 * -5.766405458635558E-4 -/*156*/, 65536 *16 * -7.897872933737203E-4 -/*157*/, 65536 *16 * -0.001006209757480115 -/*158*/, 65536 *16 * -0.0012249304977170316 -/*159*/, 65536 *16 * -0.0014449054341312839 -/*160*/, 65536 *16 * -0.0016650898600315796 -/*161*/, 65536 *16 * -0.001884343774622382 -/*162*/, 65536 *16 * -0.0021015342465919864 -/*163*/, 65536 *16 * -0.0023154975831354337 -/*164*/, 65536 *16 * -0.0025250324219407566 -/*165*/, 65536 *16 * -0.0027289312457094736 -/*166*/, 65536 *16 * -0.0029259546931934967 -/*167*/, 65536 *16 * -0.003114871201398419 -/*168*/, 65536 *16 * -0.003294430723892981 -/*169*/, 65536 *16 * -0.003463396424710959 -/*170*/, 65536 *16 * -0.003620525188769811 -/*171*/, 65536 *16 * -0.0037645967189351955 -/*172*/, 65536 *16 * -0.003894396916361478 -/*173*/, 65536 *16 * -0.00400874728567525 -/*174*/, 65536 *16 * -0.004106485394068385 -/*175*/, 65536 *16 * -0.004186497692846864 -/*176*/, 65536 *16 * -0.004247692032125654 -/*177*/, 65536 *16 * -0.004289020763525844 -/*178*/, 65536 *16 * -0.0043095197889136795 -/*179*/, 65536 *16 * -0.004308238489219152 -/*180*/, 65536 *16 * -0.004284317631022625 -/*181*/, 65536 *16 * -0.0042369380515990835 -/*182*/, 65536 *16 * -0.004165372803509635 -/*183*/, 65536 *16 * -0.004068956516951112 -/*184*/, 65536 *16 * -0.003947110543306579 -/*185*/, 65536 *16 * -0.003799332887739826 -/*186*/, 65536 *16 * -0.0036252122359255057 -/*187*/, 65536 *16 * -0.0034244255727248728 -/*188*/, 65536 *16 * -0.0031967441992062605 -/*189*/, 65536 *16 * -0.0029420359603045624 -/*190*/, 65536 *16 * -0.002660262473612329 -/*191*/, 65536 *16 * -0.0023514913391939015 -/*192*/, 65536 *16 * -0.002015874218170038 -/*193*/, 65536 *16 * -0.0016537021922741356 -/*194*/, 65536 *16 * -0.0012653326032471951 -/*195*/, 65536 *16 * -8.512425489658283E-4 -/*196*/, 65536 *16 * -4.12008134196091E-4 -/*197*/, 65536 *16 * 5.169160678832697E-5 -/*198*/, 65536 *16 * 5.3906734093252E-4 -/*199*/, 65536 *16 * 0.0010492444783799305 -/*200*/, 65536 *16 * 0.0015812369440962736 -/*201*/, 65536 *16 * 0.002133975437656693 -/*202*/, 65536 *16 * 0.002706284295633396 -/*203*/, 65536 *16 * 0.003296910987472264 -/*204*/, 65536 *16 * 0.0039045040922850343 -/*205*/, 65536 *16 * 0.004527645156076457 -/*206*/, 65536 *16 * 0.005164822580527953 -/*207*/, 65536 *16 * 0.00581446977998051 -/*208*/, 65536 *16 * 0.00647492818678252 -/*209*/, 65536 *16 * 0.007144495527005753 -/*210*/, 65536 *16 * 0.007821417135435386 -/*211*/, 65536 *16 * 0.008503870707064397 -/*212*/, 65536 *16 * 0.00919000676302643 -/*213*/, 65536 *16 * 0.009877917856582038 -/*214*/, 65536 *16 * 0.010565689475867907 -/*215*/, 65536 *16 * 0.011251366750588049 -/*216*/, 65536 *16 * 0.01193298816023733 -/*217*/, 65536 *16 * 0.012608574497468706 -/*218*/, 65536 *16 * 0.013276151008399953 -/*219*/, 65536 *16 * 0.013933744269275995 -/*220*/, 65536 *16 * 0.014579397589755912 -/*221*/, 65536 *16 * 0.015211171751139368 -/*222*/, 65536 *16 * 0.015827155422328678 -/*223*/, 65536 *16 * 0.01642547256780349 -/*224*/, 65536 *16 * 0.01700428326907068 -/*225*/, 65536 *16 * 0.017561819587529177 -/*226*/, 65536 *16 * 0.018096338432718698 -/*227*/, 65536 *16 * 0.018606183762999433 -/*228*/, 65536 *16 * 0.019089749497960648 -/*229*/, 65536 *16 * 0.019545523698532997 -/*230*/, 65536 *16 * 0.019972069058400564 -/*231*/, 65536 *16 * 0.02036803110561515 -/*232*/, 65536 *16 * 0.020732154475618856 -/*233*/, 65536 *16 * 0.021063275458886234 -/*234*/, 65536 *16 * 0.021360340738775345 -/*235*/, 65536 *16 * 0.02162239534537267 -/*236*/, 65536 *16 * 0.021848603142668337 -/*237*/, 65536 *16 * 0.02203823092181804 -/*238*/, 65536 *16 * 0.022190674411724294 -/*239*/, 65536 *16 * 0.022305434241445123 -/*240*/, 65536 *16 * 0.022382153728111424 -/*241*/, 65536 *16 * 0.022420574751016616 +/*0*/ static_cast(65536 *16 * -4.8720337170268194E-4) +/*1*/, static_cast(65536 *16 * 7.629902642634879E-7) +/*2*/, static_cast(65536 *16 * 2.1378369687164975E-6) +/*3*/, static_cast(65536 *16 * 4.2506426520122444E-6) +/*4*/, static_cast(65536 *16 * 7.369889860416342E-6) +/*5*/, static_cast(65536 *16 * 1.1216062943011637E-5) +/*6*/, static_cast(65536 *16 * 1.6073843505677063E-5) +/*7*/, static_cast(65536 *16 * 2.1633099120040373E-5) +/*8*/, static_cast(65536 *16 * 2.8206508485377597E-5) +/*9*/, static_cast(65536 *16 * 3.543629776593455E-5) +/*10*/, static_cast(65536 *16 * 4.368764327716006E-5) +/*11*/, static_cast(65536 *16 * 5.2518982409171E-5) +/*12*/, static_cast(65536 *16 * 6.239757141317561E-5) +/*13*/, static_cast(65536 *16 * 7.27096511997309E-5) +/*14*/, static_cast(65536 *16 * 8.417180660805913E-5) +/*15*/, static_cast(65536 *16 * 9.556951705928003E-5) +/*16*/, static_cast(65536 *16 * 1.0902571193097876E-4) +/*17*/, static_cast(65536 *16 * 1.227237340685471E-4) +/*18*/, static_cast(65536 *16 * 1.3608963828565135E-4) +/*19*/, static_cast(65536 *16 * 1.5074291732163737E-4) +/*20*/, static_cast(65536 *16 * 1.654957671774518E-4) +/*21*/, static_cast(65536 *16 * 1.8094544537755017E-4) +/*22*/, static_cast(65536 *16 * 1.9650254639058925E-4) +/*23*/, static_cast(65536 *16 * 2.124977005396817E-4) +/*24*/, static_cast(65536 *16 * 2.2850169154416925E-4) +/*25*/, static_cast(65536 *16 * 2.447269340662641E-4) +/*26*/, static_cast(65536 *16 * 2.60813097374866E-4) +/*27*/, static_cast(65536 *16 * 2.769089011403406E-4) +/*28*/, static_cast(65536 *16 * 2.926838284872595E-4) +/*29*/, static_cast(65536 *16 * 3.082587328683191E-4) +/*30*/, static_cast(65536 *16 * 3.233018169377691E-4) +/*31*/, static_cast(65536 *16 * 3.379664790017549E-4) +/*32*/, static_cast(65536 *16 * 3.520147829064225E-4) +/*33*/, static_cast(65536 *16 * 3.6489502104188965E-4) +/*34*/, static_cast(65536 *16 * 3.771837837785839E-4) +/*35*/, static_cast(65536 *16 * 3.8841744550992556E-4) +/*36*/, static_cast(65536 *16 * 3.985152578693797E-4) +/*37*/, static_cast(65536 *16 * 4.0737410559796126E-4) +/*38*/, static_cast(65536 *16 * 4.1485052511765913E-4) +/*39*/, static_cast(65536 *16 * 4.2087321591616255E-4) +/*40*/, static_cast(65536 *16 * 4.252880030529943E-4) +/*41*/, static_cast(65536 *16 * 4.2804175098790727E-4) +/*42*/, static_cast(65536 *16 * 4.289792011350111E-4) +/*43*/, static_cast(65536 *16 * 4.280677040429387E-4) +/*44*/, static_cast(65536 *16 * 4.251526022872329E-4) +/*45*/, static_cast(65536 *16 * 4.202312572840644E-4) +/*46*/, static_cast(65536 *16 * 4.1313629237647344E-4) +/*47*/, static_cast(65536 *16 * 4.0393669855985745E-4) +/*48*/, static_cast(65536 *16 * 3.9229544134295797E-4) +/*49*/, static_cast(65536 *16 * 3.785081882385653E-4) +/*50*/, static_cast(65536 *16 * 3.624387298611128E-4) +/*51*/, static_cast(65536 *16 * 3.439609793120755E-4) +/*52*/, static_cast(65536 *16 * 3.2317107312926493E-4) +/*53*/, static_cast(65536 *16 * 3.0001522643985015E-4) +/*54*/, static_cast(65536 *16 * 2.7456037312211196E-4) +/*55*/, static_cast(65536 *16 * 2.468022375847908E-4) +/*56*/, static_cast(65536 *16 * 2.1682011116032351E-4) +/*57*/, static_cast(65536 *16 * 1.846463359087917E-4) +/*58*/, static_cast(65536 *16 * 1.5038519581308458E-4) +/*59*/, static_cast(65536 *16 * 1.1409999503195986E-4) +/*60*/, static_cast(65536 *16 * 7.592602477010921E-5) +/*61*/, static_cast(65536 *16 * 3.594949037485983E-5) +/*62*/, static_cast(65536 *16 * -5.654205953473915E-6) +/*63*/, static_cast(65536 *16 * -4.8796158887641113E-5) +/*64*/, static_cast(65536 *16 * -9.324450907374415E-5) +/*65*/, static_cast(65536 *16 * -1.3875102646747199E-4) +/*66*/, static_cast(65536 *16 * -1.853099936736042E-4) +/*67*/, static_cast(65536 *16 * -2.3256519878196182E-4) +/*68*/, static_cast(65536 *16 * -2.803629983423417E-4) +/*69*/, static_cast(65536 *16 * -3.284299717573991E-4) +/*70*/, static_cast(65536 *16 * -3.7655572805983734E-4) +/*71*/, static_cast(65536 *16 * -4.244648731259925E-4) +/*72*/, static_cast(65536 *16 * -4.7191652130487173E-4) +/*73*/, static_cast(65536 *16 * -5.18626812434502E-4) +/*74*/, static_cast(65536 *16 * -5.64334322901072E-4) +/*75*/, static_cast(65536 *16 * -6.087503654593899E-4) +/*76*/, static_cast(65536 *16 * -6.515995849807032E-4) +/*77*/, static_cast(65536 *16 * -6.925935510204477E-4) +/*78*/, static_cast(65536 *16 * -7.314432865833455E-4) +/*79*/, static_cast(65536 *16 * -7.678735923848921E-4) +/*80*/, static_cast(65536 *16 * -8.015359919770463E-4) +/*81*/, static_cast(65536 *16 * -8.322768680565776E-4) +/*82*/, static_cast(65536 *16 * -8.597539203190856E-4) +/*83*/, static_cast(65536 *16 * -8.836879776280238E-4) +/*84*/, static_cast(65536 *16 * -9.038629010388075E-4) +/*85*/, static_cast(65536 *16 * -9.200080217158554E-4) +/*86*/, static_cast(65536 *16 * -9.319235257639778E-4) +/*87*/, static_cast(65536 *16 * -9.393690949611698E-4) +/*88*/, static_cast(65536 *16 * -9.421725179420662E-4) +/*89*/, static_cast(65536 *16 * -9.401299048871544E-4) +/*90*/, static_cast(65536 *16 * -9.33106896645869E-4) +/*91*/, static_cast(65536 *16 * -9.209400636174311E-4) +/*92*/, static_cast(65536 *16 * -9.035401279622776E-4) +/*93*/, static_cast(65536 *16 * -8.807854817776823E-4) +/*94*/, static_cast(65536 *16 * -8.526430615286829E-4) +/*95*/, static_cast(65536 *16 * -8.190296190822509E-4) +/*96*/, static_cast(65536 *16 * -7.799980167439345E-4) +/*97*/, static_cast(65536 *16 * -7.355478199155667E-4) +/*98*/, static_cast(65536 *16 * -6.8567697874281E-4) +/*99*/, static_cast(65536 *16 * -6.305240657493408E-4) +/*100*/, static_cast(65536 *16 * -5.701694385732142E-4) +/*101*/, static_cast(65536 *16 * -5.047740591296687E-4) +/*102*/, static_cast(65536 *16 * -4.344980221283718E-4) +/*103*/, static_cast(65536 *16 * -3.595556715693896E-4) +/*104*/, static_cast(65536 *16 * -2.8017864491759883E-4) +/*105*/, static_cast(65536 *16 * -1.9664106446578853E-4) +/*106*/, static_cast(65536 *16 * -1.0924056590418239E-4) +/*107*/, static_cast(65536 *16 * -1.831009861307028E-5) +/*108*/, static_cast(65536 *16 * 7.579029921420169E-5) +/*109*/, static_cast(65536 *16 * 1.726696848384902E-4) +/*110*/, static_cast(65536 *16 * 2.719067221880469E-4) +/*111*/, static_cast(65536 *16 * 3.7305728261123155E-4) +/*112*/, static_cast(65536 *16 * 4.7562651195605295E-4) +/*113*/, static_cast(65536 *16 * 5.791888527128953E-4) +/*114*/, static_cast(65536 *16 * 6.831673135667645E-4) +/*115*/, static_cast(65536 *16 * 7.870493762901182E-4) +/*116*/, static_cast(65536 *16 * 8.902822670362451E-4) +/*117*/, static_cast(65536 *16 * 9.923024258505538E-4) +/*118*/, static_cast(65536 *16 * 0.0010925350458368308) +/*119*/, static_cast(65536 *16 * 0.0011903898503065698) +/*120*/, static_cast(65536 *16 * 0.0012852771482304163) +/*121*/, static_cast(65536 *16 * 0.0013765956662458894) +/*122*/, static_cast(65536 *16 * 0.001463753120426749) +/*123*/, static_cast(65536 *16 * 0.001546148019165285) +/*124*/, static_cast(65536 *16 * 0.0016231971391851225) +/*125*/, static_cast(65536 *16 * 0.0016943089588603764) +/*126*/, static_cast(65536 *16 * 0.0017589264521182184) +/*127*/, static_cast(65536 *16 * 0.001816477825843157) +/*128*/, static_cast(65536 *16 * 0.001866465750234791) +/*129*/, static_cast(65536 *16 * 0.001908351881851273) +/*130*/, static_cast(65536 *16 * 0.0019416355874888774) +/*131*/, static_cast(65536 *16 * 0.0019658912100497094) +/*132*/, static_cast(65536 *16 * 0.0019806705540431754) +/*133*/, static_cast(65536 *16 * 0.001985602463070219) +/*134*/, static_cast(65536 *16 * 0.0019803173347810094) +/*135*/, static_cast(65536 *16 * 0.001964518487218229) +/*136*/, static_cast(65536 *16 * 0.00193792749109128) +/*137*/, static_cast(65536 *16 * 0.0019003361153152295) +/*138*/, static_cast(65536 *16 * 0.0018515636696845045) +/*139*/, static_cast(65536 *16 * 0.0017915008584460717) +/*140*/, static_cast(65536 *16 * 0.0017200735452676211) +/*141*/, static_cast(65536 *16 * 0.0016372830430278298) +/*142*/, static_cast(65536 *16 * 0.0015431709906056357) +/*143*/, static_cast(65536 *16 * 0.0014378573929982352) +/*144*/, static_cast(65536 *16 * 0.0013215084987890104) +/*145*/, static_cast(65536 *16 * 0.001194328283068528) +/*146*/, static_cast(65536 *16 * 0.0010566468386934231) +/*147*/, static_cast(65536 *16 * 9.088002025373218E-4) +/*148*/, static_cast(65536 *16 * 7.512135584215806E-4) +/*149*/, static_cast(65536 *16 * 5.843621536328689E-4) +/*150*/, static_cast(65536 *16 * 4.087894375795271E-4) +/*151*/, static_cast(65536 *16 * 2.2510227575334467E-4) +/*152*/, static_cast(65536 *16 * 3.396239791846655E-5) +/*153*/, static_cast(65536 *16 * -1.6390294871759475E-4) +/*154*/, static_cast(65536 *16 * -3.6771789280231503E-4) +/*155*/, static_cast(65536 *16 * -5.766405458635558E-4) +/*156*/, static_cast(65536 *16 * -7.897872933737203E-4) +/*157*/, static_cast(65536 *16 * -0.001006209757480115) +/*158*/, static_cast(65536 *16 * -0.0012249304977170316) +/*159*/, static_cast(65536 *16 * -0.0014449054341312839) +/*160*/, static_cast(65536 *16 * -0.0016650898600315796) +/*161*/, static_cast(65536 *16 * -0.001884343774622382) +/*162*/, static_cast(65536 *16 * -0.0021015342465919864) +/*163*/, static_cast(65536 *16 * -0.0023154975831354337) +/*164*/, static_cast(65536 *16 * -0.0025250324219407566) +/*165*/, static_cast(65536 *16 * -0.0027289312457094736) +/*166*/, static_cast(65536 *16 * -0.0029259546931934967) +/*167*/, static_cast(65536 *16 * -0.003114871201398419) +/*168*/, static_cast(65536 *16 * -0.003294430723892981) +/*169*/, static_cast(65536 *16 * -0.003463396424710959) +/*170*/, static_cast(65536 *16 * -0.003620525188769811) +/*171*/, static_cast(65536 *16 * -0.0037645967189351955) +/*172*/, static_cast(65536 *16 * -0.003894396916361478) +/*173*/, static_cast(65536 *16 * -0.00400874728567525) +/*174*/, static_cast(65536 *16 * -0.004106485394068385) +/*175*/, static_cast(65536 *16 * -0.004186497692846864) +/*176*/, static_cast(65536 *16 * -0.004247692032125654) +/*177*/, static_cast(65536 *16 * -0.004289020763525844) +/*178*/, static_cast(65536 *16 * -0.0043095197889136795) +/*179*/, static_cast(65536 *16 * -0.004308238489219152) +/*180*/, static_cast(65536 *16 * -0.004284317631022625) +/*181*/, static_cast(65536 *16 * -0.0042369380515990835) +/*182*/, static_cast(65536 *16 * -0.004165372803509635) +/*183*/, static_cast(65536 *16 * -0.004068956516951112) +/*184*/, static_cast(65536 *16 * -0.003947110543306579) +/*185*/, static_cast(65536 *16 * -0.003799332887739826) +/*186*/, static_cast(65536 *16 * -0.0036252122359255057) +/*187*/, static_cast(65536 *16 * -0.0034244255727248728) +/*188*/, static_cast(65536 *16 * -0.0031967441992062605) +/*189*/, static_cast(65536 *16 * -0.0029420359603045624) +/*190*/, static_cast(65536 *16 * -0.002660262473612329) +/*191*/, static_cast(65536 *16 * -0.0023514913391939015) +/*192*/, static_cast(65536 *16 * -0.002015874218170038) +/*193*/, static_cast(65536 *16 * -0.0016537021922741356) +/*194*/, static_cast(65536 *16 * -0.0012653326032471951) +/*195*/, static_cast(65536 *16 * -8.512425489658283E-4) +/*196*/, static_cast(65536 *16 * -4.12008134196091E-4) +/*197*/, static_cast(65536 *16 * 5.169160678832697E-5) +/*198*/, static_cast(65536 *16 * 5.3906734093252E-4) +/*199*/, static_cast(65536 *16 * 0.0010492444783799305) +/*200*/, static_cast(65536 *16 * 0.0015812369440962736) +/*201*/, static_cast(65536 *16 * 0.002133975437656693) +/*202*/, static_cast(65536 *16 * 0.002706284295633396) +/*203*/, static_cast(65536 *16 * 0.003296910987472264) +/*204*/, static_cast(65536 *16 * 0.0039045040922850343) +/*205*/, static_cast(65536 *16 * 0.004527645156076457) +/*206*/, static_cast(65536 *16 * 0.005164822580527953) +/*207*/, static_cast(65536 *16 * 0.00581446977998051) +/*208*/, static_cast(65536 *16 * 0.00647492818678252) +/*209*/, static_cast(65536 *16 * 0.007144495527005753) +/*210*/, static_cast(65536 *16 * 0.007821417135435386) +/*211*/, static_cast(65536 *16 * 0.008503870707064397) +/*212*/, static_cast(65536 *16 * 0.00919000676302643) +/*213*/, static_cast(65536 *16 * 0.009877917856582038) +/*214*/, static_cast(65536 *16 * 0.010565689475867907) +/*215*/, static_cast(65536 *16 * 0.011251366750588049) +/*216*/, static_cast(65536 *16 * 0.01193298816023733) +/*217*/, static_cast(65536 *16 * 0.012608574497468706) +/*218*/, static_cast(65536 *16 * 0.013276151008399953) +/*219*/, static_cast(65536 *16 * 0.013933744269275995) +/*220*/, static_cast(65536 *16 * 0.014579397589755912) +/*221*/, static_cast(65536 *16 * 0.015211171751139368) +/*222*/, static_cast(65536 *16 * 0.015827155422328678) +/*223*/, static_cast(65536 *16 * 0.01642547256780349) +/*224*/, static_cast(65536 *16 * 0.01700428326907068) +/*225*/, static_cast(65536 *16 * 0.017561819587529177) +/*226*/, static_cast(65536 *16 * 0.018096338432718698) +/*227*/, static_cast(65536 *16 * 0.018606183762999433) +/*228*/, static_cast(65536 *16 * 0.019089749497960648) +/*229*/, static_cast(65536 *16 * 0.019545523698532997) +/*230*/, static_cast(65536 *16 * 0.019972069058400564) +/*231*/, static_cast(65536 *16 * 0.02036803110561515) +/*232*/, static_cast(65536 *16 * 0.020732154475618856) +/*233*/, static_cast(65536 *16 * 0.021063275458886234) +/*234*/, static_cast(65536 *16 * 0.021360340738775345) +/*235*/, static_cast(65536 *16 * 0.02162239534537267) +/*236*/, static_cast(65536 *16 * 0.021848603142668337) +/*237*/, static_cast(65536 *16 * 0.02203823092181804) +/*238*/, static_cast(65536 *16 * 0.022190674411724294) +/*239*/, static_cast(65536 *16 * 0.022305434241445123) +/*240*/, static_cast(65536 *16 * 0.022382153728111424) +/*241*/, static_cast(65536 *16 * 0.022420574751016616) }; /* 44100 PAL @@ -1340,246 +1340,246 @@ Coefficients: */ static const int32 C44100PAL[NCOEFFS/2]= { -/*0*/ 65536 *16 * 5.793783958720019E-4 -/*1*/, 65536 *16 * 1.0571291666629312E-4 -/*2*/, 65536 *16 * 1.1459085882755871E-4 -/*3*/, 65536 *16 * 1.2371675029136968E-4 -/*4*/, 65536 *16 * 1.3275170325031607E-4 -/*5*/, 65536 *16 * 1.4207721167879995E-4 -/*6*/, 65536 *16 * 1.5130497600100568E-4 -/*7*/, 65536 *16 * 1.6077227873948047E-4 -/*8*/, 65536 *16 * 1.6990814771316866E-4 -/*9*/, 65536 *16 * 1.79005024990367E-4 -/*10*/, 65536 *16 * 1.8739246068939436E-4 -/*11*/, 65536 *16 * 1.9572039600801667E-4 -/*12*/, 65536 *16 * 2.0352846914404956E-4 -/*13*/, 65536 *16 * 2.1201116607443127E-4 -/*14*/, 65536 *16 * 2.188838839136502E-4 -/*15*/, 65536 *16 * 2.2495686284733203E-4 -/*16*/, 65536 *16 * 2.3149812422937834E-4 -/*17*/, 65536 *16 * 2.363635497444841E-4 -/*18*/, 65536 *16 * 2.410054979130104E-4 -/*19*/, 65536 *16 * 2.445286108284421E-4 -/*20*/, 65536 *16 * 2.474675828550653E-4 -/*21*/, 65536 *16 * 2.4934815214903343E-4 -/*22*/, 65536 *16 * 2.50372333906785E-4 -/*23*/, 65536 *16 * 2.501665763315339E-4 -/*24*/, 65536 *16 * 2.488750795254978E-4 -/*25*/, 65536 *16 * 2.4640153199411455E-4 -/*26*/, 65536 *16 * 2.428720291968876E-4 -/*27*/, 65536 *16 * 2.3801309032826844E-4 -/*28*/, 65536 *16 * 2.3160240772113682E-4 -/*29*/, 65536 *16 * 2.2423402291517938E-4 -/*30*/, 65536 *16 * 2.152856501527123E-4 -/*31*/, 65536 *16 * 2.0488674543318888E-4 -/*32*/, 65536 *16 * 1.9317919544163198E-4 -/*33*/, 65536 *16 * 1.7994016398005858E-4 -/*34*/, 65536 *16 * 1.6541109383681028E-4 -/*35*/, 65536 *16 * 1.4938382649739635E-4 -/*36*/, 65536 *16 * 1.3200975730094075E-4 -/*37*/, 65536 *16 * 1.1313240842725184E-4 -/*38*/, 65536 *16 * 9.296992728984174E-5 -/*39*/, 65536 *16 * 7.143010735440594E-5 -/*40*/, 65536 *16 * 4.8632764324109725E-5 -/*41*/, 65536 *16 * 2.443073549738759E-5 -/*42*/, 65536 *16 * -8.284349612349981E-7 -/*43*/, 65536 *16 * -2.7227387247375577E-5 -/*44*/, 65536 *16 * -5.4818038895146106E-5 -/*45*/, 65536 *16 * -8.330005435111118E-5 -/*46*/, 65536 *16 * -1.1275737974091186E-4 -/*47*/, 65536 *16 * -1.4298620796919756E-4 -/*48*/, 65536 *16 * -1.7390785487074508E-4 -/*49*/, 65536 *16 * -2.054308580401118E-4 -/*50*/, 65536 *16 * -2.37415521983132E-4 -/*51*/, 65536 *16 * -2.697456782629617E-4 -/*52*/, 65536 *16 * -3.022375619849705E-4 -/*53*/, 65536 *16 * -3.348339660959209E-4 -/*54*/, 65536 *16 * -3.673583086741243E-4 -/*55*/, 65536 *16 * -3.996554197363865E-4 -/*56*/, 65536 *16 * -4.3147108191834185E-4 -/*57*/, 65536 *16 * -4.6285023012872966E-4 -/*58*/, 65536 *16 * -4.934440989261961E-4 -/*59*/, 65536 *16 * -5.231720978150925E-4 -/*60*/, 65536 *16 * -5.518656107257292E-4 -/*61*/, 65536 *16 * -5.793049560550073E-4 -/*62*/, 65536 *16 * -6.053792205725333E-4 -/*63*/, 65536 *16 * -6.298765704841736E-4 -/*64*/, 65536 *16 * -6.526402738994988E-4 -/*65*/, 65536 *16 * -6.734722964365358E-4 -/*66*/, 65536 *16 * -6.922485843472661E-4 -/*67*/, 65536 *16 * -7.088111930758961E-4 -/*68*/, 65536 *16 * -7.229789042068006E-4 -/*69*/, 65536 *16 * -7.34572975483669E-4 -/*70*/, 65536 *16 * -7.435049180176613E-4 -/*71*/, 65536 *16 * -7.496258178311876E-4 -/*72*/, 65536 *16 * -7.527294926570751E-4 -/*73*/, 65536 *16 * -7.528075552986548E-4 -/*74*/, 65536 *16 * -7.496410435428715E-4 -/*75*/, 65536 *16 * -7.432054606042111E-4 -/*76*/, 65536 *16 * -7.33375741493331E-4 -/*77*/, 65536 *16 * -7.200753858529672E-4 -/*78*/, 65536 *16 * -7.03226653737734E-4 -/*79*/, 65536 *16 * -6.827921676621563E-4 -/*80*/, 65536 *16 * -6.58752773848678E-4 -/*81*/, 65536 *16 * -6.31061807229375E-4 -/*82*/, 65536 *16 * -5.997124150992168E-4 -/*83*/, 65536 *16 * -5.647352645065657E-4 -/*84*/, 65536 *16 * -5.261799041455252E-4 -/*85*/, 65536 *16 * -4.8402880277824417E-4 -/*86*/, 65536 *16 * -4.3840329475572E-4 -/*87*/, 65536 *16 * -3.893672279202991E-4 -/*88*/, 65536 *16 * -3.37002579326518E-4 -/*89*/, 65536 *16 * -2.8148278838384204E-4 -/*90*/, 65536 *16 * -2.2288467365854118E-4 -/*91*/, 65536 *16 * -1.6140368454103024E-4 -/*92*/, 65536 *16 * -9.718648150744015E-5 -/*93*/, 65536 *16 * -3.046343268277719E-5 -/*94*/, 65536 *16 * 3.859234051837562E-5 -/*95*/, 65536 *16 * 1.0974328274324426E-4 -/*96*/, 65536 *16 * 1.8273974279995372E-4 -/*97*/, 65536 *16 * 2.5730055402762935E-4 -/*98*/, 65536 *16 * 3.3318458939353874E-4 -/*99*/, 65536 *16 * 4.100891270013777E-4 -/*100*/, 65536 *16 * 4.876860015464126E-4 -/*101*/, 65536 *16 * 5.657011755504638E-4 -/*102*/, 65536 *16 * 6.437547403393535E-4 -/*103*/, 65536 *16 * 7.215350856659516E-4 -/*104*/, 65536 *16 * 7.986901321007353E-4 -/*105*/, 65536 *16 * 8.748424228508639E-4 -/*106*/, 65536 *16 * 9.496338070297501E-4 -/*107*/, 65536 *16 * 0.0010226804298925178 -/*108*/, 65536 *16 * 0.001093633836878271 -/*109*/, 65536 *16 * 0.0011620773771650913 -/*110*/, 65536 *16 * 0.001227641045409496 -/*111*/, 65536 *16 * 0.0012899374110895208 -/*112*/, 65536 *16 * 0.001348607725415767 -/*113*/, 65536 *16 * 0.001403236086962171 -/*114*/, 65536 *16 * 0.0014534904370406968 -/*115*/, 65536 *16 * 0.0014989864777827345 -/*116*/, 65536 *16 * 0.0015393672007052272 -/*117*/, 65536 *16 * 0.0015743174329729173 -/*118*/, 65536 *16 * 0.0016034756800234508 -/*119*/, 65536 *16 * 0.0016265420570988364 -/*120*/, 65536 *16 * 0.0016432110467175217 -/*121*/, 65536 *16 * 0.0016532197970121178 -/*122*/, 65536 *16 * 0.0016562968359550962 -/*123*/, 65536 *16 * 0.0016521969919585549 -/*124*/, 65536 *16 * 0.001640721606064916 -/*125*/, 65536 *16 * 0.001621678045313759 -/*126*/, 65536 *16 * 0.0015948992297934834 -/*127*/, 65536 *16 * 0.0015602457924787695 -/*128*/, 65536 *16 * 0.0015176354451292787 -/*129*/, 65536 *16 * 0.0014669598890367775 -/*130*/, 65536 *16 * 0.001408218899058892 -/*131*/, 65536 *16 * 0.001341376545671481 -/*132*/, 65536 *16 * 0.0012664621369705463 -/*133*/, 65536 *16 * 0.0011835425953369801 -/*134*/, 65536 *16 * 0.0010927146027981068 -/*135*/, 65536 *16 * 9.941150953832762E-4 -/*136*/, 65536 *16 * 8.878982163088053E-4 -/*137*/, 65536 *16 * 7.742911468907501E-4 -/*138*/, 65536 *16 * 6.535350381595103E-4 -/*139*/, 65536 *16 * 5.259114487251054E-4 -/*140*/, 65536 *16 * 3.9173611703422796E-4 -/*141*/, 65536 *16 * 2.513813444320677E-4 -/*142*/, 65536 *16 * 1.0522988594595334E-4 -/*143*/, 65536 *16 * -4.627799877161863E-5 -/*144*/, 65536 *16 * -2.0266153878465397E-4 -/*145*/, 65536 *16 * -3.6344539072942917E-4 -/*146*/, 65536 *16 * -5.28061484912101E-4 -/*147*/, 65536 *16 * -6.959549845043866E-4 -/*148*/, 65536 *16 * -8.665108935058429E-4 -/*149*/, 65536 *16 * -0.0010391137133997624 -/*150*/, 65536 *16 * -0.001213088248571412 -/*151*/, 65536 *16 * -0.0013877438142645866 -/*152*/, 65536 *16 * -0.0015623746142961936 -/*153*/, 65536 *16 * -0.001736242850147973 -/*154*/, 65536 *16 * -0.0019085899496564314 -/*155*/, 65536 *16 * -0.002078639823528187 -/*156*/, 65536 *16 * -0.0022456104279907118 -/*157*/, 65536 *16 * -0.002408678368623706 -/*158*/, 65536 *16 * -0.002567052121352872 -/*159*/, 65536 *16 * -0.0027198956481072887 -/*160*/, 65536 *16 * -0.0028663750213148488 -/*161*/, 65536 *16 * -0.0030056713494924794 -/*162*/, 65536 *16 * -0.0031369487365098063 -/*163*/, 65536 *16 * -0.0032593909953083865 -/*164*/, 65536 *16 * -0.0033721594370116153 -/*165*/, 65536 *16 * -0.0034744643621211356 -/*166*/, 65536 *16 * -0.0035654990231207963 -/*167*/, 65536 *16 * -0.003644488024347632 -/*168*/, 65536 *16 * -0.0037106644342197828 -/*169*/, 65536 *16 * -0.0037632989436418352 -/*170*/, 65536 *16 * -0.00380166827783197 -/*171*/, 65536 *16 * -0.0038250950477227447 -/*172*/, 65536 *16 * -0.0038329329853570827 -/*173*/, 65536 *16 * -0.0038245430145814447 -/*174*/, 65536 *16 * -0.0037993625516763766 -/*175*/, 65536 *16 * -0.003756842883124589 -/*176*/, 65536 *16 * -0.0036964913119694686 -/*177*/, 65536 *16 * -0.0036178458358447655 -/*178*/, 65536 *16 * -0.00352050628243193 -/*179*/, 65536 *16 * -0.003404123578517079 -/*180*/, 65536 *16 * -0.003268383375473133 -/*181*/, 65536 *16 * -0.0031130454148921446 -/*182*/, 65536 *16 * -0.002937909773123352 -/*183*/, 65536 *16 * -0.0027428475146560275 -/*184*/, 65536 *16 * -0.0025277729297779944 -/*185*/, 65536 *16 * -0.0022926869206439508 -/*186*/, 65536 *16 * -0.0020376141174133374 -/*187*/, 65536 *16 * -0.0017626719756025908 -/*188*/, 65536 *16 * -0.0014680351622130402 -/*189*/, 65536 *16 * -0.0011539297872750212 -/*190*/, 65536 *16 * -8.206567501069872E-4 -/*191*/, 65536 *16 * -4.685710694984321E-4 -/*192*/, 65536 *16 * -9.811116382477182E-5 -/*193*/, 65536 *16 * 2.902488429495873E-4 -/*194*/, 65536 *16 * 6.959516881166062E-4 -/*195*/, 65536 *16 * 0.0011183883405789612 -/*196*/, 65536 *16 * 0.0015568865209671754 -/*197*/, 65536 *16 * 0.0020107155705137744 -/*198*/, 65536 *16 * 0.002479084293281152 -/*199*/, 65536 *16 * 0.002961149037985776 -/*200*/, 65536 *16 * 0.0034560223628435746 -/*201*/, 65536 *16 * 0.0039627343373741354 -/*202*/, 65536 *16 * 0.0044803036416812955 -/*203*/, 65536 *16 * 0.005007678185806692 -/*204*/, 65536 *16 * 0.00554377521563058 -/*205*/, 65536 *16 * 0.006087456836491167 -/*206*/, 65536 *16 * 0.006637561024809676 -/*207*/, 65536 *16 * 0.007192890398414245 -/*208*/, 65536 *16 * 0.0077522050201042055 -/*209*/, 65536 *16 * 0.008314254820045306 -/*210*/, 65536 *16 * 0.008877749982246051 -/*211*/, 65536 *16 * 0.009441393781470539 -/*212*/, 65536 *16 * 0.010003862886118781 -/*213*/, 65536 *16 * 0.01056383933598836 -/*214*/, 65536 *16 * 0.011119972235266088 -/*215*/, 65536 *16 * 0.011670924253482212 -/*216*/, 65536 *16 * 0.012215363764388693 -/*217*/, 65536 *16 * 0.012751945584822125 -/*218*/, 65536 *16 * 0.013279348664168343 -/*219*/, 65536 *16 * 0.013796251849197938 -/*220*/, 65536 *16 * 0.0143013718962506 -/*221*/, 65536 *16 * 0.014793420656675483 -/*222*/, 65536 *16 * 0.015271157641252524 -/*223*/, 65536 *16 * 0.015733358657288442 -/*224*/, 65536 *16 * 0.016178837288118402 -/*225*/, 65536 *16 * 0.016606446422463023 -/*226*/, 65536 *16 * 0.01701507865820779 -/*227*/, 65536 *16 * 0.017403671672970734 -/*228*/, 65536 *16 * 0.01777119975394863 -/*229*/, 65536 *16 * 0.018116717572056962 -/*230*/, 65536 *16 * 0.01843930362202181 -/*231*/, 65536 *16 * 0.01873811058717855 -/*232*/, 65536 *16 * 0.01901234584784063 -/*233*/, 65536 *16 * 0.019261287195027194 -/*234*/, 65536 *16 * 0.019484271195397335 -/*235*/, 65536 *16 * 0.0196806998422779 -/*236*/, 65536 *16 * 0.019850058102456474 -/*237*/, 65536 *16 * 0.019991882444368586 -/*238*/, 65536 *16 * 0.0201058042761605 -/*239*/, 65536 *16 * 0.02019151207246131 -/*240*/, 65536 *16 * 0.02024878178965319 -/*241*/, 65536 *16 * 0.020277449712345474 +/*0*/ static_cast(65536 *16 * 5.793783958720019E-4) +/*1*/, static_cast(65536 *16 * 1.0571291666629312E-4) +/*2*/, static_cast(65536 *16 * 1.1459085882755871E-4) +/*3*/, static_cast(65536 *16 * 1.2371675029136968E-4) +/*4*/, static_cast(65536 *16 * 1.3275170325031607E-4) +/*5*/, static_cast(65536 *16 * 1.4207721167879995E-4) +/*6*/, static_cast(65536 *16 * 1.5130497600100568E-4) +/*7*/, static_cast(65536 *16 * 1.6077227873948047E-4) +/*8*/, static_cast(65536 *16 * 1.6990814771316866E-4) +/*9*/, static_cast(65536 *16 * 1.79005024990367E-4) +/*10*/, static_cast(65536 *16 * 1.8739246068939436E-4) +/*11*/, static_cast(65536 *16 * 1.9572039600801667E-4) +/*12*/, static_cast(65536 *16 * 2.0352846914404956E-4) +/*13*/, static_cast(65536 *16 * 2.1201116607443127E-4) +/*14*/, static_cast(65536 *16 * 2.188838839136502E-4) +/*15*/, static_cast(65536 *16 * 2.2495686284733203E-4) +/*16*/, static_cast(65536 *16 * 2.3149812422937834E-4) +/*17*/, static_cast(65536 *16 * 2.363635497444841E-4) +/*18*/, static_cast(65536 *16 * 2.410054979130104E-4) +/*19*/, static_cast(65536 *16 * 2.445286108284421E-4) +/*20*/, static_cast(65536 *16 * 2.474675828550653E-4) +/*21*/, static_cast(65536 *16 * 2.4934815214903343E-4) +/*22*/, static_cast(65536 *16 * 2.50372333906785E-4) +/*23*/, static_cast(65536 *16 * 2.501665763315339E-4) +/*24*/, static_cast(65536 *16 * 2.488750795254978E-4) +/*25*/, static_cast(65536 *16 * 2.4640153199411455E-4) +/*26*/, static_cast(65536 *16 * 2.428720291968876E-4) +/*27*/, static_cast(65536 *16 * 2.3801309032826844E-4) +/*28*/, static_cast(65536 *16 * 2.3160240772113682E-4) +/*29*/, static_cast(65536 *16 * 2.2423402291517938E-4) +/*30*/, static_cast(65536 *16 * 2.152856501527123E-4) +/*31*/, static_cast(65536 *16 * 2.0488674543318888E-4) +/*32*/, static_cast(65536 *16 * 1.9317919544163198E-4) +/*33*/, static_cast(65536 *16 * 1.7994016398005858E-4) +/*34*/, static_cast(65536 *16 * 1.6541109383681028E-4) +/*35*/, static_cast(65536 *16 * 1.4938382649739635E-4) +/*36*/, static_cast(65536 *16 * 1.3200975730094075E-4) +/*37*/, static_cast(65536 *16 * 1.1313240842725184E-4) +/*38*/, static_cast(65536 *16 * 9.296992728984174E-5) +/*39*/, static_cast(65536 *16 * 7.143010735440594E-5) +/*40*/, static_cast(65536 *16 * 4.8632764324109725E-5) +/*41*/, static_cast(65536 *16 * 2.443073549738759E-5) +/*42*/, static_cast(65536 *16 * -8.284349612349981E-7) +/*43*/, static_cast(65536 *16 * -2.7227387247375577E-5) +/*44*/, static_cast(65536 *16 * -5.4818038895146106E-5) +/*45*/, static_cast(65536 *16 * -8.330005435111118E-5) +/*46*/, static_cast(65536 *16 * -1.1275737974091186E-4) +/*47*/, static_cast(65536 *16 * -1.4298620796919756E-4) +/*48*/, static_cast(65536 *16 * -1.7390785487074508E-4) +/*49*/, static_cast(65536 *16 * -2.054308580401118E-4) +/*50*/, static_cast(65536 *16 * -2.37415521983132E-4) +/*51*/, static_cast(65536 *16 * -2.697456782629617E-4) +/*52*/, static_cast(65536 *16 * -3.022375619849705E-4) +/*53*/, static_cast(65536 *16 * -3.348339660959209E-4) +/*54*/, static_cast(65536 *16 * -3.673583086741243E-4) +/*55*/, static_cast(65536 *16 * -3.996554197363865E-4) +/*56*/, static_cast(65536 *16 * -4.3147108191834185E-4) +/*57*/, static_cast(65536 *16 * -4.6285023012872966E-4) +/*58*/, static_cast(65536 *16 * -4.934440989261961E-4) +/*59*/, static_cast(65536 *16 * -5.231720978150925E-4) +/*60*/, static_cast(65536 *16 * -5.518656107257292E-4) +/*61*/, static_cast(65536 *16 * -5.793049560550073E-4) +/*62*/, static_cast(65536 *16 * -6.053792205725333E-4) +/*63*/, static_cast(65536 *16 * -6.298765704841736E-4) +/*64*/, static_cast(65536 *16 * -6.526402738994988E-4) +/*65*/, static_cast(65536 *16 * -6.734722964365358E-4) +/*66*/, static_cast(65536 *16 * -6.922485843472661E-4) +/*67*/, static_cast(65536 *16 * -7.088111930758961E-4) +/*68*/, static_cast(65536 *16 * -7.229789042068006E-4) +/*69*/, static_cast(65536 *16 * -7.34572975483669E-4) +/*70*/, static_cast(65536 *16 * -7.435049180176613E-4) +/*71*/, static_cast(65536 *16 * -7.496258178311876E-4) +/*72*/, static_cast(65536 *16 * -7.527294926570751E-4) +/*73*/, static_cast(65536 *16 * -7.528075552986548E-4) +/*74*/, static_cast(65536 *16 * -7.496410435428715E-4) +/*75*/, static_cast(65536 *16 * -7.432054606042111E-4) +/*76*/, static_cast(65536 *16 * -7.33375741493331E-4) +/*77*/, static_cast(65536 *16 * -7.200753858529672E-4) +/*78*/, static_cast(65536 *16 * -7.03226653737734E-4) +/*79*/, static_cast(65536 *16 * -6.827921676621563E-4) +/*80*/, static_cast(65536 *16 * -6.58752773848678E-4) +/*81*/, static_cast(65536 *16 * -6.31061807229375E-4) +/*82*/, static_cast(65536 *16 * -5.997124150992168E-4) +/*83*/, static_cast(65536 *16 * -5.647352645065657E-4) +/*84*/, static_cast(65536 *16 * -5.261799041455252E-4) +/*85*/, static_cast(65536 *16 * -4.8402880277824417E-4) +/*86*/, static_cast(65536 *16 * -4.3840329475572E-4) +/*87*/, static_cast(65536 *16 * -3.893672279202991E-4) +/*88*/, static_cast(65536 *16 * -3.37002579326518E-4) +/*89*/, static_cast(65536 *16 * -2.8148278838384204E-4) +/*90*/, static_cast(65536 *16 * -2.2288467365854118E-4) +/*91*/, static_cast(65536 *16 * -1.6140368454103024E-4) +/*92*/, static_cast(65536 *16 * -9.718648150744015E-5) +/*93*/, static_cast(65536 *16 * -3.046343268277719E-5) +/*94*/, static_cast(65536 *16 * 3.859234051837562E-5) +/*95*/, static_cast(65536 *16 * 1.0974328274324426E-4) +/*96*/, static_cast(65536 *16 * 1.8273974279995372E-4) +/*97*/, static_cast(65536 *16 * 2.5730055402762935E-4) +/*98*/, static_cast(65536 *16 * 3.3318458939353874E-4) +/*99*/, static_cast(65536 *16 * 4.100891270013777E-4) +/*100*/, static_cast(65536 *16 * 4.876860015464126E-4) +/*101*/, static_cast(65536 *16 * 5.657011755504638E-4) +/*102*/, static_cast(65536 *16 * 6.437547403393535E-4) +/*103*/, static_cast(65536 *16 * 7.215350856659516E-4) +/*104*/, static_cast(65536 *16 * 7.986901321007353E-4) +/*105*/, static_cast(65536 *16 * 8.748424228508639E-4) +/*106*/, static_cast(65536 *16 * 9.496338070297501E-4) +/*107*/, static_cast(65536 *16 * 0.0010226804298925178) +/*108*/, static_cast(65536 *16 * 0.001093633836878271) +/*109*/, static_cast(65536 *16 * 0.0011620773771650913) +/*110*/, static_cast(65536 *16 * 0.001227641045409496) +/*111*/, static_cast(65536 *16 * 0.0012899374110895208) +/*112*/, static_cast(65536 *16 * 0.001348607725415767) +/*113*/, static_cast(65536 *16 * 0.001403236086962171) +/*114*/, static_cast(65536 *16 * 0.0014534904370406968) +/*115*/, static_cast(65536 *16 * 0.0014989864777827345) +/*116*/, static_cast(65536 *16 * 0.0015393672007052272) +/*117*/, static_cast(65536 *16 * 0.0015743174329729173) +/*118*/, static_cast(65536 *16 * 0.0016034756800234508) +/*119*/, static_cast(65536 *16 * 0.0016265420570988364) +/*120*/, static_cast(65536 *16 * 0.0016432110467175217) +/*121*/, static_cast(65536 *16 * 0.0016532197970121178) +/*122*/, static_cast(65536 *16 * 0.0016562968359550962) +/*123*/, static_cast(65536 *16 * 0.0016521969919585549) +/*124*/, static_cast(65536 *16 * 0.001640721606064916) +/*125*/, static_cast(65536 *16 * 0.001621678045313759) +/*126*/, static_cast(65536 *16 * 0.0015948992297934834) +/*127*/, static_cast(65536 *16 * 0.0015602457924787695) +/*128*/, static_cast(65536 *16 * 0.0015176354451292787) +/*129*/, static_cast(65536 *16 * 0.0014669598890367775) +/*130*/, static_cast(65536 *16 * 0.001408218899058892) +/*131*/, static_cast(65536 *16 * 0.001341376545671481) +/*132*/, static_cast(65536 *16 * 0.0012664621369705463) +/*133*/, static_cast(65536 *16 * 0.0011835425953369801) +/*134*/, static_cast(65536 *16 * 0.0010927146027981068) +/*135*/, static_cast(65536 *16 * 9.941150953832762E-4) +/*136*/, static_cast(65536 *16 * 8.878982163088053E-4) +/*137*/, static_cast(65536 *16 * 7.742911468907501E-4) +/*138*/, static_cast(65536 *16 * 6.535350381595103E-4) +/*139*/, static_cast(65536 *16 * 5.259114487251054E-4) +/*140*/, static_cast(65536 *16 * 3.9173611703422796E-4) +/*141*/, static_cast(65536 *16 * 2.513813444320677E-4) +/*142*/, static_cast(65536 *16 * 1.0522988594595334E-4) +/*143*/, static_cast(65536 *16 * -4.627799877161863E-5) +/*144*/, static_cast(65536 *16 * -2.0266153878465397E-4) +/*145*/, static_cast(65536 *16 * -3.6344539072942917E-4) +/*146*/, static_cast(65536 *16 * -5.28061484912101E-4) +/*147*/, static_cast(65536 *16 * -6.959549845043866E-4) +/*148*/, static_cast(65536 *16 * -8.665108935058429E-4) +/*149*/, static_cast(65536 *16 * -0.0010391137133997624) +/*150*/, static_cast(65536 *16 * -0.001213088248571412) +/*151*/, static_cast(65536 *16 * -0.0013877438142645866) +/*152*/, static_cast(65536 *16 * -0.0015623746142961936) +/*153*/, static_cast(65536 *16 * -0.001736242850147973) +/*154*/, static_cast(65536 *16 * -0.0019085899496564314) +/*155*/, static_cast(65536 *16 * -0.002078639823528187) +/*156*/, static_cast(65536 *16 * -0.0022456104279907118) +/*157*/, static_cast(65536 *16 * -0.002408678368623706) +/*158*/, static_cast(65536 *16 * -0.002567052121352872) +/*159*/, static_cast(65536 *16 * -0.0027198956481072887) +/*160*/, static_cast(65536 *16 * -0.0028663750213148488) +/*161*/, static_cast(65536 *16 * -0.0030056713494924794) +/*162*/, static_cast(65536 *16 * -0.0031369487365098063) +/*163*/, static_cast(65536 *16 * -0.0032593909953083865) +/*164*/, static_cast(65536 *16 * -0.0033721594370116153) +/*165*/, static_cast(65536 *16 * -0.0034744643621211356) +/*166*/, static_cast(65536 *16 * -0.0035654990231207963) +/*167*/, static_cast(65536 *16 * -0.003644488024347632) +/*168*/, static_cast(65536 *16 * -0.0037106644342197828) +/*169*/, static_cast(65536 *16 * -0.0037632989436418352) +/*170*/, static_cast(65536 *16 * -0.00380166827783197) +/*171*/, static_cast(65536 *16 * -0.0038250950477227447) +/*172*/, static_cast(65536 *16 * -0.0038329329853570827) +/*173*/, static_cast(65536 *16 * -0.0038245430145814447) +/*174*/, static_cast(65536 *16 * -0.0037993625516763766) +/*175*/, static_cast(65536 *16 * -0.003756842883124589) +/*176*/, static_cast(65536 *16 * -0.0036964913119694686) +/*177*/, static_cast(65536 *16 * -0.0036178458358447655) +/*178*/, static_cast(65536 *16 * -0.00352050628243193) +/*179*/, static_cast(65536 *16 * -0.003404123578517079) +/*180*/, static_cast(65536 *16 * -0.003268383375473133) +/*181*/, static_cast(65536 *16 * -0.0031130454148921446) +/*182*/, static_cast(65536 *16 * -0.002937909773123352) +/*183*/, static_cast(65536 *16 * -0.0027428475146560275) +/*184*/, static_cast(65536 *16 * -0.0025277729297779944) +/*185*/, static_cast(65536 *16 * -0.0022926869206439508) +/*186*/, static_cast(65536 *16 * -0.0020376141174133374) +/*187*/, static_cast(65536 *16 * -0.0017626719756025908) +/*188*/, static_cast(65536 *16 * -0.0014680351622130402) +/*189*/, static_cast(65536 *16 * -0.0011539297872750212) +/*190*/, static_cast(65536 *16 * -8.206567501069872E-4) +/*191*/, static_cast(65536 *16 * -4.685710694984321E-4) +/*192*/, static_cast(65536 *16 * -9.811116382477182E-5) +/*193*/, static_cast(65536 *16 * 2.902488429495873E-4) +/*194*/, static_cast(65536 *16 * 6.959516881166062E-4) +/*195*/, static_cast(65536 *16 * 0.0011183883405789612) +/*196*/, static_cast(65536 *16 * 0.0015568865209671754) +/*197*/, static_cast(65536 *16 * 0.0020107155705137744) +/*198*/, static_cast(65536 *16 * 0.002479084293281152) +/*199*/, static_cast(65536 *16 * 0.002961149037985776) +/*200*/, static_cast(65536 *16 * 0.0034560223628435746) +/*201*/, static_cast(65536 *16 * 0.0039627343373741354) +/*202*/, static_cast(65536 *16 * 0.0044803036416812955) +/*203*/, static_cast(65536 *16 * 0.005007678185806692) +/*204*/, static_cast(65536 *16 * 0.00554377521563058) +/*205*/, static_cast(65536 *16 * 0.006087456836491167) +/*206*/, static_cast(65536 *16 * 0.006637561024809676) +/*207*/, static_cast(65536 *16 * 0.007192890398414245) +/*208*/, static_cast(65536 *16 * 0.0077522050201042055) +/*209*/, static_cast(65536 *16 * 0.008314254820045306) +/*210*/, static_cast(65536 *16 * 0.008877749982246051) +/*211*/, static_cast(65536 *16 * 0.009441393781470539) +/*212*/, static_cast(65536 *16 * 0.010003862886118781) +/*213*/, static_cast(65536 *16 * 0.01056383933598836) +/*214*/, static_cast(65536 *16 * 0.011119972235266088) +/*215*/, static_cast(65536 *16 * 0.011670924253482212) +/*216*/, static_cast(65536 *16 * 0.012215363764388693) +/*217*/, static_cast(65536 *16 * 0.012751945584822125) +/*218*/, static_cast(65536 *16 * 0.013279348664168343) +/*219*/, static_cast(65536 *16 * 0.013796251849197938) +/*220*/, static_cast(65536 *16 * 0.0143013718962506) +/*221*/, static_cast(65536 *16 * 0.014793420656675483) +/*222*/, static_cast(65536 *16 * 0.015271157641252524) +/*223*/, static_cast(65536 *16 * 0.015733358657288442) +/*224*/, static_cast(65536 *16 * 0.016178837288118402) +/*225*/, static_cast(65536 *16 * 0.016606446422463023) +/*226*/, static_cast(65536 *16 * 0.01701507865820779) +/*227*/, static_cast(65536 *16 * 0.017403671672970734) +/*228*/, static_cast(65536 *16 * 0.01777119975394863) +/*229*/, static_cast(65536 *16 * 0.018116717572056962) +/*230*/, static_cast(65536 *16 * 0.01843930362202181) +/*231*/, static_cast(65536 *16 * 0.01873811058717855) +/*232*/, static_cast(65536 *16 * 0.01901234584784063) +/*233*/, static_cast(65536 *16 * 0.019261287195027194) +/*234*/, static_cast(65536 *16 * 0.019484271195397335) +/*235*/, static_cast(65536 *16 * 0.0196806998422779) +/*236*/, static_cast(65536 *16 * 0.019850058102456474) +/*237*/, static_cast(65536 *16 * 0.019991882444368586) +/*238*/, static_cast(65536 *16 * 0.0201058042761605) +/*239*/, static_cast(65536 *16 * 0.02019151207246131) +/*240*/, static_cast(65536 *16 * 0.02024878178965319) +/*241*/, static_cast(65536 *16 * 0.020277449712345474) }; diff --git a/source/fceultra/file.cpp b/source/fceultra/file.cpp index d61065a..1f946dd 100644 --- a/source/fceultra/file.cpp +++ b/source/fceultra/file.cpp @@ -18,11 +18,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include @@ -148,7 +148,7 @@ end: std::string FCEU_MakeIpsFilename(FileBaseInfo fbi) { char ret[FILENAME_MAX] = ""; - sprintf(ret,"%s"PSS"%s%s.ips",fbi.filebasedirectory.c_str(),fbi.filebase.c_str(),fbi.ext.c_str()); + sprintf(ret,"%s" PSS "%s%s.ips",fbi.filebasedirectory.c_str(),fbi.filebase.c_str(),fbi.ext.c_str()); return ret; } @@ -602,9 +602,9 @@ std::string FCEU_MakeFName(int type, int id1, const char *cd1) struct stat fileInfo; do { if(odirs[FCEUIOD_MOVIES]) - sprintf(ret,"%s"PSS"%s-%d.fm2",odirs[FCEUIOD_MOVIES],FileBase, id1); + sprintf(ret,"%s" PSS "%s-%d.fm2",odirs[FCEUIOD_MOVIES],FileBase, id1); else - sprintf(ret,"%s"PSS"movies"PSS"%s-%d.fm2",BaseDirectory.c_str(),FileBase, id1); + sprintf(ret,"%s" PSS "movies" PSS "%s-%d.fm2",BaseDirectory.c_str(),FileBase, id1); id1++; } while (stat(ret, &fileInfo) == 0); break; @@ -628,19 +628,19 @@ std::string FCEU_MakeFName(int type, int id1, const char *cd1) if(odirs[FCEUIOD_STATES]) { - sprintf(ret,"%s"PSS"%s%s.fc%d",odirs[FCEUIOD_STATES],FileBase,mfn,id1); + sprintf(ret,"%s" PSS "%s%s.fc%d",odirs[FCEUIOD_STATES],FileBase,mfn,id1); } else { - sprintf(ret,"%s"PSS"fcs"PSS"%s%s.fc%d",BaseDirectory.c_str(),FileBase,mfn,id1); + sprintf(ret,"%s" PSS "fcs" PSS "%s%s.fc%d",BaseDirectory.c_str(),FileBase,mfn,id1); } if(stat(ret,&tmpstat)==-1) { if(odirs[FCEUIOD_STATES]) { - sprintf(ret,"%s"PSS"%s%s.fc%d",odirs[FCEUIOD_STATES],FileBase,mfn,id1); + sprintf(ret,"%s" PSS "%s%s.fc%d",odirs[FCEUIOD_STATES],FileBase,mfn,id1); } else { - sprintf(ret,"%s"PSS"fcs"PSS"%s%s.fc%d",BaseDirectory.c_str(),FileBase,mfn,id1); + sprintf(ret,"%s" PSS "fcs" PSS "%s%s.fc%d",BaseDirectory.c_str(),FileBase,mfn,id1); } } } @@ -649,46 +649,46 @@ std::string FCEU_MakeFName(int type, int id1, const char *cd1) { if(odirs[FCEUIOD_STATES]) { - sprintf(ret,"%s"PSS"%s-resume.fcs",odirs[FCEUIOD_STATES],FileBase); + sprintf(ret,"%s" PSS "%s-resume.fcs",odirs[FCEUIOD_STATES],FileBase); } else { - sprintf(ret,"%s"PSS"fcs"PSS"%s-resume.fcs",BaseDirectory.c_str(),FileBase); + sprintf(ret,"%s" PSS "fcs" PSS "%s-resume.fcs",BaseDirectory.c_str(),FileBase); } if(stat(ret,&tmpstat)==-1) { if(odirs[FCEUIOD_STATES]) { - sprintf(ret,"%s"PSS"%s-resume.fcs",odirs[FCEUIOD_STATES],FileBase); + sprintf(ret,"%s" PSS "%s-resume.fcs",odirs[FCEUIOD_STATES],FileBase); } else { - sprintf(ret,"%s"PSS"fcs"PSS"%s-resume.fcs",BaseDirectory.c_str(),FileBase); + sprintf(ret,"%s" PSS "fcs" PSS "%s-resume.fcs",BaseDirectory.c_str(),FileBase); } } } break; case FCEUMKF_SNAP: if(odirs[FCEUIOD_SNAPS]) - sprintf(ret,"%s"PSS"%s-%d.%s",odirs[FCEUIOD_SNAPS],FileBase,id1,cd1); + sprintf(ret,"%s" PSS "%s-%d.%s",odirs[FCEUIOD_SNAPS],FileBase,id1,cd1); else - sprintf(ret,"%s"PSS"snaps"PSS"%s-%d.%s",BaseDirectory.c_str(),FileBase,id1,cd1); + sprintf(ret,"%s" PSS "snaps" PSS "%s-%d.%s",BaseDirectory.c_str(),FileBase,id1,cd1); break; case FCEUMKF_FDS: if(odirs[FCEUIOD_NV]) - sprintf(ret,"%s"PSS"%s.fds",odirs[FCEUIOD_NV],FileBase); + sprintf(ret,"%s" PSS "%s.fds",odirs[FCEUIOD_NV],FileBase); else - sprintf(ret,"%s"PSS"sav"PSS"%s.fds",BaseDirectory.c_str(),FileBase); + sprintf(ret,"%s" PSS "sav" PSS "%s.fds",BaseDirectory.c_str(),FileBase); break; case FCEUMKF_SAV: if(odirs[FCEUIOD_NV]) - sprintf(ret,"%s"PSS"%s.%s",odirs[FCEUIOD_NV],FileBase,cd1); + sprintf(ret,"%s" PSS "%s.%s",odirs[FCEUIOD_NV],FileBase,cd1); else - sprintf(ret,"%s"PSS"sav"PSS"%s.%s",BaseDirectory.c_str(),FileBase,cd1); + sprintf(ret,"%s" PSS "sav" PSS "%s.%s",BaseDirectory.c_str(),FileBase,cd1); if(stat(ret,&tmpstat)==-1) { if(odirs[FCEUIOD_NV]) - sprintf(ret,"%s"PSS"%s.%s",odirs[FCEUIOD_NV],FileBase,cd1); + sprintf(ret,"%s" PSS "%s.%s",odirs[FCEUIOD_NV],FileBase,cd1); else - sprintf(ret,"%s"PSS"sav"PSS"%s.%s",BaseDirectory.c_str(),FileBase,cd1); + sprintf(ret,"%s" PSS "sav" PSS "%s.%s",BaseDirectory.c_str(),FileBase,cd1); } break; case FCEUMKF_AUTOSTATE: @@ -706,52 +706,52 @@ std::string FCEU_MakeFName(int type, int id1, const char *cd1) if(odirs[FCEUIOD_STATES]) { - sprintf(ret,"%s"PSS"%s%s-autosave%d.fcs",odirs[FCEUIOD_STATES],FileBase,mfn,id1); + sprintf(ret,"%s" PSS "%s%s-autosave%d.fcs",odirs[FCEUIOD_STATES],FileBase,mfn,id1); } else { - sprintf(ret,"%s"PSS"fcs"PSS"%s%s-autosave%d.fcs",BaseDirectory.c_str(),FileBase,mfn,id1); + sprintf(ret,"%s" PSS "fcs" PSS "%s%s-autosave%d.fcs",BaseDirectory.c_str(),FileBase,mfn,id1); } if(stat(ret,&tmpstat)==-1) { if(odirs[FCEUIOD_STATES]) { - sprintf(ret,"%s"PSS"%s%s-autosave%d.fcs",odirs[FCEUIOD_STATES],FileBase,mfn,id1); + sprintf(ret,"%s" PSS "%s%s-autosave%d.fcs",odirs[FCEUIOD_STATES],FileBase,mfn,id1); } else { - sprintf(ret,"%s"PSS"fcs"PSS"%s%s-autosave%d.fcs",BaseDirectory.c_str(),FileBase,mfn,id1); + sprintf(ret,"%s" PSS "fcs" PSS "%s%s-autosave%d.fcs",BaseDirectory.c_str(),FileBase,mfn,id1); } } break; case FCEUMKF_CHEAT: if(odirs[FCEUIOD_CHEATS]) - sprintf(ret,"%s"PSS"%s.cht",odirs[FCEUIOD_CHEATS],FileBase); + sprintf(ret,"%s" PSS "%s.cht",odirs[FCEUIOD_CHEATS],FileBase); else - sprintf(ret,"%s"PSS"cheats"PSS"%s.cht",BaseDirectory.c_str(),FileBase); + sprintf(ret,"%s" PSS "cheats" PSS "%s.cht",BaseDirectory.c_str(),FileBase); break; case FCEUMKF_IPS: strcpy(ret,FCEU_MakeIpsFilename(CurrentFileBase()).c_str()); break; - case FCEUMKF_GGROM:sprintf(ret,"%s"PSS"gg.rom",BaseDirectory.c_str());break; + case FCEUMKF_GGROM:sprintf(ret,"%s" PSS "gg.rom",BaseDirectory.c_str());break; case FCEUMKF_FDSROM: if(odirs[FCEUIOD_FDSROM]) - sprintf(ret,"%s"PSS"disksys.rom",odirs[FCEUIOD_FDSROM]); + sprintf(ret,"%s" PSS "disksys.rom",odirs[FCEUIOD_FDSROM]); else - sprintf(ret,"%s"PSS"disksys.rom",BaseDirectory.c_str()); + sprintf(ret,"%s" PSS "disksys.rom",BaseDirectory.c_str()); break; - case FCEUMKF_PALETTE:sprintf(ret,"%s"PSS"%s.pal",BaseDirectory.c_str(),FileBase);break; + case FCEUMKF_PALETTE:sprintf(ret,"%s" PSS "%s.pal",BaseDirectory.c_str(),FileBase);break; case FCEUMKF_MOVIEGLOB: //these globs use ??? because we can load multiple formats if(odirs[FCEUIOD_MOVIES]) - sprintf(ret,"%s"PSS"*.???",odirs[FCEUIOD_MOVIES]); + sprintf(ret,"%s" PSS "*.???",odirs[FCEUIOD_MOVIES]); else - sprintf(ret,"%s"PSS"movies"PSS"*.???",BaseDirectory.c_str()); + sprintf(ret,"%s" PSS "movies" PSS "*.???",BaseDirectory.c_str()); break; - case FCEUMKF_MOVIEGLOB2:sprintf(ret,"%s"PSS"*.???",BaseDirectory.c_str());break; + case FCEUMKF_MOVIEGLOB2:sprintf(ret,"%s" PSS "*.???",BaseDirectory.c_str());break; case FCEUMKF_STATEGLOB: if(odirs[FCEUIOD_STATES]) - sprintf(ret,"%s"PSS"%s*.fc?",odirs[FCEUIOD_STATES],FileBase); + sprintf(ret,"%s" PSS "%s*.fc?",odirs[FCEUIOD_STATES],FileBase); else - sprintf(ret,"%s"PSS"fcs"PSS"%s*.fc?",BaseDirectory.c_str(),FileBase); + sprintf(ret,"%s" PSS "fcs" PSS "%s*.fc?",BaseDirectory.c_str(),FileBase); break; } diff --git a/source/fceultra/file.h b/source/fceultra/file.h index 6b8f24c..20c3dd4 100644 --- a/source/fceultra/file.h +++ b/source/fceultra/file.h @@ -3,11 +3,12 @@ #define MAX_MOVIEFILENAME_LEN 80 -#include -#include #include "types.h" #include "emufile.h" +#include +#include + extern bool bindSavestate; struct FCEUFILE { diff --git a/source/fceultra/filter.cpp b/source/fceultra/filter.cpp index 6285eea..d1e13ac 100644 --- a/source/fceultra/filter.cpp +++ b/source/fceultra/filter.cpp @@ -1,8 +1,6 @@ /// \file /// \brief Sound filtering code -#include -#include #include "types.h" #include "sound.h" @@ -12,6 +10,9 @@ #include "fcoeffs.h" +#include +#include + static int32 sq2coeffs[SQ2NCOEFFS]; static int32 coeffs[NCOEFFS]; diff --git a/source/fceultra/fir/SConscript b/source/fceultra/fir/SConscript new file mode 100644 index 0000000..ef06e5d --- /dev/null +++ b/source/fceultra/fir/SConscript @@ -0,0 +1,6 @@ +my_list = Split(""" +""") + +for x in range(len(my_list)): + my_list[x] = 'fir/' + my_list[x] +Return('my_list') diff --git a/source/fceultra/git.h b/source/fceultra/git.h index 945cbf7..d541cf1 100644 --- a/source/fceultra/git.h +++ b/source/fceultra/git.h @@ -69,14 +69,15 @@ enum ESIFC SIFC_4PLAYER = 3, SIFC_FKB = 4, SIFC_SUBORKB = 5, - SIFC_HYPERSHOT = 6, - SIFC_MAHJONG = 7, - SIFC_QUIZKING = 8, - SIFC_FTRAINERA = 9, - SIFC_FTRAINERB = 10, - SIFC_OEKAKIDS = 11, - SIFC_BWORLD = 12, - SIFC_TOPRIDER = 13, + SIFC_PEC586KB = 6, + SIFC_HYPERSHOT = 7, + SIFC_MAHJONG = 8, + SIFC_QUIZKING = 9, + SIFC_FTRAINERA = 10, + SIFC_FTRAINERB = 11, + SIFC_OEKAKIDS = 12, + SIFC_BWORLD = 13, + SIFC_TOPRIDER = 14, SIFC_COUNT = SIFC_TOPRIDER }; @@ -92,6 +93,7 @@ inline const char* ESIFC_Name(ESIFC esifc) "4-Player Adapter", "Family Keyboard", "Subor Keyboard", + "PEC586 Keyboard", "HyperShot Pads", "Mahjong", "Quiz King Buzzers", @@ -119,7 +121,7 @@ struct FCEUGI int mappernum; EGIT type; - EGIV vidsys; //Current emulated video system; + EGIV vidsys; //Current emulated video system; ESI input[2]; //Desired input for emulated input ports 1 and 2; -1 for unknown desired input. ESIFC inputfc; //Desired Famicom expansion port device. -1 for unknown desired input. ESIS cspecial; //Special cart expansion: DIP switches, barcode reader, etc. diff --git a/source/fceultra/ines-correct.h b/source/fceultra/ines-correct.h index 08c4896..128d9f1 100644 --- a/source/fceultra/ines-correct.h +++ b/source/fceultra/ines-correct.h @@ -5,7 +5,7 @@ {0x82f204ae, -1, 1}, /* Liang Shan Ying Xiong (NJ023) (Ch) [!] */ {0x684afccd, -1, 1}, /* Space Hunter (J) */ {0xad9c63e2, -1, 1}, /* Space Shadow (J) */ - {0xe1526228, -1, 1}, /* Quest of Ki */ + {0xe1526228, -1, 1}, /* Quest of Ki */ {0xaf5d7aa2, -1, 0}, /* Clu Clu Land */ {0xcfb224e6, -1, 1}, /* Dragon Ninja (J) [p1][!].nes */ {0x4f2f1846, -1, 1}, /* Famista '89 - Kaimaku Han!! (J) */ @@ -78,13 +78,19 @@ {0xbe939fce, 9, 1}, /* Punchout*/ {0x345d3a1a, 11, 1}, /* Castle of Deceit */ {0x5e66eaea, 13, 1}, /* Videomation */ + {0xcd373baa, 14, -1}, /* Samurai Spirits (Rex Soft) */ {0xbfc7a2e9, 16, 8}, {0x6e68e31a, 16, 8}, /* Dragon Ball 3*/ - {0x183859d2, 16, -1}, {0x33b899c9, 16, -1}, /* Dragon Ball - Dai Maou Fukkatsu (J) [!] */ - {0x286fcd20, 23, -1}, /* Ganbare Goemon Gaiden 2 - Tenka no Zaihou (J) [!] */ - {0xe4a291ce, 23, -1}, /* World Hero (Unl) [!] */ - {0x51e9cd33, 23, -1}, /* World Hero (Unl) [b1] */ + {0xa262a81f, 16, -1}, /* Rokudenashi Blues (J) */ + {0x286fcd20, 23, -1}, /* Ganbare Goemon Gaiden 2 - Tenka no Zaihou (J) [!] */ + {0xe4a291ce, 23, -1}, /* World Hero (Unl) [!] */ + {0x51e9cd33, 23, -1}, /* World Hero (Unl) [b1] */ + {0x105dd586, 27, -1}, /* Mi Hun Che variations... */ + {0xbc9bb6c1, 27, -1}, /* -- */ + {0x43753886, 27, -1}, /* -- */ + {0x5b3de3d1, 27, -1}, /* -- */ + {0x511e73f8, 27, -1}, /* -- */ {0x5555fca3, 32, 8}, {0x283ad224, 32, 8}, /* Ai Sensei no Oshiete */ {0x243a8735, 32, 0x10|4}, /* Major League */ @@ -95,14 +101,14 @@ {0xf46ef39a, 37, -1}, /* Super Mario Bros. + Tetris + Nintendo World Cup (E) [!] */ {0x7ccb12a3, 43, -1}, /* SMB2j */ {0x6c71feae, 45, -1}, /* Kunio 8-in-1 */ - {0xe2c94bc2, 48, -1}, /* Super Bros 8 (Unl) [!] */ + {0xe2c94bc2, 48, -1}, /* Super Bros 8 (Unl) [!] */ {0xaebd6549, 48, 8}, /* Bakushou!! Jinsei Gekijou 3 */ {0x6cdc0cd9, 48, 8}, /* Bubble Bobble 2 */ {0x99c395f9, 48, 8}, /* Captain Saver */ {0xa7b0536c, 48, 8}, /* Don Doko Don 2 */ {0x40c0ad47, 48, 8}, /* Flintstones 2 */ {0x1500e835, 48, 8}, /* Jetsons (J) */ - {0xa912b064, 51|0x800, 8}, /* 11-in-1 Ball Games(has CHR ROM when it shouldn't) */ + {0xa912b064, 51|0x800, 8}, /* 11-in-1 Ball Games (has CHR ROM when it shouldn't) */ {0xb19a55dd, 64, 8}, /* Road Runner */ {0xf92be3ec, 64, -1}, /* Rolling Thunder */ {0xe84274c5, 66, 1}, @@ -114,6 +120,7 @@ {0xbba58be5, 70, -1}, /* Family Trainer - Manhattan Police */ {0x370ceb65, 70, -1}, /* Family Trainer - Meiro Dai Sakusen */ {0xe62e3382, 71, -1}, /* Mig-29 Soviet Fighter */ + {0xac7b0742, 71, -1}, /* Golden KTV (Ch) [!], not actually 71, but UNROM without BUS conflict */ {0x054bd3e9, 74, -1}, /* Di 4 Ci - Ji Qi Ren Dai Zhan (As) */ {0x496ac8f7, 74, -1}, /* Ji Jia Zhan Shi (As) */ {0xae854cef, 74, -1}, /* Jia A Fung Yun (Chinese) */ @@ -162,12 +169,6 @@ {0xb1a94b82, 152, 8}, /* Pocket Zaurus */ {0x026c5fca, 152, 8}, /* Saint Seiya Ougon Densetsu */ {0x3f15d20d, 153, 8}, /* Famicom Jump 2 */ - {0xb7f28915, 153, -1}, /* Magical Taruruuto-kun 2 - Mahou Daibouken (J) */ - {0xa262a81f, 153, -1}, /* Rokudenashi Blues (J) */ - {0xe170404c, 153, -1}, /* SD Gundam Gaiden - Knight Gundam Monogatari (J) (V1.0) [!] */ - {0x276ac722, 153, -1}, /* SD Gundam Gaiden - Knight Gundam Monogatari (J) (V1.1) [!] */ - {0xb049a8c4, 153, -1}, /* SD Gundam Gaiden - Knight Gundam Monogatari 2 - Hikari no Kishi (J) [!] */ - {0xc2840372, 153, -1}, /* SD Gundam Gaiden - Knight Gundam Monogatari 3 - Densetsu no Kishi Dan (J) [!] */ {0xd1691028, 154, 8}, /* Devil Man */ {0xcfd4a281, 155, 8}, /* Money Game. Yay for money! */ {0x2f27cdef, 155, 8}, /* Tatakae!! Rahmen Man */ @@ -179,8 +180,14 @@ {0x0be0a328, 157, 8}, /* Datach SD Gundam Wars */ {0x5b457641, 157, 8}, /* Datach Ultraman Club */ {0xf51a7f46, 157, 8}, /* Datach Yuu Yuu Hakusho */ + {0xe170404c, 159, -1}, /* SD Gundam Gaiden - Knight Gundam Monogatari (J) (V1.0) [!] */ + {0x276ac722, 159, -1}, /* SD Gundam Gaiden - Knight Gundam Monogatari (J) (V1.1) [!] */ + {0x0cf42e69, 159, -1}, /* Magical Taruruuto-kun - Fantastic World!! (J) (V1.0) [!] */ + {0xdcb972ce, 159, -1}, /* Magical Taruruuto-kun - Fantastic World!! (J) (V1.1) [!] */ + {0xb7f28915, 159, -1}, /* Magical Taruruuto-kun 2 - Mahou Daibouken (J) */ + {0x183859d2, 159, -1}, /* Dragon Ball Z - Kyoushuu! Saiya Jin (J) [!] */ {0x58152b42, 160, 1}, /* Pipe 5 (Sachen) */ - {0x1c098942, 162, -1}, /* Xi You Ji Hou Zhuan (Ch) */ + {0x1c098942, 162, -1}, /* Xi You Ji Hou Zhuan (Ch) */ {0x081caaff, 163, -1}, /* Commandos (Ch) */ {0x02c41438, 176, -1}, /* Xing He Zhan Shi (C) */ {0x558c0dc3, 178, -1}, /* Super 2in1 (unl)[!] {mapper unsupported} */ @@ -193,7 +200,7 @@ {0xa9115bc1, 192, -1}, {0x4c7bbb0e, 192, -1}, {0x98c1cd4b, 192, -1}, /* Ying Lie Qun Xia Zhuan (Chinese) */ - {0xee810d55, 192, -1}, /* You Ling Xing Dong (Ch) */ + {0xee810d55, 192, -1}, /* You Ling Xing Dong (Ch) */ {0x442f1a29, 192, -1}, /* Young chivalry */ {0x637134e8, 193, 1}, /* Fighting Hero */ {0xa925226c, 194, -1}, /* Dai-2-Ji - Super Robot Taisen (As) */ @@ -228,26 +235,32 @@ {0x2447e03b, 210, 1}, /* Top Striker */ {0x1dc0f740, 210, 1}, /* Wagyan Land 2 */ {0xd323b806, 210, 1}, /* Wagyan Land 3 */ - {0xbd523011, 210, 2}, /* Dream Master */ + {0xbd523011, 210, 0}, /* Dream Master */ {0x5daae69a, 211, -1}, /* Aladdin - Return of Jaffar, The (Unl) [!] */ - {0x1ec1dfeb, 217, -1}, /* 255-in-1 (Cut version) [p1] */ - {0x046d70cc, 217, -1}, /* 500-in-1 (Anim Splash, Alt Mapper)[p1][!] */ - {0x12f86a4d, 217, -1}, /* 500-in-1 (Static Splash, Alt Mapper)[p1][!] */ - {0xd09f778d, 217, -1}, /* 9999999-in-1 (Static Splash, Alt Mapper)[p1][!] */ + {0x1ec1dfeb, 217, -1}, /* 255-in-1 (Cut version) [p1] */ + {0x046d70cc, 217, -1}, /* 500-in-1 (Anim Splash, Alt Mapper)[p1][!] */ + {0x12f86a4d, 217, -1}, /* 500-in-1 (Static Splash, Alt Mapper)[p1][!] */ + {0xd09f778d, 217, -1}, /* 9999999-in-1 (Static Splash, Alt Mapper)[p1][!] */ {0x62ef6c79, 232, 8}, /* Quattro Sports -Aladdin */ {0x2705eaeb, 234, -1}, /* Maxi 15 */ {0x6f12afc5, 235, -1}, /* Golden Game 150-in-1 */ {0xfb2b6b10, 241, -1}, /* Fan Kong Jing Ying (Ch) */ {0xb5e83c9a, 241, -1}, /* Xing Ji Zheng Ba (Ch) */ - {0x2537b3e6, 241, -1}, /* Dance Xtreme - Prima (Unl) */ - {0x11611e89, 241, -1}, /* Darkseed (Unl) [p1] */ - {0x81a37827, 241, -1}, /* Darkseed (Unl) [p1][b1] */ - {0xc2730c30, 241, -1}, /* Deadly Towers (U) [!] */ - {0x368c19a8, 241, -1}, /* LIKO Study Cartridge 3-in-1 (Unl) [!] */ - {0xa21e675c, 241, -1}, /* Mashou (J) [!] */ - {0x54d98b79, 241, -1}, /* Titanic 1912 (Unl) */ + {0x2537b3e6, 241, -1}, /* Dance Xtreme - Prima (Unl) */ + {0x11611e89, 241, -1}, /* Darkseed (Unl) [p1] */ + {0x81a37827, 241, -1}, /* Darkseed (Unl) [p1][b1] */ + {0xc2730c30, 241, -1}, /* Deadly Towers (U) [!] */ + {0x368c19a8, 241, -1}, /* LIKO Study Cartridge 3-in-1 (Unl) [!] */ + {0xa21e675c, 241, -1}, /* Mashou (J) [!] */ + {0x54d98b79, 241, -1}, /* Titanic 1912 (Unl) */ {0x6bea1235, 245, -1}, /* MMC3 cart, but with nobanking applied to CHR-RAM, so let it be there */ {0x345ee51a, 245, -1}, /* DQ4c */ {0x57514c6c, 245, -1}, /* Yong Zhe Dou E Long - Dragon Quest VI (Ch) */ + {0x1d75fd35, 256|0x1000,-1}, /* 2-in-1 - Street Dance + Hit Mouse (Unl) [!] */ + {0x6eef8bb7, 257|0x1000,-1}, /* PEC-586 Chinese */ + {0xac7e98fb, 257|0x1000,-1}, /* PEC-586 Chinese No Tape Out */ + {0x8d51a23b, 257|0x1000,-1}, /* [KeWang] Chao Ji Wu Bi Han Ka (C) V1 */ + {0x25c76773, 257|0x1000,-1}, /* [KeWang] Chao Ji Wu Bi Han Ka (C) V2 */ + {0x00000000, -1, -1} diff --git a/source/fceultra/ines.cpp b/source/fceultra/ines.cpp index 7538283..4c56c38 100644 --- a/source/fceultra/ines.cpp +++ b/source/fceultra/ines.cpp @@ -1,456 +1,455 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 1998 BERO - * Copyright (C) 2002 Xodnizel - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include - -#include "types.h" -#include "x6502.h" -#include "fceu.h" -#include "cart.h" -#include "ppu.h" - -#include "ines.h" -#include "unif.h" -#include "state.h" -#include "file.h" -#include "utils/general.h" -#include "utils/memory.h" -#include "utils/crc32.h" -#include "utils/md5.h" -#include "utils/xstring.h" -#include "cheat.h" -#include "vsuni.h" -#include "driver.h" - -extern SFORMAT FCEUVSUNI_STATEINFO[]; - -//mbg merge 6/29/06 - these need to be global -uint8 *trainerpoo = 0; -uint8 *ROM = NULL; -uint8 *VROM = NULL; -uint8 *ExtraNTARAM = NULL; -iNES_HEADER head; - -#ifdef GEKKO -CartInfo iNESCart; -#else -static CartInfo iNESCart; -#endif - -uint8 Mirroring = 0; -uint32 ROM_size = 0; -uint32 VROM_size = 0; -char LoadedRomFName[2048]; //mbg merge 7/17/06 added - -static int CHRRAMSize = -1; -static int iNES_Init(int num); - -static int MapperNo = 0; - -static DECLFR(TrainerRead) { - return(trainerpoo[A & 0x1FF]); -} - -static void iNES_ExecPower() { - if (CHRRAMSize != -1) - FCEU_MemoryRand(VROM, CHRRAMSize); - - if (iNESCart.Power) - iNESCart.Power(); - - if (trainerpoo) { - int x; - for (x = 0; x < 512; x++) { - X6502_DMW(0x7000 + x, trainerpoo[x]); - if (X6502_DMR(0x7000 + x) != trainerpoo[x]) { - SetReadHandler(0x7000, 0x71FF, TrainerRead); - break; - } - } - } -} - -void iNESGI(GI h) { //bbit edited: removed static keyword - switch (h) { - case GI_RESETSAVE: - FCEU_ClearGameSave(&iNESCart); - break; - - case GI_RESETM2: - if (iNESCart.Reset) - iNESCart.Reset(); - break; - case GI_POWER: - iNES_ExecPower(); - break; - case GI_CLOSE: - { - #ifndef GEKKO - FCEU_SaveGameSave(&iNESCart); - #endif - if (iNESCart.Close) - iNESCart.Close(); - if (ROM) { - free(ROM); - ROM = NULL; - } - if (VROM) { - free(VROM); - VROM = NULL; - } - if (trainerpoo) { - free(trainerpoo); - trainerpoo = NULL; - } - if (ExtraNTARAM) { - free(ExtraNTARAM); - ExtraNTARAM = NULL; - } - } - break; - } -} - -uint32 iNESGameCRC32 = 0; - -struct CRCMATCH { - uint32 crc; - char *name; -}; - -struct INPSEL { - uint32 crc32; - ESI input1; - ESI input2; - ESIFC inputfc; -}; - -static void SetInput(void) { - static struct INPSEL moo[] = - { - {0x19b0a9f1, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // 6-in-1 (MGC-023)(Unl)[!] - {0x29de87af, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Aerobics Studio - {0xd89e5a67, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid (J) - {0x0f141525, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid 2(J) - {0x32fb0583, SI_UNSET, SI_ARKANOID, SIFC_NONE }, // Arkanoid(NES) - {0x60ad090a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Athletic World - {0x48ca0ee1, SI_GAMEPAD, SI_GAMEPAD, SIFC_BWORLD }, // Barcode World - {0x4318a2f8, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Barker Bill's Trick Shooting - {0x6cca1c1f, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Dai Undoukai - {0x24598791, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Duck Hunt - {0xd5d6eac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Edu (As) - {0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Educational Computer 2000 - {0x8f7b1669, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // FP BASIC 3.3 by maxzhou88 - {0xf7606810, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.0A - {0x895037bc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.1a - {0xb2530afc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 3.0 - {0xea90f3e2, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Family Trainer: Running Stadium - {0xbba58be5, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Family Trainer: Manhattan Police - {0x3e58a87e, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Freedom Force - {0xd9f45be9, SI_GAMEPAD, SI_GAMEPAD, SIFC_QUIZKING }, // Gimme a Break ... - {0x1545bd13, SI_GAMEPAD, SI_GAMEPAD, SIFC_QUIZKING }, // Gimme a Break ... 2 - {0x4e959173, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Gotcha! - The Sport! - {0xbeb8ab01, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Gumshoe - {0xff24d794, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Hogan's Alley - {0x21f85681, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Olympic (Gentei Ban) - {0x980be936, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Olympic - {0x915a53a7, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Sports - {0x9fae4d46, SI_GAMEPAD, SI_GAMEPAD, SIFC_MAHJONG }, // Ide Yousuke Meijin no Jissen Mahjong - {0x7b44fb2a, SI_GAMEPAD, SI_GAMEPAD, SIFC_MAHJONG }, // Ide Yousuke Meijin no Jissen Mahjong 2 - {0x2f128512, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Jogging Race - {0xbb33196f, SI_UNSET, SI_UNSET, SIFC_FKB }, // Keyboard Transformer - {0x8587ee00, SI_UNSET, SI_UNSET, SIFC_FKB }, // Keyboard Transformer - {0x543ab532, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // LIKO Color Lines - {0x368c19a8, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // LIKO Study Cartridge - {0x5ee6008e, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Mechanized Attack - {0x370ceb65, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Meiro Dai Sakusen - {0x3a1694f9, SI_GAMEPAD, SI_GAMEPAD, SIFC_4PLAYER }, // Nekketsu Kakutou Densetsu - {0x9d048ea4, SI_GAMEPAD, SI_GAMEPAD, SIFC_OEKAKIDS }, // Oeka Kids - {0x2a6559a1, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Operation Wolf (J) - {0xedc3662b, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Operation Wolf - {0x912989dc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Playbox BASIC - {0x9044550e, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Rairai Kyonshizu - {0xea90f3e2, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Running Stadium - {0x851eb9be, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Shooting Range - {0x6435c095, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Short Order/Eggsplode - {0xc043a8df, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Shu Qi Yu - Shu Xue Xiao Zhuan Yuan (Ch) - {0x2cf5db05, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Shu Qi Yu - Zhi Li Xiao Zhuan Yuan (Ch) - {0xad9c63e2, SI_GAMEPAD, SI_UNSET, SIFC_SHADOW }, // Space Shadow - {0x61d86167, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Street Cop - {0xabb2f974, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Study and Game 32-in-1 - {0x41ef9ac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor - {0x8b265862, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor - {0x82f1fb96, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor 1.0 Russian - {0x9f8f200a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Super Mogura Tataki!! - Pokkun Moguraa - {0xd74b2719, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Super Team Games - {0x74bea652, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Supergun 3-in-1 - {0x5e073a1b, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Supor English (Chinese) - {0x589b6b0d, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // SuporV20 - {0x41401c6d, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // SuporV40 - {0x23d17f5e, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // The Lone Ranger - {0xc3c0811d, SI_GAMEPAD, SI_GAMEPAD, SIFC_OEKAKIDS }, // The two "Oeka Kids" games - {0xde8fd935, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // To the Earth - {0x47232739, SI_GAMEPAD, SI_GAMEPAD, SIFC_TOPRIDER }, // Top Rider - {0x8a12a7d9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Totsugeki Fuuun Takeshi Jou - {0xb8b9aca3, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman - {0x5112dc21, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman - {0xaf4010ea, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // World Class Track Meet - {0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET } - }; - int x = 0; - - while (moo[x].input1 >= 0 || moo[x].input2 >= 0 || moo[x].inputfc >= 0) { - if (moo[x].crc32 == iNESGameCRC32) { - GameInfo->input[0] = moo[x].input1; - GameInfo->input[1] = moo[x].input2; - GameInfo->inputfc = moo[x].inputfc; - break; - } - x++; - } -} - -#define INESB_INCOMPLETE 1 -#define INESB_CORRUPT 2 -#define INESB_HACKED 4 - -struct BADINF { - uint64 md5partial; - char *name; - uint32 type; -}; - - -static struct BADINF BadROMImages[] = -{ - #include "ines-bad.h" -}; - -void CheckBad(uint64 md5partial) { - int32 x = 0; - while (BadROMImages[x].name) { - if (BadROMImages[x].md5partial == md5partial) { - FCEU_PrintError("The copy game you have loaded, \"%s\", is bad, and will not work properly in FCEUX.", BadROMImages[x].name); - return; - } - x++; - } -} - - -struct CHINF { - uint32 crc32; - int32 mapper; - int32 mirror; - const char* params; -}; - -static const TMasterRomInfo sMasterRomInfo[] = { - { 0x62b51b108a01d2beLL, "bonus=0" }, //4-in-1 (FK23C8021)[p1][!].nes - { 0x8bb48490d8d22711LL, "bonus=0" }, //4-in-1 (FK23C8033)[p1][!].nes - { 0xc75888d7b48cd378LL, "bonus=0" }, //4-in-1 (FK23C8043)[p1][!].nes - { 0xf81a376fa54fdd69LL, "bonus=0" }, //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes - { 0xa37eb9163e001a46LL, "bonus=0" }, //4-in-1 (FK23C8026) [p1][!].nes - { 0xde5ce25860233f7eLL, "bonus=0" }, //4-in-1 (FK23C8045) [p1][!].nes - { 0x5b3aa4cdc484a088LL, "bonus=0" }, //4-in-1 (FK23C8056) [p1][!].nes - { 0x9342bf9bae1c798aLL, "bonus=0" }, //4-in-1 (FK23C8079) [p1][!].nes - { 0x164eea6097a1e313LL, "busc=1" }, //Cybernoid - The Fighting Machine (U)[!].nes -- needs bus conflict emulation -}; -const TMasterRomInfo* MasterRomInfo; -TMasterRomInfoParams MasterRomInfoParams; - -static void CheckHInfo(void) { - /* ROM images that have the battery-backed bit set in the header that really - don't have battery-backed RAM is not that big of a problem, so I'll - treat this differently by only listing games that should have battery-backed RAM. - - Lower 64 bits of the MD5 hash. - */ - - static uint64 savie[] = - { - 0xc04361e499748382LL, /* AD&D Heroes of the Lance */ - 0xb72ee2337ced5792LL, /* AD&D Hillsfar */ - 0x2b7103b7a27bd72fLL, /* AD&D Pool of Radiance */ - 0x498c10dc463cfe95LL, /* Battle Fleet */ - 0x854d7947a3177f57LL, /* Crystalis */ - 0x4a1f5336b86851b6LL, /* DW */ - 0xb0bcc02c843c1b79LL, /* DW */ - 0x2dcf3a98c7937c22LL, /* DW 2 */ - 0x98e55e09dfcc7533LL, /* DW 4*/ - 0x733026b6b72f2470LL, /* Dw 3 */ - 0x6917ffcaca2d8466LL, /* Famista '90 */ - 0x8da46db592a1fcf4LL, /* Faria */ - 0xedba17a2c4608d20LL, /* Final Fantasy */ - 0x91a6846d3202e3d6LL, /* Final Fantasy */ - 0x012df596e2b31174LL, /* Final Fantasy 1+2 */ - 0xf6b359a720549ecdLL, /* Final Fantasy 2 */ - 0x5a30da1d9b4af35dLL, /* Final Fantasy 3 */ - 0xd63dcc68c2b20adcLL, /* Final Fantasy J */ - 0x2ee3417ba8b69706LL, /* Hydlide 3*/ - 0xebbce5a54cf3ecc0LL, /* Justbreed */ - 0x6a858da551ba239eLL, /* Kaijuu Monogatari */ - 0x2db8f5d16c10b925LL, /* Kyonshiizu 2 */ - 0x04a31647de80fdabLL, /* Legend of Zelda */ - 0x94b9484862a26cbaLL, /* Legend of Zelda */ - 0xa40666740b7d22feLL, /* Mindseeker */ - 0x82000965f04a71bbLL, /* Mirai Shinwa Jarvas */ - 0x77b811b2760104b9LL, /* Mouryou Senki Madara */ - 0x11b69122efe86e8cLL, /* RPG Jinsei Game */ - 0x9aa1dc16c05e7de5LL, /* Startropics */ - 0x1b084107d0878bd0LL, /* Startropics 2*/ - 0xa70b495314f4d075LL, /* Ys 3 */ - 0x836c0ff4f3e06e45LL, /* Zelda 2 */ - 0 /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */ - }; - - static struct CHINF moo[] = - { - #include "ines-correct.h" - }; - int32 tofix = 0, x; - uint64 partialmd5 = 0; - - for (x = 0; x < 8; x++) - partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8); - CheckBad(partialmd5); - - MasterRomInfo = NULL; - for (int i = 0; i < ARRAY_SIZE(sMasterRomInfo); i++) { - const TMasterRomInfo& info = sMasterRomInfo[i]; - if (info.md5lower != partialmd5) - continue; - - MasterRomInfo = &info; - if (!info.params) break; - - std::vector toks = tokenize_str(info.params, ","); - for (int j = 0; j < (int)toks.size(); j++) { - std::vector parts = tokenize_str(toks[j], "="); - MasterRomInfoParams[parts[0]] = parts[1]; - } - break; - } - - x = 0; - do { - if (moo[x].crc32 == iNESGameCRC32) { - if (moo[x].mapper >= 0) { - if (moo[x].mapper & 0x800 && VROM_size) { - VROM_size = 0; - free(VROM); - VROM = NULL; - tofix |= 8; - } - if (MapperNo != (moo[x].mapper & 0xFF)) { - tofix |= 1; - MapperNo = moo[x].mapper & 0xFF; - } - } - if (moo[x].mirror >= 0) { - if (moo[x].mirror == 8) { - if (Mirroring == 2) { /* Anything but hard-wired(four screen). */ - tofix |= 2; - Mirroring = 0; - } - } else if (Mirroring != moo[x].mirror) { - if (Mirroring != (moo[x].mirror & ~4)) - if ((moo[x].mirror & ~4) <= 2) /* Don't complain if one-screen mirroring - needs to be set(the iNES header can't - hold this information). - */ - tofix |= 2; - Mirroring = moo[x].mirror; - } - } - break; - } - x++; - } while (moo[x].mirror >= 0 || moo[x].mapper >= 0); - - x = 0; - while (savie[x] != 0) { - if (savie[x] == partialmd5) { - if (!(head.ROM_type & 2)) { - tofix |= 4; - head.ROM_type |= 2; - } - } - x++; - } - - /* Games that use these iNES mappers tend to have the four-screen bit set - when it should not be. - */ - if ((MapperNo == 118 || MapperNo == 24 || MapperNo == 26) && (Mirroring == 2)) { - Mirroring = 0; - tofix |= 2; - } - - /* Four-screen mirroring implicitly set. */ - if (MapperNo == 99) - Mirroring = 2; - - if (tofix) { - char gigastr[768]; - strcpy(gigastr, "The iNES header contains incorrect information. For now, the information will be corrected in RAM. "); - if (tofix & 1) - sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", MapperNo); - if (tofix & 2) { - char *mstr[3] = { "Horizontal", "Vertical", "Four-screen" }; - sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]); - } - if (tofix & 4) - strcat(gigastr, "The battery-backed bit should be set. "); - if (tofix & 8) - strcat(gigastr, "This game should not have any CHR ROM. "); - strcat(gigastr, "\n"); - FCEU_printf("%s", gigastr); - } -} - -typedef struct { - int32 mapper; - void (*init)(CartInfo *); -} NewMI; - -//this is for games that is not the a power of 2 -//mapper based for now... -//not really accurate but this works since games -//that are not in the power of 2 tends to come -//in obscure mappers themselves which supports such -//size -static int not_power2[] = -{ - 198, 228 -}; -typedef struct { - char *name; - int32 number; - void (*init)(CartInfo *); -} BMAPPINGLocal; - -static BMAPPINGLocal bmap[] = { +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 1998 BERO + * Copyright (C) 2002 Xodnizel + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "types.h" +#include "x6502.h" +#include "fceu.h" +#include "cart.h" +#include "ppu.h" + +#include "ines.h" +#include "unif.h" +#include "state.h" +#include "file.h" +#include "utils/general.h" +#include "utils/memory.h" +#include "utils/crc32.h" +#include "utils/md5.h" +#include "utils/xstring.h" +#include "cheat.h" +#include "vsuni.h" +#include "driver.h" + +#include +#include +#include + +extern SFORMAT FCEUVSUNI_STATEINFO[]; + +//mbg merge 6/29/06 - these need to be global +uint8 *trainerpoo = NULL; +uint8 *ROM = NULL; +uint8 *VROM = NULL; +uint8 *ExtraNTARAM = NULL; +iNES_HEADER head; + +#ifdef GEKKO +CartInfo iNESCart; +#else +static CartInfo iNESCart; +#endif + +uint8 Mirroring = 0; +uint32 ROM_size = 0; +uint32 VROM_size = 0; +char LoadedRomFName[2048]; //mbg merge 7/17/06 added + +static int CHRRAMSize = -1; +static int iNES_Init(int num); + +static int MapperNo = 0; + +static int iNES2 = 0; + +static DECLFR(TrainerRead) { + return(trainerpoo[A & 0x1FF]); +} + +static void iNES_ExecPower() { + if (CHRRAMSize != -1) + FCEU_MemoryRand(VROM, CHRRAMSize); + + if (iNESCart.Power) + iNESCart.Power(); + + if (trainerpoo) { + int x; + for (x = 0; x < 512; x++) { + X6502_DMW(0x7000 + x, trainerpoo[x]); + if (X6502_DMR(0x7000 + x) != trainerpoo[x]) { + SetReadHandler(0x7000, 0x71FF, TrainerRead); + break; + } + } + } +} + +void iNESGI(GI h) { //bbit edited: removed static keyword + switch (h) { + case GI_RESETSAVE: + FCEU_ClearGameSave(&iNESCart); + break; + + case GI_RESETM2: + if (iNESCart.Reset) + iNESCart.Reset(); + break; + case GI_POWER: + iNES_ExecPower(); + break; + case GI_CLOSE: + { + FCEU_SaveGameSave(&iNESCart); + if (iNESCart.Close) + iNESCart.Close(); + if (ROM) { + free(ROM); + ROM = NULL; + } + if (VROM) { + free(VROM); + VROM = NULL; + } + if (trainerpoo) { + free(trainerpoo); + trainerpoo = NULL; + } + if (ExtraNTARAM) { + free(ExtraNTARAM); + ExtraNTARAM = NULL; + } + } + break; + } +} + +uint32 iNESGameCRC32 = 0; + +struct CRCMATCH { + uint32 crc; + char *name; +}; + +struct INPSEL { + uint32 crc32; + ESI input1; + ESI input2; + ESIFC inputfc; +}; + +static void SetInput(void) { + static struct INPSEL moo[] = + { + {0x19b0a9f1, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // 6-in-1 (MGC-023)(Unl)[!] + {0x29de87af, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Aerobics Studio + {0xd89e5a67, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid (J) + {0x0f141525, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid 2(J) + {0x32fb0583, SI_UNSET, SI_ARKANOID, SIFC_NONE }, // Arkanoid(NES) + {0x60ad090a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Athletic World + {0x48ca0ee1, SI_GAMEPAD, SI_GAMEPAD, SIFC_BWORLD }, // Barcode World + {0x4318a2f8, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Barker Bill's Trick Shooting + {0x6cca1c1f, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Dai Undoukai + {0x24598791, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Duck Hunt + {0xd5d6eac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Edu (As) + {0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Educational Computer 2000 + {0x8f7b1669, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // FP BASIC 3.3 by maxzhou88 + {0xf7606810, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.0A + {0x895037bc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.1a + {0xb2530afc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 3.0 + {0xea90f3e2, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Family Trainer: Running Stadium + {0xbba58be5, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Family Trainer: Manhattan Police + {0x3e58a87e, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Freedom Force + {0xd9f45be9, SI_GAMEPAD, SI_GAMEPAD, SIFC_QUIZKING }, // Gimme a Break ... + {0x1545bd13, SI_GAMEPAD, SI_GAMEPAD, SIFC_QUIZKING }, // Gimme a Break ... 2 + {0x4e959173, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Gotcha! - The Sport! + {0xbeb8ab01, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Gumshoe + {0xff24d794, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Hogan's Alley + {0x21f85681, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Olympic (Gentei Ban) + {0x980be936, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Olympic + {0x915a53a7, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Sports + {0x9fae4d46, SI_GAMEPAD, SI_GAMEPAD, SIFC_MAHJONG }, // Ide Yousuke Meijin no Jissen Mahjong + {0x7b44fb2a, SI_GAMEPAD, SI_GAMEPAD, SIFC_MAHJONG }, // Ide Yousuke Meijin no Jissen Mahjong 2 + {0x2f128512, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Jogging Race + {0xbb33196f, SI_UNSET, SI_UNSET, SIFC_FKB }, // Keyboard Transformer + {0x8587ee00, SI_UNSET, SI_UNSET, SIFC_FKB }, // Keyboard Transformer + {0x543ab532, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // LIKO Color Lines + {0x368c19a8, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // LIKO Study Cartridge + {0x5ee6008e, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Mechanized Attack + {0x370ceb65, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Meiro Dai Sakusen + {0x3a1694f9, SI_GAMEPAD, SI_GAMEPAD, SIFC_4PLAYER }, // Nekketsu Kakutou Densetsu + {0x9d048ea4, SI_GAMEPAD, SI_GAMEPAD, SIFC_OEKAKIDS }, // Oeka Kids + {0x2a6559a1, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Operation Wolf (J) + {0xedc3662b, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Operation Wolf + {0x912989dc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Playbox BASIC + {0x9044550e, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Rairai Kyonshizu + {0xea90f3e2, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Running Stadium + {0x851eb9be, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Shooting Range + {0x6435c095, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Short Order/Eggsplode + {0xc043a8df, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Shu Qi Yu - Shu Xue Xiao Zhuan Yuan (Ch) + {0x2cf5db05, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Shu Qi Yu - Zhi Li Xiao Zhuan Yuan (Ch) + {0xad9c63e2, SI_GAMEPAD, SI_UNSET, SIFC_SHADOW }, // Space Shadow + {0x61d86167, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Street Cop + {0xabb2f974, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Study and Game 32-in-1 + {0x41ef9ac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor + {0x8b265862, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor + {0x82f1fb96, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor 1.0 Russian + {0x9f8f200a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Super Mogura Tataki!! - Pokkun Moguraa + {0xd74b2719, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Super Team Games + {0x74bea652, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Supergun 3-in-1 + {0x5e073a1b, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Supor English (Chinese) + {0x589b6b0d, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // SuporV20 + {0x41401c6d, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // SuporV40 + {0x23d17f5e, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // The Lone Ranger + {0xc3c0811d, SI_GAMEPAD, SI_GAMEPAD, SIFC_OEKAKIDS }, // The two "Oeka Kids" games + {0xde8fd935, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // To the Earth + {0x47232739, SI_GAMEPAD, SI_GAMEPAD, SIFC_TOPRIDER }, // Top Rider + {0x8a12a7d9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Totsugeki Fuuun Takeshi Jou + {0xb8b9aca3, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman + {0x5112dc21, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman + {0xaf4010ea, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // World Class Track Meet + {0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET } + }; + int x = 0; + + while (moo[x].input1 >= 0 || moo[x].input2 >= 0 || moo[x].inputfc >= 0) { + if (moo[x].crc32 == iNESGameCRC32) { + GameInfo->input[0] = moo[x].input1; + GameInfo->input[1] = moo[x].input2; + GameInfo->inputfc = moo[x].inputfc; + break; + } + x++; + } +} + +#define INESB_INCOMPLETE 1 +#define INESB_CORRUPT 2 +#define INESB_HACKED 4 + +struct BADINF { + uint64 md5partial; + char *name; + uint32 type; +}; + +static struct BADINF BadROMImages[] = +{ + #include "ines-bad.h" +}; + +void CheckBad(uint64 md5partial) { + int32 x = 0; + while (BadROMImages[x].name) { + if (BadROMImages[x].md5partial == md5partial) { + FCEU_PrintError("The copy game you have loaded, \"%s\", is bad, and will not work properly in FCEUX.", BadROMImages[x].name); + return; + } + x++; + } +} + + +struct CHINF { + uint32 crc32; + int32 mapper; + int32 mirror; + const char* params; +}; + +static const TMasterRomInfo sMasterRomInfo[] = { + { 0x62b51b108a01d2beLL, "bonus=0" }, //4-in-1 (FK23C8021)[p1][!].nes + { 0x8bb48490d8d22711LL, "bonus=0" }, //4-in-1 (FK23C8033)[p1][!].nes + { 0xc75888d7b48cd378LL, "bonus=0" }, //4-in-1 (FK23C8043)[p1][!].nes + { 0xf81a376fa54fdd69LL, "bonus=0" }, //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes + { 0xa37eb9163e001a46LL, "bonus=0" }, //4-in-1 (FK23C8026) [p1][!].nes + { 0xde5ce25860233f7eLL, "bonus=0" }, //4-in-1 (FK23C8045) [p1][!].nes + { 0x5b3aa4cdc484a088LL, "bonus=0" }, //4-in-1 (FK23C8056) [p1][!].nes + { 0x9342bf9bae1c798aLL, "bonus=0" }, //4-in-1 (FK23C8079) [p1][!].nes + { 0x164eea6097a1e313LL, "busc=1" }, //Cybernoid - The Fighting Machine (U)[!].nes -- needs bus conflict emulation +}; +const TMasterRomInfo* MasterRomInfo; +TMasterRomInfoParams MasterRomInfoParams; + +static void CheckHInfo(void) { + /* ROM images that have the battery-backed bit set in the header that really + don't have battery-backed RAM is not that big of a problem, so I'll + treat this differently by only listing games that should have battery-backed RAM. + + Lower 64 bits of the MD5 hash. + */ + + static uint64 savie[] = + { + 0xc04361e499748382LL, /* AD&D Heroes of the Lance */ + 0xb72ee2337ced5792LL, /* AD&D Hillsfar */ + 0x2b7103b7a27bd72fLL, /* AD&D Pool of Radiance */ + 0x498c10dc463cfe95LL, /* Battle Fleet */ + 0x854d7947a3177f57LL, /* Crystalis */ + 0x4a1f5336b86851b6LL, /* DW */ + 0xb0bcc02c843c1b79LL, /* DW */ + 0x2dcf3a98c7937c22LL, /* DW 2 */ + 0x98e55e09dfcc7533LL, /* DW 4*/ + 0x733026b6b72f2470LL, /* Dw 3 */ + 0x6917ffcaca2d8466LL, /* Famista '90 */ + 0x8da46db592a1fcf4LL, /* Faria */ + 0xedba17a2c4608d20LL, /* Final Fantasy */ + 0x91a6846d3202e3d6LL, /* Final Fantasy */ + 0x012df596e2b31174LL, /* Final Fantasy 1+2 */ + 0xf6b359a720549ecdLL, /* Final Fantasy 2 */ + 0x5a30da1d9b4af35dLL, /* Final Fantasy 3 */ + 0xd63dcc68c2b20adcLL, /* Final Fantasy J */ + 0x2ee3417ba8b69706LL, /* Hydlide 3*/ + 0xebbce5a54cf3ecc0LL, /* Justbreed */ + 0x6a858da551ba239eLL, /* Kaijuu Monogatari */ + 0x2db8f5d16c10b925LL, /* Kyonshiizu 2 */ + 0x04a31647de80fdabLL, /* Legend of Zelda */ + 0x94b9484862a26cbaLL, /* Legend of Zelda */ + 0xa40666740b7d22feLL, /* Mindseeker */ + 0x82000965f04a71bbLL, /* Mirai Shinwa Jarvas */ + 0x77b811b2760104b9LL, /* Mouryou Senki Madara */ + 0x11b69122efe86e8cLL, /* RPG Jinsei Game */ + 0x9aa1dc16c05e7de5LL, /* Startropics */ + 0x1b084107d0878bd0LL, /* Startropics 2*/ + 0xa70b495314f4d075LL, /* Ys 3 */ + 0x836c0ff4f3e06e45LL, /* Zelda 2 */ + 0 /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */ + }; + + static struct CHINF moo[] = + { + #include "ines-correct.h" + }; + int32 tofix = 0, x; + uint64 partialmd5 = 0; + + for (x = 0; x < 8; x++) + partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8); + CheckBad(partialmd5); + + MasterRomInfo = NULL; + for (int i = 0; i < ARRAY_SIZE(sMasterRomInfo); i++) { + const TMasterRomInfo& info = sMasterRomInfo[i]; + if (info.md5lower != partialmd5) + continue; + + MasterRomInfo = &info; + if (!info.params) break; + + std::vector toks = tokenize_str(info.params, ","); + for (int j = 0; j < (int)toks.size(); j++) { + std::vector parts = tokenize_str(toks[j], "="); + MasterRomInfoParams[parts[0]] = parts[1]; + } + break; + } + + x = 0; + do { + if (moo[x].crc32 == iNESGameCRC32) { + if (moo[x].mapper >= 0) { + if (moo[x].mapper & 0x800 && VROM_size) { + VROM_size = 0; + free(VROM); + VROM = NULL; + tofix |= 8; + } + if (MapperNo != (moo[x].mapper & 0xFF)) { + tofix |= 1; + MapperNo = moo[x].mapper & 0xFF; + } + } + if (moo[x].mirror >= 0) { + if (moo[x].mirror == 8) { + if (Mirroring == 2) { /* Anything but hard-wired(four screen). */ + tofix |= 2; + Mirroring = 0; + } + } else if (Mirroring != moo[x].mirror) { + if (Mirroring != (moo[x].mirror & ~4)) + if ((moo[x].mirror & ~4) <= 2) /* Don't complain if one-screen mirroring + needs to be set(the iNES header can't + hold this information). + */ + tofix |= 2; + Mirroring = moo[x].mirror; + } + } + break; + } + x++; + } while (moo[x].mirror >= 0 || moo[x].mapper >= 0); + + x = 0; + while (savie[x] != 0) { + if (savie[x] == partialmd5) { + if (!(head.ROM_type & 2)) { + tofix |= 4; + head.ROM_type |= 2; + } + } + x++; + } + + /* Games that use these iNES mappers tend to have the four-screen bit set + when it should not be. + */ + if ((MapperNo == 118 || MapperNo == 24 || MapperNo == 26) && (Mirroring == 2)) { + Mirroring = 0; + tofix |= 2; + } + + /* Four-screen mirroring implicitly set. */ + if (MapperNo == 99) + Mirroring = 2; + + if (tofix) { + char gigastr[768]; + strcpy(gigastr, "The iNES header contains incorrect information. For now, the information will be corrected in RAM. "); + if (tofix & 1) + sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", MapperNo); + if (tofix & 2) { + char *mstr[3] = { "Horizontal", "Vertical", "Four-screen" }; + sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]); + } + if (tofix & 4) + strcat(gigastr, "The battery-backed bit should be set. "); + if (tofix & 8) + strcat(gigastr, "This game should not have any CHR ROM. "); + strcat(gigastr, "\n"); + FCEU_printf("%s", gigastr); + } +} + +typedef struct { + int32 mapper; + void (*init)(CartInfo *); +} NewMI; + +//this is for games that is not the a power of 2 +//mapper based for now... +//not really accurate but this works since games +//that are not in the power of 2 tends to come +//in obscure mappers themselves which supports such +//size +static int not_power2[] = +{ + 53, 198, 228 +}; +typedef struct { + char *name; + int32 number; + void (*init)(CartInfo *); +} BMAPPINGLocal; + +static BMAPPINGLocal bmap[] = { {"NROM", 0, NROM_Init}, {"MMC1", 1, Mapper1_Init}, {"UNROM", 2, UNROM_Init}, @@ -465,9 +464,9 @@ static BMAPPINGLocal bmap[] = { {"Color Dreams", 11, Mapper11_Init}, {"REX DBZ 5", 12, Mapper12_Init}, {"CPROM", 13, CPROM_Init}, -// {"", 14, Mapper14_Init}, + {"REX SL-1632", 14, UNLSL1632_Init}, {"100-in-1", 15, Mapper15_Init}, - {"Bandai", 16, Mapper16_Init}, + {"BANDAI 24C02", 16, Mapper16_Init}, {"FFE Rev. B", 17, Mapper17_Init}, {"JALECO SS880006", 18, Mapper18_Init}, // JF-NNX (EB89018-30007) boards {"Namcot 106", 19, Mapper19_Init}, @@ -478,11 +477,11 @@ static BMAPPINGLocal bmap[] = { {"Konami VRC6 Rev. A", 24, Mapper24_Init}, {"Konami VRC2/VRC4 D", 25, Mapper25_Init}, {"Konami VRC6 Rev. B", 26, Mapper26_Init}, -// {"", 27, Mapper27_Init}, // Deprecated, dupe for VRC2/VRC4 mapper -// {"", 28, Mapper28_Init}, -// {"", 29, Mapper29_Init}, -// {"", 30, Mapper30_Init}, -// {"", 31, Mapper31_Init}, + {"CC-21 MI HUN CHE", 27, UNLCC21_Init}, // Former dupe for VRC2/VRC4 mapper, redefined with crc to mihunche boards + {"", 28, Mapper28_Init}, + {"RET-CUFROM", 29, Mapper29_Init}, + {"UNROM 512", 30, UNROM512_Init}, + {"infiniteneslives-NSF", 31, Mapper31_Init}, {"IREM G-101", 32, Mapper32_Init}, {"TC0190FMC/TC0350FMR", 33, Mapper33_Init}, {"IREM I-IM/BNROM", 34, Mapper34_Init}, @@ -504,7 +503,7 @@ static BMAPPINGLocal bmap[] = { {"SMB2j FDS Rev. A", 50, Mapper50_Init}, {"11-in-1 BALL SERIES", 51, Mapper51_Init}, // 1993 year version {"MMC3 BMC PIRATE D", 52, Mapper52_Init}, -// {"", 53, Mapper53_Init}, // iNES version of complex UNIF board, can't emulate properly as iNES + {"SUPERVISION 16-in-1", 53, Supervision16_Init}, // {"", 54, Mapper54_Init}, // {"", 55, Mapper55_Init}, // {"", 56, Mapper56_Init}, @@ -517,7 +516,7 @@ static BMAPPINGLocal bmap[] = { // {"", 63, Mapper63_Init}, {"TENGEN RAMBO1", 64, Mapper64_Init}, {"IREM-H3001", 65, Mapper65_Init}, - {"MHOM", 66, MHROM_Init}, + {"MHROM", 66, MHROM_Init}, {"SUNSOFT-FZII", 67, Mapper67_Init}, {"Sunsoft Mapper #4", 68, Mapper68_Init}, {"SUNSOFT-5/FME-7", 69, Mapper69_Init}, @@ -540,11 +539,11 @@ static BMAPPINGLocal bmap[] = { {"JALECO JF-13", 86, Mapper86_Init}, {"74*139/74 DISCRETE", 87, Mapper87_Init}, {"NAMCO 3433", 88, Mapper88_Init}, - {"SUNSOFT-3", 89, Mapper89_Init}, // SUNSOFT-2 mapper + {"SUNSOFT-3", 89, Mapper89_Init}, // SUNSOFT-2 mapper {"HUMMER/JY BOARD", 90, Mapper90_Init}, {"EARLY HUMMER/JY BOARD",91, Mapper91_Init}, {"JALECO JF-19", 92, Mapper92_Init}, - {"SUNSOFT-3R", 93, SUNSOFT_UNROM_Init}, // SUNSOFT-2 mapper with VRAM, different wiring + {"SUNSOFT-3R", 93, SUNSOFT_UNROM_Init},// SUNSOFT-2 mapper with VRAM, different wiring {"HVC-UN1ROM", 94, Mapper94_Init}, {"NAMCOT 108 Rev. B", 95, Mapper95_Init}, {"BANDAI OEKAKIDS", 96, Mapper96_Init}, @@ -604,13 +603,13 @@ static BMAPPINGLocal bmap[] = { {"S74LS374N", 150, S74LS374N_Init}, {"", 151, Mapper151_Init}, {"", 152, Mapper152_Init}, - {"", 153, Mapper153_Init}, + {"BANDAI SRAM", 153, Mapper153_Init}, // Bandai board 16 with SRAM instead of EEPROM {"", 154, Mapper154_Init}, {"", 155, Mapper155_Init}, {"", 156, Mapper156_Init}, - {"", 157, Mapper157_Init}, + {"BANDAI BARCODE", 157, Mapper157_Init}, // {"", 158, Mapper158_Init}, -// {"", 159, Mapper159_Init}, + {"BANDAI 24C01", 159, Mapper159_Init}, // Different type of EEPROM on the bandai board {"SA009", 160, SA009_Init}, // {"", 161, Mapper161_Init}, {"", 162, UNLFS304_Init}, @@ -627,7 +626,7 @@ static BMAPPINGLocal bmap[] = { {"", 173, Mapper173_Init}, // {"", 174, Mapper174_Init}, {"", 175, Mapper175_Init}, - {"BMCFK23C", 176, BMCFK23C_Init}, //zero 26-may-2012 - well, i have some WXN junk games that use 176 for instance ????. i dont know what game uses this BMCFK23C as mapper 176. we'll have to make a note when we find it. + {"BMCFK23C", 176, BMCFK23C_Init}, // zero 26-may-2012 - well, i have some WXN junk games that use 176 for instance ????. i dont know what game uses this BMCFK23C as mapper 176. we'll have to make a note when we find it. {"", 177, Mapper177_Init}, {"", 178, Mapper178_Init}, // {"", 179, Mapper179_Init}, @@ -707,283 +706,313 @@ static BMAPPINGLocal bmap[] = { {"DRAGON BALL PIRATE", 253, Mapper253_Init}, {"", 254, Mapper254_Init}, // {"", 255, Mapper255_Init}, // No good dumps for this mapper + +//-------- Mappers 256-511 is the Supplementary Multilingual Plane ---------- +//-------- Mappers 512-767 is the Supplementary Ideographic Plane ----------- +//-------- Mappers 3840-4095 are for rom dumps not publicly released -------- + {"", 0, NULL} -}; - -int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { - struct md5_context md5; - - if (FCEU_fread(&head, 1, 16, fp) != 16) - return 0; - - if (memcmp(&head, "NES\x1a", 4)) - return 0; - - head.cleanup(); - - memset(&iNESCart, 0, sizeof(iNESCart)); - - MapperNo = (head.ROM_type >> 4); - MapperNo |= (head.ROM_type2 & 0xF0); - Mirroring = (head.ROM_type & 1); - - if (!head.ROM_size) - ROM_size = 256; - else - ROM_size = uppow2(head.ROM_size); - - VROM_size = uppow2(head.VROM_size); - - int round = true; - for (int i = 0; i != sizeof(not_power2) / sizeof(not_power2[0]); ++i) { - //for games not to the power of 2, so we just read enough - //prg rom from it, but we have to keep ROM_size to the power of 2 - //since PRGCartMapping wants ROM_size to be to the power of 2 - //so instead if not to power of 2, we just use head.ROM_size when - //we use FCEU_read - if (not_power2[i] == MapperNo) { - round = false; - break; - } - } - - if (head.ROM_type & 8) { - Mirroring = 2; - } - - if ((ROM = (uint8*)FCEU_malloc(ROM_size << 14)) == NULL) - return 0; - memset(ROM, 0xFF, ROM_size << 14); - - if (VROM_size) { - if ((VROM = (uint8*)FCEU_malloc(VROM_size << 13)) == NULL) { - free(ROM); - ROM = NULL; - return 0; - } - memset(VROM, 0xFF, VROM_size << 13); - } - - if (head.ROM_type & 4) { /* Trainer */ - trainerpoo = (uint8*)FCEU_gmalloc(512); - FCEU_fread(trainerpoo, 512, 1, fp); - } - - ResetCartMapping(); - ResetExState(0, 0); - - SetupCartPRGMapping(0, ROM, ROM_size << 14, 0); - - FCEU_fread(ROM, 0x4000, (round) ? ROM_size : head.ROM_size, fp); - - if (VROM_size) - FCEU_fread(VROM, 0x2000, VROM_size, fp); - - md5_starts(&md5); - md5_update(&md5, ROM, ROM_size << 14); - - iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14); - - if (VROM_size) { - iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, VROM_size << 13); - md5_update(&md5, VROM, VROM_size << 13); - } - md5_finish(&md5, iNESCart.MD5); - memcpy(&GameInfo->MD5, &iNESCart.MD5, sizeof(iNESCart.MD5)); - - iNESCart.CRC32 = iNESGameCRC32; - - FCEU_printf(" PRG ROM: %3d x 16KiB\n", (round) ? ROM_size: head.ROM_size); - FCEU_printf(" CHR ROM: %3d x 8KiB\n", head.VROM_size); - FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32); - { - int x; - FCEU_printf(" ROM MD5: 0x"); - for(x=0;x<16;x++) - FCEU_printf("%02x",iNESCart.MD5[x]); - FCEU_printf("\n"); - } - - char* mappername = "Not Listed"; - - for (int mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { - if (bmap[mappertest].number == MapperNo) { - mappername = bmap[mappertest].name; - break; - } - } - - FCEU_printf(" Mapper #: %d\n", MapperNo); - FCEU_printf(" Mapper name: %s\n", mappername); - FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal"); - FCEU_printf(" Battery-backed: %s\n", (head.ROM_type & 2) ? "Yes" : "No"); - FCEU_printf(" Trained: %s\n", (head.ROM_type & 4) ? "Yes" : "No"); - - SetInput(); - CheckHInfo(); - { - int x; - uint64 partialmd5 = 0; - - for (x = 0; x < 8; x++) { - partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8); - } - - FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring); - } - /* Must remain here because above functions might change value of - VROM_size and free(VROM). - */ - if (VROM_size) - SetupCartCHRMapping(0, VROM, VROM_size * 0x2000, 0); - - if (Mirroring == 2) { - ExtraNTARAM = (uint8*)FCEU_gmalloc(2048); - SetupCartMirroring(4, 1, ExtraNTARAM); - } else if (Mirroring >= 0x10) - SetupCartMirroring(2 + (Mirroring & 1), 1, 0); - else - SetupCartMirroring(Mirroring & 1, (Mirroring & 4) >> 2, 0); - - iNESCart.battery = (head.ROM_type & 2) ? 1 : 0; - iNESCart.mirror = Mirroring; - - if (!iNES_Init(MapperNo)) - FCEU_PrintError("iNES mapper #%d is not supported at all.", MapperNo); - - GameInfo->mappernum = MapperNo; - #ifndef GEKKO - FCEU_LoadGameSave(&iNESCart); - #endif - - strcpy(LoadedRomFName, name); //bbit edited: line added - - // Extract Filename only. Should account for Windows/Unix this way. - if (strrchr(name, '/')) { - name = strrchr(name, '/') + 1; - } else if (strrchr(name, '\\')) { - name = strrchr(name, '\\') + 1; - } - - GameInterface = iNESGI; - FCEU_printf("\n"); - - // since apparently the iNES format doesn't store this information, - // guess if the settings should be PAL or NTSC from the ROM name - // TODO: MD5 check against a list of all known PAL games instead? - if (OverwriteVidMode) { - if (strstr(name, "(E)") || strstr(name, "(e)") - || strstr(name, "(Europe)") || strstr(name, "(PAL)") - || strstr(name, "(F)") || strstr(name, "(f)") - || strstr(name, "(G)") || strstr(name, "(g)") - || strstr(name, "(I)") || strstr(name, "(i)")) - FCEUI_SetVidSystem(1); - else - FCEUI_SetVidSystem(0); - } - return 1; -} - -// bbit edited: the whole function below was added -int iNesSave() { - FILE *fp; - char name[2048]; - - if (GameInfo->type != GIT_CART) return 0; - if (GameInterface != iNESGI) return 0; - - strcpy(name, LoadedRomFName); - if (strcmp(name + strlen(name) - 4, ".nes") != 0) { //para edit - strcat(name, ".nes"); - } - - fp = fopen(name, "wb"); - - if (fwrite(&head, 1, 16, fp) != 16) { - fclose(fp); - return 0; - } - - if (head.ROM_type & 4) { /* Trainer */ - fwrite(trainerpoo, 512, 1, fp); - } - - fwrite(ROM, 0x4000, ROM_size, fp); - - if (head.VROM_size) fwrite(VROM, 0x2000, head.VROM_size, fp); - fclose(fp); - - return 1; -} - -int iNesSaveAs(char* name) { - //adelikat: TODO: iNesSave() and this have pretty much the same code, outsource the common code to a single function - FILE *fp; - - if (GameInfo->type != GIT_CART) return 0; - if (GameInterface != iNESGI) return 0; - - fp = fopen(name, "wb"); - - if (fwrite(&head, 1, 16, fp) != 16) { - fclose(fp); - return 0; - } - - if (head.ROM_type & 4) { /* Trainer */ - fwrite(trainerpoo, 512, 1, fp); - } - - fwrite(ROM, 0x4000, ROM_size, fp); - - if (head.VROM_size) fwrite(VROM, 0x2000, head.VROM_size, fp); - fclose(fp); - - return 1; -} - -//para edit: added function below -char *iNesShortFName() { - char *ret; - - if (!(ret = strrchr(LoadedRomFName, '\\'))) { - if (!(ret = strrchr(LoadedRomFName, '/'))) return 0; - } - return ret + 1; -} - -static int iNES_Init(int num) { - BMAPPINGLocal *tmp = bmap; - - CHRRAMSize = -1; - - if (GameInfo->type == GIT_VSUNI) - AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0); - - while (tmp->init) { - if (num == tmp->number) { - UNIFchrrama = 0; // need here for compatibility with UNIF mapper code - if (!VROM_size) { - switch (num) { // FIXME, mapper or game data base with the board parameters and ROM/RAM sizes - case 13: CHRRAMSize = 16 * 1024; break; - case 6: - case 96: CHRRAMSize = 32 * 1024; break; - case 176: CHRRAMSize = 128 * 1024; break; - default: CHRRAMSize = 8 * 1024; break; - } - if ((VROM = (uint8*)FCEU_dmalloc(CHRRAMSize)) == NULL) return 0; - FCEU_MemoryRand(VROM, CHRRAMSize); - - UNIFchrrama = VROM; - SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); - AddExState(VROM, CHRRAMSize, 0, "CHRR"); - } - if (head.ROM_type & 8) - AddExState(ExtraNTARAM, 2048, 0, "EXNR"); - tmp->init(&iNESCart); - return 1; - } - tmp++; - } - return 0; -} +}; + +int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { + struct md5_context md5; + + if (FCEU_fread(&head, 1, 16, fp) != 16) + return 0; + + if (memcmp(&head, "NES\x1a", 4)) + return 0; + + head.cleanup(); + + memset(&iNESCart, 0, sizeof(iNESCart)); + + iNES2 = ((head.ROM_type2 & 0x0C) == 0x08); + if(iNES2) + { + iNESCart.ines2 = true; + iNESCart.wram_size = (head.RAM_size & 0x0F)?(64 << (head.RAM_size & 0x0F)):0; + iNESCart.battery_wram_size = (head.RAM_size & 0xF0)?(64 << ((head.RAM_size & 0xF0)>>4)):0; + iNESCart.vram_size = (head.VRAM_size & 0x0F)?(64 << (head.VRAM_size & 0x0F)):0; + iNESCart.battery_vram_size = (head.VRAM_size & 0xF0)?(64 << ((head.VRAM_size & 0xF0)>>4)):0; + iNESCart.submapper = head.ROM_type3 >> 4; + } + + MapperNo = (head.ROM_type >> 4); + MapperNo |= (head.ROM_type2 & 0xF0); + if(iNES2) MapperNo |= ((head.ROM_type3 & 0x0F) << 8); + + if (head.ROM_type & 8) { + Mirroring = 2; + } else + Mirroring = (head.ROM_type & 1); + + int not_round_size = head.ROM_size; + if(iNES2) not_round_size |= ((head.Upper_ROM_VROM_size & 0x0F) << 8); + + if (!head.ROM_size && !iNES2) + ROM_size = 256; + else + ROM_size = uppow2(not_round_size); + + VROM_size = uppow2(head.VROM_size | (iNES2?((head.Upper_ROM_VROM_size & 0xF0)<<4):0)); + + int round = true; + for (int i = 0; i != sizeof(not_power2) / sizeof(not_power2[0]); ++i) { + //for games not to the power of 2, so we just read enough + //prg rom from it, but we have to keep ROM_size to the power of 2 + //since PRGCartMapping wants ROM_size to be to the power of 2 + //so instead if not to power of 2, we just use head.ROM_size when + //we use FCEU_read + if (not_power2[i] == MapperNo) { + round = false; + break; + } + } + + if ((ROM = (uint8*)FCEU_malloc(ROM_size << 14)) == NULL) + return 0; + memset(ROM, 0xFF, ROM_size << 14); + + if (VROM_size) { + if ((VROM = (uint8*)FCEU_malloc(VROM_size << 13)) == NULL) { + free(ROM); + ROM = NULL; + return 0; + } + memset(VROM, 0xFF, VROM_size << 13); + } + + if (head.ROM_type & 4) { /* Trainer */ + trainerpoo = (uint8*)FCEU_gmalloc(512); + FCEU_fread(trainerpoo, 512, 1, fp); + } + + ResetCartMapping(); + ResetExState(0, 0); + + SetupCartPRGMapping(0, ROM, ROM_size << 14, 0); + + FCEU_fread(ROM, 0x4000, (round) ? ROM_size : not_round_size, fp); + + if (VROM_size) + FCEU_fread(VROM, 0x2000, VROM_size, fp); + + md5_starts(&md5); + md5_update(&md5, ROM, ROM_size << 14); + + iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14); + + if (VROM_size) { + iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, VROM_size << 13); + md5_update(&md5, VROM, VROM_size << 13); + } + md5_finish(&md5, iNESCart.MD5); + memcpy(&GameInfo->MD5, &iNESCart.MD5, sizeof(iNESCart.MD5)); + + iNESCart.CRC32 = iNESGameCRC32; + + FCEU_printf(" PRG ROM: %3d x 16KiB\n", (round) ? ROM_size: not_round_size); + FCEU_printf(" CHR ROM: %3d x 8KiB\n", head.VROM_size); + FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32); + { + int x; + FCEU_printf(" ROM MD5: 0x"); + for(x=0;x<16;x++) + FCEU_printf("%02x",iNESCart.MD5[x]); + FCEU_printf("\n"); + } + + char* mappername = "Not Listed"; + + for (int mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { + if (bmap[mappertest].number == MapperNo) { + mappername = bmap[mappertest].name; + break; + } + } + + FCEU_printf(" Mapper #: %d\n", MapperNo); + FCEU_printf(" Mapper name: %s\n", mappername); + FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal"); + FCEU_printf(" Battery-backed: %s\n", (head.ROM_type & 2) ? "Yes" : "No"); + FCEU_printf(" Trained: %s\n", (head.ROM_type & 4) ? "Yes" : "No"); + if(iNES2) + { + FCEU_printf(" NES2.0 Extensions\n"); + FCEU_printf(" Sub Mapper #: %d\n", iNESCart.submapper); + FCEU_printf(" Total WRAM size: %d\n", iNESCart.wram_size + iNESCart.battery_wram_size); + FCEU_printf(" Total VRAM size: %d\n", iNESCart.vram_size + iNESCart.battery_vram_size); + if(head.ROM_type & 2) + { + FCEU_printf(" WRAM backked by battery: %d\n", iNESCart.battery_wram_size); + FCEU_printf(" VRAM backed by battery: %d\n", iNESCart.battery_vram_size); + } + } + + SetInput(); + CheckHInfo(); + { + int x; + uint64 partialmd5 = 0; + + for (x = 0; x < 8; x++) { + partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8); + } + + FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring); + } + /* Must remain here because above functions might change value of + VROM_size and free(VROM). + */ + if (VROM_size) + SetupCartCHRMapping(0, VROM, VROM_size * 0x2000, 0); + + if (Mirroring == 2) { + ExtraNTARAM = (uint8*)FCEU_gmalloc(2048); + SetupCartMirroring(4, 1, ExtraNTARAM); + } else if (Mirroring >= 0x10) + SetupCartMirroring(2 + (Mirroring & 1), 1, 0); + else + SetupCartMirroring(Mirroring & 1, (Mirroring & 4) >> 2, 0); + + iNESCart.battery = (head.ROM_type & 2) ? 1 : 0; + iNESCart.mirror = Mirroring; + + if (!iNES_Init(MapperNo)) + FCEU_PrintError("iNES mapper #%d is not supported at all.", MapperNo); + + GameInfo->mappernum = MapperNo; + FCEU_LoadGameSave(&iNESCart); + + strcpy(LoadedRomFName, name); //bbit edited: line added + + // Extract Filename only. Should account for Windows/Unix this way. + if (strrchr(name, '/')) { + name = strrchr(name, '/') + 1; + } else if (strrchr(name, '\\')) { + name = strrchr(name, '\\') + 1; + } + + GameInterface = iNESGI; + FCEU_printf("\n"); + + // since apparently the iNES format doesn't store this information, + // guess if the settings should be PAL or NTSC from the ROM name + // TODO: MD5 check against a list of all known PAL games instead? + if (OverwriteVidMode) { + if (strstr(name, "(E)") || strstr(name, "(e)") + || strstr(name, "(Europe)") || strstr(name, "(PAL)") + || strstr(name, "(F)") || strstr(name, "(f)") + || strstr(name, "(G)") || strstr(name, "(g)") + || strstr(name, "(I)") || strstr(name, "(i)")) + FCEUI_SetVidSystem(1); + else + FCEUI_SetVidSystem(0); + } + return 1; +} + +// bbit edited: the whole function below was added +int iNesSave() { + char name[2048]; + + strcpy(name, LoadedRomFName); + if (strcmp(name + strlen(name) - 4, ".nes") != 0) { //para edit + strcat(name, ".nes"); + } + + return iNesSaveAs(name); +} + +int iNesSaveAs(char* name) +{ + //adelikat: TODO: iNesSave() and this have pretty much the same code, outsource the common code to a single function + //caitsith2: done. iNesSave() now gets filename and calls iNesSaveAs with that filename. + FILE *fp; + + if (GameInfo->type != GIT_CART) return 0; + if (GameInterface != iNESGI) return 0; + + fp = fopen(name, "wb"); + if (!fp) + return 0; + + if (fwrite(&head, 1, 16, fp) != 16) + { + fclose(fp); + return 0; + } + + if (head.ROM_type & 4) + { + /* Trainer */ + fwrite(trainerpoo, 512, 1, fp); + } + + fwrite(ROM, 0x4000, ROM_size, fp); + + if (head.VROM_size) + fwrite(VROM, 0x2000, head.VROM_size, fp); + + fclose(fp); + return 1; +} + +//para edit: added function below +char *iNesShortFName() { + char *ret; + + if (!(ret = strrchr(LoadedRomFName, '\\'))) + { + if (!(ret = strrchr(LoadedRomFName, '/'))) + return 0; + } + return ret + 1; +} + +static int iNES_Init(int num) { + BMAPPINGLocal *tmp = bmap; + + CHRRAMSize = -1; + + if (GameInfo->type == GIT_VSUNI) + AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0); + + while (tmp->init) { + if (num == tmp->number) { + UNIFchrrama = 0; // need here for compatibility with UNIF mapper code + if (!VROM_size) { + if(!iNESCart.ines2) + { + switch (num) { // FIXME, mapper or game data base with the board parameters and ROM/RAM sizes + case 13: CHRRAMSize = 16 * 1024; break; + case 6: + case 29: + case 30: + case 96: CHRRAMSize = 32 * 1024; break; + case 176: CHRRAMSize = 128 * 1024; break; + default: CHRRAMSize = 8 * 1024; break; + } + iNESCart.vram_size = CHRRAMSize; + } + else + { + CHRRAMSize = iNESCart.battery_vram_size + iNESCart.vram_size; + } + if ((VROM = (uint8*)FCEU_dmalloc(CHRRAMSize)) == NULL) return 0; + FCEU_MemoryRand(VROM, CHRRAMSize); + + UNIFchrrama = VROM; + SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); + AddExState(VROM, CHRRAMSize, 0, "CHRR"); + } + if (head.ROM_type & 8) + AddExState(ExtraNTARAM, 2048, 0, "EXNR"); + tmp->init(&iNESCart); + return 1; + } + tmp++; + } + return 0; +} diff --git a/source/fceultra/ines.h b/source/fceultra/ines.h index 1585be0..e3ef254 100644 --- a/source/fceultra/ines.h +++ b/source/fceultra/ines.h @@ -56,7 +56,13 @@ struct iNES_HEADER { uint8 VROM_size; uint8 ROM_type; uint8 ROM_type2; - uint8 reserve[8]; + uint8 ROM_type3; + uint8 Upper_ROM_VROM_size; + uint8 RAM_size; + uint8 VRAM_size; + uint8 TV_system; + uint8 VS_hardware; + uint8 reserved[2]; void cleanup() { @@ -107,6 +113,9 @@ void Mapper23_Init(CartInfo *); void Mapper24_Init(CartInfo *); void Mapper25_Init(CartInfo *); void Mapper26_Init(CartInfo *); +void Mapper28_Init(CartInfo *); +void Mapper29_Init(CartInfo *); +void Mapper31_Init(CartInfo *); void Mapper32_Init(CartInfo *); void Mapper33_Init(CartInfo *); void Mapper34_Init(CartInfo *); @@ -187,6 +196,7 @@ void Mapper154_Init(CartInfo *); void Mapper155_Init(CartInfo *); void Mapper156_Init(CartInfo *); void Mapper157_Init(CartInfo *); +void Mapper159_Init(CartInfo *); void Mapper163_Init(CartInfo *); void Mapper164_Init(CartInfo *); void Mapper165_Init(CartInfo *); diff --git a/source/fceultra/input.cpp b/source/fceultra/input.cpp index 7e94dce..a88ea16 100644 --- a/source/fceultra/input.cpp +++ b/source/fceultra/input.cpp @@ -19,10 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include -#include - #include "types.h" #include "x6502.h" @@ -52,7 +48,12 @@ #include "drivers/win/window.h" #include "drivers/win/ntview.h" #include "drivers/win/taseditor.h" -extern bool Taseditor_rewind_now; + +#include +#include +#include + +extern bool mustRewindNow; #endif // WIN32 //it is easier to declare these input drivers extern here than include a bunch of files @@ -66,6 +67,7 @@ extern INPUTCFC *FCEU_InitArkanoidFC(void); extern INPUTCFC *FCEU_InitSpaceShadow(void); extern INPUTCFC *FCEU_InitFKB(void); extern INPUTCFC *FCEU_InitSuborKB(void); +extern INPUTCFC *FCEU_InitPEC586KB(void); extern INPUTCFC *FCEU_InitHS(void); extern INPUTCFC *FCEU_InitMahjong(void); extern INPUTCFC *FCEU_InitQuizKing(void); @@ -74,10 +76,6 @@ extern INPUTCFC *FCEU_InitFamilyTrainerB(void); extern INPUTCFC *FCEU_InitOekaKids(void); extern INPUTCFC *FCEU_InitTopRider(void); extern INPUTCFC *FCEU_InitBarcodeWorld(void); - -#ifdef GEKKO -extern INPUTCFC *FCEU_InitFamicom3D(void); -#endif //--------------- //global lag variables @@ -91,6 +89,7 @@ extern bool movieSubtitles; static uint8 joy_readbit[2]; uint8 joy[4]={0,0,0,0}; //HACK - should be static but movie needs it static uint8 LastStrobe; +uint8 RawReg4016 = 0; // Joystick strobe (W) bool replaceP2StartWithMicrophone = false; @@ -170,12 +169,13 @@ static DECLFW(B4016) portFC.driver->Strobe(); } LastStrobe=V&0x1; + RawReg4016 = V; } //a main joystick port driver representing the case where nothing is plugged in -static INPUTC DummyJPort={0,0,0,0,0,0}; +static INPUTC DummyJPort={0}; //and an expansion port driver for the same ting -static INPUTCFC DummyPortFC={0,0,0,0,0,0}; +static INPUTCFC DummyPortFC={0}; //--------4 player driver for expansion port-------- @@ -303,7 +303,7 @@ static void StrobeGP(int w) joy_readbit[w]=0; } -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^6 +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ static INPUTC GPC={ReadGP,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP}; @@ -323,8 +323,9 @@ void FCEU_UpdateInput(void) //tell all drivers to poll input and set up their logical states if(!FCEUMOV_Mode(MOVIEMODE_PLAY)) { - for(int port=0;port<2;port++) + for(int port=0;port<2;port++){ joyports[port].driver->Update(port,joyports[port].ptr,joyports[port].attrib); + } portFC.driver->Update(portFC.ptr,portFC.attrib); } @@ -337,8 +338,9 @@ void FCEU_UpdateInput(void) FCEUMOV_AddInputState(); //TODO - should this apply to the movie data? should this be displayed in the input hud? - if(GameInfo->type==GIT_VSUNI) + if(GameInfo->type==GIT_VSUNI){ FCEU_VSUniSwap(&joy[0],&joy[1]); + } } static DECLFR(VSUNIRead0) @@ -375,16 +377,18 @@ void InputScanlineHook(uint8 *bg, uint8 *spr, uint32 linets, int final) portFC.driver->SLHook(bg,spr,linets,final); } +#include //binds JPorts[pad] to the driver specified in JPType[pad] static void SetInputStuff(int port) { switch(joyports[port].type) { case SI_GAMEPAD: - if(GameInfo->type==GIT_VSUNI) + if(GameInfo->type==GIT_VSUNI){ joyports[port].driver = &GPCVS; - else + } else { joyports[port].driver= &GPC; + } break; case SI_ARKANOID: joyports[port].driver=FCEU_InitArkanoid(port); @@ -409,11 +413,7 @@ static void SetInputStuffFC() switch(portFC.type) { case SIFC_NONE: -#ifdef GEKKO - portFC.driver=FCEU_InitFamicom3D(); -#else portFC.driver=&DummyPortFC; -#endif break; case SIFC_ARKANOID: portFC.driver=FCEU_InitArkanoidFC(); @@ -434,6 +434,9 @@ static void SetInputStuffFC() case SIFC_SUBORKB: portFC.driver=FCEU_InitSuborKB(); break; + case SIFC_PEC586KB: + portFC.driver=FCEU_InitPEC586KB(); + break; case SIFC_HYPERSHOT: portFC.driver=FCEU_InitHS(); break; @@ -584,6 +587,9 @@ void FCEUI_VSUniToggleDIP(int w) void FCEUI_VSUniCoin(void) { + if(!FCEU_IsValidUI(FCEUI_INSERT_COIN)) + return; + FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN); } @@ -751,7 +757,7 @@ struct EMUCMDTABLE FCEUI_CommandTable[]= { EMUCMD_FDS_EJECT_INSERT, EMUCMDTYPE_FDS, FCEUI_FDSInsert, 0, 0, "Eject or Insert FDS Disk", EMUCMDFLAG_TASEDITOR }, { EMUCMD_FDS_SIDE_SELECT, EMUCMDTYPE_FDS, FCEUI_FDSSelect, 0, 0, "Switch FDS Disk Side", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_VSUNI_COIN, EMUCMDTYPE_VSUNI, FCEUI_VSUniCoin, 0, 0, "Insert Coin", 0 }, + { EMUCMD_VSUNI_COIN, EMUCMDTYPE_VSUNI, FCEUI_VSUniCoin, 0, 0, "Insert Coin", EMUCMDFLAG_TASEDITOR }, { EMUCMD_VSUNI_TOGGLE_DIP_0, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 0", 0 }, { EMUCMD_VSUNI_TOGGLE_DIP_1, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 1", 0 }, { EMUCMD_VSUNI_TOGGLE_DIP_2, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 2", 0 }, @@ -762,7 +768,7 @@ struct EMUCMDTABLE FCEUI_CommandTable[]= { EMUCMD_VSUNI_TOGGLE_DIP_7, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 7", 0 }, { EMUCMD_VSUNI_TOGGLE_DIP_8, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 8", 0 }, { EMUCMD_VSUNI_TOGGLE_DIP_9, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 9", 0 }, - { EMUCMD_MISC_AUTOSAVE, EMUCMDTYPE_MISC, FCEUI_Autosave, 0, 0, "Load Last Auto-save", 0}, + { EMUCMD_MISC_AUTOSAVE, EMUCMDTYPE_MISC, FCEUI_RewindToLastAutosave, 0, 0, "Load Last Auto-save", 0}, { EMUCMD_MISC_SHOWSTATES, EMUCMDTYPE_MISC, ViewSlots, 0, 0, "View save slots", 0 }, { EMUCMD_MISC_USE_INPUT_PRESET_1, EMUCMDTYPE_MISC, CommandUsePreset, 0, 0, "Use Input Preset 1", EMUCMDFLAG_TASEDITOR }, { EMUCMD_MISC_USE_INPUT_PRESET_2, EMUCMDTYPE_MISC, CommandUsePreset, 0, 0, "Use Input Preset 2", EMUCMDFLAG_TASEDITOR }, @@ -861,7 +867,7 @@ static void CommandSelectSaveSlot(void) if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) { #ifdef WIN32 - Taseditor_EMUCMD(execcmd); + handleEmuCmdByTaseditor(execcmd); #endif } else { @@ -879,7 +885,7 @@ static void CommandStateSave(void) if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) { #ifdef WIN32 - Taseditor_EMUCMD(execcmd); + handleEmuCmdByTaseditor(execcmd); #endif } else { @@ -900,7 +906,7 @@ static void CommandStateLoad(void) if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) { #ifdef WIN32 - Taseditor_EMUCMD(execcmd); + handleEmuCmdByTaseditor(execcmd); #endif } else { @@ -963,8 +969,8 @@ void LagCounterToggle(void) static void LaunchTasEditor(void) { #ifdef WIN32 - extern bool EnterTasEditor(); - EnterTasEditor(); + extern bool enterTASEditor(); + enterTASEditor(); #endif } @@ -1139,7 +1145,7 @@ static void ReloadRom(void) if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) { // load most recent project - Taseditor_EMUCMD(execcmd); + handleEmuCmdByTaseditor(execcmd); } else { // load most recent ROM @@ -1158,6 +1164,9 @@ static void MovieSubtitleToggle(void) static void UndoRedoSavestate(void) { + // FIXME this will always evaluate to true, should this be + // if (*lastSavestateMade...) to check if it holds a string or just + // a '\0'? if (lastSavestateMade && (undoSS || redoSS)) SwapSaveState(); } @@ -1188,13 +1197,13 @@ void ToggleFullscreen() static void TaseditorRewindOn(void) { #ifdef WIN32 - Taseditor_rewind_now = true; + mustRewindNow = true; #endif } static void TaseditorRewindOff(void) { #ifdef WIN32 - Taseditor_rewind_now = false; + mustRewindNow = false; #endif } @@ -1202,6 +1211,6 @@ static void TaseditorCommand(void) { #ifdef WIN32 if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) - Taseditor_EMUCMD(execcmd); + handleEmuCmdByTaseditor(execcmd); #endif } diff --git a/source/fceultra/input.h b/source/fceultra/input.h index ea75e93..3c89509 100644 --- a/source/fceultra/input.h +++ b/source/fceultra/input.h @@ -1,10 +1,11 @@ #ifndef _INPUT_H_ #define _INPUT_H_ -#include #include "git.h" +#include + void LagCounterToggle(void); class MovieRecord; diff --git a/source/fceultra/input/SConscript b/source/fceultra/input/SConscript new file mode 100644 index 0000000..2cb90e4 --- /dev/null +++ b/source/fceultra/input/SConscript @@ -0,0 +1,6 @@ +import glob +source_list = glob.glob('*.cpp') + +for x in range(len(source_list)): + source_list[x] = 'input/' + source_list[x] +Return('source_list') diff --git a/source/fceultra/input/fkb.cpp b/source/fceultra/input/fkb.cpp index 0cb7f11..c6f55bc 100644 --- a/source/fceultra/input/fkb.cpp +++ b/source/fceultra/input/fkb.cpp @@ -21,82 +21,69 @@ #include #include "share.h" #include "fkb.h" -#define AK2(x,y) ( (FKB_##x) | (FKB_##y <<8) ) -#define AK(x) FKB_##x +#define AK(x) FKB_ ## x static uint8 bufit[0x49]; static uint8 ksmode; static uint8 ksindex; - -static uint16 matrix[9][2][4]= +static uint16 matrix[9][2][4] = { -{{AK(F8),AK(RETURN),AK(BRACKETLEFT),AK(BRACKETRIGHT)}, - {AK(KANA),AK(RIGHTSHIFT),AK(BACKSLASH),AK(STOP)}}, -{{AK(F7),AK(AT),AK(COLON),AK(SEMICOLON)}, - {AK(UNDERSCORE),AK(SLASH),AK(MINUS),AK(CARET)}}, -{{AK(F6),AK(O),AK(L),AK(K)}, - {AK(PERIOD),AK(COMMA),AK(P),AK(0)}}, -{{AK(F5),AK(I),AK(U),AK(J)}, - {AK(M),AK(N),AK(9),AK(8)}}, -{{AK(F4),AK(Y),AK(G),AK(H)}, - {AK(B),AK(V),AK(7),AK(6)}}, -{{AK(F3),AK(T),AK(R),AK(D)}, - {AK(F),AK(C),AK(5),AK(4)}}, -{{AK(F2),AK(W),AK(S),AK(A)}, - {AK(X),AK(Z),AK(E),AK(3)}}, -{{AK(F1),AK(ESCAPE),AK(Q),AK(CONTROL)}, - {AK(LEFTSHIFT),AK(GRAPH),AK(1),AK(2)}}, -{{AK(CLEAR),AK(UP),AK(RIGHT),AK(LEFT)}, - {AK(DOWN),AK(SPACE),AK(DELETE),AK(INSERT)}}, + { { AK(F8), AK(RETURN), AK(BRACKETLEFT), AK(BRACKETRIGHT) }, + { AK(KANA), AK(RIGHTSHIFT), AK(BACKSLASH), AK(STOP) } }, + { { AK(F7), AK(AT), AK(COLON), AK(SEMICOLON) }, + { AK(UNDERSCORE), AK(SLASH), AK(MINUS), AK(CARET) } }, + { { AK(F6), AK(O), AK(L), AK(K) }, + { AK(PERIOD), AK(COMMA), AK(P), AK(0) } }, + { { AK(F5), AK(I), AK(U), AK(J) }, + { AK(M), AK(N), AK(9), AK(8) } }, + { { AK(F4), AK(Y), AK(G), AK(H) }, + { AK(B), AK(V), AK(7), AK(6) } }, + { { AK(F3), AK(T), AK(R), AK(D) }, + { AK(F), AK(C), AK(5), AK(4) } }, + { { AK(F2), AK(W), AK(S), AK(A) }, + { AK(X), AK(Z), AK(E), AK(3) } }, + { { AK(F1), AK(ESCAPE), AK(Q), AK(CONTROL) }, + { AK(LEFTSHIFT), AK(GRAPH), AK(1), AK(2) } }, + { { AK(CLEAR), AK(UP), AK(RIGHT), AK(LEFT) }, + { AK(DOWN), AK(SPACE), AK(DELETE), AK(INSERT) } }, }; -static void FKB_Write(uint8 v) -{ - v>>=1; - if(v&2) - { - if((ksmode&1) && !(v&1)) - ksindex=(ksindex+1)%9; - } - ksmode=v; +static void FKB_Write(uint8 v) { + v >>= 1; + if (v & 2) { + if ((ksmode & 1) && !(v & 1)) + ksindex = (ksindex + 1) % 9; + } + ksmode = v; } -static uint8 FKB_Read(int w, uint8 ret) -{ - //printf("$%04x, %d, %d\n",w+0x4016,ksindex,ksmode&1); - if(w) - { - int x; +static uint8 FKB_Read(int w, uint8 ret) { + if (w) { + int x; - ret&=~0x1E; - for(x=0;x<4;x++) - if(bufit[ matrix[ksindex][ksmode&1][x]&0xFF ] || bufit[ matrix[ksindex][ksmode&1][x]>>8]) - { - ret|=1<<(x+1); - } - ret^=0x1E; - } - return(ret); + ret &= ~0x1E; + for (x = 0; x < 4; x++) + if (bufit[ matrix[ksindex][ksmode & 1][x] & 0xFF ] || bufit[ matrix[ksindex][ksmode & 1][x] >> 8]) + ret |= 1 << (x + 1); + ret ^= 0x1E; + } + return(ret); } -static void FKB_Strobe(void) -{ - ksmode=0; - ksindex=0; - //printf("strobe\n"); +static void FKB_Strobe(void) { + ksmode = 0; + ksindex = 0; } -static void FKB_Update(void *data, int arg) -{ - memcpy(bufit+1,data,0x48); +static void FKB_Update(void *data, int arg) { + memcpy(bufit + 1, data, sizeof(bufit) - 1); } -static INPUTCFC FKB={FKB_Read,FKB_Write,FKB_Strobe,FKB_Update,0,0}; +static INPUTCFC FKB = { FKB_Read, FKB_Write, FKB_Strobe, FKB_Update, 0, 0 }; -INPUTCFC *FCEU_InitFKB(void) -{ - memset(bufit,0,sizeof(bufit)); - ksmode=ksindex=0; - return(&FKB); +INPUTCFC *FCEU_InitFKB(void) { + memset(bufit, 0, sizeof(bufit)); + ksmode = ksindex = 0; + return(&FKB); } diff --git a/source/fceultra/input/fkb.h b/source/fceultra/input/fkb.h index b5dcadd..d635d9d 100644 --- a/source/fceultra/input/fkb.h +++ b/source/fceultra/input/fkb.h @@ -1,72 +1,72 @@ -#define FKB_F1 0x01 -#define FKB_F2 0x02 -#define FKB_F3 0x03 -#define FKB_F4 0x04 -#define FKB_F5 0x05 -#define FKB_F6 0x06 -#define FKB_F7 0x07 -#define FKB_F8 0x08 -#define FKB_1 0x09 -#define FKB_2 0x0A -#define FKB_3 0x0B -#define FKB_4 0x0C -#define FKB_5 0x0D -#define FKB_6 0x0E -#define FKB_7 0x0F -#define FKB_8 0x10 -#define FKB_9 0x11 -#define FKB_0 0x12 -#define FKB_MINUS 0x13 -#define FKB_CARET 0x14 -#define FKB_BACKSLASH 0x15 -#define FKB_STOP 0x16 -#define FKB_ESCAPE 0x17 -#define FKB_Q 0x18 -#define FKB_W 0x19 -#define FKB_E 0x1A -#define FKB_R 0x1B -#define FKB_T 0x1C -#define FKB_Y 0x1D -#define FKB_U 0x1E -#define FKB_I 0x1F -#define FKB_O 0x20 -#define FKB_P 0x21 -#define FKB_AT 0x22 -#define FKB_BRACKETLEFT 0x23 -#define FKB_RETURN 0x24 -#define FKB_CONTROL 0x25 -#define FKB_A 0x26 -#define FKB_S 0x27 -#define FKB_D 0x28 -#define FKB_F 0x29 -#define FKB_G 0x2A -#define FKB_H 0x2B -#define FKB_J 0x2C -#define FKB_K 0x2D -#define FKB_L 0x2E -#define FKB_SEMICOLON 0x2F -#define FKB_COLON 0x30 -#define FKB_BRACKETRIGHT 0x31 -#define FKB_KANA 0x32 -#define FKB_LEFTSHIFT 0x33 -#define FKB_Z 0x34 -#define FKB_X 0x35 -#define FKB_C 0x36 -#define FKB_V 0x37 -#define FKB_B 0x38 -#define FKB_N 0x39 -#define FKB_M 0x3A -#define FKB_COMMA 0x3B -#define FKB_PERIOD 0x3C -#define FKB_SLASH 0x3D -#define FKB_UNDERSCORE 0x3E -#define FKB_RIGHTSHIFT 0x3F -#define FKB_GRAPH 0x40 -#define FKB_SPACE 0x41 -#define FKB_CLEAR 0x42 -#define FKB_INSERT 0x43 -#define FKB_DELETE 0x44 -#define FKB_UP 0x45 -#define FKB_LEFT 0x46 -#define FKB_RIGHT 0x47 -#define FKB_DOWN 0x48 +#define FKB_F1 0x01 +#define FKB_F2 0x02 +#define FKB_F3 0x03 +#define FKB_F4 0x04 +#define FKB_F5 0x05 +#define FKB_F6 0x06 +#define FKB_F7 0x07 +#define FKB_F8 0x08 +#define FKB_1 0x09 +#define FKB_2 0x0A +#define FKB_3 0x0B +#define FKB_4 0x0C +#define FKB_5 0x0D +#define FKB_6 0x0E +#define FKB_7 0x0F +#define FKB_8 0x10 +#define FKB_9 0x11 +#define FKB_0 0x12 +#define FKB_MINUS 0x13 +#define FKB_CARET 0x14 +#define FKB_BACKSLASH 0x15 +#define FKB_STOP 0x16 +#define FKB_ESCAPE 0x17 +#define FKB_Q 0x18 +#define FKB_W 0x19 +#define FKB_E 0x1A +#define FKB_R 0x1B +#define FKB_T 0x1C +#define FKB_Y 0x1D +#define FKB_U 0x1E +#define FKB_I 0x1F +#define FKB_O 0x20 +#define FKB_P 0x21 +#define FKB_AT 0x22 +#define FKB_BRACKETLEFT 0x23 +#define FKB_RETURN 0x24 +#define FKB_CONTROL 0x25 +#define FKB_A 0x26 +#define FKB_S 0x27 +#define FKB_D 0x28 +#define FKB_F 0x29 +#define FKB_G 0x2A +#define FKB_H 0x2B +#define FKB_J 0x2C +#define FKB_K 0x2D +#define FKB_L 0x2E +#define FKB_SEMICOLON 0x2F +#define FKB_COLON 0x30 +#define FKB_BRACKETRIGHT 0x31 +#define FKB_KANA 0x32 +#define FKB_LEFTSHIFT 0x33 +#define FKB_Z 0x34 +#define FKB_X 0x35 +#define FKB_C 0x36 +#define FKB_V 0x37 +#define FKB_B 0x38 +#define FKB_N 0x39 +#define FKB_M 0x3A +#define FKB_COMMA 0x3B +#define FKB_PERIOD 0x3C +#define FKB_SLASH 0x3D +#define FKB_UNDERSCORE 0x3E +#define FKB_RIGHTSHIFT 0x3F +#define FKB_GRAPH 0x40 +#define FKB_SPACE 0x41 +#define FKB_CLEAR 0x42 +#define FKB_INSERT 0x43 +#define FKB_DELETE 0x44 +#define FKB_UP 0x45 +#define FKB_LEFT 0x46 +#define FKB_RIGHT 0x47 +#define FKB_DOWN 0x48 diff --git a/source/fceultra/input/pec586kb.cpp b/source/fceultra/input/pec586kb.cpp new file mode 100644 index 0000000..bdc00c6 --- /dev/null +++ b/source/fceultra/input/pec586kb.cpp @@ -0,0 +1,96 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "share.h" +#include "suborkb.h" + +#define AK(x) FKB_ ## x + +static uint8 bufit[0x66]; +static uint8 kspos, kstrobe; +static uint8 ksindex; + +//TODO: check all keys, some of the are wrong + +static uint16 matrix[13][8] = +{ + { AK(ESCAPE),AK(SPACE),AK(LMENU),AK(LCONTROL),AK(LSHIFT),AK(GRAVE),AK(TAB),AK(CAPITAL) }, + { AK(F6),AK(F7),AK(F5),AK(F4),AK(F8),AK(F2),AK(F1),AK(F3) }, + { AK(EQUALS), AK(NUMPAD0),AK(PERIOD),AK(A),AK(RETURN),AK(1),AK(Q),AK(Z) }, + { 0, AK(NUMPAD3),AK(NUMPAD6),AK(S),AK(NUMPAD9),AK(2),AK(W),AK(X) }, + { AK(SLASH), AK(NUMPAD2),AK(NUMPAD5),AK(D),AK(NUMPAD8),AK(3),AK(E),AK(C) }, + { AK(BREAK), AK(NUMPAD1),AK(NUMPAD4),AK(F),AK(NUMPAD7),AK(4),AK(R),AK(V) }, + { AK(BACK),AK(BACKSLASH),AK(GRETURN),AK(G),AK(RBRACKET),AK(5),AK(T),AK(B) }, + { AK(9),AK(PERIOD),AK(L),AK(K),AK(O),AK(8),AK(I),AK(COMMA) }, + { AK(0),AK(SLASH),AK(SEMICOLON),AK(J),AK(P),AK(7),AK(U),AK(M) }, + { AK(MINUS),AK(MINUS),AK(APOSTROPHE),AK(H),AK(LBRACKET),AK(6),AK(Y),AK(N) }, + { AK(F11),AK(F12),AK(F10),0,AK(MINUS),AK(F9),0,0 }, + { AK(UP),AK(RIGHT),AK(DOWN),AK(DIVIDE),AK(LEFT),AK(MULTIPLY),AK(SUBTRACT),AK(ADD) }, + { AK(INSERT),AK(NUMPAD1),AK(HOME),AK(PRIOR),AK(DELETE),AK(END),AK(NEXT),AK(NUMLOCK) }, +}; + +static void PEC586KB_Write(uint8 v) { + if (!(kstrobe & 2) && (v & 2)) { + kspos = 0; + } + if ((kstrobe & 1) && !(v & 1)) { + ksindex = 0; + } + if ((kstrobe & 4) && !(v & 4)) { + kspos++; + kspos %= 13; + } + kstrobe = v; +} + +static uint8 PEC586KB_Read(int w, uint8 ret) { +#ifdef FCEUDEF_DEBUGGER + if (!fceuindbg) { +#endif + if (w) { + ret &= ~2; + if(bufit[matrix[kspos][7-ksindex]]) + ret |= 2; + ksindex++; + ksindex&=7; + } +#ifdef FCEUDEF_DEBUGGER + } +#endif + return(ret); +} + +static void PEC586KB_Strobe(void) { +// kstrobe = 0; +// ksindex = 0; +} + +static void PEC586KB_Update(void *data, int arg) { + memcpy(bufit + 1, data, sizeof(bufit) - 1); +} + +static INPUTCFC PEC586KB = { PEC586KB_Read, PEC586KB_Write, PEC586KB_Strobe, PEC586KB_Update, 0, 0 }; + +INPUTCFC *FCEU_InitPEC586KB(void) { + memset(bufit, 0, sizeof(bufit)); + kspos = ksindex = kstrobe = 0; + return(&PEC586KB); +} diff --git a/source/fceultra/input/suborkb.cpp b/source/fceultra/input/suborkb.cpp index 41595c2..5e54a37 100644 --- a/source/fceultra/input/suborkb.cpp +++ b/source/fceultra/input/suborkb.cpp @@ -1,94 +1,84 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include #include "share.h" #include "suborkb.h" -#define AK2(x,y) ( (FKB_##x) | (FKB_##y <<8) ) -#define AK(x) FKB_##x +#define AK(x) FKB_ ## x -static uint8 bufit[0x61]; +static uint8 bufit[0x66]; static uint8 ksmode; static uint8 ksindex; - -static uint16 matrix[13][2][4]= +static uint16 matrix[13][2][4] = { -{{AK(4),AK(G),AK(F),AK(C)}, - {AK(F2),AK(E),AK(5),AK(V)}}, -{{AK(2),AK(D),AK(S),AK(END)}, - {AK(F1),AK(W),AK(3),AK(X)}}, -{{AK(INSERT),AK(BACK),AK(NEXT),AK(RIGHT)}, - {AK(F8),AK(PRIOR),AK(DELETE),AK(HOME)}}, -{{AK(9),AK(I),AK(L),AK(COMMA)}, - {AK(F5),AK(O),AK(0),AK(PERIOD)}}, -{{AK(RBRACKET),AK(RETURN),AK(UP),AK(LEFT)}, - {AK(F7),AK(LBRACKET),AK(BACKSLASH),AK(DOWN)}}, -{{AK(Q),AK(CAPITAL),AK(Z),AK(TAB)}, - {AK(ESCAPE),AK(A),AK(1),AK(LCONTROL)}}, -{{AK(7),AK(Y),AK(K),AK(M)}, - {AK(F4),AK(U),AK(8),AK(J)}}, -{{AK(MINUS),AK(SEMICOLON),AK(APOSTROPHE),AK(SLASH)}, - {AK(F6),AK(P),AK(EQUALS),AK(LSHIFT)}}, -{{AK(T),AK(H),AK(N),AK(SPACE)}, - {AK(F3),AK(R),AK(6),AK(B)}}, -{{0,0,0,0}, - {0,0,0,0}}, -{{AK(LMENU),AK(NUMPAD4),AK(NUMPAD7),AK(F11)}, - {AK(F12),AK(NUMPAD1),AK(NUMPAD2),AK(NUMPAD8)}}, -{{AK(SUBTRACT),AK(ADD),AK(MULTIPLY),AK(NUMPAD9)}, - {AK(F10),AK(NUMPAD5),AK(DIVIDE),AK(NUMLOCK)}}, -{{AK(GRAVE),AK(NUMPAD6),AK(PAUSE),AK(SPACE)}, - {AK(F9),AK(NUMPAD3),AK(DECIMAL),AK(NUMPAD0)}}, + { { AK(4), AK(G), AK(F), AK(C) }, { AK(F2), AK(E), AK(5), AK(V) } }, + { { AK(2), AK(D), AK(S), AK(END) }, { AK(F1), AK(W), AK(3), AK(X) } }, + { { AK(INSERT), AK(BACK), AK(NEXT), AK(RIGHT) }, { AK(F8), AK(PRIOR), AK(DELETE), AK(HOME) } }, + { { AK(9), AK(I), AK(L), AK(COMMA) }, { AK(F5), AK(O), AK(0), AK(PERIOD) } }, + { { AK(RBRACKET), AK(RETURN), AK(UP), AK(LEFT) }, { AK(F7), AK(LBRACKET), AK(BACKSLASH), AK(DOWN) } }, + { { AK(Q), AK(CAPITAL), AK(Z), AK(TAB) }, { AK(ESCAPE), AK(A), AK(1), AK(LCONTROL) } }, + { { AK(7), AK(Y), AK(K), AK(M) }, { AK(F4), AK(U), AK(8), AK(J) } }, + { { AK(MINUS), AK(SEMICOLON), AK(APOSTROPHE), AK(SLASH) }, { AK(F6), AK(P), AK(EQUALS), AK(LSHIFT) } }, + { { AK(T), AK(H), AK(N), AK(SPACE) }, { AK(F3), AK(R), AK(6), AK(B) } }, + { { AK(NUMPAD6), AK(GRETURN), AK(NUMPAD4), AK(NUMPAD8) }, { AK(NUMPAD2), 0, 0, 0 } }, // baibaidino actually uses diferent layot + { { AK(LMENU), AK(NUMPAD4), AK(NUMPAD7), AK(F11) }, { AK(F12), AK(NUMPAD1), AK(NUMPAD2), AK(NUMPAD8) } }, + { { AK(SUBTRACT), AK(ADD), AK(MULTIPLY), AK(NUMPAD9) }, { AK(F10), AK(NUMPAD5), AK(DIVIDE), AK(NUMLOCK) } }, + { { AK(GRAVE), AK(NUMPAD6), AK(PAUSE), AK(SPACE) }, { AK(F9), AK(NUMPAD3), AK(DECIMAL), AK(NUMPAD0) } }, }; -static void SuborKB_Write(uint8 v) -{ - v>>=1; - if(v&2) - { - if((ksmode&1) && !(v&1)) - ksindex=(ksindex+1)%13; - } - ksmode=v; +static void SuborKB_Write(uint8 v) { + v >>= 1; + if (v & 2) { + if ((ksmode & 1) && !(v & 1)) + ksindex = (ksindex + 1) % 13; + } + ksmode = v; } -static uint8 SuborKB_Read(int w, uint8 ret) -{ - if(w) - { - int x; +static uint8 SuborKB_Read(int w, uint8 ret) { + if (w) { + int x; - ret&=~0x1E; -// if(ksindex==9) -// { -// if(ksmode&1) -// ret|=2; -// } -// else -// { - for(x=0;x<4;x++) - if(bufit[matrix[ksindex][ksmode&1][x]&0xFF]||bufit[matrix[ksindex][ksmode&1][x]>>8]) - ret|=1<<(x+1); -// } - ret^=0x1E; - } - return(ret); + ret &= ~0x1E; + for (x = 0; x < 4; x++) + if (bufit[matrix[ksindex][ksmode & 1][x]]) + ret |= 1 << (x + 1); + ret ^= 0x1E; + } + return(ret); } -static void SuborKB_Strobe(void) -{ - ksmode=0; - ksindex=0; +static void SuborKB_Strobe(void) { + ksmode = 0; + ksindex = 0; } -static void SuborKB_Update(void *data, int arg) -{ - memcpy(bufit+1,data,0x60); +static void SuborKB_Update(void *data, int arg) { + memcpy(bufit + 1, data, sizeof(bufit) - 1); } -static INPUTCFC SuborKB={SuborKB_Read,SuborKB_Write,SuborKB_Strobe,SuborKB_Update,0,0}; +static INPUTCFC SuborKB = { SuborKB_Read, SuborKB_Write, SuborKB_Strobe, SuborKB_Update, 0, 0 }; -INPUTCFC *FCEU_InitSuborKB(void) -{ - memset(bufit,0,sizeof(bufit)); - ksmode=ksindex=0; - return(&SuborKB); +INPUTCFC *FCEU_InitSuborKB(void) { + memset(bufit, 0, sizeof(bufit)); + ksmode = ksindex = 0; + return(&SuborKB); } diff --git a/source/fceultra/input/suborkb.h b/source/fceultra/input/suborkb.h index 735f820..db01bd4 100644 --- a/source/fceultra/input/suborkb.h +++ b/source/fceultra/input/suborkb.h @@ -1,96 +1,102 @@ -#define FKB_ESCAPE 0x01 -#define FKB_F1 0x02 -#define FKB_F2 0x03 -#define FKB_F3 0x04 -#define FKB_F4 0x05 -#define FKB_F5 0x06 -#define FKB_F6 0x07 -#define FKB_F7 0x08 -#define FKB_F8 0x09 -#define FKB_F9 0x0A -#define FKB_F10 0x0B -#define FKB_F11 0x0C -#define FKB_F12 0x0D -#define FKB_PAUSE 0x0E -#define FKB_GRAVE 0x0F -#define FKB_1 0x10 -#define FKB_2 0x11 -#define FKB_3 0x12 -#define FKB_4 0x13 -#define FKB_5 0x14 -#define FKB_6 0x15 -#define FKB_7 0x16 -#define FKB_8 0x17 -#define FKB_9 0x18 -#define FKB_0 0x19 -#define FKB_MINUS 0x1A -#define FKB_EQUALS 0x1B -#define FKB_BACK 0x1C -#define FKB_INSERT 0x1D -#define FKB_HOME 0x1E -#define FKB_PRIOR 0x1F -#define FKB_NUMLOCK 0x20 -#define FKB_DIVIDE 0x21 -#define FKB_MULTIPLY 0x22 -#define FKB_SUBTRACT 0x23 -#define FKB_TAB 0x24 -#define FKB_Q 0x25 -#define FKB_W 0x26 -#define FKB_E 0x27 -#define FKB_R 0x28 -#define FKB_T 0x29 -#define FKB_Y 0x2A -#define FKB_U 0x2B -#define FKB_I 0x2C -#define FKB_O 0x2D -#define FKB_P 0x2E -#define FKB_LBRACKET 0x2F -#define FKB_RBRACKET 0x30 -#define FKB_RETURN 0x31 -#define FKB_DELETE 0x32 -#define FKB_END 0x33 -#define FKB_NEXT 0x34 -#define FKB_NUMPAD7 0x35 -#define FKB_NUMPAD8 0x36 -#define FKB_NUMPAD9 0x37 -#define FKB_ADD 0x38 -#define FKB_CAPITAL 0x39 -#define FKB_A 0x3A -#define FKB_S 0x3B -#define FKB_D 0x3C -#define FKB_F 0x3D -#define FKB_G 0x3E -#define FKB_H 0x3F -#define FKB_J 0x40 -#define FKB_K 0x41 -#define FKB_L 0x42 -#define FKB_SEMICOLON 0x43 -#define FKB_APOSTROPHE 0x44 -#define FKB_NUMPAD4 0x45 -#define FKB_NUMPAD5 0x46 -#define FKB_NUMPAD6 0x47 -#define FKB_LSHIFT 0x48 -#define FKB_Z 0x49 -#define FKB_X 0x4A -#define FKB_C 0x4B -#define FKB_V 0x4C -#define FKB_B 0x4D -#define FKB_N 0x4E -#define FKB_M 0x4F -#define FKB_COMMA 0x50 -#define FKB_PERIOD 0x51 -#define FKB_SLASH 0x52 -#define FKB_BACKSLASH 0x53 -#define FKB_UP 0x54 -#define FKB_NUMPAD1 0x55 -#define FKB_NUMPAD2 0x56 -#define FKB_NUMPAD3 0x57 -#define FKB_LCONTROL 0x58 -#define FKB_LMENU 0x59 -#define FKB_SPACE 0x5A -#define FKB_LEFT 0x5B -#define FKB_DOWN 0x5C -#define FKB_RIGHT 0x5D -#define FKB_NUMPAD0 0x5E -#define FKB_DECIMAL 0x5F +#define FKB_ESCAPE 0x01 +#define FKB_F1 0x02 +#define FKB_F2 0x03 +#define FKB_F3 0x04 +#define FKB_F4 0x05 +#define FKB_F5 0x06 +#define FKB_F6 0x07 +#define FKB_F7 0x08 +#define FKB_F8 0x09 +#define FKB_F9 0x0A +#define FKB_F10 0x0B +#define FKB_F11 0x0C +#define FKB_F12 0x0D +#define FKB_PAUSE 0x0E +#define FKB_GRAVE 0x0F +#define FKB_1 0x10 +#define FKB_2 0x11 +#define FKB_3 0x12 +#define FKB_4 0x13 +#define FKB_5 0x14 +#define FKB_6 0x15 +#define FKB_7 0x16 +#define FKB_8 0x17 +#define FKB_9 0x18 +#define FKB_0 0x19 +#define FKB_MINUS 0x1A +#define FKB_EQUALS 0x1B +#define FKB_BACK 0x1C +#define FKB_INSERT 0x1D +#define FKB_HOME 0x1E +#define FKB_PRIOR 0x1F +#define FKB_NUMLOCK 0x20 +#define FKB_DIVIDE 0x21 +#define FKB_MULTIPLY 0x22 +#define FKB_SUBTRACT 0x23 +#define FKB_TAB 0x24 +#define FKB_Q 0x25 +#define FKB_W 0x26 +#define FKB_E 0x27 +#define FKB_R 0x28 +#define FKB_T 0x29 +#define FKB_Y 0x2A +#define FKB_U 0x2B +#define FKB_I 0x2C +#define FKB_O 0x2D +#define FKB_P 0x2E +#define FKB_LBRACKET 0x2F +#define FKB_RBRACKET 0x30 +#define FKB_RETURN 0x31 +#define FKB_DELETE 0x32 +#define FKB_END 0x33 +#define FKB_NEXT 0x34 +#define FKB_NUMPAD7 0x35 +#define FKB_NUMPAD8 0x36 +#define FKB_NUMPAD9 0x37 +#define FKB_ADD 0x38 +#define FKB_CAPITAL 0x39 +#define FKB_A 0x3A +#define FKB_S 0x3B +#define FKB_D 0x3C +#define FKB_F 0x3D +#define FKB_G 0x3E +#define FKB_H 0x3F +#define FKB_J 0x40 +#define FKB_K 0x41 +#define FKB_L 0x42 +#define FKB_SEMICOLON 0x43 +#define FKB_APOSTROPHE 0x44 +#define FKB_NUMPAD4 0x45 +#define FKB_NUMPAD5 0x46 +#define FKB_NUMPAD6 0x47 +#define FKB_LSHIFT 0x48 +#define FKB_Z 0x49 +#define FKB_X 0x4A +#define FKB_C 0x4B +#define FKB_V 0x4C +#define FKB_B 0x4D +#define FKB_N 0x4E +#define FKB_M 0x4F +#define FKB_COMMA 0x50 +#define FKB_PERIOD 0x51 +#define FKB_SLASH 0x52 +#define FKB_BACKSLASH 0x53 +#define FKB_UP 0x54 +#define FKB_NUMPAD1 0x55 +#define FKB_NUMPAD2 0x56 +#define FKB_NUMPAD3 0x57 +#define FKB_LCONTROL 0x58 +#define FKB_LMENU 0x59 +#define FKB_SPACE 0x5A +#define FKB_LEFT 0x5B +#define FKB_DOWN 0x5C +#define FKB_RIGHT 0x5D +#define FKB_NUMPAD0 0x5E +#define FKB_DECIMAL 0x5F +#define FKB_RSHIFT 0x60 +#define FKB_RMENU 0x61 +#define FKB_RCONTROL 0x62 +#define FKB_BREAK 0x63 +#define FKB_RESET 0x64 +#define FKB_GRETURN 0x65 diff --git a/source/fceultra/input/zapper.cpp b/source/fceultra/input/zapper.cpp index b95a73b..6635b0f 100644 --- a/source/fceultra/input/zapper.cpp +++ b/source/fceultra/input/zapper.cpp @@ -76,19 +76,18 @@ static void ZapperFrapper(int w, uint8 *bg, uint8 *spr, uint32 linets, int final } endo: ZD[w].zappo=final; - -#ifndef GEKKO - //if this was a miss, clear out the hit + + //if this was a miss, clear out the hit if(ZD[w].mzb&2) ZD[w].zaphit=0; -#endif + } static INLINE int CheckColor(int w) { FCEUPPU_LineUpdate(); - - if(newppu) + + if(newppu) { int x = (int)ZD[w].mzx; int y = (int)ZD[w].mzy; @@ -117,15 +116,10 @@ static INLINE int CheckColor(int w) } -#ifdef GEKKO - if((ZD[w].zaphit+100)>=(timestampbase+timestamp) - && !(ZD[w].mzb&2)) return 0; -#else if((ZD[w].zaphit+100)>=(timestampbase+timestamp)) { return 0; } -#endif return 1; } @@ -174,16 +168,7 @@ static void DrawZapper(int w, uint8 *buf, int arg) static void UpdateZapper(int w, void *data, int arg) { uint32 *ptr=(uint32 *)data; -#ifdef GEKKO - if(ZD[w].bogo) - ZD[w].bogo--; - if(ptr[2]&3 && (!(ZD[w].mzb&3))) - ZD[w].bogo=5; - ZD[w].mzx=ptr[0]; - ZD[w].mzy=ptr[1]; - ZD[w].mzb=ptr[2]; -#else bool newclicked = (ptr[2]&3)!=0; bool oldclicked = (ZD[w].lastInput)!=0; @@ -202,7 +187,7 @@ static void UpdateZapper(int w, void *data, int arg) ZD[w].mzx=ptr[0]; ZD[w].mzy=ptr[1]; } -#endif + } static void LogZapper(int w, MovieRecord* mr) diff --git a/source/fceultra/lua-engine.cpp b/source/fceultra/lua-engine.cpp new file mode 100644 index 0000000..ae86af1 --- /dev/null +++ b/source/fceultra/lua-engine.cpp @@ -0,0 +1,6025 @@ +#if 0 +#ifdef __linux +#include +#define SetCurrentDir chdir +#include +#include +#endif + +#ifdef WIN32 +#include +#define SetCurrentDir _chdir +#endif + +#include "types.h" +#include "fceu.h" +#include "video.h" +#include "debug.h" +#include "sound.h" +#include "drawing.h" +#include "state.h" +#include "movie.h" +#include "driver.h" +#include "cheat.h" +#include "x6502.h" +#include "utils/xstring.h" +#include "utils/memory.h" +#include "fceulua.h" + +#ifdef WIN32 +#include "drivers/win/common.h" +#include "drivers/win/taseditor/selection.h" +#include "drivers/win/taseditor/laglog.h" +#include "drivers/win/taseditor/markers.h" +#include "drivers/win/taseditor/snapshot.h" +#include "drivers/win/taseditor/taseditor_lua.h" +extern TASEDITOR_LUA taseditor_lua; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "x6502abbrev.h" + +bool CheckLua() +{ +#ifdef WIN32 + HMODULE mod = LoadLibrary("lua51.dll"); + if(!mod) + { + return false; + } + FreeLibrary(mod); + return true; +#else + return true; +#endif +} + +bool DemandLua() +{ +#ifdef WIN32 + if(!CheckLua()) + { + MessageBox(NULL, "lua51.dll was not found. Please get it into your PATH or in the same directory as fceux.exe", "FCEUX", MB_OK | MB_ICONERROR); + return false; + } + return true; +#else + return true; +#endif +} + +extern "C" +{ +#include +#include +#include +#ifdef WIN32 +#include + int iuplua_open(lua_State * L); + int iupcontrolslua_open(lua_State * L); + int luaopen_winapi(lua_State * L); + + //luasocket + int luaopen_socket_core(lua_State *L); + int luaopen_mime_core(lua_State *L); +#endif +} + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifndef _MSC_VER + #define stricmp strcasecmp + #define strnicmp strncasecmp + + #ifdef __GNUC__ + #define __forceinline __attribute__ ((always_inline)) + #else + #define __forceinline + #endif +#endif + +#ifdef WIN32 +extern void AddRecentLuaFile(const char *filename); +#endif + +extern bool turbo; +extern int32 fps_scale; + +struct LuaSaveState { + std::string filename; + EMUFILE_MEMORY *data; + bool anonymous, persisted; + LuaSaveState() + : data(0) + , anonymous(false) + , persisted(false) + {} + ~LuaSaveState() { + if(data) delete data; + } + void persist() { + persisted = true; + FILE* outf = fopen(filename.c_str(),"wb"); + fwrite(data->buf(),1,data->size(),outf); + fclose(outf); + } + void ensureLoad() { + if(data) return; + persisted = true; + FILE* inf = fopen(filename.c_str(),"rb"); + fseek(inf,0,SEEK_END); + int len = ftell(inf); + fseek(inf,0,SEEK_SET); + data = new EMUFILE_MEMORY(len); + fread(data->buf(),1,len,inf); + fclose(inf); + } +}; + +static void(*info_print)(int uid, const char* str); +static void(*info_onstart)(int uid); +static void(*info_onstop)(int uid); +static int info_uid; +#ifdef WIN32 +extern HWND LuaConsoleHWnd; +extern INT_PTR CALLBACK DlgLuaScriptDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); +extern void PrintToWindowConsole(int hDlgAsInt, const char* str); +extern void WinLuaOnStart(int hDlgAsInt); +extern void WinLuaOnStop(int hDlgAsInt); +void TaseditorDisableManualFunctionIfNeeded(); +#endif + +static lua_State *L; + +static int luaexiterrorcount = 8; + +// Are we running any code right now? +static char *luaScriptName = NULL; + +// Are we running any code right now? +int luaRunning = FALSE; + +// True at the frame boundary, false otherwise. +static int frameBoundary = FALSE; + +// The execution speed we're running at. +static enum {SPEED_NORMAL, SPEED_NOTHROTTLE, SPEED_TURBO, SPEED_MAXIMUM} speedmode = SPEED_NORMAL; + +// Rerecord count skip mode +static int skipRerecords = FALSE; + +// Used by the registry to find our functions +static const char *frameAdvanceThread = "FCEU.FrameAdvance"; +static const char *guiCallbackTable = "FCEU.GUI"; + +// True if there's a thread waiting to run after a run of frame-advance. +static int frameAdvanceWaiting = FALSE; + +// We save our pause status in the case of a natural death. +static int wasPaused = FALSE; + +// Transparency strength. 255=opaque, 0=so transparent it's invisible +static int transparencyModifier = 255; + +// Our joypads. +static uint8 luajoypads1[4]= { 0xFF, 0xFF, 0xFF, 0xFF }; //x1 +static uint8 luajoypads2[4]= { 0x00, 0x00, 0x00, 0x00 }; //0x +/* Crazy logic stuff. + 11 - true 01 - pass-through (default) + 00 - false 10 - invert */ + +static enum { GUI_USED_SINCE_LAST_DISPLAY, GUI_USED_SINCE_LAST_FRAME, GUI_CLEAR } gui_used = GUI_CLEAR; +static uint8 *gui_data = NULL; +static int gui_saw_current_palette = FALSE; + +// Protects Lua calls from going nuts. +// We set this to a big number like 1000 and decrement it +// over time. The script gets knifed once this reaches zero. +static int numTries; + +// number of registered memory functions (1 per hooked byte) +static unsigned int numMemHooks; + +// Look in fceu.h for macros named like JOY_UP to determine the order. +static const char *button_mappings[] = { + "A", "B", "select", "start", "up", "down", "left", "right" +}; + +#ifdef _MSC_VER + #define snprintf _snprintf + #define vscprintf _vscprintf +#else + #define stricmp strcasecmp + #define strnicmp strncasecmp +#endif + +static const char* luaCallIDStrings [] = +{ + "CALL_BEFOREEMULATION", + "CALL_AFTEREMULATION", + "CALL_BEFOREEXIT", + "CALL_BEFORESAVE", + "CALL_AFTERLOAD", + "CALL_TASEDITOR_AUTO", + "CALL_TASEDITOR_MANUAL", + +}; + +//make sure we have the right number of strings +CTASSERT(sizeof(luaCallIDStrings)/sizeof(*luaCallIDStrings) == LUACALL_COUNT) + +static const char* luaMemHookTypeStrings [] = +{ + "MEMHOOK_WRITE", + "MEMHOOK_READ", + "MEMHOOK_EXEC", + + "MEMHOOK_WRITE_SUB", + "MEMHOOK_READ_SUB", + "MEMHOOK_EXEC_SUB", +}; + +//make sure we have the right number of strings +CTASSERT(sizeof(luaMemHookTypeStrings)/sizeof(*luaMemHookTypeStrings) == LUAMEMHOOK_COUNT) + +static char* rawToCString(lua_State* L, int idx=0); +static const char* toCString(lua_State* L, int idx=0); + +/** + * Resets emulator speed / pause states after script exit. + */ +static void FCEU_LuaOnStop() +{ + luaRunning = FALSE; + for (int i = 0 ; i < 4 ; i++ ){ + luajoypads1[i]= 0xFF; // Set these back to pass-through + luajoypads2[i]= 0x00; + } + gui_used = GUI_CLEAR; + //if (wasPaused && !FCEUI_EmulationPaused()) + // FCEUI_ToggleEmulationPause(); + + //zero 21-nov-2014 - this variable doesnt exist outside windows so it cant have this feature + #ifdef _MSC_VER + if (fps_scale != 256) //thanks, we already know it's on normal speed + FCEUD_SetEmulationSpeed(EMUSPEED_NORMAL); //TODO: Ideally lua returns the speed to the speed the user set before running the script + //rather than returning it to normal, and turbo off. Perhaps some flags and a FCEUD_GetEmulationSpeed function + #endif + + turbo = false; + //FCEUD_TurboOff(); +#ifdef WIN32 + TaseditorDisableManualFunctionIfNeeded(); +#endif +} + + +/** + * Asks Lua if it wants control of the emulator's speed. + * Returns 0 if no, 1 if yes. If yes, caller should also + * consult FCEU_LuaFrameSkip(). + */ +int FCEU_LuaSpeed() { + if (!L || !luaRunning) + return 0; + + //printf("%d\n", speedmode); + + switch (speedmode) { + case SPEED_NOTHROTTLE: + case SPEED_TURBO: + case SPEED_MAXIMUM: + return 1; + case SPEED_NORMAL: + default: + return 0; + } +} + +/** + * Asks Lua if it wants control whether this frame is skipped. + * Returns 0 if no, 1 if frame should be skipped, -1 if it should not be. + */ +int FCEU_LuaFrameSkip() { + if (!L || !luaRunning) + return 0; + + switch (speedmode) { + case SPEED_NORMAL: + return 0; + case SPEED_NOTHROTTLE: + return -1; + case SPEED_TURBO: + return 0; + case SPEED_MAXIMUM: + return 1; + } + return 0; +} + +/** + * Toggle certain rendering planes + * emu.setrenderingplanes(sprites, background) + * Accepts two (lua) boolean values and acts accordingly +*/ +static int emu_setrenderplanes(lua_State *L) { + bool sprites = (lua_toboolean( L, 1 ) == 1); + bool background = (lua_toboolean( L, 2 ) == 1); + FCEUI_SetRenderPlanes(sprites, background); + return 0; +} + +/////////////////////////// + + + +// emu.speedmode(string mode) +// +// Takes control of the emulation speed +// of the system. Normal is normal speed (60fps, 50 for PAL), +// nothrottle disables speed control but renders every frame, +// turbo renders only a few frames in order to speed up emulation, +// maximum renders no frames +// TODO: better enforcement, done in the same way as basicbot... +static int emu_speedmode(lua_State *L) { + const char *mode = luaL_checkstring(L,1); + + if (strcasecmp(mode, "normal")==0) { + speedmode = SPEED_NORMAL; + } else if (strcasecmp(mode, "nothrottle")==0) { + speedmode = SPEED_NOTHROTTLE; + } else if (strcasecmp(mode, "turbo")==0) { + speedmode = SPEED_TURBO; + } else if (strcasecmp(mode, "maximum")==0) { + speedmode = SPEED_MAXIMUM; + } else + luaL_error(L, "Invalid mode %s to emu.speedmode",mode); + + //printf("new speed mode: %d\n", speedmode); + if (speedmode == SPEED_NORMAL) + { + FCEUD_SetEmulationSpeed(EMUSPEED_NORMAL); + FCEUD_TurboOff(); + } + else if (speedmode == SPEED_TURBO) //adelikat: Making turbo actually use turbo. + FCEUD_TurboOn(); //Turbo and max speed are two different results. Turbo employs frame skipping and sound bypassing if mute turbo option is enabled. + //This makes it faster but with frame skipping. Therefore, maximum is still a useful feature, in case the user is recording an avi or making screenshots (or something else that needs all frames) + else + FCEUD_SetEmulationSpeed(EMUSPEED_FASTEST); //TODO: Make nothrottle turn off throttle, or remove the option + return 0; +} + +// emu.poweron() +// +// Executes a power cycle +static int emu_poweron(lua_State *L) { + if (GameInfo) + FCEUI_PowerNES(); + + return 0; +} + +// emu.softreset() +// +// Executes a power cycle +static int emu_softreset(lua_State *L) { + if (GameInfo) + FCEUI_ResetNES(); + + return 0; +} + +// emu.frameadvance() +// +// Executes a frame advance. Occurs by yielding the coroutine, then re-running +// when we break out. +static int emu_frameadvance(lua_State *L) { + // We're going to sleep for a frame-advance. Take notes. + + if (frameAdvanceWaiting) + return luaL_error(L, "can't call emu.frameadvance() from here"); + + frameAdvanceWaiting = TRUE; + + // Now we can yield to the main + return lua_yield(L, 0); + + + // It's actually rather disappointing... +} + +// bool emu.paused() +static int emu_paused(lua_State *L) +{ + lua_pushboolean(L, FCEUI_EmulationPaused() != 0); + return 1; +} + +// emu.pause() +// +// Pauses the emulator. Returns immediately. +static int emu_pause(lua_State *L) +{ + if (!FCEUI_EmulationPaused()) + FCEUI_ToggleEmulationPause(); + return 0; +} + +//emu.unpause() +// +// Unpauses the emulator. Returns immediately. +static int emu_unpause(lua_State *L) +{ + if (FCEUI_EmulationPaused()) + FCEUI_ToggleEmulationPause(); + return 0; +} + + +// emu.message(string msg) +// +// Displays the given message on the screen. +static int emu_message(lua_State *L) { + + const char *msg = luaL_checkstring(L,1); + FCEU_DispMessage("%s",0, msg); + + return 0; + +} + + +static int emu_registerbefore(lua_State *L) { + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L,1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]); + lua_insert(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]); + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; +} + +static int emu_registerafter(lua_State *L) { + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L,1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]); + lua_insert(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]); + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; +} + +static int emu_registerexit(lua_State *L) { + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L,1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); + lua_insert(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; +} + +static int emu_addgamegenie(lua_State *L) { + + const char *msg = luaL_checkstring(L,1); + + // Add a Game Genie code if it hasn't already been added + int GGaddr, GGcomp, GGval; + int i=0; + + uint32 Caddr; + uint8 Cval; + int Ccompare, Ctype; + + if (!FCEUI_DecodeGG(msg, &GGaddr, &GGval, &GGcomp)) { + luaL_error(L, "Failed to decode game genie code"); + lua_pushboolean(L, false); + return 1; + } + + while (FCEUI_GetCheat(i,NULL,&Caddr,&Cval,&Ccompare,NULL,&Ctype)) { + + if ((GGaddr == Caddr) && (GGval == Cval) && (GGcomp == Ccompare) && (Ctype == 1)) { + // Already Added, so consider it a success + lua_pushboolean(L, true); + return 1; + } + + i = i + 1; + } + + if (FCEUI_AddCheat(msg,GGaddr,GGval,GGcomp,1)) { + // Code was added + // Can't manage the display update the way I want, so I won't bother with it + // UpdateCheatsAdded(); + lua_pushboolean(L, true); + return 1; + } else { + // Code didn't get added + lua_pushboolean(L, false); + return 1; + } +} + +static int emu_delgamegenie(lua_State *L) { + + const char *msg = luaL_checkstring(L,1); + + // Remove a Game Genie code. Very restrictive about deleted code. + int GGaddr, GGcomp, GGval; + uint32 i=0; + + char * Cname; + uint32 Caddr; + uint8 Cval; + int Ccompare, Ctype; + + if (!FCEUI_DecodeGG(msg, &GGaddr, &GGval, &GGcomp)) { + luaL_error(L, "Failed to decode game genie code"); + lua_pushboolean(L, false); + return 1; + } + + while (FCEUI_GetCheat(i,&Cname,&Caddr,&Cval,&Ccompare,NULL,&Ctype)) { + + if ((!strcmp(msg,Cname)) && (GGaddr == Caddr) && (GGval == Cval) && (GGcomp == Ccompare) && (Ctype == 1)) { + // Delete cheat code + if (FCEUI_DelCheat(i)) { + lua_pushboolean(L, true); + return 1; + } + else { + lua_pushboolean(L, false); + return 1; + } + } + + i = i + 1; + } + + // Cheat didn't exist, so it's not an error + lua_pushboolean(L, true); + return 1; +} + + +// can't remember what the best way of doing this is... +#if defined(i386) || defined(__i386) || defined(__i386__) || defined(M_I86) || defined(_M_IX86) || defined(WIN32) + #define IS_LITTLE_ENDIAN +#endif + +// push a value's bytes onto the output stack +template +void PushBinaryItem(T item, std::vector& output) +{ + unsigned char* buf = (unsigned char*)&item; +#ifdef IS_LITTLE_ENDIAN + for(int i = sizeof(T); i; i--) + output.push_back(*buf++); +#else + int vecsize = output.size(); + for(int i = sizeof(T); i; i--) + output.insert(output.begin() + vecsize, *buf++); +#endif +} +// read a value from the byte stream and advance the stream by its size +template +T AdvanceByteStream(const unsigned char*& data, unsigned int& remaining) +{ +#ifdef IS_LITTLE_ENDIAN + T rv = *(T*)data; + data += sizeof(T); +#else + T rv; unsigned char* rvptr = (unsigned char*)&rv; + for(int i = sizeof(T)-1; i>=0; i--) + rvptr[i] = *data++; +#endif + remaining -= sizeof(T); + return rv; +} +// advance the byte stream by a certain size without reading a value +void AdvanceByteStream(const unsigned char*& data, unsigned int& remaining, int amount) +{ + data += amount; + remaining -= amount; +} + +#define LUAEXT_TLONG 30 // 0x1E // 4-byte signed integer +#define LUAEXT_TUSHORT 31 // 0x1F // 2-byte unsigned integer +#define LUAEXT_TSHORT 32 // 0x20 // 2-byte signed integer +#define LUAEXT_TBYTE 33 // 0x21 // 1-byte unsigned integer +#define LUAEXT_TNILS 34 // 0x22 // multiple nils represented by a 4-byte integer (warning: becomes multiple stack entities) +#define LUAEXT_TTABLE 0x40 // 0x40 through 0x4F // tables of different sizes: +#define LUAEXT_BITS_1A 0x01 // size of array part fits in a 1-byte unsigned integer +#define LUAEXT_BITS_2A 0x02 // size of array part fits in a 2-byte unsigned integer +#define LUAEXT_BITS_4A 0x03 // size of array part fits in a 4-byte unsigned integer +#define LUAEXT_BITS_1H 0x04 // size of hash part fits in a 1-byte unsigned integer +#define LUAEXT_BITS_2H 0x08 // size of hash part fits in a 2-byte unsigned integer +#define LUAEXT_BITS_4H 0x0C // size of hash part fits in a 4-byte unsigned integer +#define BITMATCH(x,y) (((x) & (y)) == (y)) + +static void PushNils(std::vector& output, int& nilcount) +{ + int count = nilcount; + nilcount = 0; + + static const int minNilsWorthEncoding = 6; // because a LUAEXT_TNILS entry is 5 bytes + + if(count < minNilsWorthEncoding) + { + for(int i = 0; i < count; i++) + output.push_back(LUA_TNIL); + } + else + { + output.push_back(LUAEXT_TNILS); + PushBinaryItem(count, output); + } +} + +static std::vector s_tableAddressStack; // prevents infinite recursion of a table within a table (when cycle is found, print something like table:parent) +static std::vector s_metacallStack; // prevents infinite recursion if something's __tostring returns another table that contains that something (when cycle is found, print the inner result without using __tostring) + +static void LuaStackToBinaryConverter(lua_State* L, int i, std::vector& output) +{ + int type = lua_type(L, i); + + // the first byte of every serialized item says what Lua type it is + output.push_back(type & 0xFF); + + switch(type) + { + default: + { + char errmsg [1024]; + sprintf(errmsg, "values of type \"%s\" are not allowed to be returned from registered save functions.\r\n", luaL_typename(L,i)); + if(info_print) + info_print(info_uid, errmsg); + else + puts(errmsg); + } + break; + case LUA_TNIL: + // no information necessary beyond the type + break; + case LUA_TBOOLEAN: + // serialize as 0 or 1 + output.push_back(lua_toboolean(L,i)); + break; + case LUA_TSTRING: + // serialize as a 0-terminated string of characters + { + const char* str = lua_tostring(L,i); + while(*str) + output.push_back(*str++); + output.push_back('\0'); + } + break; + case LUA_TNUMBER: + { + double num = (double)lua_tonumber(L,i); + int32 inum = (int32)lua_tointeger(L,i); + if(num != inum) + { + PushBinaryItem(num, output); + } + else + { + if((inum & ~0xFF) == 0) + type = LUAEXT_TBYTE; + else if((uint16)(inum & 0xFFFF) == inum) + type = LUAEXT_TUSHORT; + else if((int16)(inum & 0xFFFF) == inum) + type = LUAEXT_TSHORT; + else + type = LUAEXT_TLONG; + output.back() = type; + switch(type) + { + case LUAEXT_TLONG: + PushBinaryItem(static_cast(inum), output); + break; + case LUAEXT_TUSHORT: + PushBinaryItem(static_cast(inum), output); + break; + case LUAEXT_TSHORT: + PushBinaryItem(static_cast(inum), output); + break; + case LUAEXT_TBYTE: + output.push_back(static_cast(inum)); + break; + } + } + } + break; + case LUA_TTABLE: + // serialize as a type that describes how many bytes are used for storing the counts, + // followed by the number of array entries if any, then the number of hash entries if any, + // then a Lua value per array entry, then a (key,value) pair of Lua values per hashed entry + // note that the structure of table references are not faithfully serialized (yet) + { + int outputTypeIndex = output.size() - 1; + int arraySize = 0; + int hashSize = 0; + + if(lua_checkstack(L, 4) && std::find(s_tableAddressStack.begin(), s_tableAddressStack.end(), lua_topointer(L,i)) == s_tableAddressStack.end()) + { + s_tableAddressStack.push_back(lua_topointer(L,i)); + struct Scope { ~Scope(){ s_tableAddressStack.pop_back(); } } scope; + + bool wasnil = false; + int nilcount = 0; + arraySize = lua_objlen(L, i); + int arrayValIndex = lua_gettop(L) + 1; + for(int j = 1; j <= arraySize; j++) + { + lua_rawgeti(L, i, j); + bool isnil = lua_isnil(L, arrayValIndex); + if(isnil) + nilcount++; + else + { + if(wasnil) + PushNils(output, nilcount); + LuaStackToBinaryConverter(L, arrayValIndex, output); + } + lua_pop(L, 1); + wasnil = isnil; + } + if(wasnil) + PushNils(output, nilcount); + + if(arraySize) + lua_pushinteger(L, arraySize); // before first key + else + lua_pushnil(L); // before first key + + int keyIndex = lua_gettop(L); + int valueIndex = keyIndex + 1; + while(lua_next(L, i)) + { +// assert(lua_type(L, keyIndex) && "nil key in Lua table, impossible"); +// assert(lua_type(L, valueIndex) && "nil value in Lua table, impossible"); + LuaStackToBinaryConverter(L, keyIndex, output); + LuaStackToBinaryConverter(L, valueIndex, output); + lua_pop(L, 1); + hashSize++; + } + } + + int outputType = LUAEXT_TTABLE; + if(arraySize & 0xFFFF0000) + outputType |= LUAEXT_BITS_4A; + else if(arraySize & 0xFF00) + outputType |= LUAEXT_BITS_2A; + else if(arraySize & 0xFF) + outputType |= LUAEXT_BITS_1A; + if(hashSize & 0xFFFF0000) + outputType |= LUAEXT_BITS_4H; + else if(hashSize & 0xFF00) + outputType |= LUAEXT_BITS_2H; + else if(hashSize & 0xFF) + outputType |= LUAEXT_BITS_1H; + output[outputTypeIndex] = outputType; + + int insertIndex = outputTypeIndex; + if(BITMATCH(outputType,LUAEXT_BITS_4A) || BITMATCH(outputType,LUAEXT_BITS_2A) || BITMATCH(outputType,LUAEXT_BITS_1A)) + output.insert(output.begin() + (++insertIndex), arraySize & 0xFF); + if(BITMATCH(outputType,LUAEXT_BITS_4A) || BITMATCH(outputType,LUAEXT_BITS_2A)) + output.insert(output.begin() + (++insertIndex), (arraySize & 0xFF00) >> 8); + if(BITMATCH(outputType,LUAEXT_BITS_4A)) + output.insert(output.begin() + (++insertIndex), (arraySize & 0x00FF0000) >> 16), + output.insert(output.begin() + (++insertIndex), (arraySize & 0xFF000000) >> 24); + if(BITMATCH(outputType,LUAEXT_BITS_4H) || BITMATCH(outputType,LUAEXT_BITS_2H) || BITMATCH(outputType,LUAEXT_BITS_1H)) + output.insert(output.begin() + (++insertIndex), hashSize & 0xFF); + if(BITMATCH(outputType,LUAEXT_BITS_4H) || BITMATCH(outputType,LUAEXT_BITS_2H)) + output.insert(output.begin() + (++insertIndex), (hashSize & 0xFF00) >> 8); + if(BITMATCH(outputType,LUAEXT_BITS_4H)) + output.insert(output.begin() + (++insertIndex), (hashSize & 0x00FF0000) >> 16), + output.insert(output.begin() + (++insertIndex), (hashSize & 0xFF000000) >> 24); + + } break; + } +} + + +// complements LuaStackToBinaryConverter +void BinaryToLuaStackConverter(lua_State* L, const unsigned char*& data, unsigned int& remaining) +{ +// assert(s_dbg_dataSize - (data - s_dbg_dataStart) == remaining); + + unsigned char type = AdvanceByteStream(data, remaining); + + switch(type) + { + default: + { + char errmsg [1024]; + if(type <= 10 && type != LUA_TTABLE) + sprintf(errmsg, "values of type \"%s\" are not allowed to be loaded into registered load functions. The save state's Lua save data file might be corrupted.\r\n", lua_typename(L,type)); + else + sprintf(errmsg, "The save state's Lua save data file seems to be corrupted.\r\n"); + if(info_print) + info_print(info_uid, errmsg); + else + puts(errmsg); + } + break; + case LUA_TNIL: + lua_pushnil(L); + break; + case LUA_TBOOLEAN: + lua_pushboolean(L, AdvanceByteStream(data, remaining)); + break; + case LUA_TSTRING: + lua_pushstring(L, (const char*)data); + AdvanceByteStream(data, remaining, strlen((const char*)data) + 1); + break; + case LUA_TNUMBER: + lua_pushnumber(L, AdvanceByteStream(data, remaining)); + break; + case LUAEXT_TLONG: + lua_pushinteger(L, AdvanceByteStream(data, remaining)); + break; + case LUAEXT_TUSHORT: + lua_pushinteger(L, AdvanceByteStream(data, remaining)); + break; + case LUAEXT_TSHORT: + lua_pushinteger(L, AdvanceByteStream(data, remaining)); + break; + case LUAEXT_TBYTE: + lua_pushinteger(L, AdvanceByteStream(data, remaining)); + break; + case LUAEXT_TTABLE: + case LUAEXT_TTABLE | LUAEXT_BITS_1A: + case LUAEXT_TTABLE | LUAEXT_BITS_2A: + case LUAEXT_TTABLE | LUAEXT_BITS_4A: + case LUAEXT_TTABLE | LUAEXT_BITS_1H: + case LUAEXT_TTABLE | LUAEXT_BITS_2H: + case LUAEXT_TTABLE | LUAEXT_BITS_4H: + case LUAEXT_TTABLE | LUAEXT_BITS_1A | LUAEXT_BITS_1H: + case LUAEXT_TTABLE | LUAEXT_BITS_2A | LUAEXT_BITS_1H: + case LUAEXT_TTABLE | LUAEXT_BITS_4A | LUAEXT_BITS_1H: + case LUAEXT_TTABLE | LUAEXT_BITS_1A | LUAEXT_BITS_2H: + case LUAEXT_TTABLE | LUAEXT_BITS_2A | LUAEXT_BITS_2H: + case LUAEXT_TTABLE | LUAEXT_BITS_4A | LUAEXT_BITS_2H: + case LUAEXT_TTABLE | LUAEXT_BITS_1A | LUAEXT_BITS_4H: + case LUAEXT_TTABLE | LUAEXT_BITS_2A | LUAEXT_BITS_4H: + case LUAEXT_TTABLE | LUAEXT_BITS_4A | LUAEXT_BITS_4H: + { + unsigned int arraySize = 0; + if(BITMATCH(type,LUAEXT_BITS_4A) || BITMATCH(type,LUAEXT_BITS_2A) || BITMATCH(type,LUAEXT_BITS_1A)) + arraySize |= AdvanceByteStream(data, remaining); + if(BITMATCH(type,LUAEXT_BITS_4A) || BITMATCH(type,LUAEXT_BITS_2A)) + arraySize |= ((uint16)AdvanceByteStream(data, remaining)) << 8; + if(BITMATCH(type,LUAEXT_BITS_4A)) + arraySize |= ((uint32)AdvanceByteStream(data, remaining)) << 16, + arraySize |= ((uint32)AdvanceByteStream(data, remaining)) << 24; + + unsigned int hashSize = 0; + if(BITMATCH(type,LUAEXT_BITS_4H) || BITMATCH(type,LUAEXT_BITS_2H) || BITMATCH(type,LUAEXT_BITS_1H)) + hashSize |= AdvanceByteStream(data, remaining); + if(BITMATCH(type,LUAEXT_BITS_4H) || BITMATCH(type,LUAEXT_BITS_2H)) + hashSize |= ((uint16)AdvanceByteStream(data, remaining)) << 8; + if(BITMATCH(type,LUAEXT_BITS_4H)) + hashSize |= ((uint32)AdvanceByteStream(data, remaining)) << 16, + hashSize |= ((uint32)AdvanceByteStream(data, remaining)) << 24; + + lua_checkstack(L, 8); + + lua_createtable(L, arraySize, hashSize); + + unsigned int n = 1; + while(n <= arraySize) + { + if(*data == LUAEXT_TNILS) + { + AdvanceByteStream(data, remaining, 1); + n += AdvanceByteStream(data, remaining); + } + else + { + BinaryToLuaStackConverter(L, data, remaining); // push value + lua_rawseti(L, -2, n); // table[n] = value + n++; + } + } + + for(unsigned int h = 1; h <= hashSize; h++) + { + BinaryToLuaStackConverter(L, data, remaining); // push key + BinaryToLuaStackConverter(L, data, remaining); // push value + lua_rawset(L, -3); // table[key] = value + } + } + break; + } +} + +static const unsigned char luaBinaryMajorVersion = 9; +static const unsigned char luaBinaryMinorVersion = 1; + +unsigned char* LuaStackToBinary(lua_State* L, unsigned int& size) +{ + int n = lua_gettop(L); + if(n == 0) + return NULL; + + std::vector output; + output.push_back(luaBinaryMajorVersion); + output.push_back(luaBinaryMinorVersion); + + for(int i = 1; i <= n; i++) + LuaStackToBinaryConverter(L, i, output); + + unsigned char* rv = new unsigned char [output.size()]; + memcpy(rv, &output.front(), output.size()); + size = output.size(); + return rv; +} + +void BinaryToLuaStack(lua_State* L, const unsigned char* data, unsigned int size, unsigned int itemsToLoad) +{ + unsigned char major = *data++; + unsigned char minor = *data++; + size -= 2; + if(luaBinaryMajorVersion != major || luaBinaryMinorVersion != minor) + return; + + while(size > 0 && itemsToLoad > 0) + { + BinaryToLuaStackConverter(L, data, size); + itemsToLoad--; + } +} + +// saves Lua stack into a record and pops it +void LuaSaveData::SaveRecord(lua_State* L, unsigned int key) +{ + if(!L) + return; + + Record* cur = new Record(); + cur->key = key; + cur->data = LuaStackToBinary(L, cur->size); + cur->next = NULL; + + lua_settop(L,0); + + if(cur->size <= 0) + { + delete cur; + return; + } + + Record* last = recordList; + while(last && last->next) + last = last->next; + if(last) + last->next = cur; + else + recordList = cur; +} + +// pushes a record's data onto the Lua stack +void LuaSaveData::LoadRecord(struct lua_State* L, unsigned int key, unsigned int itemsToLoad) const +{ + if(!L) + return; + + Record* cur = recordList; + while(cur) + { + if(cur->key == key) + { +// s_dbg_dataStart = cur->data; +// s_dbg_dataSize = cur->size; + BinaryToLuaStack(L, cur->data, cur->size, itemsToLoad); + return; + } + cur = cur->next; + } +} + +// saves part of the Lua stack (at the given index) into a record and does NOT pop anything +void LuaSaveData::SaveRecordPartial(struct lua_State* L, unsigned int key, int idx) +{ + if(!L) + return; + + if(idx < 0) + idx += lua_gettop(L)+1; + + Record* cur = new Record(); + cur->key = key; + cur->next = NULL; + + if(idx <= lua_gettop(L)) + { + std::vector output; + output.push_back(luaBinaryMajorVersion); + output.push_back(luaBinaryMinorVersion); + + LuaStackToBinaryConverter(L, idx, output); + + unsigned char* rv = new unsigned char [output.size()]; + memcpy(rv, &output.front(), output.size()); + cur->size = output.size(); + cur->data = rv; + } + + if(cur->size <= 0) + { + delete cur; + return; + } + + Record* last = recordList; + while(last && last->next) + last = last->next; + if(last) + last->next = cur; + else + recordList = cur; +} + +void fwriteint(unsigned int value, FILE* file) +{ + for(int i=0;i<4;i++) + { + int w = value & 0xFF; + fwrite(&w, 1, 1, file); + value >>= 8; + } +} +void freadint(unsigned int& value, FILE* file) +{ + int rv = 0; + for(int i=0;i<4;i++) + { + int r = 0; + fread(&r, 1, 1, file); + rv |= r << (i*8); + } + value = rv; +} + +// writes all records to an already-open file +void LuaSaveData::ExportRecords(void* fileV) const +{ + FILE* file = (FILE*)fileV; + if(!file) + return; + + Record* cur = recordList; + while(cur) + { + fwriteint(cur->key, file); + fwriteint(cur->size, file); + fwrite(cur->data, cur->size, 1, file); + cur = cur->next; + } +} + +// reads records from an already-open file +void LuaSaveData::ImportRecords(void* fileV) +{ + FILE* file = (FILE*)fileV; + if(!file) + return; + + ClearRecords(); + + Record rec; + Record* cur = &rec; + Record* last = NULL; + while(1) + { + freadint(cur->key, file); + freadint(cur->size, file); + + if(feof(file) || ferror(file)) + break; + + cur->data = new unsigned char [cur->size]; + fread(cur->data, cur->size, 1, file); + + Record* next = new Record(); + memcpy(next, cur, sizeof(Record)); + next->next = NULL; + + if(last) + last->next = next; + else + recordList = next; + last = next; + } +} + +void LuaSaveData::ClearRecords() +{ + Record* cur = recordList; + while(cur) + { + Record* del = cur; + cur = cur->next; + + delete[] del->data; + delete del; + } + + recordList = NULL; +} + + + + + + +void CallRegisteredLuaSaveFunctions(int savestateNumber, LuaSaveData& saveData) +{ + //lua_State* L = FCEU_GetLuaState(); + if(L) + { + lua_settop(L, 0); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFORESAVE]); + + if (lua_isfunction(L, -1)) + { + lua_pushinteger(L, savestateNumber); + int ret = lua_pcall(L, 1, LUA_MULTRET, 0); + if (ret != 0) { + // This is grounds for trashing the function + lua_pushnil(L); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFORESAVE]); +#ifdef WIN32 + MessageBox(hAppWnd, lua_tostring(L, -1), "Lua Error in SAVE function", MB_OK); +#else + fprintf(stderr, "Lua error in registersave function: %s\n", lua_tostring(L, -1)); +#endif + } + saveData.SaveRecord(L, LUA_DATARECORDKEY); + } + else + { + lua_pop(L, 1); + } + } +} + + +void CallRegisteredLuaLoadFunctions(int savestateNumber, const LuaSaveData& saveData) +{ + //lua_State* L = FCEU_GetLuaState(); + if(L) + { + lua_settop(L, 0); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTERLOAD]); + + if (lua_isfunction(L, -1)) + { +#ifdef WIN32 + // since the scriptdata can be very expensive to load + // (e.g. the registered save function returned some huge tables) + // check the number of parameters the registered load function expects + // and don't bother loading the parameters it wouldn't receive anyway + int numParamsExpected = (L->top - 1)->value.gc->cl.l.p->numparams; // NOTE: if this line crashes, that means your Lua headers are out of sync with your Lua lib + if(numParamsExpected) numParamsExpected--; // minus one for the savestate number we always pass in + + int prevGarbage = lua_gc(L, LUA_GCCOUNT, 0); + + lua_pushinteger(L, savestateNumber); + saveData.LoadRecord(L, LUA_DATARECORDKEY, numParamsExpected); +#else + int prevGarbage = lua_gc(L, LUA_GCCOUNT, 0); + + lua_pushinteger(L, savestateNumber); + saveData.LoadRecord(L, LUA_DATARECORDKEY, (unsigned int) -1); +#endif + + int n = lua_gettop(L) - 1; + + int ret = lua_pcall(L, n, 0, 0); + if (ret != 0) { + // This is grounds for trashing the function + lua_pushnil(L); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTERLOAD]); +#ifdef WIN32 + MessageBox(hAppWnd, lua_tostring(L, -1), "Lua Error in LOAD function", MB_OK); +#else + fprintf(stderr, "Lua error in registerload function: %s\n", lua_tostring(L, -1)); +#endif + } + else + { + int newGarbage = lua_gc(L, LUA_GCCOUNT, 0); + if(newGarbage - prevGarbage > 50) + { + // now seems to be a very good time to run the garbage collector + // it might take a while now but that's better than taking 10 whiles 9 loads from now + lua_gc(L, LUA_GCCOLLECT, 0); + } + } + } + else + { + lua_pop(L, 1); + } + } +} + + +static int rom_readbyte(lua_State *L) { + lua_pushinteger(L, FCEU_ReadRomByte(luaL_checkinteger(L,1))); + return 1; +} + +static int rom_readbytesigned(lua_State *L) { + lua_pushinteger(L, (signed char)FCEU_ReadRomByte(luaL_checkinteger(L,1))); + return 1; +} + +static int rom_gethash(lua_State *L) { + const char *type = luaL_checkstring(L, 1); + if(!type) lua_pushstring(L, ""); + else if(!stricmp(type,"md5")) lua_pushstring(L, md5_asciistr(GameInfo->MD5)); + else lua_pushstring(L, ""); + return 1; +} + +static int memory_readbyte(lua_State *L) { + lua_pushinteger(L, FCEU_CheatGetByte(luaL_checkinteger(L,1))); + return 1; +} + +static int memory_readbytesigned(lua_State *L) { + signed char c = (signed char) FCEU_CheatGetByte(luaL_checkinteger(L,1)); + lua_pushinteger(L, c); + return 1; +} + +static int GetWord(lua_State *L, bool isSigned) +{ + // little endian, unless the high byte address is specified as a 2nd parameter + uint16 addressLow = luaL_checkinteger(L, 1); + uint16 addressHigh = addressLow + 1; + if (lua_type(L, 2) == LUA_TNUMBER) + addressHigh = luaL_checkinteger(L, 2); + uint16 result = FCEU_CheatGetByte(addressLow) | (FCEU_CheatGetByte(addressHigh) << 8); + return isSigned ? (int16)result : result; +} + +static int memory_readword(lua_State *L) +{ + lua_pushinteger(L, GetWord(L, false)); + return 1; +} + +static int memory_readwordsigned(lua_State *L) { + lua_pushinteger(L, GetWord(L, true)); + return 1; +} + +static int memory_writebyte(lua_State *L) { + FCEU_CheatSetByte(luaL_checkinteger(L,1), luaL_checkinteger(L,2)); + return 0; +} + +static int memory_readbyterange(lua_State *L) { + + int range_start = luaL_checkinteger(L,1); + int range_size = luaL_checkinteger(L,2); + if(range_size < 0) + return 0; + + char* buf = (char*)alloca(range_size); + for(int i=0;i= 0) { ptr += _n; remaining -= _n; } else { remaining = 0; } } +static void toCStringConverter(lua_State* L, int i, char*& ptr, int& remaining) +{ + if(remaining <= 0) + return; + + const char* str = ptr; // for debugging + + // if there is a __tostring metamethod then call it + int usedMeta = luaL_callmeta(L, i, "__tostring"); + if(usedMeta) + { + std::vector::const_iterator foundCycleIter = std::find(s_metacallStack.begin(), s_metacallStack.end(), lua_topointer(L,i)); + if(foundCycleIter != s_metacallStack.end()) + { + lua_pop(L, 1); + usedMeta = false; + } + else + { + s_metacallStack.push_back(lua_topointer(L,i)); + i = lua_gettop(L); + } + } + + switch(lua_type(L, i)) + { + case LUA_TNONE: break; + case LUA_TNIL: APPENDPRINT "nil" END break; + case LUA_TBOOLEAN: APPENDPRINT lua_toboolean(L,i) ? "true" : "false" END break; + case LUA_TSTRING: APPENDPRINT "%s",lua_tostring(L,i) END break; + case LUA_TNUMBER: APPENDPRINT "%.12Lg",lua_tonumber(L,i) END break; + case LUA_TFUNCTION: + /*if((L->base + i-1)->value.gc->cl.c.isC) + { + //lua_CFunction func = lua_tocfunction(L, i); + //std::map::iterator iter = s_cFuncInfoMap.find(func); + //if(iter == s_cFuncInfoMap.end()) + goto defcase; + //APPENDPRINT "function(%s)", iter->second END + } + else + { + APPENDPRINT "function(" END + Proto* p = (L->base + i-1)->value.gc->cl.l.p; + int numParams = p->numparams + (p->is_vararg?1:0); + for (int n=0; nnumparams; n++) + { + APPENDPRINT "%s", getstr(p->locvars[n].varname) END + if(n != numParams-1) + APPENDPRINT "," END + } + if(p->is_vararg) + APPENDPRINT "..." END + APPENDPRINT ")" END + }*/ + goto defcase; + break; +defcase:default: APPENDPRINT "%s:%p",luaL_typename(L,i),lua_topointer(L,i) END break; + case LUA_TTABLE: + { + // first make sure there's enough stack space + if(!lua_checkstack(L, 4)) + { + // note that even if lua_checkstack never returns false, + // that doesn't mean we didn't need to call it, + // because calling it retrieves stack space past LUA_MINSTACK + goto defcase; + } + + std::vector::const_iterator foundCycleIter = std::find(s_tableAddressStack.begin(), s_tableAddressStack.end(), lua_topointer(L,i)); + if(foundCycleIter != s_tableAddressStack.end()) + { + int parentNum = s_tableAddressStack.end() - foundCycleIter; + if(parentNum > 1) + APPENDPRINT "%s:parent^%d",luaL_typename(L,i),parentNum END + else + APPENDPRINT "%s:parent",luaL_typename(L,i) END + } + else + { + s_tableAddressStack.push_back(lua_topointer(L,i)); + struct Scope { ~Scope(){ s_tableAddressStack.pop_back(); } } scope; + + APPENDPRINT "{" END + + lua_pushnil(L); // first key + int keyIndex = lua_gettop(L); + int valueIndex = keyIndex + 1; + bool first = true; + bool skipKey = true; // true if we're still in the "array part" of the table + lua_Number arrayIndex = (lua_Number)0; + while(lua_next(L, i)) + { + if(first) + first = false; + else + APPENDPRINT ", " END + if(skipKey) + { + arrayIndex += (lua_Number)1; + bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER); + skipKey = keyIsNumber && (lua_tonumber(L, keyIndex) == arrayIndex); + } + if(!skipKey) + { + bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING); + bool invalidLuaIdentifier = (!keyIsString || !isalphaorunderscore(*lua_tostring(L, keyIndex))); + if(invalidLuaIdentifier) + if(keyIsString) + APPENDPRINT "['" END + else + APPENDPRINT "[" END + + toCStringConverter(L, keyIndex, ptr, remaining); // key + + if(invalidLuaIdentifier) + if(keyIsString) + APPENDPRINT "']=" END + else + APPENDPRINT "]=" END + else + APPENDPRINT "=" END + } + + bool valueIsString = (lua_type(L, valueIndex) == LUA_TSTRING); + if(valueIsString) + APPENDPRINT "'" END + + toCStringConverter(L, valueIndex, ptr, remaining); // value + + if(valueIsString) + APPENDPRINT "'" END + + lua_pop(L, 1); + + if(remaining <= 0) + { + lua_settop(L, keyIndex-1); // stack might not be clean yet if we're breaking early + break; + } + } + APPENDPRINT "}" END + } + } break; + } + + if(usedMeta) + { + s_metacallStack.pop_back(); + lua_pop(L, 1); + } +} + +static const int s_tempStrMaxLen = 64 * 1024; +static char s_tempStr [s_tempStrMaxLen]; + +static char* rawToCString(lua_State* L, int idx) +{ + int a = idx>0 ? idx : 1; + int n = idx>0 ? idx : lua_gettop(L); + + char* ptr = s_tempStr; + *ptr = 0; + + int remaining = s_tempStrMaxLen; + for(int i = a; i <= n; i++) + { + toCStringConverter(L, i, ptr, remaining); + if(i != n) + APPENDPRINT " " END + } + + if(remaining < 3) + { + while(remaining < 6) + remaining++, ptr--; + APPENDPRINT "..." END + } + APPENDPRINT "\r\n" END + // the trailing newline is so print() can avoid having to do wasteful things to print its newline + // (string copying would be wasteful and calling info.print() twice can be extremely slow) + // at the cost of functions that don't want the newline needing to trim off the last two characters + // (which is a very fast operation and thus acceptable in this case) + + return s_tempStr; +} +#undef APPENDPRINT +#undef END + + +// replacement for luaB_tostring() that is able to show the contents of tables (and formats numbers better, and show function prototypes) +// can be called directly from lua via tostring(), assuming tostring hasn't been reassigned +static int tostring(lua_State *L) +{ + char* str = rawToCString(L); + str[strlen(str)-2] = 0; // hack: trim off the \r\n (which is there to simplify the print function's task) + lua_pushstring(L, str); + return 1; +} + +// tobitstring(int value) +// +// Converts byte to binary string +static int tobitstring(lua_State *L) +{ + std::bitset<8> bits (luaL_checkinteger(L, 1)); + std::string temp = bits.to_string().insert(4, " "); + const char * result = temp.c_str(); + lua_pushstring(L,result); + return 1; +} + +// like rawToCString, but will check if the global Lua function tostring() +// has been replaced with a custom function, and call that instead if so +static const char* toCString(lua_State* L, int idx) +{ + int a = idx>0 ? idx : 1; + int n = idx>0 ? idx : lua_gettop(L); + lua_getglobal(L, "tostring"); + lua_CFunction cf = lua_tocfunction(L,-1); + if(cf == tostring) // optimization: if using our own C tostring function, we can bypass the call through Lua and all the string object allocation that would entail + { + lua_pop(L,1); + return rawToCString(L, idx); + } + else // if the user overrided the tostring function, we have to actually call it and store the temporarily allocated string it returns + { + lua_pushstring(L, ""); + for (int i=a; i<=n; i++) { + lua_pushvalue(L, -2); // function to be called + lua_pushvalue(L, i); // value to print + lua_call(L, 1, 1); + if(lua_tostring(L, -1) == NULL) + luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print")); + lua_pushstring(L, (il_G->mainthread]; + //LuaContextInfo& info = GetCurrentInfo(); + + if(info_print) + info_print(uid, str); + else + puts(str); + + //worry(L, 100); + return 0; +} + +// provides an easy way to copy a table from Lua +// (simple assignment only makes an alias, but sometimes an independent table is desired) +// currently this function only performs a shallow copy, +// but I think it should be changed to do a deep copy (possibly of configurable depth?) +// that maintains the internal table reference structure +static int copytable(lua_State *L) +{ + int origIndex = 1; // we only care about the first argument + int origType = lua_type(L, origIndex); + if(origType == LUA_TNIL) + { + lua_pushnil(L); + return 1; + } + if(origType != LUA_TTABLE) + { + luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE)); + lua_pushnil(L); + return 1; + } + + lua_createtable(L, lua_objlen(L,1), 0); + int copyIndex = lua_gettop(L); + + lua_pushnil(L); // first key + int keyIndex = lua_gettop(L); + int valueIndex = keyIndex + 1; + + while(lua_next(L, origIndex)) + { + lua_pushvalue(L, keyIndex); + lua_pushvalue(L, valueIndex); + lua_rawset(L, copyIndex); // copytable[key] = value + lua_pop(L, 1); + } + + // copy the reference to the metatable as well, if any + if(lua_getmetatable(L, origIndex)) + lua_setmetatable(L, copyIndex); + + return 1; // return the new table +} + +// because print traditionally shows the address of tables, +// and the print function I provide instead shows the contents of tables, +// I also provide this function +// (otherwise there would be no way to see a table's address, AFAICT) +static int addressof(lua_State *L) +{ + const void* ptr = lua_topointer(L,-1); + lua_pushinteger(L, (lua_Integer)ptr); + return 1; +} + +struct registerPointerMap +{ + const char* registerName; + unsigned int* pointer; + int dataSize; +}; + +#define RPM_ENTRY(name,var) {name, (unsigned int*)&var, sizeof(var)}, + +registerPointerMap regPointerMap [] = { + RPM_ENTRY("pc", _PC) + RPM_ENTRY("a", _A) + RPM_ENTRY("x", _X) + RPM_ENTRY("y", _Y) + RPM_ENTRY("s", _S) + RPM_ENTRY("p", _P) + {} +}; + +struct cpuToRegisterMap +{ + const char* cpuName; + registerPointerMap* rpmap; +} +cpuToRegisterMaps [] = +{ + {"", regPointerMap}, +}; + + +//DEFINE_LUA_FUNCTION(memory_getregister, "cpu_dot_registername_string") +static int memory_getregister(lua_State *L) +{ + const char* qualifiedRegisterName = luaL_checkstring(L,1); + lua_settop(L,0); + for(int cpu = 0; cpu < sizeof(cpuToRegisterMaps)/sizeof(*cpuToRegisterMaps); cpu++) + { + cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu]; + int cpuNameLen = strlen(ctrm.cpuName); + if(!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen)) + { + qualifiedRegisterName += cpuNameLen; + for(int reg = 0; ctrm.rpmap[reg].dataSize; reg++) + { + registerPointerMap rpm = ctrm.rpmap[reg]; + if(!stricmp(qualifiedRegisterName, rpm.registerName)) + { + switch(rpm.dataSize) + { default: + case 1: lua_pushinteger(L, *(unsigned char*)rpm.pointer); break; + case 2: lua_pushinteger(L, *(unsigned short*)rpm.pointer); break; + case 4: lua_pushinteger(L, *(unsigned long*)rpm.pointer); break; + } + return 1; + } + } + lua_pushnil(L); + return 1; + } + } + lua_pushnil(L); + return 1; +} +//DEFINE_LUA_FUNCTION(memory_setregister, "cpu_dot_registername_string,value") +static int memory_setregister(lua_State *L) +{ + const char* qualifiedRegisterName = luaL_checkstring(L,1); + unsigned long value = (unsigned long)(luaL_checkinteger(L,2)); + lua_settop(L,0); + for(int cpu = 0; cpu < sizeof(cpuToRegisterMaps)/sizeof(*cpuToRegisterMaps); cpu++) + { + cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu]; + int cpuNameLen = strlen(ctrm.cpuName); + if(!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen)) + { + qualifiedRegisterName += cpuNameLen; + for(int reg = 0; ctrm.rpmap[reg].dataSize; reg++) + { + registerPointerMap rpm = ctrm.rpmap[reg]; + if(!stricmp(qualifiedRegisterName, rpm.registerName)) + { + switch(rpm.dataSize) + { default: + case 1: *(unsigned char*)rpm.pointer = (unsigned char)(value & 0xFF); break; + case 2: *(unsigned short*)rpm.pointer = (unsigned short)(value & 0xFFFF); break; + case 4: *(unsigned long*)rpm.pointer = value; break; + } + return 0; + } + } + return 0; + } + } + return 0; +} + + +void HandleCallbackError(lua_State* L) +{ + //if(L->errfunc || L->errorJmp) + // luaL_error(L, "%s", lua_tostring(L,-1)); + //else + { + lua_pushnil(L); + lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable); + + // Error? +#ifdef WIN32 + MessageBox( hAppWnd, lua_tostring(L,-1), "Lua run error", MB_OK | MB_ICONSTOP); +#else + fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(L,-1)); +#endif + + FCEU_LuaStop(); + } +} + + +// the purpose of this structure is to provide a way of +// QUICKLY determining whether a memory address range has a hook associated with it, +// with a bias toward fast rejection because the majority of addresses will not be hooked. +// (it must not use any part of Lua or perform any per-script operations, +// otherwise it would definitely be too slow.) +// calculating the regions when a hook is added/removed may be slow, +// but this is an intentional tradeoff to obtain a high speed of checking during later execution +struct TieredRegion +{ + template + struct Region + { + struct Island + { + unsigned int start; + unsigned int end; +#ifdef NEED_MINGW_HACKS + bool Contains(unsigned int address, int size) const { return address < end && address+size > start; } +#else + __forceinline bool Contains(unsigned int address, int size) const { return address < end && address+size > start; } +#endif + }; + std::vector islands; + + void Calculate(const std::vector& bytes) + { + islands.clear(); + + unsigned int lastEnd = ~0; + + std::vector::const_iterator iter = bytes.begin(); + std::vector::const_iterator end = bytes.end(); + for(; iter != end; ++iter) + { + unsigned int addr = *iter; + if(addr < lastEnd || addr > lastEnd + (long long)maxGap) + { + islands.push_back(Island()); + islands.back().start = addr; + } + islands.back().end = addr+1; + lastEnd = addr+1; + } + } + bool Contains(unsigned int address, int size) const + { + for (size_t i = 0; i != islands.size(); ++i) + { + if (islands[i].Contains(address, size)) + return true; + } + return false; + } + }; + + Region<0xFFFFFFFF> broad; + Region<0x1000> mid; + Region<0> narrow; + + void Calculate(std::vector& bytes) + { + std::sort(bytes.begin(), bytes.end()); + + broad.Calculate(bytes); + mid.Calculate(bytes); + narrow.Calculate(bytes); + } + + TieredRegion() + { + std::vector temp; + Calculate(temp); + } + + __forceinline int NotEmpty() + { + return broad.islands.size(); + } + + // note: it is illegal to call this if NotEmpty() returns 0 + __forceinline bool Contains(unsigned int address, int size) + { + return broad.islands[0].Contains(address,size) && + mid.Contains(address,size) && + narrow.Contains(address,size); + } +}; +TieredRegion hookedRegions [LUAMEMHOOK_COUNT]; + + +static void CalculateMemHookRegions(LuaMemHookType hookType) +{ + std::vector hookedBytes; +// std::map::iterator iter = luaContextInfo.begin(); +// std::map::iterator end = luaContextInfo.end(); +// while(iter != end) +// { +// LuaContextInfo& info = *iter->second; + if(/*info.*/ numMemHooks) + { +// lua_State* L = info.L; + if(L) + { + lua_settop(L, 0); + lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); + lua_pushnil(L); + while(lua_next(L, -2)) + { + if(lua_isfunction(L, -1)) + { + unsigned int addr = lua_tointeger(L, -2); + hookedBytes.push_back(addr); + } + lua_pop(L, 1); + } + lua_settop(L, 0); + } + } +// ++iter; +// } + hookedRegions[hookType].Calculate(hookedBytes); +} + +static void CallRegisteredLuaMemHook_LuaMatch(unsigned int address, int size, unsigned int value, LuaMemHookType hookType) +{ +// std::map::iterator iter = luaContextInfo.begin(); +// std::map::iterator end = luaContextInfo.end(); +// while(iter != end) +// { +// LuaContextInfo& info = *iter->second; + if(/*info.*/ numMemHooks) + { +// lua_State* L = info.L; + if(L/* && !info.panic*/) + { +#ifdef USE_INFO_STACK + infoStack.insert(infoStack.begin(), &info); + struct Scope { ~Scope(){ infoStack.erase(infoStack.begin()); } } scope; +#endif + lua_settop(L, 0); + lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); + for(int i = address; i != address+size; i++) + { + lua_rawgeti(L, -1, i); + if (lua_isfunction(L, -1)) + { + bool wasRunning = (luaRunning!=0) /*info.running*/; + luaRunning /*info.running*/ = true; + //RefreshScriptSpeedStatus(); + lua_pushinteger(L, address); + lua_pushinteger(L, size); + int errorcode = lua_pcall(L, 2, 0, 0); + luaRunning /*info.running*/ = wasRunning; + //RefreshScriptSpeedStatus(); + if (errorcode) + { + HandleCallbackError(L); + //int uid = iter->first; + //HandleCallbackError(L,info,uid,true); + } + break; + } + else + { + lua_pop(L,1); + } + } + lua_settop(L, 0); + } + } +// ++iter; +// } +} +void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType) +{ + // performance critical! (called VERY frequently) + // I suggest timing a large number of calls to this function in Release if you change anything in here, + // before and after, because even the most innocent change can make it become 30% to 400% slower. + // a good amount to test is: 100000000 calls with no hook set, and another 100000000 with a hook set. + // (on my system that consistently took 200 ms total in the former case and 350 ms total in the latter case) + if(hookedRegions[hookType].NotEmpty()) + { + //if((hookType <= LUAMEMHOOK_EXEC) && (address >= 0xE00000)) + // address |= 0xFF0000; // account for mirroring of RAM + if(hookedRegions[hookType].Contains(address, size)) + CallRegisteredLuaMemHook_LuaMatch(address, size, value, hookType); // something has hooked this specific address + } +} + +void CallRegisteredLuaFunctions(LuaCallID calltype) +{ + assert((unsigned int)calltype < (unsigned int)LUACALL_COUNT); + const char* idstring = luaCallIDStrings[calltype]; + + if (!L) + return; + + lua_settop(L, 0); + lua_getfield(L, LUA_REGISTRYINDEX, idstring); + + int errorcode = 0; + if (lua_isfunction(L, -1)) + { + errorcode = lua_pcall(L, 0, 0, 0); + if (errorcode) + HandleCallbackError(L); + } + else + { + lua_pop(L, 1); + } +} + +void ForceExecuteLuaFrameFunctions() +{ + FCEU_LuaFrameBoundary(); + CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION); + CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION); +} + +void TaseditorAutoFunction() +{ + CallRegisteredLuaFunctions(LUACALL_TASEDITOR_AUTO); +} + +void TaseditorManualFunction() +{ + CallRegisteredLuaFunctions(LUACALL_TASEDITOR_MANUAL); +} + +#ifdef WIN32 +void TaseditorDisableManualFunctionIfNeeded() +{ + if (L) + { + // check if LUACALL_TASEDITOR_MANUAL function is not nil + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_TASEDITOR_MANUAL]); + if (!lua_isfunction(L, -1)) + taseditor_lua.disableRunFunction(); + lua_pop(L, 1); + } else taseditor_lua.disableRunFunction(); +} +#endif + +static int memory_registerHook(lua_State* L, LuaMemHookType hookType, int defaultSize) +{ + // get first argument: address + unsigned int addr = luaL_checkinteger(L,1); + //if((addr & ~0xFFFFFF) == ~0xFFFFFF) + // addr &= 0xFFFFFF; + + // get optional second argument: size + int size = defaultSize; + int funcIdx = 2; + if(lua_isnumber(L,2)) + { + size = luaL_checkinteger(L,2); + if(size < 0) + { + size = -size; + addr -= size; + } + funcIdx++; + } + + // check last argument: callback function + bool clearing = lua_isnil(L,funcIdx); + if(!clearing) + luaL_checktype(L, funcIdx, LUA_TFUNCTION); + lua_settop(L,funcIdx); + + // get the address-to-callback table for this hook type of the current script + lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); + + // count how many callback functions we'll be displacing + int numFuncsAfter = clearing ? 0 : size; + int numFuncsBefore = 0; + for(unsigned int i = addr; i != addr+size; i++) + { + lua_rawgeti(L, -1, i); + if(lua_isfunction(L, -1)) + numFuncsBefore++; + lua_pop(L,1); + } + + // put the callback function in the address slots + for(unsigned int i = addr; i != addr+size; i++) + { + lua_pushvalue(L, -2); + lua_rawseti(L, -2, i); + } + + // adjust the count of active hooks + //LuaContextInfo& info = GetCurrentInfo(); + /*info.*/ numMemHooks += numFuncsAfter - numFuncsBefore; + + // re-cache regions of hooked memory across all scripts + CalculateMemHookRegions(hookType); + + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 0; +} + +LuaMemHookType MatchHookTypeToCPU(lua_State* L, LuaMemHookType hookType) +{ + int cpuID = 0; + + int cpunameIndex = 0; + if(lua_type(L,2) == LUA_TSTRING) + cpunameIndex = 2; + else if(lua_type(L,3) == LUA_TSTRING) + cpunameIndex = 3; + + if(cpunameIndex) + { + const char* cpuName = lua_tostring(L, cpunameIndex); + if(!stricmp(cpuName, "sub")) + cpuID = 1; + lua_remove(L, cpunameIndex); + } + + switch(cpuID) + { + case 0: + return hookType; + + case 1: + switch(hookType) + { + case LUAMEMHOOK_WRITE: return LUAMEMHOOK_WRITE_SUB; + case LUAMEMHOOK_READ: return LUAMEMHOOK_READ_SUB; + case LUAMEMHOOK_EXEC: return LUAMEMHOOK_EXEC_SUB; + } + } + return hookType; +} + +static int memory_registerwrite(lua_State *L) +{ + return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_WRITE), 1); +} +static int memory_registerread(lua_State *L) +{ + return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_READ), 1); +} +static int memory_registerexec(lua_State *L) +{ + return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_EXEC), 1); +} + +//adelikat: table pulled from GENS. credz nitsuja! + +#ifdef WIN32 +const char* s_keyToName[256] = +{ + NULL, + "leftclick", + "rightclick", + NULL, + "middleclick", + NULL, + NULL, + NULL, + "backspace", + "tab", + NULL, + NULL, + NULL, + "enter", + NULL, + NULL, + "shift", // 0x10 + "control", + "alt", + "pause", + "capslock", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "escape", + NULL, + NULL, + NULL, + NULL, + "space", // 0x20 + "pageup", + "pagedown", + "end", + "home", + "left", + "up", + "right", + "down", + NULL, + NULL, + NULL, + NULL, + "insert", + "delete", + NULL, + "0","1","2","3","4","5","6","7","8","9", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "A","B","C","D","E","F","G","H","I","J", + "K","L","M","N","O","P","Q","R","S","T", + "U","V","W","X","Y","Z", + NULL, + NULL, + NULL, + NULL, + NULL, + "numpad0","numpad1","numpad2","numpad3","numpad4","numpad5","numpad6","numpad7","numpad8","numpad9", + "numpad*","numpad+", + NULL, + "numpad-","numpad.","numpad/", + "F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12", + "F13","F14","F15","F16","F17","F18","F19","F20","F21","F22","F23","F24", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "numlock", + "scrolllock", + NULL, // 0x92 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, // 0xB9 + "semicolon", + "plus", + "comma", + "minus", + "period", + "slash", + "tilde", + NULL, // 0xC1 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, // 0xDA + "leftbracket", + "backslash", + "rightbracket", + "quote", +}; +#endif + +//adelikat - the code for the keys is copied directly from GENS. Props to nitsuja +// the code for the mouse is simply the same code from zapper.get +// input.get() +// takes no input, returns a lua table of entries representing the current input state, +// independent of the joypad buttons the emulated game thinks are pressed +// for example: +// if the user is holding the W key and the left mouse button +// and has the mouse at the bottom-right corner of the game screen, +// then this would return {W=true, leftclick=true, xmouse=319, ymouse=223} +static int input_get(lua_State *L) { + lua_newtable(L); + +#ifdef WIN32 + // keyboard and mouse button status + { + extern int EnableBackgroundInput; + unsigned char keys [256]; + if(!EnableBackgroundInput) + { + if(GetKeyboardState(keys)) + { + for(int i = 1; i < 255; i++) + { + int mask = (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) ? 0x01 : 0x80; + if(keys[i] & mask) + { + const char* name = s_keyToName[i]; + if(name) + { + lua_pushboolean(L, true); + lua_setfield(L, -2, name); + } + } + } + } + } + else // use a slightly different method that will detect background input: + { + for(int i = 1; i < 255; i++) + { + const char* name = s_keyToName[i]; + if(name) + { + int active; + if(i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) + active = GetKeyState(i) & 0x01; + else + active = GetAsyncKeyState(i) & 0x8000; + if(active) + { + lua_pushboolean(L, true); + lua_setfield(L, -2, name); + } + } + } + } + } +#else + //SDL TODO: implement this for keyboard!! +#endif + + // mouse position in game screen pixel coordinates + + extern void GetMouseData(uint32 (&md)[3]); + + uint32 MouseData[3]; + GetMouseData (MouseData); + int x = MouseData[0]; + int y = MouseData[1]; + int click = MouseData[2]; ///adelikat TODO: remove the ability to store the value 2? Since 2 is right-clicking and not part of zapper input and is used for context menus + + lua_pushinteger(L, x); + lua_setfield(L, -2, "xmouse"); + lua_pushinteger(L, y); + lua_setfield(L, -2, "ymouse"); + lua_pushinteger(L, click); + lua_setfield(L, -2, "click"); + + return 1; +} + +// table zapper.read +//int which unecessary because zapper is always controller 2 +//Reads the zapper coordinates and a click value (1 if clicked, 0 if not, 2 if right click (but this is not used for zapper input) +static int zapper_read(lua_State *L){ + + lua_newtable(L); + int z = 0; + extern void GetMouseData(uint32 (&md)[3]); //adelikat: shouldn't this be ifdef'ed for Win32? + int x,y,click; + if (FCEUMOV_Mode(MOVIEMODE_PLAY)) + { + if (!currFrameCounter) + z = 0; + else + z = currFrameCounter -1; + + x = currMovieData.records[z].zappers[1].x; //adelikat: Used hardcoded port 1 since as far as I know, only port 1 is valid for zappers + y = currMovieData.records[z].zappers[1].y; + click = currMovieData.records[z].zappers[1].b; + } + else + { + uint32 MouseData[3]; + GetMouseData (MouseData); + x = MouseData[0]; + y = MouseData[1]; + click = MouseData[2]; + if (click > 1) + click = 1; //adelikat: This is zapper.read() thus should only give valid zapper input (instead of simply mouse input + } + lua_pushinteger(L, x); + lua_setfield(L, -2, "x"); + lua_pushinteger(L, y); + lua_setfield(L, -2, "y"); + lua_pushinteger(L, click); + lua_setfield(L, -2, "fire"); + return 1; +} + + + +// table joypad.read(int which = 1) +// +// Reads the joypads as inputted by the user. +// TODO: Don't read in *everything*... +static int joy_get_internal(lua_State *L, bool reportUp, bool reportDown) { + + // Reads the joypads as inputted by the user + int which = luaL_checkinteger(L,1); + + if (which < 1 || which > 4) { + luaL_error(L,"Invalid input port (valid range 1-4, specified %d)", which); + } + + // Use the OS-specific code to do the reading. + extern SFORMAT FCEUCTRL_STATEINFO[]; + uint8 buttons = ((uint8 *) FCEUCTRL_STATEINFO[1].v)[which - 1]; + + lua_newtable(L); + + int i; + for (i = 0; i < 8; i++) { + bool pressed = (buttons & (1< 4) + { + luaL_error(L,"Invalid input port (valid range 1-4, specified %d)", which); + } + // Currently only supports Windows, sorry... +#ifdef WIN32 + extern uint32 GetGamepadPressedImmediate(); + uint8 buttons = GetGamepadPressedImmediate() >> ((which - 1) * 8); + + lua_newtable(L); + for (int i = 0; i < 8; ++i) + { + lua_pushboolean(L, (buttons & (1 << i)) != 0); + lua_setfield(L, -2, button_mappings[i]); + } +#else + lua_pushnil(L); +#endif + return 1; +} + + +// joypad.set(int which, table buttons) +// +// Sets the given buttons to be pressed during the next +// frame advance. The table should have the right +// keys (no pun intended) set. +/*FatRatKnight: I changed some of the logic. + Now with 4 options!*/ +static int joypad_set(lua_State *L) { + + // Which joypad we're tampering with + int which = luaL_checkinteger(L,1); + if (which < 1 || which > 4) { + luaL_error(L,"Invalid output port (valid range 1-4, specified %d)", which); + + } + + // And the table of buttons. + luaL_checktype(L,2,LUA_TTABLE); + + // Set up for taking control of the indicated controller + luajoypads1[which-1] = 0xFF; // .1 Reset right bit + luajoypads2[which-1] = 0x00; // 0. Reset left bit + + int i; + for (i=0; i < 8; i++) { + lua_getfield(L, 2, button_mappings[i]); + + //Button is not nil, so find out if it is true/false + if (!lua_isnil(L,-1)) + { + if (lua_toboolean(L,-1)) //True or string + luajoypads2[which-1] |= 1 << i; + if (lua_toboolean(L,-1) == 0 || lua_isstring(L,-1)) //False or string + luajoypads1[which-1] &= ~(1 << i); + } + + else + { + + } + lua_pop(L,1); + } + + return 0; +} + +// Helper function to convert a savestate object to the filename it represents. +static const char *savestateobj2filename(lua_State *L, int offset) { + + // First we get the metatable of the indicated object + int result = lua_getmetatable(L, offset); + + if (!result) + luaL_error(L, "object not a savestate object"); + + // Also check that the type entry is set + lua_getfield(L, -1, "__metatable"); + if (strcmp(lua_tostring(L,-1), "FCEU Savestate") != 0) + luaL_error(L, "object not a savestate object"); + lua_pop(L,1); + + // Now, get the field we want + lua_getfield(L, -1, "filename"); + + // Return it + return lua_tostring(L, -1); +} + +// Helper function for garbage collection. +static int savestate_gc(lua_State *L) { + + LuaSaveState *ss = (LuaSaveState *)lua_touserdata(L, 1); + if(ss->persisted && ss->anonymous) + remove(ss->filename.c_str()); + ss->~LuaSaveState(); + + //// The object we're collecting is on top of the stack + //lua_getmetatable(L,1); + // + //// Get the filename + //const char *filename; + //lua_getfield(L, -1, "filename"); + //filename = lua_tostring(L,-1); + + //// Delete the file + //remove(filename); + // + + // We exit, and the garbage collector takes care of the rest. + return 0; +} + +// Referenced by: +// savestate.create(int which = nil) +// savestate.object(int which = nil) +// +// Creates an object used for savestates. +// The object can be associated with a player-accessible savestate +// ("which" between 1 and 10) or not (which == nil). +static int savestate_create_aliased(lua_State *L, bool newnumbering) { + int which = -1; + if (lua_gettop(L) >= 1) { + which = luaL_checkinteger(L, 1); + if (which < 1 || which > 10) { + luaL_error(L, "invalid player's savestate %d", which); + } + } + + //lets use lua to allocate the memory, since it is effectively a memory pool. + LuaSaveState *ss = new(lua_newuserdata(L,sizeof(LuaSaveState))) LuaSaveState(); + + if (which > 0) { + // Find an appropriate filename. This is OS specific, unfortunately. + // So I turned the filename selection code into my bitch. :) + // Numbers are 0 through 9. + if (newnumbering) //1-9, 10 = 0. QWERTY style. + ss->filename = FCEU_MakeFName(FCEUMKF_STATE, (which % 10), 0); + else // Note: Windows Slots 1-10 = Which 2-10, 1 + ss->filename = FCEU_MakeFName(FCEUMKF_STATE, which - 1, 0); + + // Only ensure load if the file exists + // Also makes it persistent, but files are like that + if (CheckFileExists(ss->filename.c_str())) + ss->ensureLoad(); + + } + else { + //char tempbuf[100] = "snluaXXXXXX"; + //filename = mktemp(tempbuf); + //doesnt work -^ + + //mbg 8/13/08 - this needs to be this way. we'll make a better system later: + ss->filename = tempnam(NULL, "snlua"); + ss->anonymous = true; + } + + + // The metatable we use, protected from Lua and contains garbage collection info and stuff. + lua_newtable(L); + + //// First, we must protect it + lua_pushstring(L, "FCEU Savestate"); + lua_setfield(L, -2, "__metatable"); + // + // + //// Now we need to save the file itself. + //lua_pushstring(L, filename.c_str()); + //lua_setfield(L, -2, "filename"); + + // If it's an anonymous savestate, we must delete the file from disk should it be gargage collected + //if (which < 0) { + lua_pushcfunction(L, savestate_gc); + lua_setfield(L, -2, "__gc"); + //} + + // Set the metatable + lua_setmetatable(L, -2); + + // Awesome. Return the object + return 1; +} + +// object savestate.object(int which = nil) +// +// Creates an object used for savestates. +// The object can be associated with a player-accessible savestate +// ("which" between 1 and 10) or not (which == nil). +// Uses more windows-friendly slot numbering +static int savestate_object(lua_State *L) { + // New Save Slot Numbers: + // 1-9 refer to 1-9, 10 refers to 0. QWERTY style. + return savestate_create_aliased(L,true); +} + +// object savestate.create(int which = nil) +// +// Creates an object used for savestates. +// The object can be associated with a player-accessible savestate +// ("which" between 1 and 10) or not (which == nil). +// Uses original slot numbering +static int savestate_create(lua_State *L) { + // Original Save Slot Numbers: + // 1-10, 1 refers to slot 0, 2-10 refer to 1-9 + return savestate_create_aliased(L,false); +} + + +// savestate.save(object state) +// +// Saves a state to the given object. +static int savestate_save(lua_State *L) { + + //char *filename = savestateobj2filename(L,1); + + LuaSaveState *ss = (LuaSaveState *)lua_touserdata(L, 1); + if (!ss) { + luaL_error(L, "Invalid savestate.save object"); + return 0; + } + + if(ss->data) delete ss->data; + ss->data = new EMUFILE_MEMORY(); + +// printf("saving %s\n", filename); + + // Save states are very expensive. They take time. + numTries--; + + FCEUSS_SaveMS(ss->data,Z_NO_COMPRESSION); + ss->data->fseek(0,SEEK_SET); + return 0; +} + +static int savestate_persist(lua_State *L) { + + LuaSaveState *ss = (LuaSaveState *)lua_touserdata(L, 1); + ss->persist(); + return 0; +} + +// savestate.load(object state) +// +// Loads the given state +static int savestate_load(lua_State *L) { + + //char *filename = savestateobj2filename(L,1); + + LuaSaveState *ss = (LuaSaveState *)lua_touserdata(L, 1); + + if (!ss) { + luaL_error(L, "Invalid savestate.load object"); + return 0; + } + + numTries--; + + /*if (!ss->data) { + luaL_error(L, "Invalid savestate.load data"); + return 0; + } */ + if (FCEUSS_LoadFP(ss->data,SSLOADPARAM_NOBACKUP)) + ss->data->fseek(0,SEEK_SET); + + return 0; + +} + +static int savestate_registersave(lua_State *L) { + + lua_settop(L,1); + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFORESAVE]); + lua_pushvalue(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFORESAVE]); + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; +} +static int savestate_registerload(lua_State *L) { + + lua_settop(L,1); + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTERLOAD]); + lua_pushvalue(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTERLOAD]); + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; +} + +static int savestate_loadscriptdata(lua_State *L) { + + const char *filename = savestateobj2filename(L,1); + + { + LuaSaveData saveData; + + char luaSaveFilename [512]; + strncpy(luaSaveFilename, filename, 512); + luaSaveFilename[512-(1+7/*strlen(".luasav")*/)] = '\0'; + strcat(luaSaveFilename, ".luasav"); + FILE* luaSaveFile = fopen(luaSaveFilename, "rb"); + if(luaSaveFile) + { + saveData.ImportRecords(luaSaveFile); + fclose(luaSaveFile); + + lua_settop(L, 0); + saveData.LoadRecord(L, LUA_DATARECORDKEY, (unsigned int)-1); + return lua_gettop(L); + } + } + return 0; +} + + +// int emu.framecount() +// +// Gets the frame counter +int emu_framecount(lua_State *L) { + + lua_pushinteger(L, FCEUMOV_GetFrame()); + return 1; +} + +// int emu.lagcount() +// +// Gets the current lag count +int emu_lagcount(lua_State *L) { + + lua_pushinteger(L, FCEUI_GetLagCount()); + return 1; +} + +// emu.lagged() +// +// Returns true if the game is currently on a lag frame +int emu_lagged (lua_State *L) { + + bool Lag_Frame = FCEUI_GetLagged(); + lua_pushboolean(L, Lag_Frame); + return 1; +} + +// emu.setlagflag(bool value) +// +// Returns true if the game is currently on a lag frame +int emu_setlagflag(lua_State *L) +{ + FCEUI_SetLagFlag(lua_toboolean(L, 1) == 1); + return 0; +} + +// boolean emu.emulating() +int emu_emulating(lua_State *L) { + lua_pushboolean(L, GameInfo != NULL); + return 1; +} + +// string movie.mode() +// +// Returns "taseditor", "record", "playback", "finished" or nil +int movie_mode(lua_State *L) +{ + if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) + lua_pushstring(L, "taseditor"); + else if (FCEUMOV_IsRecording()) + lua_pushstring(L, "record"); + else if (FCEUMOV_IsFinished()) + lua_pushstring(L, "finished"); //Note: this comes before playback since playback checks for finished as well + else if (FCEUMOV_IsPlaying()) + lua_pushstring(L, "playback"); + else + lua_pushnil(L); + return 1; +} + + +static int movie_rerecordcounting(lua_State *L) { + if (lua_gettop(L) == 0) + luaL_error(L, "no parameters specified"); + + skipRerecords = lua_toboolean(L,1); + return 0; +} + +// movie.stop() +// +// Stops movie playback/recording. Bombs out if movie is not running. +static int movie_stop(lua_State *L) { + if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying()) + luaL_error(L, "no movie"); + + FCEUI_StopMovie(); + return 0; + +} + +// movie.active() +// +//returns a bool value is there is a movie currently open +int movie_isactive (lua_State *L) { + + bool movieactive = (FCEUMOV_IsRecording() || FCEUMOV_IsPlaying()); + lua_pushboolean(L, movieactive); + return 1; +} + +// movie.recording() +int movie_isrecording (lua_State *L) { + + lua_pushboolean(L, FCEUMOV_IsRecording()); + return 1; +} + +// movie.playing() +int movie_isplaying (lua_State *L) { + + lua_pushboolean(L, FCEUMOV_IsPlaying()); + return 1; +} + +//movie.rerecordcount() +// +//returns the rerecord count of the current movie +static int movie_rerecordcount (lua_State *L) { + if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying() && !FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) + luaL_error(L, "No movie loaded."); + + lua_pushinteger(L, FCEUI_GetMovieRerecordCount()); + + return 1; +} + +//movie.length() +// +//returns an int value representing the total length of the current movie loaded + +static int movie_getlength (lua_State *L) { + if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying() && !FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) + luaL_error(L, "No movie loaded."); + + lua_pushinteger(L, FCEUI_GetMovieLength()); + + return 1; +} + +//movie.readonly +// +//returns true is emulator is in read-only mode, false if it is in read+write +static int movie_getreadonly (lua_State *L) { + lua_pushboolean(L, FCEUI_GetMovieToggleReadOnly()); + + return 1; +} + +//movie.setreadonly +// +//Sets readonly / read+write status +static int movie_setreadonly (lua_State *L) { + bool which = (lua_toboolean( L, 1 ) == 1); + FCEUI_SetMovieToggleReadOnly(which); + + return 0; +} + +//movie.getname +// +//returns the filename of the movie loaded +static int movie_getname (lua_State *L) { + + if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying() && !FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) + luaL_error(L, "No movie loaded."); + + std::string name = FCEUI_GetMovieName(); + lua_pushstring(L, name.c_str()); + return 1; +} + +//movie.getfilename +// +//returns the filename of movie loaded with no path +static int movie_getfilename (lua_State *L) { + + if (!FCEUMOV_IsRecording() && !FCEUMOV_IsPlaying() && !FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) + luaL_error(L, "No movie loaded."); + + std::string name = FCEUI_GetMovieName(); + int x = name.find_last_of("/\\") + 1; + if (x) + name = name.substr(x, name.length()-x); + lua_pushstring(L, name.c_str()); + return 1; +} + +//movie.replay +// +//calls the play movie from beginning function +static int movie_replay (lua_State *L) { + + FCEUI_MoviePlayFromBeginning(); + + return 0; +} + +//movie.ispoweron +// +//If movie is recorded from power-on +static int movie_ispoweron (lua_State *L) { + if (FCEUMOV_IsRecording() || FCEUMOV_IsPlaying()) { + return FCEUMOV_FromPoweron(); + } + else + return 0; +} + +//movie.isfromsavestate() +// +//If movie is recorded from a savestate +static int movie_isfromsavestate (lua_State *L) { + if (FCEUMOV_IsRecording() || FCEUMOV_IsPlaying()) { + return !FCEUMOV_FromPoweron(); + } + else + return 0; +} + + +#define LUA_SCREEN_WIDTH 256 +#define LUA_SCREEN_HEIGHT 240 + +// Common code by the gui library: make sure the screen array is ready +static void gui_prepare() { + if (!gui_data) + gui_data = (uint8*) FCEU_dmalloc(LUA_SCREEN_WIDTH*LUA_SCREEN_HEIGHT*4); + if (gui_used != GUI_USED_SINCE_LAST_DISPLAY) + memset(gui_data, 0, LUA_SCREEN_WIDTH*LUA_SCREEN_HEIGHT*4); + gui_used = GUI_USED_SINCE_LAST_DISPLAY; +} + +// pixform for lua graphics +#define BUILD_PIXEL_ARGB8888(A,R,G,B) (((int) (A) << 24) | ((int) (R) << 16) | ((int) (G) << 8) | (int) (B)) +#define DECOMPOSE_PIXEL_ARGB8888(PIX,A,R,G,B) { (A) = ((PIX) >> 24) & 0xff; (R) = ((PIX) >> 16) & 0xff; (G) = ((PIX) >> 8) & 0xff; (B) = (PIX) & 0xff; } +#define LUA_BUILD_PIXEL BUILD_PIXEL_ARGB8888 +#define LUA_DECOMPOSE_PIXEL DECOMPOSE_PIXEL_ARGB8888 +#define LUA_PIXEL_A(PIX) (((PIX) >> 24) & 0xff) +#define LUA_PIXEL_R(PIX) (((PIX) >> 16) & 0xff) +#define LUA_PIXEL_G(PIX) (((PIX) >> 8) & 0xff) +#define LUA_PIXEL_B(PIX) ((PIX) & 0xff) + +template static void swap(T &one, T &two) { + T temp = one; + one = two; + two = temp; +} + +// write a pixel to buffer +static inline void blend32(uint32 *dstPixel, uint32 colour) +{ + uint8 *dst = (uint8*) dstPixel; + int a, r, g, b; + LUA_DECOMPOSE_PIXEL(colour, a, r, g, b); + + if (a == 255 || dst[3] == 0) { + // direct copy + *(uint32*)(dst) = colour; + } + else if (a == 0) { + // do not copy + } + else { + // alpha-blending + int a_dst = ((255 - a) * dst[3] + 128) / 255; + int a_new = a + a_dst; + + dst[0] = (uint8) ((( dst[0] * a_dst + b * a) + (a_new / 2)) / a_new); + dst[1] = (uint8) ((( dst[1] * a_dst + g * a) + (a_new / 2)) / a_new); + dst[2] = (uint8) ((( dst[2] * a_dst + r * a) + (a_new / 2)) / a_new); + dst[3] = (uint8) a_new; + } +} +// check if a pixel is in the lua canvas +static inline bool gui_check_boundary(int x, int y) { + return !(x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= LUA_SCREEN_HEIGHT); +} + +// write a pixel to gui_data (do not check boundaries for speedup) +static inline void gui_drawpixel_fast(int x, int y, uint32 colour) { + //gui_prepare(); + blend32((uint32*) &gui_data[(y*LUA_SCREEN_WIDTH+x)*4], colour); +} + +// write a pixel to gui_data (check boundaries) +static inline void gui_drawpixel_internal(int x, int y, uint32 colour) { + //gui_prepare(); + if (gui_check_boundary(x, y)) + gui_drawpixel_fast(x, y, colour); +} + +// draw a line on gui_data (checks boundaries) +static void gui_drawline_internal(int x1, int y1, int x2, int y2, bool lastPixel, uint32 colour) { + + //gui_prepare(); + + // Note: New version of Bresenham's Line Algorithm + // http://groups.google.co.jp/group/rec.games.roguelike.development/browse_thread/thread/345f4c42c3b25858/29e07a3af3a450e6?show_docid=29e07a3af3a450e6 + + int swappedx = 0; + int swappedy = 0; + + int xtemp = x1-x2; + int ytemp = y1-y2; + if (xtemp == 0 && ytemp == 0) { + gui_drawpixel_internal(x1, y1, colour); + return; + } + if (xtemp < 0) { + xtemp = -xtemp; + swappedx = 1; + } + if (ytemp < 0) { + ytemp = -ytemp; + swappedy = 1; + } + + int delta_x = xtemp << 1; + int delta_y = ytemp << 1; + + signed char ix = x1 > x2?1:-1; + signed char iy = y1 > y2?1:-1; + + if (lastPixel) + gui_drawpixel_internal(x2, y2, colour); + + if (delta_x >= delta_y) { + int error = delta_y - (delta_x >> 1); + + while (x2 != x1) { + if (error == 0 && !swappedx) + gui_drawpixel_internal(x2+ix, y2, colour); + if (error >= 0) { + if (error || (ix > 0)) { + y2 += iy; + error -= delta_x; + } + } + x2 += ix; + gui_drawpixel_internal(x2, y2, colour); + if (error == 0 && swappedx) + gui_drawpixel_internal(x2, y2+iy, colour); + error += delta_y; + } + } + else { + int error = delta_x - (delta_y >> 1); + + while (y2 != y1) { + if (error == 0 && !swappedy) + gui_drawpixel_internal(x2, y2+iy, colour); + if (error >= 0) { + if (error || (iy > 0)) { + x2 += ix; + error -= delta_y; + } + } + y2 += iy; + gui_drawpixel_internal(x2, y2, colour); + if (error == 0 && swappedy) + gui_drawpixel_internal(x2+ix, y2, colour); + error += delta_x; + } + } +} + +// draw a rect on gui_data +static void gui_drawbox_internal(int x1, int y1, int x2, int y2, uint32 colour) { + + if (x1 > x2) + swap(x1, x2); + if (y1 > y2) + swap(y1, y2); + if (x1 < 0) + x1 = -1; + if (y1 < 0) + y1 = -1; + if (x2 >= LUA_SCREEN_WIDTH) + x2 = LUA_SCREEN_WIDTH; + if (y2 >= LUA_SCREEN_HEIGHT) + y2 = LUA_SCREEN_HEIGHT; + + //gui_prepare(); + + gui_drawline_internal(x1, y1, x2, y1, true, colour); + gui_drawline_internal(x1, y2, x2, y2, true, colour); + gui_drawline_internal(x1, y1, x1, y2, true, colour); + gui_drawline_internal(x2, y1, x2, y2, true, colour); +} + +// draw fill rect on gui_data +static void gui_fillbox_internal(int x1, int y1, int x2, int y2, uint32 colour) +{ + if (x1 > x2) + std::swap(x1, x2); + if (y1 > y2) + std::swap(y1, y2); + if (x1 < 0) + x1 = 0; + if (y1 < 0) + y1 = 0; + if (x2 >= LUA_SCREEN_WIDTH) + x2 = LUA_SCREEN_WIDTH - 1; + if (y2 >= LUA_SCREEN_HEIGHT) + y2 = LUA_SCREEN_HEIGHT - 1; + + //gui_prepare(); + int ix, iy; + for (iy = y1; iy <= y2; iy++) + { + for (ix = x1; ix <= x2; ix++) + { + gui_drawpixel_fast(ix, iy, colour); + } + } +} + +enum +{ + GUI_COLOUR_CLEAR + /* + , GUI_COLOUR_WHITE, GUI_COLOUR_BLACK, GUI_COLOUR_GREY + , GUI_COLOUR_RED, GUI_COLOUR_GREEN, GUI_COLOUR_BLUE + */ +}; +/** + * Returns an index approximating an RGB colour. + * TODO: This is easily improvable in terms of speed and probably + * quality of matches. (gd overlay & transparency code call it a lot.) + * With effort we could also cheat and map indices 0x08 .. 0x3F + * ourselves. + */ +static uint8 gui_colour_rgb(uint8 r, uint8 g, uint8 b) { + static uint8 index_lookup[1 << (3+3+3)]; + int k; + + if (!gui_saw_current_palette) + { + memset(index_lookup, GUI_COLOUR_CLEAR, sizeof(index_lookup)); + gui_saw_current_palette = TRUE; + } + + k = ((r & 0xE0) << 1) | ((g & 0xE0) >> 2) | ((b & 0xE0) >> 5); + uint16 test, best = GUI_COLOUR_CLEAR; + uint32 best_score = 0xffffffffu, test_score; + if (index_lookup[k] != GUI_COLOUR_CLEAR) return index_lookup[k]; + for (test = 0; test < 0xff; test++) + { + uint8 tr, tg, tb; + if (test == GUI_COLOUR_CLEAR) continue; + FCEUD_GetPalette(test, &tr, &tg, &tb); + test_score = abs(r - tr) * 66 + + abs(g - tg) * 129 + + abs(b - tb) * 25; + if (test_score < best_score) best_score = test_score, best = test; + } + index_lookup[k] = best; + return best; +} + +void FCEU_LuaUpdatePalette() +{ + gui_saw_current_palette = FALSE; +} + +// Helper for a simple hex parser +static int hex2int(lua_State *L, char c) { + if (c >= '0' && c <= '9') + return c-'0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return luaL_error(L, "invalid hex in colour"); +} + +static const struct ColorMapping +{ + const char* name; + unsigned int value; +} +s_colorMapping [] = +{ + {"white", 0xFFFFFFFF}, + {"black", 0x000000FF}, + {"clear", 0x00000000}, + {"gray", 0x7F7F7FFF}, + {"grey", 0x7F7F7FFF}, + {"red", 0xFF0000FF}, + {"orange", 0xFF7F00FF}, + {"yellow", 0xFFFF00FF}, + {"chartreuse",0x7FFF00FF}, + {"green", 0x00FF00FF}, + {"teal", 0x00FF7FFF}, + {"cyan" , 0x00FFFFFF}, + {"blue", 0x0000FFFF}, + {"purple", 0x7F00FFFF}, + {"magenta", 0xFF00FFFF}, +}; + +/** + * Converts an integer or a string on the stack at the given + * offset to a RGB32 colour. Several encodings are supported. + * The user may construct their own RGB value, given a simple colour name, + * or an HTML-style "#09abcd" colour. 16 bit reduction doesn't occur at this time. + * NES palettes added with notation "P00" to "P3F". "P40" to "P7F" denote LUA palettes. + */ +static inline bool str2colour(uint32 *colour, lua_State *L, const char *str) { + if (str[0] == '#') { + int color; + sscanf(str+1, "%X", &color); + int len = strlen(str+1); + int missing = std::max(0, 8-len); + color <<= missing << 2; + if(missing >= 2) color |= 0xFF; + *colour = color; + return true; + } + else if (str[0] == 'P') { + uint8 palette; + uint8 tr, tg, tb; + + if (strlen(str+1) == 2) { + palette = ((hex2int(L, str[1]) * 0x10) + hex2int(L, str[2])); + } else if (strlen(str+1) == 1) { + palette = (hex2int(L, str[1])); + } else { + luaL_error(L, "palettes are defined with P## hex notion"); + return false; + } + + if (palette > 0x7F) { + luaL_error(L, "palettes range from P00 to P7F"); + return false; + } + + FCEUD_GetPalette(palette + 0x80, &tr, &tg, &tb); + // Feeding it RGBA, because it will spit out the right value for me + *colour = LUA_BUILD_PIXEL(tr, tg, tb, 0xFF); + return true; + } + else { + if(!strnicmp(str, "rand", 4)) { + *colour = ((rand()*255/RAND_MAX) << 8) | ((rand()*255/RAND_MAX) << 16) | ((rand()*255/RAND_MAX) << 24) | 0xFF; + return true; + } + for(int i = 0; i < sizeof(s_colorMapping)/sizeof(*s_colorMapping); i++) { + if(!stricmp(str,s_colorMapping[i].name)) { + *colour = s_colorMapping[i].value; + return true; + } + } + } + return false; +} +static inline uint32 gui_getcolour_wrapped(lua_State *L, int offset, bool hasDefaultValue, uint32 defaultColour) { + switch (lua_type(L,offset)) { + case LUA_TSTRING: + { + const char *str = lua_tostring(L,offset); + uint32 colour; + + if (str2colour(&colour, L, str)) + return colour; + else { + if (hasDefaultValue) + return defaultColour; + else + return luaL_error(L, "unknown colour %s", str); + } + } + case LUA_TNUMBER: + { + uint32 colour = (uint32) lua_tointeger(L,offset); + return colour; + } + case LUA_TTABLE: + { + int color = 0xFF; + lua_pushnil(L); // first key + int keyIndex = lua_gettop(L); + int valueIndex = keyIndex + 1; + bool first = true; + while(lua_next(L, offset)) + { + bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING); + bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER); + int key = keyIsString ? tolower(*lua_tostring(L, keyIndex)) : (keyIsNumber ? lua_tointeger(L, keyIndex) : 0); + int value = lua_tointeger(L, valueIndex); + if(value < 0) value = 0; + if(value > 255) value = 255; + switch(key) + { + case 1: case 'r': color |= value << 24; break; + case 2: case 'g': color |= value << 16; break; + case 3: case 'b': color |= value << 8; break; + case 4: case 'a': color = (color & ~0xFF) | value; break; + } + lua_pop(L, 1); + } + return color; + } break; + case LUA_TFUNCTION: + luaL_error(L, "invalid colour"); // NYI + return 0; + default: + if (hasDefaultValue) + return defaultColour; + else + return luaL_error(L, "invalid colour"); + } +} +static uint32 gui_getcolour(lua_State *L, int offset) { + uint32 colour; + int a, r, g, b; + + colour = gui_getcolour_wrapped(L, offset, false, 0); + a = ((colour & 0xff) * transparencyModifier) / 255; + if (a > 255) a = 255; + b = (colour >> 8) & 0xff; + g = (colour >> 16) & 0xff; + r = (colour >> 24) & 0xff; + return LUA_BUILD_PIXEL(a, r, g, b); +} +static uint32 gui_optcolour(lua_State *L, int offset, uint32 defaultColour) { + uint32 colour; + int a, r, g, b; + uint8 defA, defB, defG, defR; + + LUA_DECOMPOSE_PIXEL(defaultColour, defA, defR, defG, defB); + defaultColour = (defR << 24) | (defG << 16) | (defB << 8) | defA; + + colour = gui_getcolour_wrapped(L, offset, true, defaultColour); + a = ((colour & 0xff) * transparencyModifier) / 255; + if (a > 255) a = 255; + b = (colour >> 8) & 0xff; + g = (colour >> 16) & 0xff; + r = (colour >> 24) & 0xff; + return LUA_BUILD_PIXEL(a, r, g, b); +} + +// gui.pixel(x,y,colour) +static int gui_pixel(lua_State *L) { + + int x = luaL_checkinteger(L, 1); + int y = luaL_checkinteger(L,2); + + uint32 colour = gui_getcolour(L,3); + +// if (!gui_check_boundary(x, y)) +// luaL_error(L,"bad coordinates"); + + gui_prepare(); + + gui_drawpixel_internal(x, y, colour); + + return 0; +} + +// Usage: +// local r,g,b,a = gui.getpixel(255, 223) +// Gets the LUA set pixel color +static int gui_getpixel(lua_State *L) { + + int x = luaL_checkinteger(L, 1); + int y = luaL_checkinteger(L,2); + + int r, g, b, a; + + if (!gui_check_boundary(x, y)) + luaL_error(L,"bad coordinates. Use 0-%d x 0-%d", LUA_SCREEN_WIDTH - 1, LUA_SCREEN_HEIGHT - 1); + + if (!gui_data) { + // Return all 0s, including for alpha. + // If alpha == 0, there was no color data for that spot + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + return 4; + } + + //uint8 *dst = (uint8*) &gui_data[(y*LUA_SCREEN_WIDTH+x)*4]; + + //uint32 color = *(uint32*) &gui_data[(y*LUA_SCREEN_WIDTH+x)*4]; + + LUA_DECOMPOSE_PIXEL(*(uint32*) &gui_data[(y*LUA_SCREEN_WIDTH+x)*4], a, r, g, b); + + lua_pushinteger(L, r); + lua_pushinteger(L, g); + lua_pushinteger(L, b); + lua_pushinteger(L, a); + return 4; + +} + +// Usage: +// local r,g,b,palette = gui.getpixel(255, 255) +// Gets the screen pixel color +// Palette will be 254 on error +static int emu_getscreenpixel(lua_State *L) { + + int x = luaL_checkinteger(L, 1); + int y = luaL_checkinteger(L,2); + bool getemuscreen = (lua_toboolean(L,3) == 1); + + int r, g, b; + int palette; + + if (((x < 0) || (x > 255)) || ((y < 0) || (y > 239))) { + luaL_error(L,"bad coordinates. Use 0-255 x 0-239"); + + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + lua_pushinteger(L, 254); + return 4; + } + + if (!XBuf) { + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + lua_pushinteger(L, 254); + return 4; + } + + uint32 pixelinfo = GetScreenPixel(x,y,getemuscreen); + + LUA_DECOMPOSE_PIXEL(pixelinfo, palette, r, g, b); + palette = GetScreenPixelPalette(x,y,getemuscreen); + + lua_pushinteger(L, r); + lua_pushinteger(L, g); + lua_pushinteger(L, b); + lua_pushinteger(L, palette); + return 4; + +} + +// gui.line(x1,y1,x2,y2,color,skipFirst) +static int gui_line(lua_State *L) { + + int x1,y1,x2,y2; + uint32 color; + x1 = luaL_checkinteger(L,1); + y1 = luaL_checkinteger(L,2); + x2 = luaL_checkinteger(L,3); + y2 = luaL_checkinteger(L,4); + color = gui_optcolour(L,5,LUA_BUILD_PIXEL(255, 255, 255, 255)); + int skipFirst = lua_toboolean(L,6); + + gui_prepare(); + + gui_drawline_internal(x2, y2, x1, y1, !skipFirst, color); + + return 0; +} + +// gui.box(x1, y1, x2, y2, fillcolor, outlinecolor) +static int gui_box(lua_State *L) { + + int x1,y1,x2,y2; + uint32 fillcolor; + uint32 outlinecolor; + + x1 = luaL_checkinteger(L,1); + y1 = luaL_checkinteger(L,2); + x2 = luaL_checkinteger(L,3); + y2 = luaL_checkinteger(L,4); + fillcolor = gui_optcolour(L,5,LUA_BUILD_PIXEL(63, 255, 255, 255)); + outlinecolor = gui_optcolour(L,6,LUA_BUILD_PIXEL(255, LUA_PIXEL_R(fillcolor), LUA_PIXEL_G(fillcolor), LUA_PIXEL_B(fillcolor))); + + if (x1 > x2) + std::swap(x1, x2); + if (y1 > y2) + std::swap(y1, y2); + + gui_prepare(); + + gui_drawbox_internal(x1, y1, x2, y2, outlinecolor); + if ((x2 - x1) >= 2 && (y2 - y1) >= 2) + gui_fillbox_internal(x1+1, y1+1, x2-1, y2-1, fillcolor); + + return 0; +} + +// (old) gui.box(x1, y1, x2, y2, color) +static int gui_box_old(lua_State *L) { + + int x1,y1,x2,y2; + uint32 colour; + + x1 = luaL_checkinteger(L,1); + y1 = luaL_checkinteger(L,2); + x2 = luaL_checkinteger(L,3); + y2 = luaL_checkinteger(L,4); + colour = gui_getcolour(L,5); + +// if (!gui_check_boundary(x1, y1)) +// luaL_error(L,"bad coordinates"); +// +// if (!gui_check_boundary(x2, y2)) +// luaL_error(L,"bad coordinates"); + + gui_prepare(); + + gui_drawbox_internal(x1, y1, x2, y2, colour); + + return 0; +} + +static int gui_parsecolor(lua_State *L) +{ + int r, g, b, a; + uint32 color = gui_getcolour(L,1); + LUA_DECOMPOSE_PIXEL(color, a, r, g, b); + lua_pushinteger(L, r); + lua_pushinteger(L, g); + lua_pushinteger(L, b); + lua_pushinteger(L, a); + return 4; +} + + +// gui.savescreenshotas() +// +// Causes FCEUX to write a screenshot to a file based on a received filename, caution: will overwrite existing screenshot files +// +// Unconditionally retrns 1; any failure in taking a screenshot would be reported on-screen +// from the function ReallySnap(). +static int gui_savescreenshotas(lua_State *L) { + const char* name = NULL; + size_t l; + name = luaL_checklstring(L,1,&l); + lua_pushstring(L, name); + if (name) + FCEUI_SetSnapshotAsName(name); + else + luaL_error(L,"gui.savesnapshotas must have a string parameter"); + FCEUI_SaveSnapshotAs(); + return 1; +} + + +// gui.savescreenshot() +// +// Causes FCEUX to write a screenshot to a file as if the user pressed the associated hotkey. +// +// Unconditionally retrns 1; any failure in taking a screenshot would be reported on-screen +// from the function ReallySnap(). +static int gui_savescreenshot(lua_State *L) { + FCEUI_SaveSnapshot(); + return 1; +} + +// gui.gdscreenshot() +// +// Returns a screen shot as a string in gd's v1 file format. +// This allows us to make screen shots available without gd installed locally. +// Users can also just grab pixels via substring selection. +// +// I think... Does lua support grabbing byte values from a string? // yes, string.byte(str,offset) +// Well, either way, just install gd and do what you like with it. +// It really is easier that way. +// example: gd.createFromGdStr(gui.gdscreenshot()):png("outputimage.png") +static int gui_gdscreenshot(lua_State *L) { + + int width = LUA_SCREEN_WIDTH; + int height = LUA_SCREEN_HEIGHT; + + int size = 11 + width * height * 4; + char* str = new char[size+1]; + str[size] = 0; + unsigned char* ptr = (unsigned char*)str; + + // GD format header for truecolor image (11 bytes) + *ptr++ = (65534 >> 8) & 0xFF; + *ptr++ = (65534 ) & 0xFF; + *ptr++ = (width >> 8) & 0xFF; + *ptr++ = (width ) & 0xFF; + *ptr++ = (height >> 8) & 0xFF; + *ptr++ = (height ) & 0xFF; + *ptr++ = 1; + *ptr++ = 255; + *ptr++ = 255; + *ptr++ = 255; + *ptr++ = 255; + + for (int y=0; y < height; y++) { + for (int x=0; x < width; x++) { + uint8 index = XBuf[(y)*256 + x]; + + // Write A,R,G,B (alpha=0 for us): + *ptr = 0; + FCEUD_GetPalette(index, ptr + 1, ptr + 2, ptr + 3); + ptr += 4; + } + } + + lua_pushlstring(L, str, size); + delete[] str; + return 1; +} + +// gui.opacity(number alphaValue) +// sets the transparency of subsequent draw calls +// 0.0 is completely transparent, 1.0 is completely opaque +// non-integer values are supported and meaningful, as are values greater than 1.0 +// it is not necessary to use this function to get transparency (or the less-recommended gui.transparency() either), +// because you can provide an alpha value in the color argument of each draw call. +// however, it can be convenient to be able to globally modify the drawing transparency +static int gui_setopacity(lua_State *L) { + double opacF = luaL_checknumber(L,1); + transparencyModifier = (int) (opacF * 255); + if (transparencyModifier < 0) + transparencyModifier = 0; + return 0; +} + +// gui.transparency(int strength) +// +// 0 = solid, +static int gui_transparency(lua_State *L) { + double trans = luaL_checknumber(L,1); + transparencyModifier = (int) ((4.0 - trans) / 4.0 * 255); + if (transparencyModifier < 0) + transparencyModifier = 0; + return 0; +} + + +static const uint32 Small_Font_Data[] = +{ + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 32 + 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 33 ! + 0x00000000, 0x00040002, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 34 " + 0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 35 # + 0x00000000, 0x00040300, 0x00000403, 0x00000500, 0x00070600, 0x00000706, 0x00000000, // 36 $ + 0x00000000, 0x00000002, 0x00050000, 0x00000500, 0x00000005, 0x00080000, 0x00000000, // 37 % + 0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00080700, 0x00000000, // 38 & + 0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 39 ' + 0x00000000, 0x00000300, 0x00000003, 0x00000004, 0x00000005, 0x00000700, 0x00000000, // 40 ( + 0x00000000, 0x00000300, 0x00050000, 0x00060000, 0x00070000, 0x00000700, 0x00000000, // 41 ) + 0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00080006, 0x00000000, // 42 * + 0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00000000, 0x00000000, // 43 + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000600, 0x00000700, 0x00000007, // 44 , + 0x00000000, 0x00000000, 0x00000000, 0x00060504, 0x00000000, 0x00000000, 0x00000000, // 45 - + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 46 . + 0x00030000, 0x00040000, 0x00000400, 0x00000500, 0x00000005, 0x00000006, 0x00000000, // 47 / + 0x00000000, 0x00000300, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 48 0 + 0x00000000, 0x00000300, 0x00000403, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 49 1 + 0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 50 2 + 0x00000000, 0x00000302, 0x00050000, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 51 3 + 0x00000000, 0x00000300, 0x00000003, 0x00060004, 0x00070605, 0x00080000, 0x00000000, // 52 4 + 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 53 5 + 0x00000000, 0x00000300, 0x00000003, 0x00000504, 0x00070005, 0x00000700, 0x00000000, // 54 6 + 0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 55 7 + 0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00000700, 0x00000000, // 56 8 + 0x00000000, 0x00000300, 0x00050003, 0x00060500, 0x00070000, 0x00000700, 0x00000000, // 57 9 + 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 58 : + 0x00000000, 0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000700, 0x00000007, // 59 ; + 0x00000000, 0x00040000, 0x00000400, 0x00000004, 0x00000600, 0x00080000, 0x00000000, // 60 < + 0x00000000, 0x00000000, 0x00050403, 0x00000000, 0x00070605, 0x00000000, 0x00000000, // 61 = + 0x00000000, 0x00000002, 0x00000400, 0x00060000, 0x00000600, 0x00000006, 0x00000000, // 62 > + 0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 63 ? + 0x00000000, 0x00000300, 0x00050400, 0x00060004, 0x00070600, 0x00000000, 0x00000000, // 64 @ + 0x00000000, 0x00000300, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 65 A + 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 66 B + 0x00000000, 0x00040300, 0x00000003, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 67 C + 0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00000706, 0x00000000, // 68 D + 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00080706, 0x00000000, // 69 E + 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 70 F + 0x00000000, 0x00040300, 0x00000003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 71 G + 0x00000000, 0x00040002, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 72 H + 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 73 I + 0x00000000, 0x00040000, 0x00050000, 0x00060000, 0x00070005, 0x00000700, 0x00000000, // 74 J + 0x00000000, 0x00040002, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 75 K + 0x00000000, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00080706, 0x00000000, // 76 l + 0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 77 M + 0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 78 N + 0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 79 O + 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 80 P + 0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00090000, // 81 Q + 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 82 R + 0x00000000, 0x00040300, 0x00000003, 0x00000500, 0x00070000, 0x00000706, 0x00000000, // 83 S + 0x00000000, 0x00040302, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 84 T + 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 85 U + 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000000, // 86 V + 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 87 W + 0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 88 X + 0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 89 Y + 0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 90 Z + 0x00000000, 0x00040300, 0x00000400, 0x00000500, 0x00000600, 0x00080700, 0x00000000, // 91 [ + 0x00000000, 0x00000002, 0x00000400, 0x00000500, 0x00070000, 0x00080000, 0x00000000, // 92 '\' + 0x00000000, 0x00000302, 0x00000400, 0x00000500, 0x00000600, 0x00000706, 0x00000000, // 93 ] + 0x00000000, 0x00000300, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 94 ^ + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080706, 0x00000000, // 95 _ + 0x00000000, 0x00000002, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 96 ` + 0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 97 a + 0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 98 b + 0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 99 c + 0x00000000, 0x00040000, 0x00050000, 0x00060500, 0x00070005, 0x00080700, 0x00000000, // 100 d + 0x00000000, 0x00000000, 0x00050400, 0x00060504, 0x00000005, 0x00080700, 0x00000000, // 101 e + 0x00000000, 0x00040300, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 102 f + 0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070600, 0x00080000, 0x00000807, // 103 g + 0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 104 h + 0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 105 i + 0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000007, // 106 j + 0x00000000, 0x00000002, 0x00000003, 0x00060004, 0x00000605, 0x00080006, 0x00000000, // 107 k + 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 108 l + 0x00000000, 0x00000000, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 109 m + 0x00000000, 0x00000000, 0x00000403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 110 n + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 111 o + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00000605, 0x00000006, 0x00000007, // 112 p + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070600, 0x00080000, 0x00090000, // 113 q + 0x00000000, 0x00000000, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 114 r + 0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00070600, 0x00000706, 0x00000000, // 115 s + 0x00000000, 0x00000300, 0x00050403, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 116 t + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 117 u + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 118 v + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 119 w + 0x00000000, 0x00000000, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 120 x + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000007, // 121 y + 0x00000000, 0x00000000, 0x00050403, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 122 z + 0x00000000, 0x00040300, 0x00000400, 0x00000504, 0x00000600, 0x00080700, 0x00000000, // 123 { + 0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000600, 0x00000700, 0x00000000, // 124 | + 0x00000000, 0x00000302, 0x00000400, 0x00060500, 0x00000600, 0x00000706, 0x00000000, // 125 } + 0x00000000, 0x00000302, 0x00050000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 126 ~ + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070605, 0x00000000, 0x00000000, // 127  + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static void PutTextInternal (const char *str, int len, short x, short y, int color, int backcolor) +{ + int Opac = (color >> 24) & 0xFF; + int backOpac = (backcolor >> 24) & 0xFF; + int origX = x; + + if(!Opac && !backOpac) + return; + + while(*str && len && y < LUA_SCREEN_HEIGHT) + { + int c = *str++; + while (x > LUA_SCREEN_WIDTH && c != '\n') { + c = *str; + if (c == '\0') + break; + str++; + } + if(c == '\n') + { + x = origX; + y += 8; + continue; + } + else if(c == '\t') // just in case + { + const int tabSpace = 8; + x += (tabSpace-(((x-origX)/4)%tabSpace))*4; + continue; + } + if((unsigned int)(c-32) >= 96) + continue; + const unsigned char* Cur_Glyph = (const unsigned char*)&Small_Font_Data + (c-32)*7*4; + + for(int y2 = 0; y2 < 8; y2++) + { + unsigned int glyphLine = *((unsigned int*)Cur_Glyph + y2); + for(int x2 = -1; x2 < 4; x2++) + { + int shift = x2 << 3; + int mask = 0xFF << shift; + int intensity = (glyphLine & mask) >> shift; + + if(intensity && x2 >= 0 && y2 < 7) + { + //int xdraw = std::max(0,std::min(LUA_SCREEN_WIDTH - 1,x+x2)); + //int ydraw = std::max(0,std::min(LUA_SCREEN_HEIGHT - 1,y+y2)); + //gui_drawpixel_fast(xdraw, ydraw, color); + gui_drawpixel_internal(x+x2, y+y2, color); + } + else if(backOpac) + { + for(int y3 = std::max(0,y2-1); y3 <= std::min(6,y2+1); y3++) + { + unsigned int glyphLine = *((unsigned int*)Cur_Glyph + y3); + for(int x3 = std::max(0,x2-1); x3 <= std::min(3,x2+1); x3++) + { + int shift = x3 << 3; + int mask = 0xFF << shift; + intensity |= (glyphLine & mask) >> shift; + if (intensity) + goto draw_outline; // speedup? + } + } +draw_outline: + if(intensity) + { + //int xdraw = std::max(0,std::min(LUA_SCREEN_WIDTH - 1,x+x2)); + //int ydraw = std::max(0,std::min(LUA_SCREEN_HEIGHT - 1,y+y2)); + //gui_drawpixel_fast(xdraw, ydraw, backcolor); + gui_drawpixel_internal(x+x2, y+y2, backcolor); + } + } + } + } + + x += 4; + len--; + } +} + +static int strlinelen(const char* string) +{ + const char* s = string; + while(*s && *s != '\n') + s++; + if(*s) + s++; + return s - string; +} + +static void LuaDisplayString (const char *string, int y, int x, uint32 color, uint32 outlineColor) +{ + if(!string) + return; + + gui_prepare(); + + PutTextInternal(string, strlen(string), x, y, color, outlineColor); +/* + const char* ptr = string; + while(*ptr && y < LUA_SCREEN_HEIGHT) + { + int len = strlinelen(ptr); + int skip = 0; + if(len < 1) len = 1; + + // break up the line if it's too long to display otherwise + if(len > 63) + { + len = 63; + const char* ptr2 = ptr + len-1; + for(int j = len-1; j; j--, ptr2--) + { + if(*ptr2 == ' ' || *ptr2 == '\t') + { + len = j; + skip = 1; + break; + } + } + } + + int xl = 0; + int yl = 0; + int xh = (LUA_SCREEN_WIDTH - 1 - 1) - 4*len; + int yh = LUA_SCREEN_HEIGHT - 1; + int x2 = std::min(std::max(x,xl),xh); + int y2 = std::min(std::max(y,yl),yh); + + PutTextInternal(ptr,len,x2,y2,color,outlineColor); + + ptr += len + skip; + y += 8; + } +*/ +} + + +static uint8 FCEUFont[792] = +{ + 6, 0, 0, 0, 0, 0, 0, 0, // 0x20 - Spacebar + 3, 64, 64, 64, 64, 64, 0, 64, + 5, 80, 80, 80, 0, 0, 0, 0, + 6, 80, 80,248, 80,248, 80, 80, + 6, 32,120,160,112, 40,240, 32, + 6, 64,168, 80, 32, 80,168, 16, + 6, 96,144,160, 64,168,144,104, + 3, 64, 64, 0, 0, 0, 0, 0, + 4, 32, 64, 64, 64, 64, 64, 32, + 4, 64, 32, 32, 32, 32, 32, 64, + 6, 0, 80, 32,248, 32, 80, 0, + 6, 0, 32, 32,248, 32, 32, 0, + 3, 0, 0, 0, 0, 0, 64,128, + 5, 0, 0, 0,240, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 64, + 5, 16, 16, 32, 32, 32, 64, 64, + 6,112,136,136,136,136,136,112, // 0x30 - 0 + 6, 32, 96, 32, 32, 32, 32, 32, + 6,112,136, 8, 48, 64,128,248, + 6,112,136, 8, 48, 8,136,112, + 6, 16, 48, 80,144,248, 16, 16, + 6,248,128,128,240, 8, 8,240, + 6, 48, 64,128,240,136,136,112, + 6,248, 8, 16, 16, 32, 32, 32, + 6,112,136,136,112,136,136,112, + 6,112,136,136,120, 8, 16, 96, + 3, 0, 0, 64, 0, 0, 64, 0, + 3, 0, 0, 64, 0, 0, 64,128, + 4, 0, 32, 64,128, 64, 32, 0, + 5, 0, 0,240, 0,240, 0, 0, + 4, 0,128, 64, 32, 64,128, 0, + 6,112,136, 8, 16, 32, 0, 32, // 0x3F - ? + 6,112,136,136,184,176,128,112, // 0x40 - @ + 6,112,136,136,248,136,136,136, // 0x41 - A + 6,240,136,136,240,136,136,240, + 6,112,136,128,128,128,136,112, + 6,224,144,136,136,136,144,224, + 6,248,128,128,240,128,128,248, + 6,248,128,128,240,128,128,128, + 6,112,136,128,184,136,136,120, + 6,136,136,136,248,136,136,136, + 4,224, 64, 64, 64, 64, 64,224, + 6, 8, 8, 8, 8, 8,136,112, + 6,136,144,160,192,160,144,136, + 6,128,128,128,128,128,128,248, + 6,136,216,168,168,136,136,136, + 6,136,136,200,168,152,136,136, + 7, 48, 72,132,132,132, 72, 48, + 6,240,136,136,240,128,128,128, + 6,112,136,136,136,168,144,104, + 6,240,136,136,240,144,136,136, + 6,112,136,128,112, 8,136,112, + 6,248, 32, 32, 32, 32, 32, 32, + 6,136,136,136,136,136,136,112, + 6,136,136,136, 80, 80, 32, 32, + 6,136,136,136,136,168,168, 80, + 6,136,136, 80, 32, 80,136,136, + 6,136,136, 80, 32, 32, 32, 32, + 6,248, 8, 16, 32, 64,128,248, + 3,192,128,128,128,128,128,192, + 5, 64, 64, 32, 32, 32, 16, 16, + 3,192, 64, 64, 64, 64, 64,192, + 4, 64,160, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0,248, + 3,128, 64, 0, 0, 0, 0, 0, + 5, 0, 0, 96, 16,112,144,112, // 0x61 - a + 5,128,128,224,144,144,144,224, + 5, 0, 0,112,128,128,128,112, + 5, 16, 16,112,144,144,144,112, + 5, 0, 0, 96,144,240,128,112, + 5, 48, 64,224, 64, 64, 64, 64, + 5, 0,112,144,144,112, 16,224, + 5,128,128,224,144,144,144,144, + 2,128, 0,128,128,128,128,128, + 4, 32, 0, 32, 32, 32, 32,192, + 5,128,128,144,160,192,160,144, + 2,128,128,128,128,128,128,128, + 6, 0, 0,208,168,168,168,168, + 5, 0, 0,224,144,144,144,144, + 5, 0, 0, 96,144,144,144, 96, + 5, 0, 0,224,144,144,224,128, + 5, 0, 0,112,144,144,112, 16, + 5, 0, 0,176,192,128,128,128, + 5, 0, 0,112,128, 96, 16,224, + 4, 64, 64,224, 64, 64, 64, 32, + 5, 0, 0,144,144,144,144,112, + 5, 0, 0,144,144,144,160,192, + 6, 0, 0,136,136,168,168, 80, + 5, 0, 0,144,144, 96,144,144, + 5, 0,144,144,144,112, 16, 96, + 5, 0, 0,240, 32, 64,128,240, + 4, 32, 64, 64,128, 64, 64, 32, + 3, 64, 64, 64, 64, 64, 64, 64, + 4,128, 64, 64, 32, 64, 64,128, + 6, 0,104,176, 0, 0, 0, 0 +}; + +static int FixJoedChar(uint8 ch) +{ + int c = ch; c -= 32; + return (c < 0 || c > 98) ? 0 : c; +} +static int JoedCharWidth(uint8 ch) +{ + return FCEUFont[FixJoedChar(ch)*8]; +} + +void LuaDrawTextTransWH(const char *str, size_t l, int &x, int y, uint32 color, uint32 backcolor) +{ + int Opac = (color >> 24) & 0xFF; + int backOpac = (backcolor >> 24) & 0xFF; + int origX = x; + + if(!Opac && !backOpac) + return; + + size_t len = l; + int defaultAlpha = std::max(0, std::min(transparencyModifier, 255)); + int diffx; + int diffy = std::max(0, std::min(7, LUA_SCREEN_HEIGHT - y)); + + while(*str && len && y < LUA_SCREEN_HEIGHT) + { + int c = *str++; + while (x >= LUA_SCREEN_WIDTH && c != '\n') { + c = *str; + if (c == '\0') + break; + str++; + if (!(--len)) + break; + } + if(c == '\n') + { + x = origX; + y += 8; + diffy = std::max(0, std::min(7, LUA_SCREEN_HEIGHT - y)); + continue; + } + else if(c == '\t') // just in case + { + const int tabSpace = 8; + x += (tabSpace-(((x-origX)/8)%tabSpace))*8; + continue; + } + + diffx = std::max(0, std::min(7, LUA_SCREEN_WIDTH - x)); + int ch = FixJoedChar(c); + int wid = std::min(diffx, JoedCharWidth(c)); + + for(int y2 = 0; y2 < diffy; y2++) + { + uint8 d = FCEUFont[ch*8 + 1+y2]; + for(int x2 = 0; x2 < wid; x2++) + { + int c = (d >> (7-x2)) & 1; + if(c) + gui_drawpixel_internal(x+x2, y+y2, color); + else + gui_drawpixel_internal(x+x2, y+y2, backcolor); + } + } + /* + // shadows :P + if (diffy >= 7) for(int x2 = 0; x2 < wid; x2++) + gui_drawpixel_internal(x+x2, y+7, LUA_BUILD_PIXEL(defaultAlpha, 0, 0, 0)); + if (*str == '\0' || *str == '\n') for(int y2 = 0; y2 < diffy; y2++) + gui_drawpixel_internal(x+wid, y+y2, LUA_BUILD_PIXEL(defaultAlpha, 0, 0, 0)); + */ + + x += wid; + len--; + } +} + + +// gui.text(int x, int y, string msg) +// +// Displays the given text on the screen, using the same font and techniques as the +// main HUD. +static int gui_text(lua_State *L) { + + extern int font_height; + const char *msg; + int x, y; + size_t l; + + x = luaL_checkinteger(L,1); + y = luaL_checkinteger(L,2); + msg = luaL_checklstring(L,3,&l); + + //if (x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= (LUA_SCREEN_HEIGHT - font_height)) + // luaL_error(L,"bad coordinates"); + +#if 0 + uint32 colour = gui_optcolour(L,4,LUA_BUILD_PIXEL(255, 255, 255, 255)); + uint32 borderColour = gui_optcolour(L,5,LUA_BUILD_PIXEL(255, 0, 0, 0)); + + gui_prepare(); + + LuaDisplayString(msg, y, x, colour, borderColour); +#else + uint32 color = gui_optcolour(L,4,LUA_BUILD_PIXEL(255, 255, 255, 255)); + uint32 bgcolor = gui_optcolour(L,5,LUA_BUILD_PIXEL(255, 27, 18, 105)); + + gui_prepare(); + + LuaDrawTextTransWH(msg, l, x, y, color, bgcolor); + + lua_pushinteger(L, x); +#endif + return 1; + +} + + +// gui.gdoverlay([int dx=0, int dy=0,] string str [, sx=0, sy=0, sw, sh] [, float alphamul=1.0]) +// +// Overlays the given image on the screen. +// example: gui.gdoverlay(gd.createFromPng("myimage.png"):gdStr()) +static int gui_gdoverlay(lua_State *L) { + + int argCount = lua_gettop(L); + + int xStartDst = 0; + int yStartDst = 0; + int xStartSrc = 0; + int yStartSrc = 0; + + int index = 1; + if(lua_type(L,index) == LUA_TNUMBER) + { + xStartDst = lua_tointeger(L,index++); + if(lua_type(L,index) == LUA_TNUMBER) + yStartDst = lua_tointeger(L,index++); + } + + luaL_checktype(L,index,LUA_TSTRING); + const unsigned char* ptr = (const unsigned char*)lua_tostring(L,index++); + + if (ptr[0] != 255 || (ptr[1] != 254 && ptr[1] != 255)) + luaL_error(L, "bad image data"); + bool trueColor = (ptr[1] == 254); + ptr += 2; + int imgwidth = *ptr++ << 8; + imgwidth |= *ptr++; + int width = imgwidth; + int imgheight = *ptr++ << 8; + imgheight |= *ptr++; + int height = imgheight; + if ((!trueColor && *ptr) || (trueColor && !*ptr)) + luaL_error(L, "bad image data"); + ptr++; + int pitch = imgwidth * (trueColor?4:1); + + if ((argCount - index + 1) >= 4) { + xStartSrc = luaL_checkinteger(L,index++); + yStartSrc = luaL_checkinteger(L,index++); + width = luaL_checkinteger(L,index++); + height = luaL_checkinteger(L,index++); + } + + int alphaMul = transparencyModifier; + if(lua_isnumber(L, index)) + alphaMul = (int)(alphaMul * lua_tonumber(L, index++)); + if(alphaMul <= 0) + return 0; + + // since there aren't that many possible opacity levels, + // do the opacity modification calculations beforehand instead of per pixel + int opacMap[256]; + for(int i = 0; i < 128; i++) + { + int opac = 255 - ((i << 1) | (i & 1)); // gdAlphaMax = 127, not 255 + opac = (opac * alphaMul) / 255; + if(opac < 0) opac = 0; + if(opac > 255) opac = 255; + opacMap[i] = opac; + } + for(int i = 128; i < 256; i++) + opacMap[i] = 0; // what should we do for them, actually? + + int colorsTotal = 0; + if (!trueColor) { + colorsTotal = *ptr++ << 8; + colorsTotal |= *ptr++; + } + int transparent = *ptr++ << 24; + transparent |= *ptr++ << 16; + transparent |= *ptr++ << 8; + transparent |= *ptr++; + struct { uint8 r, g, b, a; } pal[256]; + if (!trueColor) for (int i = 0; i < 256; i++) { + pal[i].r = *ptr++; + pal[i].g = *ptr++; + pal[i].b = *ptr++; + pal[i].a = opacMap[*ptr++]; + } + + // some of clippings + if (xStartSrc < 0) { + width += xStartSrc; + xStartDst -= xStartSrc; + xStartSrc = 0; + } + if (yStartSrc < 0) { + height += yStartSrc; + yStartDst -= yStartSrc; + yStartSrc = 0; + } + if (xStartSrc+width >= imgwidth) + width = imgwidth - xStartSrc; + if (yStartSrc+height >= imgheight) + height = imgheight - yStartSrc; + if (xStartDst < 0) { + width += xStartDst; + if (width <= 0) + return 0; + xStartSrc = -xStartDst; + xStartDst = 0; + } + if (yStartDst < 0) { + height += yStartDst; + if (height <= 0) + return 0; + yStartSrc = -yStartDst; + yStartDst = 0; + } + if (xStartDst+width >= LUA_SCREEN_WIDTH) + width = LUA_SCREEN_WIDTH - xStartDst; + if (yStartDst+height >= LUA_SCREEN_HEIGHT) + height = LUA_SCREEN_HEIGHT - yStartDst; + if (width <= 0 || height <= 0) + return 0; // out of screen or invalid size + + gui_prepare(); + + const uint8* pix = (const uint8*)(&ptr[yStartSrc*pitch + (xStartSrc*(trueColor?4:1))]); + int bytesToNextLine = pitch - (width * (trueColor?4:1)); + if (trueColor) + for (int y = yStartDst; y < height+yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine) { + for (int x = xStartDst; x < width+xStartDst && x < LUA_SCREEN_WIDTH; x++, pix += 4) { + gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(opacMap[pix[0]], pix[1], pix[2], pix[3])); + } + } + else + for (int y = yStartDst; y < height+yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine) { + for (int x = xStartDst; x < width+xStartDst && x < LUA_SCREEN_WIDTH; x++, pix++) { + gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(pal[*pix].a, pal[*pix].r, pal[*pix].g, pal[*pix].b)); + } + } + + return 0; +} + + +// function gui.register(function f) +// +// This function will be called just before a graphical update. +// More complicated, but doesn't suffer any frame delays. +// Nil will be accepted in place of a function to erase +// a previously registered function, and the previous function +// (if any) is returned, or nil if none. +static int gui_register(lua_State *L) { + + // We'll do this straight up. + + + // First set up the stack. + lua_settop(L,1); + + // Verify the validity of the entry + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + + // Get the old value + lua_getfield(L, LUA_REGISTRYINDEX, guiCallbackTable); + + // Save the new value + lua_pushvalue(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable); + + // The old value is on top of the stack. Return it. + return 1; + +} + +// table sound.get() +static int sound_get(lua_State *L) +{ + extern ENVUNIT EnvUnits[3]; + extern int CheckFreq(uint32 cf, uint8 sr); + extern int32 curfreq[2]; + extern uint8 PSG[0x10]; + extern int32 lengthcount[4]; + extern uint8 TriCount; + extern const uint32 *NoiseFreqTable; + extern int32 DMCPeriod; + extern uint8 DMCAddressLatch, DMCSizeLatch; + extern uint8 DMCFormat; + extern char DMCHaveSample; + extern uint8 InitialRawDALatch; + + int freqReg; + double freq; + + lua_newtable(L); + + // rp2a03 start + lua_newtable(L); + // rp2a03 info setup + double nesVolumes[3]; + for (int i = 0; i < 3; i++) + { + if ((EnvUnits[i].Mode & 1) != 0) + nesVolumes[i] = EnvUnits[i].Speed; + else + nesVolumes[i] = EnvUnits[i].decvolume; + nesVolumes[i] /= 15.0; + } + // rp2a03/square1 + lua_newtable(L); + if((curfreq[0] < 8 || curfreq[0] > 0x7ff) || + (CheckFreq(curfreq[0], PSG[1]) == 0) || + (lengthcount[0] == 0)) + lua_pushnumber(L, 0.0); + else + lua_pushnumber(L, nesVolumes[0]); + lua_setfield(L, -2, "volume"); + freq = (39375000.0/352.0) / (curfreq[0] + 1); + lua_pushnumber(L, freq); + lua_setfield(L, -2, "frequency"); + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); + lua_setfield(L, -2, "midikey"); + lua_pushinteger(L, (PSG[0] & 0xC0) >> 6); + lua_setfield(L, -2, "duty"); + lua_newtable(L); + lua_pushinteger(L, curfreq[0]); + lua_setfield(L, -2, "frequency"); + lua_setfield(L, -2, "regs"); + lua_setfield(L, -2, "square1"); + // rp2a03/square2 + lua_newtable(L); + if((curfreq[1] < 8 || curfreq[1] > 0x7ff) || + (CheckFreq(curfreq[1], PSG[5]) == 0) || + (lengthcount[1] == 0)) + lua_pushnumber(L, 0.0); + else + lua_pushnumber(L, nesVolumes[1]); + lua_setfield(L, -2, "volume"); + freq = (39375000.0/352.0) / (curfreq[1] + 1); + lua_pushnumber(L, freq); + lua_setfield(L, -2, "frequency"); + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); + lua_setfield(L, -2, "midikey"); + lua_pushinteger(L, (PSG[4] & 0xC0) >> 6); + lua_setfield(L, -2, "duty"); + lua_newtable(L); + lua_pushinteger(L, curfreq[1]); + lua_setfield(L, -2, "frequency"); + lua_setfield(L, -2, "regs"); + lua_setfield(L, -2, "square2"); + // rp2a03/triangle + lua_newtable(L); + if(lengthcount[2] == 0 || TriCount == 0) + lua_pushnumber(L, 0.0); + else + lua_pushnumber(L, 1.0); + lua_setfield(L, -2, "volume"); + freqReg = PSG[0xa] | ((PSG[0xb] & 7) << 8); + freq = (39375000.0/704.0) / (freqReg + 1); + lua_pushnumber(L, freq); + lua_setfield(L, -2, "frequency"); + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); + lua_setfield(L, -2, "midikey"); + lua_newtable(L); + lua_pushinteger(L, freqReg); + lua_setfield(L, -2, "frequency"); + lua_setfield(L, -2, "regs"); + lua_setfield(L, -2, "triangle"); + // rp2a03/noise + lua_newtable(L); + if(lengthcount[3] == 0) + lua_pushnumber(L, 0.0); + else + lua_pushnumber(L, nesVolumes[2]); + lua_setfield(L, -2, "volume"); + freqReg = PSG[0xE] & 0xF; + lua_pushboolean(L, (PSG[0xE] & 0x80) != 0); + lua_setfield(L, -2, "short"); + freq = (39375000.0/44.0) / NoiseFreqTable[freqReg]; // probably wrong + lua_pushnumber(L, freq); + lua_setfield(L, -2, "frequency"); + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); + lua_setfield(L, -2, "midikey"); + lua_newtable(L); + lua_pushinteger(L, freqReg); + lua_setfield(L, -2, "frequency"); + lua_setfield(L, -2, "regs"); + lua_setfield(L, -2, "noise"); + // rp2a03/dpcm + lua_newtable(L); + if (DMCHaveSample == 0) + lua_pushnumber(L, 0.0); + else + lua_pushnumber(L, 1.0); + lua_setfield(L, -2, "volume"); + freq = (39375000.0/2.0) / DMCPeriod; + lua_pushnumber(L, freq); + lua_setfield(L, -2, "frequency"); + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); + lua_setfield(L, -2, "midikey"); + lua_pushinteger(L, 0xC000 + (DMCAddressLatch << 6)); + lua_setfield(L, -2, "dmcaddress"); + lua_pushinteger(L, (DMCSizeLatch << 4) + 1); + lua_setfield(L, -2, "dmcsize"); + lua_pushboolean(L, DMCFormat & 0x40); + lua_setfield(L, -2, "dmcloop"); + lua_pushinteger(L, InitialRawDALatch); + lua_setfield(L, -2, "dmcseed"); + lua_newtable(L); + lua_pushinteger(L, DMCFormat & 0xF); + lua_setfield(L, -2, "frequency"); + lua_setfield(L, -2, "regs"); + lua_setfield(L, -2, "dpcm"); + // rp2a03 end + lua_setfield(L, -2, "rp2a03"); + + return 1; +} + +// Debugger functions library + +// debugger.hitbreakpoint() +static int debugger_hitbreakpoint(lua_State *L) +{ + break_asap = true; + return 0; +} + +// debugger.getcyclescount() +static int debugger_getcyclescount(lua_State *L) +{ + int64 counter_value = timestampbase + (uint64)timestamp - total_cycles_base; + if (counter_value < 0) // sanity check + { + ResetDebugStatisticsCounters(); + counter_value = 0; + } + lua_pushinteger(L, counter_value); + return 1; +} + +// debugger.getinstructionscount() +static int debugger_getinstructionscount(lua_State *L) +{ + lua_pushinteger(L, total_instructions); + return 1; +} + +// debugger.resetcyclescount() +static int debugger_resetcyclescount(lua_State *L) +{ + ResetCyclesCounter(); + return 0; +} + +// debugger.resetinstructionscount() +static int debugger_resetinstructionscount(lua_State *L) +{ + ResetInstructionsCounter(); + return 0; +} + +// TAS Editor functions library + +// bool taseditor.registerauto() +static int taseditor_registerauto(lua_State *L) +{ + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L,1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_TASEDITOR_AUTO]); + lua_insert(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_TASEDITOR_AUTO]); + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; +} + +// bool taseditor.registermanual(string caption) +static int taseditor_registermanual(lua_State *L) +{ + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + + const char* caption = NULL; + if (!lua_isnil(L, 2)) + caption = lua_tostring(L, 2); + + lua_settop(L,1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_TASEDITOR_MANUAL]); + lua_insert(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_TASEDITOR_MANUAL]); +#ifdef WIN32 + taseditor_lua.enableRunFunction(caption); +#endif + return 1; +} + +// bool taseditor.engaged() +static int taseditor_engaged(lua_State *L) +{ +#ifdef WIN32 + lua_pushboolean(L, taseditor_lua.engaged()); +#else + lua_pushboolean(L, false); +#endif + return 1; +} + +// bool taseditor.markedframe(int frame) +static int taseditor_markedframe(lua_State *L) +{ +#ifdef WIN32 + lua_pushboolean(L, taseditor_lua.markedframe(luaL_checkinteger(L, 1))); +#else + lua_pushboolean(L, false); +#endif + return 1; +} + +// int taseditor.getmarker(int frame) +static int taseditor_getmarker(lua_State *L) +{ +#ifdef WIN32 + lua_pushinteger(L, taseditor_lua.getmarker(luaL_checkinteger(L, 1))); +#else + lua_pushinteger(L, -1); +#endif + return 1; +} + +// int taseditor.setmarker(int frame) +static int taseditor_setmarker(lua_State *L) +{ +#ifdef WIN32 + lua_pushinteger(L, taseditor_lua.setmarker(luaL_checkinteger(L, 1))); +#else + lua_pushinteger(L, -1); +#endif + return 1; +} + +// taseditor.removemarker(int frame) +static int taseditor_removemarker(lua_State *L) +{ +#ifdef WIN32 + taseditor_lua.removemarker(luaL_checkinteger(L, 1)); +#endif + return 0; +} + +// string taseditor.getnote(int index) +static int taseditor_getnote(lua_State *L) +{ +#ifdef WIN32 + lua_pushstring(L, taseditor_lua.getnote(luaL_checkinteger(L, 1))); +#else + lua_pushnil(L); +#endif + return 1; +} + +// taseditor.setnote(int index, string newtext) +static int taseditor_setnote(lua_State *L) +{ +#ifdef WIN32 + taseditor_lua.setnote(luaL_checkinteger(L, 1), luaL_checkstring(L, 2)); +#endif + return 0; +} + +// int taseditor.getcurrentbranch() +static int taseditor_getcurrentbranch(lua_State *L) +{ +#ifdef WIN32 + lua_pushinteger(L, taseditor_lua.getcurrentbranch()); +#else + lua_pushinteger(L, -1); +#endif + return 1; +} + +// string taseditor.getrecordermode() +static int taseditor_getrecordermode(lua_State *L) +{ +#ifdef WIN32 + lua_pushstring(L, taseditor_lua.getrecordermode()); +#else + lua_pushnil(L); +#endif + return 1; +} + +// int taseditor.getsuperimpose() +static int taseditor_getsuperimpose(lua_State *L) +{ +#ifdef WIN32 + lua_pushinteger(L, taseditor_lua.getsuperimpose()); +#else + lua_pushinteger(L, -1); +#endif + return 1; +} + +// int taseditor.getlostplayback() +static int taseditor_getlostplayback(lua_State *L) +{ +#ifdef WIN32 + lua_pushinteger(L, taseditor_lua.getlostplayback()); +#else + lua_pushinteger(L, -1); +#endif + return 1; +} + +// int taseditor.getplaybacktarget() +static int taseditor_getplaybacktarget(lua_State *L) +{ +#ifdef WIN32 + lua_pushinteger(L, taseditor_lua.getplaybacktarget()); +#else + lua_pushinteger(L, -1); +#endif + return 1; +} + +// taseditor.setplayback(int frame) +static int taseditor_setplayback(lua_State *L) +{ +#ifdef WIN32 + taseditor_lua.setplayback(luaL_checkinteger(L, 1)); +#endif + return 0; +} + +// taseditor.stopseeking() +static int taseditor_stopseeking(lua_State *L) +{ +#ifdef WIN32 + taseditor_lua.stopseeking(); +#endif + return 0; +} + +// table taseditor.getselection() +static int taseditor_getselection(lua_State *L) +{ +#ifdef WIN32 + // create temp vector and provide its reference to TAS Editor for filling the vector with data + std::vector cur_set; + taseditor_lua.getselection(cur_set); + int size = cur_set.size(); + if (size) + { + lua_createtable(L, size, 0); + for (int i = 0; i < size; ++i) + { + lua_pushinteger(L, cur_set[i]); + lua_rawseti(L, -2, i + 1); + } + } else + { + lua_pushnil(L); + } +#else + lua_pushnil(L); +#endif + return 1; +} + +// taseditor.setselection(table new_set) +static int taseditor_setselection(lua_State *L) +{ +#ifdef WIN32 + std::vector cur_set; + // retrieve new_set data from table to vector + if (!lua_isnil(L, 1)) + { + luaL_checktype(L, 1, LUA_TTABLE); + int max_index = luaL_getn(L, 1); + int i = 1; + while (i <= max_index) + { + lua_rawgeti(L, 1, i); + cur_set.push_back(lua_tonumber(L, -1)); + lua_pop(L, 1); + i++; + } + } + // and provide its reference to TAS Editor for changing selection + taseditor_lua.setselection(cur_set); +#endif + return 0; +} + +// int taseditor.getinput(int frame, int joypad) +static int taseditor_getinput(lua_State *L) +{ +#ifdef WIN32 + lua_pushinteger(L, taseditor_lua.getinput(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2))); +#else + lua_pushinteger(L, -1); +#endif + return 1; +} + +// taseditor.submitinputchange(int frame, int joypad, int input) +static int taseditor_submitinputchange(lua_State *L) +{ +#ifdef WIN32 + taseditor_lua.submitinputchange(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), luaL_checkinteger(L, 3)); +#endif + return 0; +} + +// taseditor.submitinsertframes(int frame, int joypad, int input) +static int taseditor_submitinsertframes(lua_State *L) +{ +#ifdef WIN32 + taseditor_lua.submitinsertframes(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2)); +#endif + return 0; +} + +// taseditor.submitdeleteframes(int frame, int joypad, int input) +static int taseditor_submitdeleteframes(lua_State *L) +{ +#ifdef WIN32 + taseditor_lua.submitdeleteframes(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2)); +#endif + return 0; +} + +// int taseditor.applyinputchanges([string name]) +static int taseditor_applyinputchanges(lua_State *L) +{ +#ifdef WIN32 + if (lua_isnil(L, 1)) + { + lua_pushinteger(L, taseditor_lua.applyinputchanges("")); + } else + { + const char* name = lua_tostring(L, 1); + if (name) + lua_pushinteger(L, taseditor_lua.applyinputchanges(name)); + else + lua_pushinteger(L, taseditor_lua.applyinputchanges("")); + } +#else + lua_pushinteger(L, -1); +#endif + return 1; +} + +// taseditor.clearinputchanges() +static int taseditor_clearinputchanges(lua_State *L) +{ +#ifdef WIN32 + taseditor_lua.clearinputchanges(); +#endif + return 0; +} + + +static int doPopup(lua_State *L, const char* deftype, const char* deficon) { + const char *str = luaL_checkstring(L, 1); + const char* type = lua_type(L,2) == LUA_TSTRING ? lua_tostring(L,2) : deftype; + const char* icon = lua_type(L,3) == LUA_TSTRING ? lua_tostring(L,3) : deficon; + + int itype = -1, iters = 0; + while(itype == -1 && iters++ < 2) + { + if(!stricmp(type, "ok")) itype = 0; + else if(!stricmp(type, "yesno")) itype = 1; + else if(!stricmp(type, "yesnocancel")) itype = 2; + else if(!stricmp(type, "okcancel")) itype = 3; + else if(!stricmp(type, "abortretryignore")) itype = 4; + else type = deftype; + } + assert(itype >= 0 && itype <= 4); + if(!(itype >= 0 && itype <= 4)) itype = 0; + + int iicon = -1; iters = 0; + while(iicon == -1 && iters++ < 2) + { + if(!stricmp(icon, "message") || !stricmp(icon, "notice")) iicon = 0; + else if(!stricmp(icon, "question")) iicon = 1; + else if(!stricmp(icon, "warning")) iicon = 2; + else if(!stricmp(icon, "error")) iicon = 3; + else icon = deficon; + } + assert(iicon >= 0 && iicon <= 3); + if(!(iicon >= 0 && iicon <= 3)) iicon = 0; + + static const char * const titles [] = {"Notice", "Question", "Warning", "Error"}; + const char* answer = "ok"; + +#ifdef WIN32 + static const int etypes [] = {MB_OK, MB_YESNO, MB_YESNOCANCEL, MB_OKCANCEL, MB_ABORTRETRYIGNORE}; + static const int eicons [] = {MB_ICONINFORMATION, MB_ICONQUESTION, MB_ICONWARNING, MB_ICONERROR}; + //StopSound(); //mbg merge 7/27/08 + int ianswer = MessageBox(hAppWnd, str, titles[iicon], etypes[itype] | eicons[iicon]); + switch(ianswer) + { + case IDOK: answer = "ok"; break; + case IDCANCEL: answer = "cancel"; break; + case IDABORT: answer = "abort"; break; + case IDRETRY: answer = "retry"; break; + case IDIGNORE: answer = "ignore"; break; + case IDYES: answer = "yes"; break; + case IDNO: answer = "no"; break; + } + + lua_pushstring(L, answer); + return 1; +#else + + char *t; +#ifdef __linux + + int pid; // appease compiler + + // Before doing any work, verify the correctness of the parameters. + if (strcmp(type, "ok") == 0) + t = "OK:100"; + else if (strcmp(type, "yesno") == 0) + t = "Yes:100,No:101"; + else if (strcmp(type, "yesnocancel") == 0) + t = "Yes:100,No:101,Cancel:102"; + else + return luaL_error(L, "invalid popup type \"%s\"", type); + + // Can we find a copy of xmessage? Search the path. + + char *path = strdup(getenv("PATH")); + + char *current = path; + + char *colon; + + int found = 0; + + while (current) { + colon = strchr(current, ':'); + + // Clip off the colon. + *colon++ = 0; + + int len = strlen(current); + char *filename = (char*)FCEU_dmalloc(len + 12); // always give excess + snprintf(filename, len+12, "%s/xmessage", current); + + if (access(filename, X_OK) == 0) { + free(filename); + found = 1; + break; + } + + // Failed, move on. + current = colon; + free(filename); + + } + + free(path); + + // We've found it? + if (!found) + goto use_console; + + pid = fork(); + if (pid == 0) {// I'm the virgin sacrifice + + // I'm gonna be dead in a matter of microseconds anyways, so wasted memory doesn't matter to me. + // Go ahead and abuse strdup. + char * parameters[] = {"xmessage", "-buttons", t, strdup(str), NULL}; + + execvp("xmessage", parameters); + + // Aw shitty + perror("exec xmessage"); + exit(1); + } + else if (pid < 0) // something went wrong!!! Oh hell... use the console + goto use_console; + else { + // We're the parent. Watch for the child. + int r; + int res = waitpid(pid, &r, 0); + if (res < 0) // wtf? + goto use_console; + + // The return value gets copmlicated... + if (!WIFEXITED(r)) { + luaL_error(L, "don't screw with my xmessage process!"); + } + r = WEXITSTATUS(r); + + // We assume it's worked. + if (r == 0) + { + return 0; // no parameters for an OK + } + if (r == 100) { + lua_pushstring(L, "yes"); + return 1; + } + if (r == 101) { + lua_pushstring(L, "no"); + return 1; + } + if (r == 102) { + lua_pushstring(L, "cancel"); + return 1; + } + + // Wtf? + return luaL_error(L, "popup failed due to unknown results involving xmessage (%d)", r); + } + +use_console: +#endif + + // All else has failed + + if (strcmp(type, "ok") == 0) + t = ""; + else if (strcmp(type, "yesno") == 0) + t = "yn"; + else if (strcmp(type, "yesnocancel") == 0) + t = "ync"; + else + return luaL_error(L, "invalid popup type \"%s\"", type); + + fprintf(stderr, "Lua Message: %s\n", str); + + while (true) { + char buffer[64]; + + // We don't want parameters + if (!t[0]) { + fprintf(stderr, "[Press Enter]"); + fgets(buffer, sizeof(buffer), stdin); + // We're done + return 0; + + } + fprintf(stderr, "(%s): ", t); + fgets(buffer, sizeof(buffer), stdin); + + // Check if the option is in the list + if (strchr(t, tolower(buffer[0]))) { + switch (tolower(buffer[0])) { + case 'y': + lua_pushstring(L, "yes"); + return 1; + case 'n': + lua_pushstring(L, "no"); + return 1; + case 'c': + lua_pushstring(L, "cancel"); + return 1; + default: + luaL_error(L, "internal logic error in console based prompts for gui.popup"); + + } + } + + // We fell through, so we assume the user answered wrong and prompt again. + + } + + // Nothing here, since the only way out is in the loop. +#endif + +} + +static int doOpenFilePopup(lua_State *L, bool saveFile) { +#ifdef WIN32 + char filename[PATH_MAX]; + OPENFILENAME ofn; + ZeroMemory(&ofn, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hAppWnd; + ofn.lpstrFilter = TEXT("All files (*.*)\0*.*\0\0"); + ofn.nFilterIndex = 0; + filename[0] = TEXT('\0'); + ofn.lpstrFile = filename; + ofn.nMaxFile = PATH_MAX; + ofn.Flags = OFN_NOCHANGEDIR | (saveFile ? OFN_OVERWRITEPROMPT : OFN_FILEMUSTEXIST); + BOOL bResult = saveFile ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn); + lua_newtable(L); + if (bResult) + { + lua_pushstring(L, filename); + lua_rawseti(L, -2, 1); + } +#else + // TODO: more sophisticated interface + char filename[PATH_MAX]; + printf("Enter %s filename: ", saveFile ? "save" : "open"); + fgets(filename, PATH_MAX, stdin); + lua_newtable(L); + lua_pushstring(L, filename); + lua_rawseti(L, -2, 1); +#endif + return 1; +} + +// string gui.popup(string message, string type = "ok", string icon = "message") +// string input.popup(string message, string type = "yesno", string icon = "question") +static int gui_popup(lua_State *L) +{ + return doPopup(L, "ok", "message"); +} +static int input_popup(lua_State *L) +{ + return doPopup(L, "yesno", "question"); +} + +static int input_openfilepopup(lua_State *L) +{ + return doOpenFilePopup(L, false); +} +static int input_savefilepopup(lua_State *L) +{ + return doOpenFilePopup(L, true); +} + +// the following bit operations are ported from LuaBitOp 1.0.1, +// because it can handle the sign bit (bit 31) correctly. + +/* +** Lua BitOp -- a bit operations library for Lua 5.1. +** http://bitop.luajit.org/ +** +** Copyright (C) 2008-2009 Mike Pall. All rights reserved. +** +** 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. +** +** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] +*/ + +#ifdef _MSC_VER +/* MSVC is stuck in the last century and doesn't have C99's stdint.h. */ +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +typedef int32_t SBits; +typedef uint32_t UBits; + +typedef union { + lua_Number n; +#ifdef LUA_NUMBER_DOUBLE + uint64_t b; +#else + UBits b; +#endif +} BitNum; + +/* Convert argument to bit type. */ +static UBits barg(lua_State *L, int idx) +{ + BitNum bn; + UBits b; + bn.n = lua_tonumber(L, idx); +#if defined(LUA_NUMBER_DOUBLE) + bn.n += 6755399441055744.0; /* 2^52+2^51 */ +#ifdef SWAPPED_DOUBLE + b = (UBits)(bn.b >> 32); +#else + b = (UBits)bn.b; +#endif +#elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \ + defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \ + defined(LUA_NUMBER_LLONG) + if (sizeof(UBits) == sizeof(lua_Number)) + b = bn.b; + else + b = (UBits)(SBits)bn.n; +#elif defined(LUA_NUMBER_FLOAT) +#error "A 'float' lua_Number type is incompatible with this library" +#else +#error "Unknown number type, check LUA_NUMBER_* in luaconf.h" +#endif + if (b == 0 && !lua_isnumber(L, idx)) + luaL_typerror(L, idx, "number"); + return b; +} + +/* Return bit type. */ +#define BRET(b) lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1; + +static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) } +static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) } + +#define BIT_OP(func, opr) \ + static int func(lua_State *L) { int i; UBits b = barg(L, 1); \ + for (i = lua_gettop(L); i > 1; i--) b opr barg(L, i); BRET(b) } +BIT_OP(bit_band, &=) +BIT_OP(bit_bor, |=) +BIT_OP(bit_bxor, ^=) + +#define bshl(b, n) (b << n) +#define bshr(b, n) (b >> n) +#define bsar(b, n) ((SBits)b >> n) +#define brol(b, n) ((b << n) | (b >> (32-n))) +#define bror(b, n) ((b << (32-n)) | (b >> n)) +#define BIT_SH(func, fn) \ + static int func(lua_State *L) { \ + UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) } +BIT_SH(bit_lshift, bshl) +BIT_SH(bit_rshift, bshr) +BIT_SH(bit_arshift, bsar) +BIT_SH(bit_rol, brol) +BIT_SH(bit_ror, bror) + +static int bit_bswap(lua_State *L) +{ + UBits b = barg(L, 1); + b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24); + BRET(b) +} + +static int bit_tohex(lua_State *L) +{ + UBits b = barg(L, 1); + SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2); + const char *hexdigits = "0123456789abcdef"; + char buf[8]; + int i; + if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; } + if (n > 8) n = 8; + for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; } + lua_pushlstring(L, buf, (size_t)n); + return 1; +} + +static const struct luaL_Reg bit_funcs[] = { + { "tobit", bit_tobit }, + { "bnot", bit_bnot }, + { "band", bit_band }, + { "bor", bit_bor }, + { "bxor", bit_bxor }, + { "lshift", bit_lshift }, + { "rshift", bit_rshift }, + { "arshift", bit_arshift }, + { "rol", bit_rol }, + { "ror", bit_ror }, + { "bswap", bit_bswap }, + { "tohex", bit_tohex }, + { NULL, NULL } +}; + +/* Signed right-shifts are implementation-defined per C89/C99. +** But the de facto standard are arithmetic right-shifts on two's +** complement CPUs. This behaviour is required here, so test for it. +*/ +#define BAD_SAR (bsar(-8, 2) != (SBits)-2) + +bool luabitop_validate(lua_State *L) // originally named as luaopen_bit +{ + UBits b; + lua_pushnumber(L, (lua_Number)1437217655L); + b = barg(L, -1); + if (b != (UBits)1437217655L || BAD_SAR) { /* Perform a simple self-test. */ + const char *msg = "compiled with incompatible luaconf.h"; +#ifdef LUA_NUMBER_DOUBLE +#ifdef WIN32 + if (b == (UBits)1610612736L) + msg = "use D3DCREATE_FPU_PRESERVE with DirectX"; +#endif + if (b == (UBits)1127743488L) + msg = "not compiled with SWAPPED_DOUBLE"; +#endif + if (BAD_SAR) + msg = "arithmetic right-shift broken"; + luaL_error(L, "bit library self-test failed (%s)", msg); + return false; + } + return true; +} + +// LuaBitOp ends here + +static int bit_bshift_emulua(lua_State *L) +{ + int shift = luaL_checkinteger(L,2); + if (shift < 0) { + lua_pushinteger(L, -shift); + lua_replace(L, 2); + return bit_lshift(L); + } + else + return bit_rshift(L); +} + +static int bitbit(lua_State *L) +{ + int rv = 0; + int numArgs = lua_gettop(L); + for(int i = 1; i <= numArgs; i++) { + int where = luaL_checkinteger(L,i); + if (where >= 0 && where < 32) + rv |= (1 << where); + } + lua_settop(L,0); + BRET(rv); +} + +// The function called periodically to ensure Lua doesn't run amok. +static void FCEU_LuaHookFunction(lua_State *L, lua_Debug *dbg) { + + if (numTries-- == 0) { + + int kill = 0; + +#ifdef WIN32 + // Uh oh + //StopSound(); //mbg merge 7/23/08 + int ret = MessageBox(hAppWnd, "The Lua script running has been running a long time. It may have gone crazy. Kill it?\n\n(No = don't check anymore either)", "Lua Script Gone Nuts?", MB_YESNO); + + if (ret == IDYES) { + kill = 1; + } + +#else + fprintf(stderr, "The Lua script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n"); + char buffer[64]; + while (TRUE) { + fprintf(stderr, "(y/n): "); + fgets(buffer, sizeof(buffer), stdin); + if (buffer[0] == 'y' || buffer[0] == 'Y') { + kill = 1; + break; + } + + if (buffer[0] == 'n' || buffer[0] == 'N') + break; + } +#endif + + if (kill) { + luaL_error(L, "Killed by user request."); + FCEU_LuaOnStop(); + } + + // else, kill the debug hook. + lua_sethook(L, NULL, 0, 0); + } + + +} + +static void emu_exec_count_hook(lua_State *L, lua_Debug *dbg) { + luaL_error(L, "exec_count timeout"); +} + +static int emu_exec_count(lua_State *L) { + int count = (int)luaL_checkinteger(L,1); + lua_pushvalue(L, 2); + lua_sethook(L, emu_exec_count_hook, LUA_MASKCOUNT, count); + int ret = lua_pcall(L, 0, 0, 0); + lua_sethook(L, NULL, 0, 0); + lua_settop(L,0); + lua_pushinteger(L, ret); + return 1; +} + +#ifdef WIN32 +static HANDLE readyEvent, goEvent; +DWORD WINAPI emu_exec_time_proc(LPVOID lpParameter) +{ + SetEvent(readyEvent); + WaitForSingleObject(goEvent,INFINITE); + lua_State *L = (lua_State *)lpParameter; + lua_pushvalue(L, 2); + int ret = lua_pcall(L, 0, 0, 0); + lua_settop(L,0); + lua_pushinteger(L, ret); + SetEvent(readyEvent); + return 0; +} + +static void emu_exec_time_hook(lua_State *L, lua_Debug *dbg) { + luaL_error(L, "exec_time timeout"); +} + +static int emu_exec_time(lua_State *L) +{ + int count = (int)luaL_checkinteger(L,1); + + readyEvent = CreateEvent(0,true,false,0); + goEvent = CreateEvent(0,true,false,0); + DWORD threadid; + HANDLE thread = CreateThread(0,0,emu_exec_time_proc,(LPVOID)L,0,&threadid); + SetThreadAffinityMask(thread,1); + //wait for the lua thread to start + WaitForSingleObject(readyEvent,INFINITE); + ResetEvent(readyEvent); + //tell the lua thread to proceed + SetEvent(goEvent); + //wait for the lua thread to finish, but no more than the specified amount of time + WaitForSingleObject(readyEvent,count); + + //kill lua (if it hasnt already been killed) + lua_sethook(L, emu_exec_time_hook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); + + //keep on waiting for the lua thread to come back + WaitForSingleObject(readyEvent,count); + + //clear the lua thread-killer + lua_sethook(L, NULL, 0, 0); + + CloseHandle(readyEvent); + CloseHandle(goEvent); + CloseHandle(thread); + + return 1; +} + +#else +static int emu_exec_time(lua_State *L) { return 0; } +#endif + +static const struct luaL_reg emulib [] = { + + {"poweron", emu_poweron}, + {"softreset", emu_softreset}, + {"speedmode", emu_speedmode}, + {"frameadvance", emu_frameadvance}, + {"paused", emu_paused}, + {"pause", emu_pause}, + {"unpause", emu_unpause}, + {"exec_count", emu_exec_count}, + {"exec_time", emu_exec_time}, + {"setrenderplanes", emu_setrenderplanes}, + {"message", emu_message}, + {"framecount", emu_framecount}, + {"lagcount", emu_lagcount}, + {"lagged", emu_lagged}, + {"setlagflag", emu_setlagflag}, + {"emulating", emu_emulating}, + {"registerbefore", emu_registerbefore}, + {"registerafter", emu_registerafter}, + {"registerexit", emu_registerexit}, + {"addgamegenie", emu_addgamegenie}, + {"delgamegenie", emu_delgamegenie}, + {"getscreenpixel", emu_getscreenpixel}, + {"readonly", movie_getreadonly}, + {"setreadonly", movie_setreadonly}, + {"print", print}, // sure, why not + {NULL,NULL} +}; + +static const struct luaL_reg romlib [] = { + {"readbyte", rom_readbyte}, + {"readbytesigned", rom_readbytesigned}, + // alternate naming scheme for unsigned + {"readbyteunsigned", rom_readbyte}, + + {"gethash", rom_gethash}, + {NULL,NULL} +}; + + +static const struct luaL_reg memorylib [] = { + + {"readbyte", memory_readbyte}, + {"readbyterange", memory_readbyterange}, + {"readbytesigned", memory_readbytesigned}, + {"readbyteunsigned", memory_readbyte}, // alternate naming scheme for unsigned + {"readword", memory_readword}, + {"readwordsigned", memory_readwordsigned}, + {"readwordunsigned", memory_readword}, // alternate naming scheme for unsigned + {"writebyte", memory_writebyte}, + {"getregister", memory_getregister}, + {"setregister", memory_setregister}, + + // memory hooks + {"registerwrite", memory_registerwrite}, + //{"registerread", memory_registerread}, TODO + {"registerexec", memory_registerexec}, + // alternate names + {"register", memory_registerwrite}, + {"registerrun", memory_registerexec}, + {"registerexecute", memory_registerexec}, + + {NULL,NULL} +}; + +static const struct luaL_reg joypadlib[] = { + {"get", joypad_get}, + {"getdown", joypad_getdown}, + {"getup", joypad_getup}, + {"getimmediate", joypad_getimmediate}, + {"set", joypad_set}, + // alternative names + {"read", joypad_get}, + {"write", joypad_set}, + {"readdown", joypad_getdown}, + {"readup", joypad_getup}, + {"readimmediate", joypad_getimmediate}, + {NULL,NULL} +}; + +static const struct luaL_reg zapperlib[] = { + {"read", zapper_read}, + {NULL,NULL} +}; + +static const struct luaL_reg inputlib[] = { + {"get", input_get}, + {"popup", input_popup}, + {"openfilepopup", input_openfilepopup}, + {"savefilepopup", input_savefilepopup}, + // alternative names + {"read", input_get}, + {NULL,NULL} +}; + +static const struct luaL_reg savestatelib[] = { + {"create", savestate_create}, + {"object", savestate_object}, + {"save", savestate_save}, + {"persist", savestate_persist}, + {"load", savestate_load}, + + {"registersave", savestate_registersave}, + {"registerload", savestate_registerload}, + {"loadscriptdata", savestate_loadscriptdata}, + + {NULL,NULL} +}; + +static const struct luaL_reg movielib[] = { + + {"framecount", emu_framecount}, // for those familiar with other emulators that have movie.framecount() instead of emulatorname.framecount() + {"mode", movie_mode}, + {"rerecordcounting", movie_rerecordcounting}, + {"stop", movie_stop}, + {"active", movie_isactive}, + {"recording", movie_isrecording}, + {"playing", movie_isplaying}, + {"length", movie_getlength}, + {"rerecordcount", movie_rerecordcount}, + {"name", movie_getname}, + {"filename", movie_getfilename}, + {"readonly", movie_getreadonly}, + {"setreadonly", movie_setreadonly}, + {"replay", movie_replay}, +// {"record", movie_record}, +// {"play", movie_playback}, + + // alternative names + {"close", movie_stop}, + {"getname", movie_getname}, +// {"playback", movie_playback}, + {"playbeginning", movie_replay}, + {"getreadonly", movie_getreadonly}, + {"ispoweron", movie_ispoweron}, //If movie recorded from power-on + {"isfromsavestate", movie_isfromsavestate}, //If movie is recorded from savestate + {NULL,NULL} + +}; + + +static const struct luaL_reg guilib[] = { + + {"pixel", gui_pixel}, + {"getpixel", gui_getpixel}, + {"line", gui_line}, + {"box", gui_box}, + {"text", gui_text}, + + {"parsecolor", gui_parsecolor}, + + {"savescreenshot", gui_savescreenshot}, + {"savescreenshotas", gui_savescreenshotas}, + {"gdscreenshot", gui_gdscreenshot}, + {"gdoverlay", gui_gdoverlay}, + {"opacity", gui_setopacity}, + {"transparency", gui_transparency}, + + {"register", gui_register}, + + {"popup", gui_popup}, + // alternative names + {"drawtext", gui_text}, + {"drawbox", gui_box}, + {"drawline", gui_line}, + {"drawpixel", gui_pixel}, + {"setpixel", gui_pixel}, + {"writepixel", gui_pixel}, + {"rect", gui_box}, + {"drawrect", gui_box}, + {"drawimage", gui_gdoverlay}, + {"image", gui_gdoverlay}, + {NULL,NULL} +}; + +static const struct luaL_reg soundlib[] = { + + {"get", sound_get}, + {NULL,NULL} +}; + +static const struct luaL_reg debuggerlib[] = { + + {"hitbreakpoint", debugger_hitbreakpoint}, + {"getcyclescount", debugger_getcyclescount}, + {"getinstructionscount", debugger_getinstructionscount}, + {"resetcyclescount", debugger_resetcyclescount}, + {"resetinstructionscount", debugger_resetinstructionscount}, + {NULL,NULL} +}; + +static const struct luaL_reg taseditorlib[] = { + + {"registerauto", taseditor_registerauto}, + {"registermanual", taseditor_registermanual}, + {"engaged", taseditor_engaged}, + {"markedframe", taseditor_markedframe}, + {"getmarker", taseditor_getmarker}, + {"setmarker", taseditor_setmarker}, + {"removemarker", taseditor_removemarker}, + {"getnote", taseditor_getnote}, + {"setnote", taseditor_setnote}, + {"getcurrentbranch", taseditor_getcurrentbranch}, + {"getrecordermode", taseditor_getrecordermode}, + {"getsuperimpose", taseditor_getsuperimpose}, + {"getlostplayback", taseditor_getlostplayback}, + {"getplaybacktarget", taseditor_getplaybacktarget}, + {"setplayback", taseditor_setplayback}, + {"stopseeking", taseditor_stopseeking}, + {"getselection", taseditor_getselection}, + {"setselection", taseditor_setselection}, + {"getinput", taseditor_getinput}, + {"submitinputchange", taseditor_submitinputchange}, + {"submitinsertframes", taseditor_submitinsertframes}, + {"submitdeleteframes", taseditor_submitdeleteframes}, + {"applyinputchanges", taseditor_applyinputchanges}, + {"clearinputchanges", taseditor_clearinputchanges}, + {NULL,NULL} +}; + +void CallExitFunction() { + if (!L) + return; + + lua_settop(L, 0); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); + + int errorcode = 0; + if (lua_isfunction(L, -1)) + { + //chdir(luaCWD); + errorcode = lua_pcall(L, 0, 0, 0); + //_getcwd(luaCWD, _MAX_PATH); + } + + if (errorcode) + HandleCallbackError(L); +} + +void FCEU_LuaFrameBoundary() +{ + //printf("Lua Frame\n"); + + // HA! + if (!L || !luaRunning) + return; + + // Our function needs calling + lua_settop(L,0); + lua_getfield(L, LUA_REGISTRYINDEX, frameAdvanceThread); + lua_State *thread = lua_tothread(L,1); + + // Lua calling C must know that we're busy inside a frame boundary + frameBoundary = TRUE; + frameAdvanceWaiting = FALSE; + + numTries = 1000; + int result = lua_resume(thread, 0); + + if (result == LUA_YIELD) { + // Okay, we're fine with that. + } else if (result != 0) { + // Done execution by bad causes + FCEU_LuaOnStop(); + lua_pushnil(L); + lua_setfield(L, LUA_REGISTRYINDEX, frameAdvanceThread); + + // Error? +#ifdef WIN32 + //StopSound();//StopSound(); //mbg merge 7/23/08 + MessageBox( hAppWnd, lua_tostring(thread,-1), "Lua run error", MB_OK | MB_ICONSTOP); +#else + fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(thread,-1)); +#endif + + } else { + FCEU_LuaOnStop(); + //FCEU_DispMessage("Script died of natural causes.\n",0); + // weird sequence of functions calls the above message each time the script starts or stops, + // then this message is overrided by "emu speed" within the same frame, which hides this bug + // uncomment onse solution is found + } + + // Past here, the nes actually runs, so any Lua code is called mid-frame. We must + // not do anything too stupid, so let ourselves know. + frameBoundary = FALSE; + + if (!frameAdvanceWaiting) { + FCEU_LuaOnStop(); + } + +} + +/** + * Loads and runs the given Lua script. + * The emulator MUST be paused for this function to be + * called. Otherwise, all frame boundary assumptions go out the window. + * + * Returns true on success, false on failure. + */ +int FCEU_LoadLuaCode(const char *filename, const char *arg) { + if (!DemandLua()) + { + return 0; + } + + if (filename != luaScriptName) + { + if (luaScriptName) free(luaScriptName); + luaScriptName = strdup(filename); + } + +#if defined(WIN32) || defined(__linux) + std::string getfilepath = filename; + + getfilepath = getfilepath.substr(0,getfilepath.find_last_of("/\\") + 1); + + SetCurrentDir(getfilepath.c_str()); +#endif + + //stop any lua we might already have had running + FCEU_LuaStop(); + + //Reinit the error count + luaexiterrorcount = 8; + + if (!L) { + + L = lua_open(); + luaL_openlibs(L); + #if defined( WIN32) && !defined(NEED_MINGW_HACKS) + iuplua_open(L); + iupcontrolslua_open(L); + luaopen_winapi(L); + + //luasocket - yeah, have to open this in a weird way + lua_pushcfunction(L,luaopen_socket_core); + lua_setglobal(L,"tmp"); + luaL_dostring(L, "package.preload[\"socket.core\"] = _G.tmp"); + lua_pushcfunction(L,luaopen_mime_core); + lua_setglobal(L,"tmp"); + luaL_dostring(L, "package.preload[\"mime.core\"] = _G.tmp"); + #endif + + luaL_register(L, "emu", emulib); // added for better cross-emulator compatibility + luaL_register(L, "FCEU", emulib); // kept for backward compatibility + luaL_register(L, "memory", memorylib); + luaL_register(L, "rom", romlib); + luaL_register(L, "joypad", joypadlib); + luaL_register(L, "zapper", zapperlib); + luaL_register(L, "input", inputlib); + luaL_register(L, "savestate", savestatelib); + luaL_register(L, "movie", movielib); + luaL_register(L, "gui", guilib); + luaL_register(L, "sound", soundlib); + luaL_register(L, "debugger", debuggerlib); + luaL_register(L, "taseditor", taseditorlib); + luaL_register(L, "bit", bit_funcs); // LuaBitOp library + lua_settop(L, 0); // clean the stack, because each call to luaL_register leaves a table on top + + // register a few utility functions outside of libraries (in the global namespace) + lua_register(L, "print", print); + lua_register(L, "tostring", tostring); + lua_register(L, "tobitstring", tobitstring); + lua_register(L, "addressof", addressof); + lua_register(L, "copytable", copytable); + + // old bit operation functions + lua_register(L, "AND", bit_band); + lua_register(L, "OR", bit_bor); + lua_register(L, "XOR", bit_bxor); + lua_register(L, "SHIFT", bit_bshift_emulua); + lua_register(L, "BIT", bitbit); + + if (arg) + { + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addstring(&b, arg); + luaL_pushresult(&b); + + lua_setglobal(L, "arg"); + } + + luabitop_validate(L); + + // push arrays for storing hook functions in + for(int i = 0; i < LUAMEMHOOK_COUNT; i++) + { + lua_newtable(L); + lua_setfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[i]); + } + } + + // We make our thread NOW because we want it at the bottom of the stack. + // If all goes wrong, we let the garbage collector remove it. + lua_State *thread = lua_newthread(L); + + // Load the data + int result = luaL_loadfile(L,filename); + + if (result) { +#ifdef WIN32 + // Doing this here caused nasty problems; reverting to MessageBox-from-dialog behavior. + //StopSound();//StopSound(); //mbg merge 7/23/08 + MessageBox(NULL, lua_tostring(L,-1), "Lua load error", MB_OK | MB_ICONSTOP); +#else + fprintf(stderr, "Failed to compile file: %s\n", lua_tostring(L,-1)); +#endif + + // Wipe the stack. Our thread + lua_settop(L,0); + return 0; // Oh shit. + } +#ifdef WIN32 + AddRecentLuaFile(filename); //Add the filename to our recent lua menu +#endif + + // Get our function into it + lua_xmove(L, thread, 1); + + // Save the thread to the registry. This is why I make the thread FIRST. + lua_setfield(L, LUA_REGISTRYINDEX, frameAdvanceThread); + + + // Initialize settings + luaRunning = TRUE; + skipRerecords = FALSE; + numMemHooks = 0; + transparencyModifier = 255; // opaque + + //wasPaused = FCEUI_EmulationPaused(); + //if (wasPaused) FCEUI_ToggleEmulationPause(); + + // And run it right now. :) + //FCEU_LuaFrameBoundary(); + + // Set up our protection hook to be executed once every 10,000 bytecode instructions. + //lua_sethook(thread, FCEU_LuaHookFunction, LUA_MASKCOUNT, 10000); + +#ifdef WIN32 + info_print = PrintToWindowConsole; + info_onstart = WinLuaOnStart; + info_onstop = WinLuaOnStop; + if(!LuaConsoleHWnd) + LuaConsoleHWnd = CreateDialog(fceu_hInstance, MAKEINTRESOURCE(IDD_LUA), hAppWnd, (DLGPROC) DlgLuaScriptDialog); + info_uid = (int)LuaConsoleHWnd; +#else + info_print = NULL; + info_onstart = NULL; + info_onstop = NULL; +#endif + if (info_onstart) + info_onstart(info_uid); + + // We're done. + return 1; +} + +/** + * Equivalent to repeating the last FCEU_LoadLuaCode() call. + */ +void FCEU_ReloadLuaCode() +{ + if (!luaScriptName) + { +#ifdef WIN32 + // no script currently running, then try loading the most recent + extern char *recent_lua[]; + char*& fname = recent_lua[0]; + extern void UpdateLuaConsole(const char* fname); + if (fname) + { + UpdateLuaConsole(fname); + FCEU_LoadLuaCode(fname); + } else + { + FCEU_DispMessage("There's no script to reload.", 0); + } +#else + FCEU_DispMessage("There's no script to reload.", 0); +#endif + } else + { + FCEU_LoadLuaCode(luaScriptName); + } +} + + +/** + * Terminates a running Lua script by killing the whole Lua engine. + * + * Always safe to call, except from within a lua call itself (duh). + * + */ +void FCEU_LuaStop() { + + if (!CheckLua()) + return; + + //already killed + if (!L) return; + + // Since the script is exiting, we want to prevent an infinite loop. + // CallExitFunction() > HandleCallbackError() > FCEU_LuaStop() > CallExitFunction() ... + if (luaexiterrorcount > 0) { + luaexiterrorcount = luaexiterrorcount - 1; + //execute the user's shutdown callbacks + CallExitFunction(); + } + + luaexiterrorcount = luaexiterrorcount + 1; + + //already killed (after multiple errors) + if (!L) return; + + /*info.*/numMemHooks = 0; + for(int i = 0; i < LUAMEMHOOK_COUNT; i++) + CalculateMemHookRegions((LuaMemHookType)i); + + //sometimes iup uninitializes com + //MBG TODO - test whether this is really necessary. i dont think it is + #ifdef WIN32 + CoInitialize(0); + #endif + + if (info_onstop) + info_onstop(info_uid); + + //lua_gc(L,LUA_GCCOLLECT,0); + + + lua_close(L); // this invokes our garbage collectors for us + L = NULL; + FCEU_LuaOnStop(); +} + +/** + * Returns true if there is a Lua script running. + * + */ +int FCEU_LuaRunning() { + // FIXME: return false when no callback functions are registered. + return (int) (L != NULL); // should return true if callback functions are active. +} + + +/** + * Returns true if Lua would like to steal the given joypad control. + */ +//int FCEU_LuaUsingJoypad(int which) { +// return lua_joypads_used & (1 << which); +//} + +//adelikat: TODO: should I have a FCEU_LuaUsingJoypadFalse? + +/** + * Reads the buttons Lua is feeding for the given joypad, in the same + * format as the OS-specific code. + * + * It may force set or force clear the buttons. It may also simply + * pass the input along or invert it. The act of calling this + * function will reset everything back to pass-through, though. + * Generally means don't call it more than once per frame! + */ +uint8 FCEU_LuaReadJoypad(int which, uint8 joyl) { + joyl = (joyl & luajoypads1[which]) | (~joyl & luajoypads2[which]); + luajoypads1[which] = 0xFF; + luajoypads2[which] = 0x00; + return joyl; +} + +//adelikat: Returns the buttons that will be specifically set to false (as opposed to on or nil) +//This will be used in input.cpp to &(and) against the input to override a button with a false value. This is a work around to allow 3 conditions to be sent be lua, true, false, nil +//uint8 FCEU_LuaReadJoypadFalse(int which) { +// lua_joypads_used_false &= ~(1 << which); +// return lua_joypads_false[which]; +//} + +/** + * If this function returns true, the movie code should NOT increment + * the rerecord count for a load-state. + * + * This function will not return true if a script is not running. + */ +int FCEU_LuaRerecordCountSkip() { + // FIXME: return true if (there are any active callback functions && skipRerecords) + return L && luaRunning && skipRerecords; +} + +/** + * Given an 8-bit screen with the indicated resolution, + * draw the current GUI onto it. + * + * Currently we only support 256x* resolutions. + */ +void FCEU_LuaGui(uint8 *XBuf) +{ + if (!L/* || !luaRunning*/) + return; + + // First, check if we're being called by anybody + lua_getfield(L, LUA_REGISTRYINDEX, guiCallbackTable); + + if (lua_isfunction(L, -1)) { + // We call it now + numTries = 1000; + int ret = lua_pcall(L, 0, 0, 0); + if (ret != 0) { +#ifdef WIN32 + //StopSound();//StopSound(); //mbg merge 7/23/08 + MessageBox(hAppWnd, lua_tostring(L, -1), "Lua Error in GUI function", MB_OK); +#else + fprintf(stderr, "Lua error in gui.register function: %s\n", lua_tostring(L, -1)); +#endif + // This is grounds for trashing the function + lua_pushnil(L); + lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable); + + } + } + + // And wreak the stack + lua_settop(L, 0); + + if (gui_used == GUI_CLEAR) + return; + + if (gui_used == GUI_USED_SINCE_LAST_FRAME && !FCEUI_EmulationPaused()) + { + memset(gui_data, 0, LUA_SCREEN_WIDTH*LUA_SCREEN_HEIGHT*4); + gui_used = GUI_CLEAR; + return; + } + + gui_used = GUI_USED_SINCE_LAST_FRAME; + + int x, y; + + for (y = 0; y < LUA_SCREEN_HEIGHT; y++) + { + for (x=0; x < LUA_SCREEN_WIDTH; x++) + { + const uint8 gui_alpha = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+3]; + if (gui_alpha == 0) + { + // do nothing + continue; + } + + const uint8 gui_red = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+2]; + const uint8 gui_green = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+1]; + const uint8 gui_blue = gui_data[(y*LUA_SCREEN_WIDTH+x)*4]; + + int r, g, b; + if (gui_alpha == 255) { + // direct copy + r = gui_red; + g = gui_green; + b = gui_blue; + } + else { + // alpha-blending + uint8 scr_red, scr_green, scr_blue; + FCEUD_GetPalette(XBuf[(y)*256+x], &scr_red, &scr_green, &scr_blue); + r = (((int) gui_red - scr_red) * gui_alpha / 255 + scr_red) & 255; + g = (((int) gui_green - scr_green) * gui_alpha / 255 + scr_green) & 255; + b = (((int) gui_blue - scr_blue) * gui_alpha / 255 + scr_blue) & 255; + } + + XBuf[(y)*256+x] = gui_colour_rgb(r, g, b); + } + } + + return; +} + + +lua_State* FCEU_GetLuaState() { + return L; +} +char* FCEU_GetLuaScriptName() { + return luaScriptName; +} +#endif diff --git a/source/fceultra/lua/COPYRIGHT b/source/fceultra/lua/COPYRIGHT new file mode 100644 index 0000000..3a53e74 --- /dev/null +++ b/source/fceultra/lua/COPYRIGHT @@ -0,0 +1,34 @@ +Lua License +----------- + +Lua is licensed under the terms of the MIT license reproduced below. +This means that Lua is free software and can be used for both academic +and commercial purposes at absolutely no cost. + +For details and rationale, see http://www.lua.org/license.html . + +=============================================================================== + +Copyright (C) 1994-2008 Lua.org, PUC-Rio. + +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. + +=============================================================================== + +(end of COPYRIGHT) diff --git a/source/fceultra/lua/HISTORY b/source/fceultra/lua/HISTORY new file mode 100644 index 0000000..ce0c95b --- /dev/null +++ b/source/fceultra/lua/HISTORY @@ -0,0 +1,183 @@ +HISTORY for Lua 5.1 + +* Changes from version 5.0 to 5.1 + ------------------------------- + Language: + + new module system. + + new semantics for control variables of fors. + + new semantics for setn/getn. + + new syntax/semantics for varargs. + + new long strings and comments. + + new `mod' operator (`%') + + new length operator #t + + metatables for all types + API: + + new functions: lua_createtable, lua_get(set)field, lua_push(to)integer. + + user supplies memory allocator (lua_open becomes lua_newstate). + + luaopen_* functions must be called through Lua. + Implementation: + + new configuration scheme via luaconf.h. + + incremental garbage collection. + + better handling of end-of-line in the lexer. + + fully reentrant parser (new Lua function `load') + + better support for 64-bit machines. + + native loadlib support for Mac OS X. + + standard distribution in only one library (lualib.a merged into lua.a) + +* Changes from version 4.0 to 5.0 + ------------------------------- + Language: + + lexical scoping. + + Lua coroutines. + + standard libraries now packaged in tables. + + tags replaced by metatables and tag methods replaced by metamethods, + stored in metatables. + + proper tail calls. + + each function can have its own global table, which can be shared. + + new __newindex metamethod, called when we insert a new key into a table. + + new block comments: --[[ ... ]]. + + new generic for. + + new weak tables. + + new boolean type. + + new syntax "local function". + + (f()) returns the first value returned by f. + + {f()} fills a table with all values returned by f. + + \n ignored in [[\n . + + fixed and-or priorities. + + more general syntax for function definition (e.g. function a.x.y:f()...end). + + more general syntax for function calls (e.g. (print or write)(9)). + + new functions (time/date, tmpfile, unpack, require, load*, etc.). + API: + + chunks are loaded by using lua_load; new luaL_loadfile and luaL_loadbuffer. + + introduced lightweight userdata, a simple "void*" without a metatable. + + new error handling protocol: the core no longer prints error messages; + all errors are reported to the caller on the stack. + + new lua_atpanic for host cleanup. + + new, signal-safe, hook scheme. + Implementation: + + new license: MIT. + + new, faster, register-based virtual machine. + + support for external multithreading and coroutines. + + new and consistent error message format. + + the core no longer needs "stdio.h" for anything (except for a single + use of sprintf to convert numbers to strings). + + lua.c now runs the environment variable LUA_INIT, if present. It can + be "@filename", to run a file, or the chunk itself. + + support for user extensions in lua.c. + sample implementation given for command line editing. + + new dynamic loading library, active by default on several platforms. + + safe garbage-collector metamethods. + + precompiled bytecodes checked for integrity (secure binary dostring). + + strings are fully aligned. + + position capture in string.find. + + read('*l') can read lines with embedded zeros. + +* Changes from version 3.2 to 4.0 + ------------------------------- + Language: + + new "break" and "for" statements (both numerical and for tables). + + uniform treatment of globals: globals are now stored in a Lua table. + + improved error messages. + + no more '$debug': full speed *and* full debug information. + + new read form: read(N) for next N bytes. + + general read patterns now deprecated. + (still available with -DCOMPAT_READPATTERNS.) + + all return values are passed as arguments for the last function + (old semantics still available with -DLUA_COMPAT_ARGRET) + + garbage collection tag methods for tables now deprecated. + + there is now only one tag method for order. + API: + + New API: fully re-entrant, simpler, and more efficient. + + New debug API. + Implementation: + + faster than ever: cleaner virtual machine and new hashing algorithm. + + non-recursive garbage-collector algorithm. + + reduced memory usage for programs with many strings. + + improved treatment for memory allocation errors. + + improved support for 16-bit machines (we hope). + + code now compiles unmodified as both ANSI C and C++. + + numbers in bases other than 10 are converted using strtoul. + + new -f option in Lua to support #! scripts. + + luac can now combine text and binaries. + +* Changes from version 3.1 to 3.2 + ------------------------------- + + redirected all output in Lua's core to _ERRORMESSAGE and _ALERT. + + increased limit on the number of constants and globals per function + (from 2^16 to 2^24). + + debugging info (lua_debug and hooks) moved into lua_state and new API + functions provided to get and set this info. + + new debug lib gives full debugging access within Lua. + + new table functions "foreachi", "sort", "tinsert", "tremove", "getn". + + new io functions "flush", "seek". + +* Changes from version 3.0 to 3.1 + ------------------------------- + + NEW FEATURE: anonymous functions with closures (via "upvalues"). + + new syntax: + - local variables in chunks. + - better scope control with DO block END. + - constructors can now be also written: { record-part; list-part }. + - more general syntax for function calls and lvalues, e.g.: + f(x).y=1 + o:f(x,y):g(z) + f"string" is sugar for f("string") + + strings may now contain arbitrary binary data (e.g., embedded zeros). + + major code re-organization and clean-up; reduced module interdependecies. + + no arbitrary limits on the total number of constants and globals. + + support for multiple global contexts. + + better syntax error messages. + + new traversal functions "foreach" and "foreachvar". + + the default for numbers is now double. + changing it to use floats or longs is easy. + + complete debug information stored in pre-compiled chunks. + + sample interpreter now prompts user when run interactively, and also + handles control-C interruptions gracefully. + +* Changes from version 2.5 to 3.0 + ------------------------------- + + NEW CONCEPT: "tag methods". + Tag methods replace fallbacks as the meta-mechanism for extending the + semantics of Lua. Whereas fallbacks had a global nature, tag methods + work on objects having the same tag (e.g., groups of tables). + Existing code that uses fallbacks should work without change. + + new, general syntax for constructors {[exp] = exp, ... }. + + support for handling variable number of arguments in functions (varargs). + + support for conditional compilation ($if ... $else ... $end). + + cleaner semantics in API simplifies host code. + + better support for writing libraries (auxlib.h). + + better type checking and error messages in the standard library. + + luac can now also undump. + +* Changes from version 2.4 to 2.5 + ------------------------------- + + io and string libraries are now based on pattern matching; + the old libraries are still available for compatibility + + dofile and dostring can now return values (via return statement) + + better support for 16- and 64-bit machines + + expanded documentation, with more examples + +* Changes from version 2.2 to 2.4 + ------------------------------- + + external compiler creates portable binary files that can be loaded faster + + interface for debugging and profiling + + new "getglobal" fallback + + new functions for handling references to Lua objects + + new functions in standard lib + + only one copy of each string is stored + + expanded documentation, with more examples + +* Changes from version 2.1 to 2.2 + ------------------------------- + + functions now may be declared with any "lvalue" as a name + + garbage collection of functions + + support for pipes + +* Changes from version 1.1 to 2.1 + ------------------------------- + + object-oriented support + + fallbacks + + simplified syntax for tables + + many internal improvements + +(end of HISTORY) diff --git a/source/fceultra/lua/README b/source/fceultra/lua/README new file mode 100644 index 0000000..11b4dff --- /dev/null +++ b/source/fceultra/lua/README @@ -0,0 +1,37 @@ +README for Lua 5.1 + +See INSTALL for installation instructions. +See HISTORY for a summary of changes since the last released version. + +* What is Lua? + ------------ + Lua is a powerful, light-weight programming language designed for extending + applications. Lua is also frequently used as a general-purpose, stand-alone + language. Lua is free software. + + For complete information, visit Lua's web site at http://www.lua.org/ . + For an executive summary, see http://www.lua.org/about.html . + + Lua has been used in many different projects around the world. + For a short list, see http://www.lua.org/uses.html . + +* Availability + ------------ + Lua is freely available for both academic and commercial purposes. + See COPYRIGHT and http://www.lua.org/license.html for details. + Lua can be downloaded at http://www.lua.org/download.html . + +* Installation + ------------ + Lua is implemented in pure ANSI C, and compiles unmodified in all known + platforms that have an ANSI C compiler. In most Unix-like platforms, simply + do "make" with a suitable target. See INSTALL for detailed instructions. + +* Origin + ------ + Lua is developed at Lua.org, a laboratory of the Department of Computer + Science of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro + in Brazil). + For more information about the authors, see http://www.lua.org/authors.html . + +(end of README) diff --git a/source/fceultra/lua/SConscript b/source/fceultra/lua/SConscript new file mode 100644 index 0000000..83a51b3 --- /dev/null +++ b/source/fceultra/lua/SConscript @@ -0,0 +1,8 @@ +import glob +source_list = glob.glob('src/*.c') +source_list.remove('src/lua.c') +source_list.remove('src/luac.c') + +for x in range(len(source_list)): + source_list[x] = 'lua/' + source_list[x] +Return('source_list') diff --git a/source/fceultra/lua/lua.vcproj b/source/fceultra/lua/lua.vcproj new file mode 100644 index 0000000..582a2dc --- /dev/null +++ b/source/fceultra/lua/lua.vcproj @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/fceultra/lua/src/Makefile b/source/fceultra/lua/src/Makefile new file mode 100644 index 0000000..e4a3cd6 --- /dev/null +++ b/source/fceultra/lua/src/Makefile @@ -0,0 +1,182 @@ +# makefile for building Lua +# see ../INSTALL for installation instructions +# see ../Makefile and luaconf.h for further customization + +# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= + +# Your platform. See PLATS for possible values. +PLAT= none + +CC= gcc +CFLAGS= -O2 -Wall $(MYCFLAGS) +AR= ar rcu +RANLIB= ranlib +RM= rm -f +LIBS= -lm $(MYLIBS) + +MYCFLAGS= +MYLDFLAGS= +MYLIBS= + +# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= + +PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris + +LUA_A= liblua.a +CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ + lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ + lundump.o lvm.o lzio.o +LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ + lstrlib.o loadlib.o linit.o + +LUA_T= lua +LUA_O= lua.o + +LUAC_T= luac +LUAC_O= luac.o print.o + +ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) +ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) +ALL_A= $(LUA_A) + +default: $(PLAT) + +all: $(ALL_T) + +o: $(ALL_O) + +a: $(ALL_A) + +$(LUA_A): $(CORE_O) $(LIB_O) + $(AR) $@ $? + $(RANLIB) $@ + +$(LUA_T): $(LUA_O) $(LUA_A) + $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) + +$(LUAC_T): $(LUAC_O) $(LUA_A) + $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) + +clean: + $(RM) $(ALL_T) $(ALL_O) + +depend: + @$(CC) $(CFLAGS) -MM l*.c print.c + +echo: + @echo "PLAT = $(PLAT)" + @echo "CC = $(CC)" + @echo "CFLAGS = $(CFLAGS)" + @echo "AR = $(AR)" + @echo "RANLIB = $(RANLIB)" + @echo "RM = $(RM)" + @echo "MYCFLAGS = $(MYCFLAGS)" + @echo "MYLDFLAGS = $(MYLDFLAGS)" + @echo "MYLIBS = $(MYLIBS)" + +# convenience targets for popular platforms + +none: + @echo "Please choose a platform:" + @echo " $(PLATS)" + +aix: + $(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" + +ansi: + $(MAKE) all MYCFLAGS=-DLUA_ANSI + +bsd: + $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" + +freebsd: + $(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" + +generic: + $(MAKE) all MYCFLAGS= + +linux: + $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" + +macosx: + $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-lreadline" +# use this on Mac OS X 10.3- +# $(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX + +mingw: + $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ + "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ + "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe + $(MAKE) "LUAC_T=luac.exe" luac.exe + +posix: + $(MAKE) all MYCFLAGS=-DLUA_USE_POSIX + +solaris: + $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" + +# list targets that do not create files (but not all makes understand .PHONY) +.PHONY: all $(PLATS) default o a clean depend echo none + +# DO NOT DELETE + +lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ + lstate.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h \ + lundump.h lvm.h +lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h +lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h +lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ + lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ + ltable.h +ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h +ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \ + llex.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ + lfunc.h lstring.h lgc.h ltable.h lvm.h +ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ + lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h lstring.h \ + ltable.h lundump.h lvm.h +ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ + lzio.h lmem.h lundump.h +lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ + lstate.h ltm.h lzio.h +lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ + lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h +linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h +liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h +llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ + lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h +lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h +lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h ldo.h +loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h +lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ + ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h +lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h +loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h +lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ + lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ + lfunc.h lstring.h lgc.h ltable.h +lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h ltable.h +lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ + ltm.h lzio.h lstring.h lgc.h +lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h +ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h +ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h +ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ + lmem.h lstring.h lgc.h ltable.h +lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h +luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \ + lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ + lundump.h +lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ + llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h +lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ + lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h +lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ + lzio.h +print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h lopcodes.h lundump.h + +# (end of Makefile) diff --git a/source/fceultra/lua/src/lapi.c b/source/fceultra/lua/src/lapi.c new file mode 100644 index 0000000..5d5145d --- /dev/null +++ b/source/fceultra/lua/src/lapi.c @@ -0,0 +1,1087 @@ +/* +** $Id: lapi.c,v 2.55.1.5 2008/07/04 18:41:18 roberto Exp $ +** Lua API +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define lapi_c +#define LUA_CORE + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" + + + +const char lua_ident[] = + "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n" + "$Authors: " LUA_AUTHORS " $\n" + "$URL: www.lua.org $\n"; + + + +#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) + +#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject) + +#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} + + + +static TValue *index2adr (lua_State *L, int idx) { + if (idx > 0) { + TValue *o = L->base + (idx - 1); + api_check(L, idx <= L->ci->top - L->base); + if (o >= L->top) return cast(TValue *, luaO_nilobject); + else return o; + } + else if (idx > LUA_REGISTRYINDEX) { + api_check(L, idx != 0 && -idx <= L->top - L->base); + return L->top + idx; + } + else switch (idx) { /* pseudo-indices */ + case LUA_REGISTRYINDEX: return registry(L); + case LUA_ENVIRONINDEX: { + Closure *func = curr_func(L); + sethvalue(L, &L->env, func->c.env); + return &L->env; + } + case LUA_GLOBALSINDEX: return gt(L); + default: { + Closure *func = curr_func(L); + idx = LUA_GLOBALSINDEX - idx; + return (idx <= func->c.nupvalues) + ? &func->c.upvalue[idx-1] + : cast(TValue *, luaO_nilobject); + } + } +} + + +static Table *getcurrenv (lua_State *L) { + if (L->ci == L->base_ci) /* no enclosing function? */ + return hvalue(gt(L)); /* use global table as environment */ + else { + Closure *func = curr_func(L); + return func->c.env; + } +} + + +void luaA_pushobject (lua_State *L, const TValue *o) { + setobj2s(L, L->top, o); + api_incr_top(L); +} + + +LUA_API int lua_checkstack (lua_State *L, int size) { + int res = 1; + lua_lock(L); + if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK) + res = 0; /* stack overflow */ + else if (size > 0) { + luaD_checkstack(L, size); + if (L->ci->top < L->top + size) + L->ci->top = L->top + size; + } + lua_unlock(L); + return res; +} + + +LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { + int i; + if (from == to) return; + lua_lock(to); + api_checknelems(from, n); + api_check(from, G(from) == G(to)); + api_check(from, to->ci->top - to->top >= n); + from->top -= n; + for (i = 0; i < n; i++) { + setobj2s(to, to->top++, from->top + i); + } + lua_unlock(to); +} + + +LUA_API void lua_setlevel (lua_State *from, lua_State *to) { + to->nCcalls = from->nCcalls; +} + + +LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { + lua_CFunction old; + lua_lock(L); + old = G(L)->panic; + G(L)->panic = panicf; + lua_unlock(L); + return old; +} + + +LUA_API lua_State *lua_newthread (lua_State *L) { + lua_State *L1; + lua_lock(L); + luaC_checkGC(L); + L1 = luaE_newthread(L); + setthvalue(L, L->top, L1); + api_incr_top(L); + lua_unlock(L); + luai_userstatethread(L, L1); + return L1; +} + + + +/* +** basic stack manipulation +*/ + + +LUA_API int lua_gettop (lua_State *L) { + return cast_int(L->top - L->base); +} + + +LUA_API void lua_settop (lua_State *L, int idx) { + lua_lock(L); + if (idx >= 0) { + api_check(L, idx <= L->stack_last - L->base); + while (L->top < L->base + idx) + setnilvalue(L->top++); + L->top = L->base + idx; + } + else { + api_check(L, -(idx+1) <= (L->top - L->base)); + L->top += idx+1; /* `subtract' index (index is negative) */ + } + lua_unlock(L); +} + + +LUA_API void lua_remove (lua_State *L, int idx) { + StkId p; + lua_lock(L); + p = index2adr(L, idx); + api_checkvalidindex(L, p); + while (++p < L->top) setobjs2s(L, p-1, p); + L->top--; + lua_unlock(L); +} + + +LUA_API void lua_insert (lua_State *L, int idx) { + StkId p; + StkId q; + lua_lock(L); + p = index2adr(L, idx); + api_checkvalidindex(L, p); + for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); + setobjs2s(L, p, L->top); + lua_unlock(L); +} + + +LUA_API void lua_replace (lua_State *L, int idx) { + StkId o; + lua_lock(L); + /* explicit test for incompatible code */ + if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci) + luaG_runerror(L, "no calling environment"); + api_checknelems(L, 1); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + if (idx == LUA_ENVIRONINDEX) { + Closure *func = curr_func(L); + api_check(L, ttistable(L->top - 1)); + func->c.env = hvalue(L->top - 1); + luaC_barrier(L, func, L->top - 1); + } + else { + setobj(L, o, L->top - 1); + if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ + luaC_barrier(L, curr_func(L), L->top - 1); + } + L->top--; + lua_unlock(L); +} + + +LUA_API void lua_pushvalue (lua_State *L, int idx) { + lua_lock(L); + setobj2s(L, L->top, index2adr(L, idx)); + api_incr_top(L); + lua_unlock(L); +} + + + +/* +** access functions (stack -> C) +*/ + + +LUA_API int lua_type (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); +} + + +LUA_API const char *lua_typename (lua_State *L, int t) { + UNUSED(L); + return (t == LUA_TNONE) ? "no value" : luaT_typenames[t]; +} + + +LUA_API int lua_iscfunction (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + return iscfunction(o); +} + + +LUA_API int lua_isnumber (lua_State *L, int idx) { + TValue n; + const TValue *o = index2adr(L, idx); + return tonumber(o, &n); +} + + +LUA_API int lua_isstring (lua_State *L, int idx) { + int t = lua_type(L, idx); + return (t == LUA_TSTRING || t == LUA_TNUMBER); +} + + +LUA_API int lua_isuserdata (lua_State *L, int idx) { + const TValue *o = index2adr(L, idx); + return (ttisuserdata(o) || ttislightuserdata(o)); +} + + +LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { + StkId o1 = index2adr(L, index1); + StkId o2 = index2adr(L, index2); + return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaO_rawequalObj(o1, o2); +} + + +LUA_API int lua_equal (lua_State *L, int index1, int index2) { + StkId o1, o2; + int i; + lua_lock(L); /* may call tag method */ + o1 = index2adr(L, index1); + o2 = index2adr(L, index2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); + lua_unlock(L); + return i; +} + + +LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { + StkId o1, o2; + int i; + lua_lock(L); /* may call tag method */ + o1 = index2adr(L, index1); + o2 = index2adr(L, index2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaV_lessthan(L, o1, o2); + lua_unlock(L); + return i; +} + + + +LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { + TValue n; + const TValue *o = index2adr(L, idx); + if (tonumber(o, &n)) + return nvalue(o); + else + return 0; +} + + +LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { + TValue n; + const TValue *o = index2adr(L, idx); + if (tonumber(o, &n)) { + lua_Integer res; + lua_Number num = nvalue(o); + lua_number2integer(res, num); + return res; + } + else + return 0; +} + + +LUA_API int lua_toboolean (lua_State *L, int idx) { + const TValue *o = index2adr(L, idx); + return !l_isfalse(o); +} + + +LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { + StkId o = index2adr(L, idx); + if (!ttisstring(o)) { + lua_lock(L); /* `luaV_tostring' may create a new string */ + if (!luaV_tostring(L, o)) { /* conversion failed? */ + if (len != NULL) *len = 0; + lua_unlock(L); + return NULL; + } + luaC_checkGC(L); + o = index2adr(L, idx); /* previous call may reallocate the stack */ + lua_unlock(L); + } + if (len != NULL) *len = tsvalue(o)->len; + return svalue(o); +} + + +LUA_API size_t lua_objlen (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TSTRING: return tsvalue(o)->len; + case LUA_TUSERDATA: return uvalue(o)->len; + case LUA_TTABLE: return luaH_getn(hvalue(o)); + case LUA_TNUMBER: { + size_t l; + lua_lock(L); /* `luaV_tostring' may create a new string */ + l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); + lua_unlock(L); + return l; + } + default: return 0; + } +} + + +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; +} + + +LUA_API void *lua_touserdata (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TUSERDATA: return (rawuvalue(o) + 1); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } +} + + +LUA_API lua_State *lua_tothread (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + return (!ttisthread(o)) ? NULL : thvalue(o); +} + + +LUA_API const void *lua_topointer (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TTABLE: return hvalue(o); + case LUA_TFUNCTION: return clvalue(o); + case LUA_TTHREAD: return thvalue(o); + case LUA_TUSERDATA: + case LUA_TLIGHTUSERDATA: + return lua_touserdata(L, idx); + default: return NULL; + } +} + + + +/* +** push functions (C -> stack) +*/ + + +LUA_API void lua_pushnil (lua_State *L) { + lua_lock(L); + setnilvalue(L->top); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { + lua_lock(L); + setnvalue(L->top, n); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { + lua_lock(L); + setnvalue(L->top, cast_num(n)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { + lua_lock(L); + luaC_checkGC(L); + setsvalue2s(L, L->top, luaS_newlstr(L, s, len)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushstring (lua_State *L, const char *s) { + if (s == NULL) + lua_pushnil(L); + else + lua_pushlstring(L, s, strlen(s)); +} + + +LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, + va_list argp) { + const char *ret; + lua_lock(L); + luaC_checkGC(L); + ret = luaO_pushvfstring(L, fmt, argp); + lua_unlock(L); + return ret; +} + + +LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { + const char *ret; + va_list argp; + lua_lock(L); + luaC_checkGC(L); + va_start(argp, fmt); + ret = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + lua_unlock(L); + return ret; +} + + +LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { + Closure *cl; + lua_lock(L); + luaC_checkGC(L); + api_checknelems(L, n); + cl = luaF_newCclosure(L, n, getcurrenv(L)); + cl->c.f = fn; + L->top -= n; + while (n--) + setobj2n(L, &cl->c.upvalue[n], L->top+n); + setclvalue(L, L->top, cl); + lua_assert(iswhite(obj2gco(cl))); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushboolean (lua_State *L, int b) { + lua_lock(L); + setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { + lua_lock(L); + setpvalue(L->top, p); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API int lua_pushthread (lua_State *L) { + lua_lock(L); + setthvalue(L, L->top, L); + api_incr_top(L); + lua_unlock(L); + return (G(L)->mainthread == L); +} + + + +/* +** get functions (Lua -> stack) +*/ + + +LUA_API void lua_gettable (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + luaV_gettable(L, t, L->top - 1, L->top - 1); + lua_unlock(L); +} + + +LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { + StkId t; + TValue key; + lua_lock(L); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, &key, luaS_new(L, k)); + luaV_gettable(L, t, &key, L->top); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_rawget (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2adr(L, idx); + api_check(L, ttistable(t)); + setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); + lua_unlock(L); +} + + +LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { + StkId o; + lua_lock(L); + o = index2adr(L, idx); + api_check(L, ttistable(o)); + setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { + lua_lock(L); + luaC_checkGC(L); + sethvalue(L, L->top, luaH_new(L, narray, nrec)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API int lua_getmetatable (lua_State *L, int objindex) { + const TValue *obj; + Table *mt = NULL; + int res; + lua_lock(L); + obj = index2adr(L, objindex); + switch (ttype(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; + default: + mt = G(L)->mt[ttype(obj)]; + break; + } + if (mt == NULL) + res = 0; + else { + sethvalue(L, L->top, mt); + api_incr_top(L); + res = 1; + } + lua_unlock(L); + return res; +} + + +LUA_API void lua_getfenv (lua_State *L, int idx) { + StkId o; + lua_lock(L); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + switch (ttype(o)) { + case LUA_TFUNCTION: + sethvalue(L, L->top, clvalue(o)->c.env); + break; + case LUA_TUSERDATA: + sethvalue(L, L->top, uvalue(o)->env); + break; + case LUA_TTHREAD: + setobj2s(L, L->top, gt(thvalue(o))); + break; + default: + setnilvalue(L->top); + break; + } + api_incr_top(L); + lua_unlock(L); +} + + +/* +** set functions (stack -> Lua) +*/ + + +LUA_API void lua_settable (lua_State *L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + luaV_settable(L, t, L->top - 2, L->top - 1); + L->top -= 2; /* pop index and value */ + lua_unlock(L); +} + + +LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + StkId t; + TValue key; + lua_lock(L); + api_checknelems(L, 1); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, &key, luaS_new(L, k)); + luaV_settable(L, t, &key, L->top - 1); + L->top--; /* pop value */ + lua_unlock(L); +} + + +LUA_API void lua_rawset (lua_State *L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = index2adr(L, idx); + api_check(L, ttistable(t)); + setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); + luaC_barriert(L, hvalue(t), L->top-1); + L->top -= 2; + lua_unlock(L); +} + + +LUA_API void lua_rawseti (lua_State *L, int idx, int n) { + StkId o; + lua_lock(L); + api_checknelems(L, 1); + o = index2adr(L, idx); + api_check(L, ttistable(o)); + setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); + luaC_barriert(L, hvalue(o), L->top-1); + L->top--; + lua_unlock(L); +} + + +LUA_API int lua_setmetatable (lua_State *L, int objindex) { + TValue *obj; + Table *mt; + lua_lock(L); + api_checknelems(L, 1); + obj = index2adr(L, objindex); + api_checkvalidindex(L, obj); + if (ttisnil(L->top - 1)) + mt = NULL; + else { + api_check(L, ttistable(L->top - 1)); + mt = hvalue(L->top - 1); + } + switch (ttype(obj)) { + case LUA_TTABLE: { + hvalue(obj)->metatable = mt; + if (mt) + luaC_objbarriert(L, hvalue(obj), mt); + break; + } + case LUA_TUSERDATA: { + uvalue(obj)->metatable = mt; + if (mt) + luaC_objbarrier(L, rawuvalue(obj), mt); + break; + } + default: { + G(L)->mt[ttype(obj)] = mt; + break; + } + } + L->top--; + lua_unlock(L); + return 1; +} + + +LUA_API int lua_setfenv (lua_State *L, int idx) { + StkId o; + int res = 1; + lua_lock(L); + api_checknelems(L, 1); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + api_check(L, ttistable(L->top - 1)); + switch (ttype(o)) { + case LUA_TFUNCTION: + clvalue(o)->c.env = hvalue(L->top - 1); + break; + case LUA_TUSERDATA: + uvalue(o)->env = hvalue(L->top - 1); + break; + case LUA_TTHREAD: + sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1)); + break; + default: + res = 0; + break; + } + if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); + L->top--; + lua_unlock(L); + return res; +} + + +/* +** `load' and `call' functions (run Lua code) +*/ + + +#define adjustresults(L,nres) \ + { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; } + + +#define checkresults(L,na,nr) \ + api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) + + +LUA_API void lua_call (lua_State *L, int nargs, int nresults) { + StkId func; + lua_lock(L); + api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); + func = L->top - (nargs+1); + luaD_call(L, func, nresults); + adjustresults(L, nresults); + lua_unlock(L); +} + + + +/* +** Execute a protected call. +*/ +struct CallS { /* data to `f_call' */ + StkId func; + int nresults; +}; + + +static void f_call (lua_State *L, void *ud) { + struct CallS *c = cast(struct CallS *, ud); + luaD_call(L, c->func, c->nresults); +} + + + +LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { + struct CallS c; + int status; + ptrdiff_t func; + lua_lock(L); + api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else { + StkId o = index2adr(L, errfunc); + api_checkvalidindex(L, o); + func = savestack(L, o); + } + c.func = L->top - (nargs+1); /* function to be called */ + c.nresults = nresults; + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + adjustresults(L, nresults); + lua_unlock(L); + return status; +} + + +/* +** Execute a protected C call. +*/ +struct CCallS { /* data to `f_Ccall' */ + lua_CFunction func; + void *ud; +}; + + +static void f_Ccall (lua_State *L, void *ud) { + struct CCallS *c = cast(struct CCallS *, ud); + Closure *cl; + cl = luaF_newCclosure(L, 0, getcurrenv(L)); + cl->c.f = c->func; + setclvalue(L, L->top, cl); /* push function */ + api_incr_top(L); + setpvalue(L->top, c->ud); /* push only argument */ + api_incr_top(L); + luaD_call(L, L->top - 2, 0); +} + + +LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { + struct CCallS c; + int status; + lua_lock(L); + c.func = func; + c.ud = ud; + status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0); + lua_unlock(L); + return status; +} + + +LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, + const char *chunkname) { + ZIO z; + int status; + lua_lock(L); + if (!chunkname) chunkname = "?"; + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname); + lua_unlock(L); + return status; +} + + +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { + int status; + TValue *o; + lua_lock(L); + api_checknelems(L, 1); + o = L->top - 1; + if (isLfunction(o)) + status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0); + else + status = 1; + lua_unlock(L); + return status; +} + + +LUA_API int lua_status (lua_State *L) { + return L->status; +} + + +/* +** Garbage-collection function +*/ + +LUA_API int lua_gc (lua_State *L, int what, int data) { + int res = 0; + global_State *g; + lua_lock(L); + g = G(L); + switch (what) { + case LUA_GCSTOP: { + g->GCthreshold = MAX_LUMEM; + break; + } + case LUA_GCRESTART: { + g->GCthreshold = g->totalbytes; + break; + } + case LUA_GCCOLLECT: { + luaC_fullgc(L); + break; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + res = cast_int(g->totalbytes >> 10); + break; + } + case LUA_GCCOUNTB: { + res = cast_int(g->totalbytes & 0x3ff); + break; + } + case LUA_GCSTEP: { + lu_mem a = (cast(lu_mem, data) << 10); + if (a <= g->totalbytes) + g->GCthreshold = g->totalbytes - a; + else + g->GCthreshold = 0; + while (g->GCthreshold <= g->totalbytes) { + luaC_step(L); + if (g->gcstate == GCSpause) { /* end of cycle? */ + res = 1; /* signal it */ + break; + } + } + break; + } + case LUA_GCSETPAUSE: { + res = g->gcpause; + g->gcpause = data; + break; + } + case LUA_GCSETSTEPMUL: { + res = g->gcstepmul; + g->gcstepmul = data; + break; + } + default: res = -1; /* invalid option */ + } + lua_unlock(L); + return res; +} + + + +/* +** miscellaneous functions +*/ + + +LUA_API int lua_error (lua_State *L) { + lua_lock(L); + api_checknelems(L, 1); + luaG_errormsg(L); + lua_unlock(L); + return 0; /* to avoid warnings */ +} + + +LUA_API int lua_next (lua_State *L, int idx) { + StkId t; + int more; + lua_lock(L); + t = index2adr(L, idx); + api_check(L, ttistable(t)); + more = luaH_next(L, hvalue(t), L->top - 1); + if (more) { + api_incr_top(L); + } + else /* no more elements */ + L->top -= 1; /* remove key */ + lua_unlock(L); + return more; +} + + +LUA_API void lua_concat (lua_State *L, int n) { + lua_lock(L); + api_checknelems(L, n); + if (n >= 2) { + luaC_checkGC(L); + luaV_concat(L, n, cast_int(L->top - L->base) - 1); + L->top -= (n-1); + } + else if (n == 0) { /* push empty string */ + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); + api_incr_top(L); + } + /* else n == 1; nothing to do */ + lua_unlock(L); +} + + +LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { + lua_Alloc f; + lua_lock(L); + if (ud) *ud = G(L)->ud; + f = G(L)->frealloc; + lua_unlock(L); + return f; +} + + +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { + lua_lock(L); + G(L)->ud = ud; + G(L)->frealloc = f; + lua_unlock(L); +} + + +LUA_API void *lua_newuserdata (lua_State *L, size_t size) { + Udata *u; + lua_lock(L); + luaC_checkGC(L); + u = luaS_newudata(L, size, getcurrenv(L)); + setuvalue(L, L->top, u); + api_incr_top(L); + lua_unlock(L); + return u + 1; +} + + + + +static const char *aux_upvalue (StkId fi, int n, TValue **val) { + Closure *f; + if (!ttisfunction(fi)) return NULL; + f = clvalue(fi); + if (f->c.isC) { + if (!(1 <= n && n <= f->c.nupvalues)) return NULL; + *val = &f->c.upvalue[n-1]; + return ""; + } + else { + Proto *p = f->l.p; + if (!(1 <= n && n <= p->sizeupvalues)) return NULL; + *val = f->l.upvals[n-1]->v; + return getstr(p->upvalues[n-1]); + } +} + + +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val; + lua_lock(L); + name = aux_upvalue(index2adr(L, funcindex), n, &val); + if (name) { + setobj2s(L, L->top, val); + api_incr_top(L); + } + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val; + StkId fi; + lua_lock(L); + fi = index2adr(L, funcindex); + api_checknelems(L, 1); + name = aux_upvalue(fi, n, &val); + if (name) { + L->top--; + setobj(L, val, L->top); + luaC_barrier(L, clvalue(fi), L->top); + } + lua_unlock(L); + return name; +} + diff --git a/source/fceultra/lua/src/lapi.h b/source/fceultra/lua/src/lapi.h new file mode 100644 index 0000000..2c3fab2 --- /dev/null +++ b/source/fceultra/lua/src/lapi.h @@ -0,0 +1,16 @@ +/* +** $Id: lapi.h,v 2.2.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions from Lua API +** See Copyright Notice in lua.h +*/ + +#ifndef lapi_h +#define lapi_h + + +#include "lobject.h" + + +LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o); + +#endif diff --git a/source/fceultra/lua/src/lauxlib.c b/source/fceultra/lua/src/lauxlib.c new file mode 100644 index 0000000..10f14e2 --- /dev/null +++ b/source/fceultra/lua/src/lauxlib.c @@ -0,0 +1,652 @@ +/* +** $Id: lauxlib.c,v 1.159.1.3 2008/01/21 13:20:51 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include +#include +#include + + +/* This file uses only the official API of Lua. +** Any function declared here could be written as an application function. +*/ + +#define lauxlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" + + +#define FREELIST_REF 0 /* free list of references */ + + +/* convert a stack index to positive */ +#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ + lua_gettop(L) + (i) + 1) + + +/* +** {====================================================== +** Error-report functions +** ======================================================= +*/ + + +LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { + lua_Debug ar; + if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ + return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); + lua_getinfo(L, "n", &ar); + if (strcmp(ar.namewhat, "method") == 0) { + narg--; /* do not count `self' */ + if (narg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling " LUA_QS " on bad self (%s)", + ar.name, extramsg); + } + if (ar.name == NULL) + ar.name = "?"; + return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", + narg, ar.name, extramsg); +} + + +LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", + tname, luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); +} + + +static void tag_error (lua_State *L, int narg, int tag) { + luaL_typerror(L, narg, lua_typename(L, tag)); +} + + +LUALIB_API void luaL_where (lua_State *L, int level) { + lua_Debug ar; + if (lua_getstack(L, level, &ar)) { /* check function at level */ + lua_getinfo(L, "Sl", &ar); /* get info about it */ + if (ar.currentline > 0) { /* is there info? */ + lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); + return; + } + } + lua_pushliteral(L, ""); /* else, no information available... */ +} + + +LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + luaL_where(L, 1); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + lua_concat(L, 2); + return lua_error(L); +} + +/* }====================================================== */ + + +LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, + const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, narg, def) : + luaL_checkstring(L, narg); + int i; + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) + return i; + return luaL_argerror(L, narg, + lua_pushfstring(L, "invalid option " LUA_QS, name)); +} + + +LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ + if (!lua_isnil(L, -1)) /* name already in use? */ + return 0; /* leave previous value on top, but return 0 */ + lua_pop(L, 1); + lua_newtable(L); /* create metatable */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ + return 1; +} + + +LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + } + luaL_typerror(L, ud, tname); /* else error */ + return NULL; /* to avoid warnings */ +} + + +LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { + if (!lua_checkstack(L, space)) + luaL_error(L, "stack overflow (%s)", mes); +} + + +LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { + if (lua_type(L, narg) != t) + tag_error(L, narg, t); +} + + +LUALIB_API void luaL_checkany (lua_State *L, int narg) { + if (lua_type(L, narg) == LUA_TNONE) + luaL_argerror(L, narg, "value expected"); +} + + +LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { + const char *s = lua_tolstring(L, narg, len); + if (!s) tag_error(L, narg, LUA_TSTRING); + return s; +} + + +LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, + const char *def, size_t *len) { + if (lua_isnoneornil(L, narg)) { + if (len) + *len = (def ? strlen(def) : 0); + return def; + } + else return luaL_checklstring(L, narg, len); +} + + +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { + lua_Number d = lua_tonumber(L, narg); + if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + tag_error(L, narg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { + return luaL_opt(L, luaL_checknumber, narg, def); +} + + +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { + lua_Integer d = lua_tointeger(L, narg); + if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + tag_error(L, narg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, + lua_Integer def) { + return luaL_opt(L, luaL_checkinteger, narg, def); +} + + +LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { + if (!lua_getmetatable(L, obj)) /* no metatable? */ + return 0; + lua_pushstring(L, event); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { + lua_pop(L, 2); /* remove metatable and metafield */ + return 0; + } + else { + lua_remove(L, -2); /* remove only metatable */ + return 1; + } +} + + +LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { + obj = abs_index(L, obj); + if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ + return 0; + lua_pushvalue(L, obj); + lua_call(L, 1, 1); + return 1; +} + + +LUALIB_API void (luaL_register) (lua_State *L, const char *libname, + const luaL_Reg *l) { + luaI_openlib(L, libname, l, 0); +} + + +static int libsize (const luaL_Reg *l) { + int size = 0; + for (; l->name; l++) size++; + return size; +} + + +LUALIB_API void luaI_openlib (lua_State *L, const char *libname, + const luaL_Reg *l, int nup) { + if (libname) { + int size = libsize(l); + /* check whether lib already exists */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); + lua_getfield(L, -1, libname); /* get _LOADED[libname] */ + if (!lua_istable(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) + luaL_error(L, "name conflict for module " LUA_QS, libname); + lua_pushvalue(L, -1); + lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ + } + lua_remove(L, -2); /* remove _LOADED table */ + lua_insert(L, -(nup+1)); /* move library table to below upvalues */ + } + for (; l->name; l++) { + int i; + for (i=0; ifunc, nup); + lua_setfield(L, -(nup+2), l->name); + } + lua_pop(L, nup); /* remove upvalues */ +} + + + +/* +** {====================================================== +** getn-setn: size for arrays +** ======================================================= +*/ + +#if defined(LUA_COMPAT_GETN) + +static int checkint (lua_State *L, int topop) { + int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; + lua_pop(L, topop); + return n; +} + + +static void getsizes (lua_State *L) { + lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); + if (lua_isnil(L, -1)) { /* no `size' table? */ + lua_pop(L, 1); /* remove nil */ + lua_newtable(L); /* create it */ + lua_pushvalue(L, -1); /* `size' will be its own metatable */ + lua_setmetatable(L, -2); + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */ + } +} + + +LUALIB_API void luaL_setn (lua_State *L, int t, int n) { + t = abs_index(L, t); + lua_pushliteral(L, "n"); + lua_rawget(L, t); + if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ + lua_pushliteral(L, "n"); /* use it */ + lua_pushinteger(L, n); + lua_rawset(L, t); + } + else { /* use `sizes' */ + getsizes(L); + lua_pushvalue(L, t); + lua_pushinteger(L, n); + lua_rawset(L, -3); /* sizes[t] = n */ + lua_pop(L, 1); /* remove `sizes' */ + } +} + + +LUALIB_API int luaL_getn (lua_State *L, int t) { + int n; + t = abs_index(L, t); + lua_pushliteral(L, "n"); /* try t.n */ + lua_rawget(L, t); + if ((n = checkint(L, 1)) >= 0) return n; + getsizes(L); /* else try sizes[t] */ + lua_pushvalue(L, t); + lua_rawget(L, -2); + if ((n = checkint(L, 2)) >= 0) return n; + return (int)lua_objlen(L, t); +} + +#endif + +/* }====================================================== */ + + + +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, + const char *r) { + const char *wild; + size_t l = strlen(p); + luaL_Buffer b; + luaL_buffinit(L, &b); + while ((wild = strstr(s, p)) != NULL) { + luaL_addlstring(&b, s, wild - s); /* push prefix */ + luaL_addstring(&b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after `p' */ + } + luaL_addstring(&b, s); /* push last suffix */ + luaL_pushresult(&b); + return lua_tostring(L, -1); +} + + +LUALIB_API const char *luaL_findtable (lua_State *L, int idx, + const char *fname, int szhint) { + const char *e; + lua_pushvalue(L, idx); + do { + e = strchr(fname, '.'); + if (e == NULL) e = fname + strlen(fname); + lua_pushlstring(L, fname, e - fname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { /* no such field? */ + lua_pop(L, 1); /* remove this nil */ + lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ + lua_pushlstring(L, fname, e - fname); + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ + lua_pop(L, 2); /* remove table and value */ + return fname; /* return problematic part of the name */ + } + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + } while (*e == '.'); + return NULL; +} + + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + +#define bufflen(B) ((B)->p - (B)->buffer) +#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) + +#define LIMIT (LUA_MINSTACK/2) + + +static int emptybuffer (luaL_Buffer *B) { + size_t l = bufflen(B); + if (l == 0) return 0; /* put nothing on stack */ + else { + lua_pushlstring(B->L, B->buffer, l); + B->p = B->buffer; + B->lvl++; + return 1; + } +} + + +static void adjuststack (luaL_Buffer *B) { + if (B->lvl > 1) { + lua_State *L = B->L; + int toget = 1; /* number of levels to concat */ + size_t toplen = lua_strlen(L, -1); + do { + size_t l = lua_strlen(L, -(toget+1)); + if (B->lvl - toget + 1 >= LIMIT || toplen > l) { + toplen += l; + toget++; + } + else break; + } while (toget < B->lvl); + lua_concat(L, toget); + B->lvl = B->lvl - toget + 1; + } +} + + +LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { + if (emptybuffer(B)) + adjuststack(B); + return B->buffer; +} + + +LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { + while (l--) + luaL_addchar(B, *s++); +} + + +LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { + luaL_addlstring(B, s, strlen(s)); +} + + +LUALIB_API void luaL_pushresult (luaL_Buffer *B) { + emptybuffer(B); + lua_concat(B->L, B->lvl); + B->lvl = 1; +} + + +LUALIB_API void luaL_addvalue (luaL_Buffer *B) { + lua_State *L = B->L; + size_t vl; + const char *s = lua_tolstring(L, -1, &vl); + if (vl <= bufffree(B)) { /* fit into buffer? */ + memcpy(B->p, s, vl); /* put it there */ + B->p += vl; + lua_pop(L, 1); /* remove from stack */ + } + else { + if (emptybuffer(B)) + lua_insert(L, -2); /* put buffer before new value */ + B->lvl++; /* add new value into B stack */ + adjuststack(B); + } +} + + +LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + B->L = L; + B->p = B->buffer; + B->lvl = 0; +} + +/* }====================================================== */ + + +LUALIB_API int luaL_ref (lua_State *L, int t) { + int ref; + t = abs_index(L, t); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* remove from stack */ + return LUA_REFNIL; /* `nil' has a unique fixed reference */ + } + lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ + ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ + lua_pop(L, 1); /* remove it from stack */ + if (ref != 0) { /* any free element? */ + lua_rawgeti(L, t, ref); /* remove it from list */ + lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ + } + else { /* no free elements */ + ref = (int)lua_objlen(L, t); + ref++; /* create new reference */ + } + lua_rawseti(L, t, ref); + return ref; +} + + +LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { + if (ref >= 0) { + t = abs_index(L, t); + lua_rawgeti(L, t, FREELIST_REF); + lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ + lua_pushinteger(L, ref); + lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ + } +} + + + +/* +** {====================================================== +** Load functions +** ======================================================= +*/ + +typedef struct LoadF { + int extraline; + FILE *f; + char buff[LUAL_BUFFERSIZE]; +} LoadF; + + +static const char *getF (lua_State *L, void *ud, size_t *size) { + LoadF *lf = (LoadF *)ud; + (void)L; + if (lf->extraline) { + lf->extraline = 0; + *size = 1; + return "\n"; + } + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); + return (*size > 0) ? lf->buff : NULL; +} + + +static int errfile (lua_State *L, const char *what, int fnameindex) { + const char *serr = strerror(errno); + const char *filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + + +LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { + LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + lf.extraline = 0; + if (filename == NULL) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); + lf.f = fopen(filename, "r"); + if (lf.f == NULL) return errfile(L, "open", fnameindex); + } + c = getc(lf.f); + if (c == '#') { /* Unix exec. file? */ + lf.extraline = 1; + while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ + if (c == '\n') c = getc(lf.f); + } + if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); + /* skip eventual `#!...' */ + while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; + lf.extraline = 0; + } + ungetc(c, lf.f); + status = lua_load(L, getF, &lf, lua_tostring(L, -1)); + readstatus = ferror(lf.f); + if (filename) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from `lua_load' */ + return errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; +} + + +typedef struct LoadS { + const char *s; + size_t size; +} LoadS; + + +static const char *getS (lua_State *L, void *ud, size_t *size) { + LoadS *ls = (LoadS *)ud; + (void)L; + if (ls->size == 0) return NULL; + *size = ls->size; + ls->size = 0; + return ls->s; +} + + +LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, + const char *name) { + LoadS ls; + ls.s = buff; + ls.size = size; + return lua_load(L, getS, &ls, name); +} + + +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { + return luaL_loadbuffer(L, s, strlen(s), s); +} + + + +/* }====================================================== */ + + +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; + (void)osize; + if (nsize == 0) { + free(ptr); + return NULL; + } + else + return realloc(ptr, nsize); +} + + +static int panic (lua_State *L) { + (void)L; /* to avoid warnings */ + fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); + return 0; +} + + +LUALIB_API lua_State *luaL_newstate (void) { + lua_State *L = lua_newstate(l_alloc, NULL); + if (L) lua_atpanic(L, &panic); + return L; +} + diff --git a/source/fceultra/lua/src/lauxlib.h b/source/fceultra/lua/src/lauxlib.h new file mode 100644 index 0000000..3425823 --- /dev/null +++ b/source/fceultra/lua/src/lauxlib.h @@ -0,0 +1,174 @@ +/* +** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lauxlib_h +#define lauxlib_h + + +#include +#include + +#include "lua.h" + + +#if defined(LUA_COMPAT_GETN) +LUALIB_API int (luaL_getn) (lua_State *L, int t); +LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); +#else +#define luaL_getn(L,i) ((int)lua_objlen(L, i)) +#define luaL_setn(L,i,j) ((void)0) /* no op! */ +#endif + +#if defined(LUA_COMPAT_OPENLIB) +#define luaI_openlib luaL_openlib +#endif + + +/* extra error code for `luaL_load' */ +#define LUA_ERRFILE (LUA_ERRERR+1) + + +typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} luaL_Reg; + + + +LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); +LUALIB_API void (luaL_register) (lua_State *L, const char *libname, + const luaL_Reg *l); +LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); +LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, + size_t *l); +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, + const char *def, size_t *l); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); + +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, + lua_Integer def); + +LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); +LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int narg); + +LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); + +LUALIB_API void (luaL_where) (lua_State *L, int lvl); +LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); + +LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, + const char *const lst[]); + +LUALIB_API int (luaL_ref) (lua_State *L, int t); +LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); + +LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); +LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, + const char *name); +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); + +LUALIB_API lua_State *(luaL_newstate) (void); + + +LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, + const char *r); + +LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, + const char *fname, int szhint); + + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define luaL_argcheck(L, cond,numarg,extramsg) \ + ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) +#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) +#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) + +#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) + +#define luaL_dofile(L, fn) \ + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_dostring(L, s) \ + (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) + +#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + + +typedef struct luaL_Buffer { + char *p; /* current position in buffer */ + int lvl; /* number of strings in the stack (level) */ + lua_State *L; + char buffer[LUAL_BUFFERSIZE]; +} luaL_Buffer; + +#define luaL_addchar(B,c) \ + ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ + (*(B)->p++ = (char)(c))) + +/* compatibility only */ +#define luaL_putchar(B,c) luaL_addchar(B,c) + +#define luaL_addsize(B,n) ((B)->p += (n)) + +LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); +LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); +LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); +LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); + + +/* }====================================================== */ + + +/* compatibility with ref system */ + +/* pre-defined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) + +#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ + (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) + +#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) + +#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) + + +#define luaL_reg luaL_Reg + +#endif + + diff --git a/source/fceultra/lua/src/lbaselib.c b/source/fceultra/lua/src/lbaselib.c new file mode 100644 index 0000000..2a4c079 --- /dev/null +++ b/source/fceultra/lua/src/lbaselib.c @@ -0,0 +1,653 @@ +/* +** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $ +** Basic library +** See Copyright Notice in lua.h +*/ + + + +#include +#include +#include +#include + +#define lbaselib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + + +/* +** If your system does not support `stdout', you can just remove this function. +** If you need, you can define your own `print' function, following this +** model but changing `fputs' to put the strings at a proper place +** (a console window or a log file, for instance). +*/ +static int luaB_print (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + lua_getglobal(L, "tostring"); + for (i=1; i<=n; i++) { + const char *s; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + s = lua_tostring(L, -1); /* get result */ + if (s == NULL) + return luaL_error(L, LUA_QL("tostring") " must return a string to " + LUA_QL("print")); + if (i>1) fputs("\t", stdout); + fputs(s, stdout); + lua_pop(L, 1); /* pop result */ + } + fputs("\n", stdout); + return 0; +} + + +static int luaB_tonumber (lua_State *L) { + int base = luaL_optint(L, 2, 10); + if (base == 10) { /* standard conversion */ + luaL_checkany(L, 1); + if (lua_isnumber(L, 1)) { + lua_pushnumber(L, lua_tonumber(L, 1)); + return 1; + } + } + else { + const char *s1 = luaL_checkstring(L, 1); + char *s2; + unsigned long n; + luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); + n = strtoul(s1, &s2, base); + if (s1 != s2) { /* at least one valid digit? */ + while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ + if (*s2 == '\0') { /* no invalid trailing characters? */ + lua_pushnumber(L, (lua_Number)n); + return 1; + } + } + } + lua_pushnil(L); /* else not a number */ + return 1; +} + + +static int luaB_error (lua_State *L) { + int level = luaL_optint(L, 2, 1); + lua_settop(L, 1); + if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ + luaL_where(L, level); + lua_pushvalue(L, 1); + lua_concat(L, 2); + } + return lua_error(L); +} + + +static int luaB_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); + return 1; /* no metatable */ + } + luaL_getmetafield(L, 1, "__metatable"); + return 1; /* returns either __metatable field (if present) or metatable */ +} + + +static int luaB_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + if (luaL_getmetafield(L, 1, "__metatable")) + luaL_error(L, "cannot change a protected metatable"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; +} + + +static void getfunc (lua_State *L, int opt) { + if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); + else { + lua_Debug ar; + int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); + luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); + if (lua_getstack(L, level, &ar) == 0) + luaL_argerror(L, 1, "invalid level"); + lua_getinfo(L, "f", &ar); + if (lua_isnil(L, -1)) + luaL_error(L, "no function environment for tail call at level %d", + level); + } +} + + +static int luaB_getfenv (lua_State *L) { + getfunc(L, 1); + if (lua_iscfunction(L, -1)) /* is a C function? */ + lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ + else + lua_getfenv(L, -1); + return 1; +} + + +static int luaB_setfenv (lua_State *L) { + luaL_checktype(L, 2, LUA_TTABLE); + getfunc(L, 0); + lua_pushvalue(L, 2); + if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { + /* change environment of current thread */ + lua_pushthread(L); + lua_insert(L, -2); + lua_setfenv(L, -2); + return 0; + } + else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) + luaL_error(L, + LUA_QL("setfenv") " cannot change environment of given object"); + return 1; +} + + +static int luaB_rawequal (lua_State *L) { + luaL_checkany(L, 1); + luaL_checkany(L, 2); + lua_pushboolean(L, lua_rawequal(L, 1, 2)); + return 1; +} + + +static int luaB_rawget (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_rawget(L, 1); + return 1; +} + +static int luaB_rawset (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_settop(L, 3); + lua_rawset(L, 1); + return 1; +} + + +static int luaB_gcinfo (lua_State *L) { + lua_pushinteger(L, lua_getgccount(L)); + return 1; +} + + +static int luaB_collectgarbage (lua_State *L) { + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", NULL}; + static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; + int o = luaL_checkoption(L, 1, "collect", opts); + int ex = luaL_optint(L, 2, 0); + int res = lua_gc(L, optsnum[o], ex); + switch (optsnum[o]) { + case LUA_GCCOUNT: { + int b = lua_gc(L, LUA_GCCOUNTB, 0); + lua_pushnumber(L, res + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: { + lua_pushboolean(L, res); + return 1; + } + default: { + lua_pushnumber(L, res); + return 1; + } + } +} + + +static int luaB_type (lua_State *L) { + luaL_checkany(L, 1); + lua_pushstring(L, luaL_typename(L, 1)); + return 1; +} + + +static int luaB_next (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1)) + return 2; + else { + lua_pushnil(L); + return 1; + } +} + + +static int luaB_pairs (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushnil(L); /* and initial value */ + return 3; +} + + +static int ipairsaux (lua_State *L) { + int i = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + i++; /* next value */ + lua_pushinteger(L, i); + lua_rawgeti(L, 1, i); + return (lua_isnil(L, -1)) ? 0 : 2; +} + + +static int luaB_ipairs (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushinteger(L, 0); /* and initial value */ + return 3; +} + + +static int load_aux (lua_State *L, int status) { + if (status == 0) /* OK? */ + return 1; + else { + lua_pushnil(L); + lua_insert(L, -2); /* put before error message */ + return 2; /* return nil plus error message */ + } +} + + +static int luaB_loadstring (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + const char *chunkname = luaL_optstring(L, 2, s); + return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); +} + + +static int luaB_loadfile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + return load_aux(L, luaL_loadfile(L, fname)); +} + + +/* +** Reader for generic `load' function: `lua_load' uses the +** stack for internal stuff, so the reader cannot change the +** stack top. Instead, it keeps its resulting string in a +** reserved slot inside the stack. +*/ +static const char *generic_reader (lua_State *L, void *ud, size_t *size) { + (void)ud; /* to avoid warnings */ + luaL_checkstack(L, 2, "too many nested functions"); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ + if (lua_isnil(L, -1)) { + *size = 0; + return NULL; + } + else if (lua_isstring(L, -1)) { + lua_replace(L, 3); /* save string in a reserved stack slot */ + return lua_tolstring(L, 3, size); + } + else luaL_error(L, "reader function must return a string"); + return NULL; /* to avoid warnings */ +} + + +static int luaB_load (lua_State *L) { + int status; + const char *cname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ + status = lua_load(L, generic_reader, NULL, cname); + return load_aux(L, status); +} + + +static int luaB_dofile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + int n = lua_gettop(L); + if (luaL_loadfile(L, fname) != 0) lua_error(L); + lua_call(L, 0, LUA_MULTRET); + return lua_gettop(L) - n; +} + + +static int luaB_assert (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_toboolean(L, 1)) + return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); + return lua_gettop(L); +} + + +static int luaB_unpack (lua_State *L) { + int i, e, n; + luaL_checktype(L, 1, LUA_TTABLE); + i = luaL_optint(L, 2, 1); + e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); + if (i > e) return 0; /* empty range */ + n = e - i + 1; /* number of elements */ + if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ + return luaL_error(L, "too many results to unpack"); + lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ + while (i++ < e) /* push arg[i + 1...e] */ + lua_rawgeti(L, 1, i); + return n; +} + + +static int luaB_select (lua_State *L) { + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { + lua_pushinteger(L, n-1); + return 1; + } + else { + int i = luaL_checkint(L, 1); + if (i < 0) i = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - i; + } +} + + +static int luaB_pcall (lua_State *L) { + int status; + luaL_checkany(L, 1); + status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); + lua_pushboolean(L, (status == 0)); + lua_insert(L, 1); + return lua_gettop(L); /* return status + all results */ +} + + +static int luaB_xpcall (lua_State *L) { + int status; + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_insert(L, 1); /* put error function under function to be called */ + status = lua_pcall(L, 0, LUA_MULTRET, 1); + lua_pushboolean(L, (status == 0)); + lua_replace(L, 1); + return lua_gettop(L); /* return status + all results */ +} + + +static int luaB_tostring (lua_State *L) { + luaL_checkany(L, 1); + if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ + return 1; /* use its value */ + switch (lua_type(L, 1)) { + case LUA_TNUMBER: + lua_pushstring(L, lua_tostring(L, 1)); + break; + case LUA_TSTRING: + lua_pushvalue(L, 1); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); + break; + } + return 1; +} + + +static int luaB_newproxy (lua_State *L) { + lua_settop(L, 1); + lua_newuserdata(L, 0); /* create proxy */ + if (lua_toboolean(L, 1) == 0) + return 1; /* no metatable */ + else if (lua_isboolean(L, 1)) { + lua_newtable(L); /* create a new metatable `m' ... */ + lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ + lua_pushboolean(L, 1); + lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ + } + else { + int validproxy = 0; /* to check if weaktable[metatable(u)] == true */ + if (lua_getmetatable(L, 1)) { + lua_rawget(L, lua_upvalueindex(1)); + validproxy = lua_toboolean(L, -1); + lua_pop(L, 1); /* remove value */ + } + luaL_argcheck(L, validproxy, 1, "boolean or proxy expected"); + lua_getmetatable(L, 1); /* metatable is valid; get it */ + } + lua_setmetatable(L, 2); + return 1; +} + + +static const luaL_Reg base_funcs[] = { + {"assert", luaB_assert}, + {"collectgarbage", luaB_collectgarbage}, + {"dofile", luaB_dofile}, + {"error", luaB_error}, + {"gcinfo", luaB_gcinfo}, + {"getfenv", luaB_getfenv}, + {"getmetatable", luaB_getmetatable}, + {"loadfile", luaB_loadfile}, + {"load", luaB_load}, + {"loadstring", luaB_loadstring}, + {"next", luaB_next}, + {"pcall", luaB_pcall}, + {"print", luaB_print}, + {"rawequal", luaB_rawequal}, + {"rawget", luaB_rawget}, + {"rawset", luaB_rawset}, + {"select", luaB_select}, + {"setfenv", luaB_setfenv}, + {"setmetatable", luaB_setmetatable}, + {"tonumber", luaB_tonumber}, + {"tostring", luaB_tostring}, + {"type", luaB_type}, + {"unpack", luaB_unpack}, + {"xpcall", luaB_xpcall}, + {NULL, NULL} +}; + + +/* +** {====================================================== +** Coroutine library +** ======================================================= +*/ + +#define CO_RUN 0 /* running */ +#define CO_SUS 1 /* suspended */ +#define CO_NOR 2 /* 'normal' (it resumed another coroutine) */ +#define CO_DEAD 3 + +static const char *const statnames[] = + {"running", "suspended", "normal", "dead"}; + +static int costatus (lua_State *L, lua_State *co) { + if (L == co) return CO_RUN; + switch (lua_status(co)) { + case LUA_YIELD: + return CO_SUS; + case 0: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + return CO_NOR; /* it is running */ + else if (lua_gettop(co) == 0) + return CO_DEAD; + else + return CO_SUS; /* initial state */ + } + default: /* some error occured */ + return CO_DEAD; + } +} + + +static int luaB_costatus (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "coroutine expected"); + lua_pushstring(L, statnames[costatus(L, co)]); + return 1; +} + + +static int auxresume (lua_State *L, lua_State *co, int narg) { + int status = costatus(L, co); + if (!lua_checkstack(co, narg)) + luaL_error(L, "too many arguments to resume"); + if (status != CO_SUS) { + lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]); + return -1; /* error flag */ + } + lua_xmove(L, co, narg); + lua_setlevel(L, co); + status = lua_resume(co, narg); + if (status == 0 || status == LUA_YIELD) { + int nres = lua_gettop(co); + if (!lua_checkstack(L, nres + 1)) + luaL_error(L, "too many results to resume"); + lua_xmove(co, L, nres); /* move yielded values */ + return nres; + } + else { + lua_xmove(co, L, 1); /* move error message */ + return -1; /* error flag */ + } +} + + +static int luaB_coresume (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + int r; + luaL_argcheck(L, co, 1, "coroutine expected"); + r = auxresume(L, co, lua_gettop(L) - 1); + if (r < 0) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + `resume' returns */ + } +} + + +static int luaB_auxwrap (lua_State *L) { + lua_State *co = lua_tothread(L, lua_upvalueindex(1)); + int r = auxresume(L, co, lua_gettop(L)); + if (r < 0) { + if (lua_isstring(L, -1)) { /* error object is a string? */ + luaL_where(L, 1); /* add extra info */ + lua_insert(L, -2); + lua_concat(L, 2); + } + lua_error(L); /* propagate error */ + } + return r; +} + + +static int luaB_cocreate (lua_State *L) { + lua_State *NL = lua_newthread(L); + luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, + "Lua function expected"); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + return 1; +} + + +static int luaB_cowrap (lua_State *L) { + luaB_cocreate(L); + lua_pushcclosure(L, luaB_auxwrap, 1); + return 1; +} + + +static int luaB_yield (lua_State *L) { + return lua_yield(L, lua_gettop(L)); +} + + +static int luaB_corunning (lua_State *L) { + if (lua_pushthread(L)) + lua_pushnil(L); /* main thread is not a coroutine */ + return 1; +} + + +static const luaL_Reg co_funcs[] = { + {"create", luaB_cocreate}, + {"resume", luaB_coresume}, + {"running", luaB_corunning}, + {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, + {NULL, NULL} +}; + +/* }====================================================== */ + + +static void auxopen (lua_State *L, const char *name, + lua_CFunction f, lua_CFunction u) { + lua_pushcfunction(L, u); + lua_pushcclosure(L, f, 1); + lua_setfield(L, -2, name); +} + + +static void base_open (lua_State *L) { + /* set global _G */ + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setglobal(L, "_G"); + /* open lib into global table */ + luaL_register(L, "_G", base_funcs); + lua_pushliteral(L, LUA_VERSION); + lua_setglobal(L, "_VERSION"); /* set global _VERSION */ + /* `ipairs' and `pairs' need auxliliary functions as upvalues */ + auxopen(L, "ipairs", luaB_ipairs, ipairsaux); + auxopen(L, "pairs", luaB_pairs, luaB_next); + /* `newproxy' needs a weaktable as upvalue */ + lua_createtable(L, 0, 1); /* new table `w' */ + lua_pushvalue(L, -1); /* `w' will be its own metatable */ + lua_setmetatable(L, -2); + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ + lua_pushcclosure(L, luaB_newproxy, 1); + lua_setglobal(L, "newproxy"); /* set global `newproxy' */ +} + + +LUALIB_API int luaopen_base (lua_State *L) { + base_open(L); + luaL_register(L, LUA_COLIBNAME, co_funcs); + return 2; +} + diff --git a/source/fceultra/lua/src/lcode.c b/source/fceultra/lua/src/lcode.c new file mode 100644 index 0000000..cff626b --- /dev/null +++ b/source/fceultra/lua/src/lcode.c @@ -0,0 +1,839 @@ +/* +** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + + +#include + +#define lcode_c +#define LUA_CORE + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "ltable.h" + + +#define hasjumps(e) ((e)->t != (e)->f) + + +static int isnumeral(expdesc *e) { + return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); +} + + +void luaK_nil (FuncState *fs, int from, int n) { + Instruction *previous; + if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ + if (fs->pc == 0) { /* function start? */ + if (from >= fs->nactvar) + return; /* positions are already clean */ + } + else { + previous = &fs->f->code[fs->pc-1]; + if (GET_OPCODE(*previous) == OP_LOADNIL) { + int pfrom = GETARG_A(*previous); + int pto = GETARG_B(*previous); + if (pfrom <= from && from <= pto+1) { /* can connect both? */ + if (from+n-1 > pto) + SETARG_B(*previous, from+n-1); + return; + } + } + } + } + luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ +} + + +int luaK_jump (FuncState *fs) { + int jpc = fs->jpc; /* save list of jumps to here */ + int j; + fs->jpc = NO_JUMP; + j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); + luaK_concat(fs, &j, jpc); /* keep them on hold */ + return j; +} + + +void luaK_ret (FuncState *fs, int first, int nret) { + luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); +} + + +static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { + luaK_codeABC(fs, op, A, B, C); + return luaK_jump(fs); +} + + +static void fixjump (FuncState *fs, int pc, int dest) { + Instruction *jmp = &fs->f->code[pc]; + int offset = dest-(pc+1); + lua_assert(dest != NO_JUMP); + if (abs(offset) > MAXARG_sBx) + luaX_syntaxerror(fs->ls, "control structure too long"); + SETARG_sBx(*jmp, offset); +} + + +/* +** returns current `pc' and marks it as a jump target (to avoid wrong +** optimizations with consecutive instructions not in the same basic block). +*/ +int luaK_getlabel (FuncState *fs) { + fs->lasttarget = fs->pc; + return fs->pc; +} + + +static int getjump (FuncState *fs, int pc) { + int offset = GETARG_sBx(fs->f->code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + + +static Instruction *getjumpcontrol (FuncState *fs, int pc) { + Instruction *pi = &fs->f->code[pc]; + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) + return pi-1; + else + return pi; +} + + +/* +** check whether list has any jump that do not produce a value +** (or produce an inverted value) +*/ +static int need_value (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) return 1; + } + return 0; /* not found */ +} + + +static int patchtestreg (FuncState *fs, int node, int reg) { + Instruction *i = getjumpcontrol(fs, node); + if (GET_OPCODE(*i) != OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(*i)) + SETARG_A(*i, reg); + else /* no register to put value or register already has the value */ + *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); + + return 1; +} + + +static void removevalues (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); +} + + +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, + int dtarget) { + while (list != NO_JUMP) { + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg)) + fixjump(fs, list, vtarget); + else + fixjump(fs, list, dtarget); /* jump to default target */ + list = next; + } +} + + +static void dischargejpc (FuncState *fs) { + patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); + fs->jpc = NO_JUMP; +} + + +void luaK_patchlist (FuncState *fs, int list, int target) { + if (target == fs->pc) + luaK_patchtohere(fs, list); + else { + lua_assert(target < fs->pc); + patchlistaux(fs, list, target, NO_REG, target); + } +} + + +void luaK_patchtohere (FuncState *fs, int list) { + luaK_getlabel(fs); + luaK_concat(fs, &fs->jpc, list); +} + + +void luaK_concat (FuncState *fs, int *l1, int l2) { + if (l2 == NO_JUMP) return; + else if (*l1 == NO_JUMP) + *l1 = l2; + else { + int list = *l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); + } +} + + +void luaK_checkstack (FuncState *fs, int n) { + int newstack = fs->freereg + n; + if (newstack > fs->f->maxstacksize) { + if (newstack >= MAXSTACK) + luaX_syntaxerror(fs->ls, "function or expression too complex"); + fs->f->maxstacksize = cast_byte(newstack); + } +} + + +void luaK_reserveregs (FuncState *fs, int n) { + luaK_checkstack(fs, n); + fs->freereg += n; +} + + +static void freereg (FuncState *fs, int reg) { + if (!ISK(reg) && reg >= fs->nactvar) { + fs->freereg--; + lua_assert(reg == fs->freereg); + } +} + + +static void freeexp (FuncState *fs, expdesc *e) { + if (e->k == VNONRELOC) + freereg(fs, e->u.s.info); +} + + +static int addk (FuncState *fs, TValue *k, TValue *v) { + lua_State *L = fs->L; + TValue *idx = luaH_set(L, fs->h, k); + Proto *f = fs->f; + int oldsize = f->sizek; + if (ttisnumber(idx)) { + lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); + return cast_int(nvalue(idx)); + } + else { /* constant not found; create a new entry */ + setnvalue(idx, cast_num(fs->nk)); + luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, + MAXARG_Bx, "constant table overflow"); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[fs->nk], v); + luaC_barrier(L, f, v); + return fs->nk++; + } +} + + +int luaK_stringK (FuncState *fs, TString *s) { + TValue o; + setsvalue(fs->L, &o, s); + return addk(fs, &o, &o); +} + + +int luaK_numberK (FuncState *fs, lua_Number r) { + TValue o; + setnvalue(&o, r); + return addk(fs, &o, &o); +} + + +static int boolK (FuncState *fs, int b) { + TValue o; + setbvalue(&o, b); + return addk(fs, &o, &o); +} + + +static int nilK (FuncState *fs) { + TValue k, v; + setnilvalue(&v); + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->L, &k, fs->h); + return addk(fs, &k, &v); +} + + +void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { + if (e->k == VCALL) { /* expression is an open function call? */ + SETARG_C(getcode(fs, e), nresults+1); + } + else if (e->k == VVARARG) { + SETARG_B(getcode(fs, e), nresults+1); + SETARG_A(getcode(fs, e), fs->freereg); + luaK_reserveregs(fs, 1); + } +} + + +void luaK_setoneret (FuncState *fs, expdesc *e) { + if (e->k == VCALL) { /* expression is an open function call? */ + e->k = VNONRELOC; + e->u.s.info = GETARG_A(getcode(fs, e)); + } + else if (e->k == VVARARG) { + SETARG_B(getcode(fs, e), 2); + e->k = VRELOCABLE; /* can relocate its simple result */ + } +} + + +void luaK_dischargevars (FuncState *fs, expdesc *e) { + switch (e->k) { + case VLOCAL: { + e->k = VNONRELOC; + break; + } + case VUPVAL: { + e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); + e->k = VRELOCABLE; + break; + } + case VGLOBAL: { + e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); + e->k = VRELOCABLE; + break; + } + case VINDEXED: { + freereg(fs, e->u.s.aux); + freereg(fs, e->u.s.info); + e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); + e->k = VRELOCABLE; + break; + } + case VVARARG: + case VCALL: { + luaK_setoneret(fs, e); + break; + } + default: break; /* there is one value available (somewhere) */ + } +} + + +static int code_label (FuncState *fs, int A, int b, int jump) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); +} + + +static void discharge2reg (FuncState *fs, expdesc *e, int reg) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: { + luaK_nil(fs, reg, 1); + break; + } + case VFALSE: case VTRUE: { + luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); + break; + } + case VK: { + luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); + break; + } + case VKNUM: { + luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); + break; + } + case VRELOCABLE: { + Instruction *pc = &getcode(fs, e); + SETARG_A(*pc, reg); + break; + } + case VNONRELOC: { + if (reg != e->u.s.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); + break; + } + default: { + lua_assert(e->k == VVOID || e->k == VJMP); + return; /* nothing to do... */ + } + } + e->u.s.info = reg; + e->k = VNONRELOC; +} + + +static void discharge2anyreg (FuncState *fs, expdesc *e) { + if (e->k != VNONRELOC) { + luaK_reserveregs(fs, 1); + discharge2reg(fs, e, fs->freereg-1); + } +} + + +static void exp2reg (FuncState *fs, expdesc *e, int reg) { + discharge2reg(fs, e, reg); + if (e->k == VJMP) + luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */ + if (hasjumps(e)) { + int final; /* position after whole expression */ + int p_f = NO_JUMP; /* position of an eventual LOAD false */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + if (need_value(fs, e->t) || need_value(fs, e->f)) { + int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); + p_f = code_label(fs, reg, 0, 1); + p_t = code_label(fs, reg, 1, 0); + luaK_patchtohere(fs, fj); + } + final = luaK_getlabel(fs); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); + } + e->f = e->t = NO_JUMP; + e->u.s.info = reg; + e->k = VNONRELOC; +} + + +void luaK_exp2nextreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + freeexp(fs, e); + luaK_reserveregs(fs, 1); + exp2reg(fs, e, fs->freereg - 1); +} + + +int luaK_exp2anyreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + if (e->k == VNONRELOC) { + if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */ + if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */ + exp2reg(fs, e, e->u.s.info); /* put value on it */ + return e->u.s.info; + } + } + luaK_exp2nextreg(fs, e); /* default */ + return e->u.s.info; +} + + +void luaK_exp2val (FuncState *fs, expdesc *e) { + if (hasjumps(e)) + luaK_exp2anyreg(fs, e); + else + luaK_dischargevars(fs, e); +} + + +int luaK_exp2RK (FuncState *fs, expdesc *e) { + luaK_exp2val(fs, e); + switch (e->k) { + case VKNUM: + case VTRUE: + case VFALSE: + case VNIL: { + if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ + e->u.s.info = (e->k == VNIL) ? nilK(fs) : + (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : + boolK(fs, (e->k == VTRUE)); + e->k = VK; + return RKASK(e->u.s.info); + } + else break; + } + case VK: { + if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ + return RKASK(e->u.s.info); + else break; + } + default: break; + } + /* not a constant in the right range: put it in a register */ + return luaK_exp2anyreg(fs, e); +} + + +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { + switch (var->k) { + case VLOCAL: { + freeexp(fs, ex); + exp2reg(fs, ex, var->u.s.info); + return; + } + case VUPVAL: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); + break; + } + case VGLOBAL: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); + break; + } + case VINDEXED: { + int e = luaK_exp2RK(fs, ex); + luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); + break; + } + default: { + lua_assert(0); /* invalid var kind to store */ + break; + } + } + freeexp(fs, ex); +} + + +void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { + int func; + luaK_exp2anyreg(fs, e); + freeexp(fs, e); + func = fs->freereg; + luaK_reserveregs(fs, 2); + luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); + freeexp(fs, key); + e->u.s.info = func; + e->k = VNONRELOC; +} + + +static void invertjump (FuncState *fs, expdesc *e) { + Instruction *pc = getjumpcontrol(fs, e->u.s.info); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && + GET_OPCODE(*pc) != OP_TEST); + SETARG_A(*pc, !(GETARG_A(*pc))); +} + + +static int jumponcond (FuncState *fs, expdesc *e, int cond) { + if (e->k == VRELOCABLE) { + Instruction ie = getcode(fs, e); + if (GET_OPCODE(ie) == OP_NOT) { + fs->pc--; /* remove previous OP_NOT */ + return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); +} + + +void luaK_goiftrue (FuncState *fs, expdesc *e) { + int pc; /* pc of last jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VK: case VKNUM: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ + break; + } + case VFALSE: { + pc = luaK_jump(fs); /* always jump */ + break; + } + case VJMP: { + invertjump(fs, e); + pc = e->u.s.info; + break; + } + default: { + pc = jumponcond(fs, e, 0); + break; + } + } + luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ + luaK_patchtohere(fs, e->t); + e->t = NO_JUMP; +} + + +static void luaK_goiffalse (FuncState *fs, expdesc *e) { + int pc; /* pc of last jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ + break; + } + case VTRUE: { + pc = luaK_jump(fs); /* always jump */ + break; + } + case VJMP: { + pc = e->u.s.info; + break; + } + default: { + pc = jumponcond(fs, e, 1); + break; + } + } + luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ + luaK_patchtohere(fs, e->f); + e->f = NO_JUMP; +} + + +static void codenot (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: case VFALSE: { + e->k = VTRUE; + break; + } + case VK: case VKNUM: case VTRUE: { + e->k = VFALSE; + break; + } + case VJMP: { + invertjump(fs, e); + break; + } + case VRELOCABLE: + case VNONRELOC: { + discharge2anyreg(fs, e); + freeexp(fs, e); + e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); + e->k = VRELOCABLE; + break; + } + default: { + lua_assert(0); /* cannot happen */ + break; + } + } + /* interchange true and false lists */ + { int temp = e->f; e->f = e->t; e->t = temp; } + removevalues(fs, e->f); + removevalues(fs, e->t); +} + + +void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + t->u.s.aux = luaK_exp2RK(fs, k); + t->k = VINDEXED; +} + + +static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { + lua_Number v1, v2, r; + if (!isnumeral(e1) || !isnumeral(e2)) return 0; + v1 = e1->u.nval; + v2 = e2->u.nval; + switch (op) { + case OP_ADD: r = luai_numadd(v1, v2); break; + case OP_SUB: r = luai_numsub(v1, v2); break; + case OP_MUL: r = luai_nummul(v1, v2); break; + case OP_DIV: + if (v2 == 0) return 0; /* do not attempt to divide by 0 */ + r = luai_numdiv(v1, v2); break; + case OP_MOD: + if (v2 == 0) return 0; /* do not attempt to divide by 0 */ + r = luai_nummod(v1, v2); break; + case OP_POW: r = luai_numpow(v1, v2); break; + case OP_UNM: r = luai_numunm(v1); break; + case OP_LEN: return 0; /* no constant folding for 'len' */ + default: lua_assert(0); r = 0; break; + } + if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ + e1->u.nval = r; + return 1; +} + + +static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { + if (constfolding(op, e1, e2)) + return; + else { + int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; + int o1 = luaK_exp2RK(fs, e1); + if (o1 > o2) { + freeexp(fs, e1); + freeexp(fs, e2); + } + else { + freeexp(fs, e2); + freeexp(fs, e1); + } + e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); + e1->k = VRELOCABLE; + } +} + + +static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, + expdesc *e2) { + int o1 = luaK_exp2RK(fs, e1); + int o2 = luaK_exp2RK(fs, e2); + freeexp(fs, e2); + freeexp(fs, e1); + if (cond == 0 && op != OP_EQ) { + int temp; /* exchange args to replace by `<' or `<=' */ + temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ + cond = 1; + } + e1->u.s.info = condjump(fs, op, cond, o1, o2); + e1->k = VJMP; +} + + +void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { + expdesc e2; + e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; + switch (op) { + case OPR_MINUS: { + if (!isnumeral(e)) + luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ + codearith(fs, OP_UNM, e, &e2); + break; + } + case OPR_NOT: codenot(fs, e); break; + case OPR_LEN: { + luaK_exp2anyreg(fs, e); /* cannot operate on constants */ + codearith(fs, OP_LEN, e, &e2); + break; + } + default: lua_assert(0); + } +} + + +void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { + switch (op) { + case OPR_AND: { + luaK_goiftrue(fs, v); + break; + } + case OPR_OR: { + luaK_goiffalse(fs, v); + break; + } + case OPR_CONCAT: { + luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ + break; + } + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_MOD: case OPR_POW: { + if (!isnumeral(v)) luaK_exp2RK(fs, v); + break; + } + default: { + luaK_exp2RK(fs, v); + break; + } + } +} + + +void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { + switch (op) { + case OPR_AND: { + lua_assert(e1->t == NO_JUMP); /* list must be closed */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e2->f, e1->f); + *e1 = *e2; + break; + } + case OPR_OR: { + lua_assert(e1->f == NO_JUMP); /* list must be closed */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e2->t, e1->t); + *e1 = *e2; + break; + } + case OPR_CONCAT: { + luaK_exp2val(fs, e2); + if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { + lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); + freeexp(fs, e1); + SETARG_B(getcode(fs, e2), e1->u.s.info); + e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info; + } + else { + luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ + codearith(fs, OP_CONCAT, e1, e2); + } + break; + } + case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; + case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; + case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; + case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; + case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; + case OPR_POW: codearith(fs, OP_POW, e1, e2); break; + case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; + case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; + case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; + case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; + case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; + case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; + default: lua_assert(0); + } +} + + +void luaK_fixline (FuncState *fs, int line) { + fs->f->lineinfo[fs->pc - 1] = line; +} + + +static int luaK_code (FuncState *fs, Instruction i, int line) { + Proto *f = fs->f; + dischargejpc(fs); /* `pc' will change */ + /* put new instruction in code array */ + luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "code size overflow"); + f->code[fs->pc] = i; + /* save corresponding line information */ + luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, + MAX_INT, "code size overflow"); + f->lineinfo[fs->pc] = line; + return fs->pc++; +} + + +int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { + lua_assert(getOpMode(o) == iABC); + lua_assert(getBMode(o) != OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgN || c == 0); + return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); +} + + +int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { + lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + lua_assert(getCMode(o) == OpArgN); + return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); +} + + +void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { + int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; + int b = (tostore == LUA_MULTRET) ? 0 : tostore; + lua_assert(tostore != 0); + if (c <= MAXARG_C) + luaK_codeABC(fs, OP_SETLIST, base, b, c); + else { + luaK_codeABC(fs, OP_SETLIST, base, b, 0); + luaK_code(fs, cast(Instruction, c), fs->ls->lastline); + } + fs->freereg = base + 1; /* free registers with list values */ +} + diff --git a/source/fceultra/lua/src/lcode.h b/source/fceultra/lua/src/lcode.h new file mode 100644 index 0000000..b941c60 --- /dev/null +++ b/source/fceultra/lua/src/lcode.h @@ -0,0 +1,76 @@ +/* +** $Id: lcode.h,v 1.48.1.1 2007/12/27 13:02:25 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lcode_h +#define lcode_h + +#include "llex.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" + + +/* +** Marks the end of a patch list. It is an invalid value both as an absolute +** address, and as a list link (would link an element to itself). +*/ +#define NO_JUMP (-1) + + +/* +** grep "ORDER OPR" if you change these enums +*/ +typedef enum BinOpr { + OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, + OPR_CONCAT, + OPR_NE, OPR_EQ, + OPR_LT, OPR_LE, OPR_GT, OPR_GE, + OPR_AND, OPR_OR, + OPR_NOBINOPR +} BinOpr; + + +typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; + + +#define getcode(fs,e) ((fs)->f->code[(e)->u.s.info]) + +#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) + +#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) + +LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); +LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); +LUAI_FUNC void luaK_fixline (FuncState *fs, int line); +LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); +LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); +LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); +LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); +LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); +LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); +LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); +LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); +LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); +LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_jump (FuncState *fs); +LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); +LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); +LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); +LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); +LUAI_FUNC int luaK_getlabel (FuncState *fs); +LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); +LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); +LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); +LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); + + +#endif diff --git a/source/fceultra/lua/src/ldblib.c b/source/fceultra/lua/src/ldblib.c new file mode 100644 index 0000000..67de122 --- /dev/null +++ b/source/fceultra/lua/src/ldblib.c @@ -0,0 +1,397 @@ +/* +** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $ +** Interface from Lua to its debug API +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +#define ldblib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +static int db_getregistry (lua_State *L) { + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; +} + + +static int db_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); /* no metatable */ + } + return 1; +} + + +static int db_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + lua_settop(L, 2); + lua_pushboolean(L, lua_setmetatable(L, 1)); + return 1; +} + + +static int db_getfenv (lua_State *L) { + lua_getfenv(L, 1); + return 1; +} + + +static int db_setfenv (lua_State *L) { + luaL_checktype(L, 2, LUA_TTABLE); + lua_settop(L, 2); + if (lua_setfenv(L, 1) == 0) + luaL_error(L, LUA_QL("setfenv") + " cannot change environment of given object"); + return 1; +} + + +static void settabss (lua_State *L, const char *i, const char *v) { + lua_pushstring(L, v); + lua_setfield(L, -2, i); +} + + +static void settabsi (lua_State *L, const char *i, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, i); +} + + +static lua_State *getthread (lua_State *L, int *arg) { + if (lua_isthread(L, 1)) { + *arg = 1; + return lua_tothread(L, 1); + } + else { + *arg = 0; + return L; + } +} + + +static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { + if (L == L1) { + lua_pushvalue(L, -2); + lua_remove(L, -3); + } + else + lua_xmove(L1, L, 1); + lua_setfield(L, -2, fname); +} + + +static int db_getinfo (lua_State *L) { + lua_Debug ar; + int arg; + lua_State *L1 = getthread(L, &arg); + const char *options = luaL_optstring(L, arg+2, "flnSu"); + if (lua_isnumber(L, arg+1)) { + if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { + lua_pushnil(L); /* level out of range */ + return 1; + } + } + else if (lua_isfunction(L, arg+1)) { + lua_pushfstring(L, ">%s", options); + options = lua_tostring(L, -1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); + } + else + return luaL_argerror(L, arg+1, "function or level expected"); + if (!lua_getinfo(L1, options, &ar)) + return luaL_argerror(L, arg+2, "invalid option"); + lua_createtable(L, 0, 2); + if (strchr(options, 'S')) { + settabss(L, "source", ar.source); + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabsi(L, "lastlinedefined", ar.lastlinedefined); + settabss(L, "what", ar.what); + } + if (strchr(options, 'l')) + settabsi(L, "currentline", ar.currentline); + if (strchr(options, 'u')) + settabsi(L, "nups", ar.nups); + if (strchr(options, 'n')) { + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); + } + if (strchr(options, 'L')) + treatstackoption(L, L1, "activelines"); + if (strchr(options, 'f')) + treatstackoption(L, L1, "func"); + return 1; /* return table */ +} + + +static int db_getlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + const char *name; + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); + if (name) { + lua_xmove(L1, L, 1); + lua_pushstring(L, name); + lua_pushvalue(L, -2); + return 2; + } + else { + lua_pushnil(L); + return 1; + } +} + + +static int db_setlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + luaL_checkany(L, arg+3); + lua_settop(L, arg+3); + lua_xmove(L, L1, 1); + lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); + return 1; +} + + +static int auxupvalue (lua_State *L, int get) { + const char *name; + int n = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ + name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); + if (name == NULL) return 0; + lua_pushstring(L, name); + lua_insert(L, -(get+1)); + return get + 1; +} + + +static int db_getupvalue (lua_State *L) { + return auxupvalue(L, 1); +} + + +static int db_setupvalue (lua_State *L) { + luaL_checkany(L, 3); + return auxupvalue(L, 0); +} + + + +static const char KEY_HOOK = 'h'; + + +static void hookf (lua_State *L, lua_Debug *ar) { + static const char *const hooknames[] = + {"call", "return", "line", "count", "tail return"}; + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushlightuserdata(L, L); + lua_rawget(L, -2); + if (lua_isfunction(L, -1)) { + lua_pushstring(L, hooknames[(int)ar->event]); + if (ar->currentline >= 0) + lua_pushinteger(L, ar->currentline); + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); + } +} + + +static int makemask (const char *smask, int count) { + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + return mask; +} + + +static char *unmakemask (int mask, char *smask) { + int i = 0; + if (mask & LUA_MASKCALL) smask[i++] = 'c'; + if (mask & LUA_MASKRET) smask[i++] = 'r'; + if (mask & LUA_MASKLINE) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; +} + + +static void gethooktable (lua_State *L) { + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + lua_createtable(L, 0, 1); + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + } +} + + +static int db_sethook (lua_State *L) { + int arg, mask, count; + lua_Hook func; + lua_State *L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) { + lua_settop(L, arg+1); + func = NULL; mask = 0; count = 0; /* turn off hooks */ + } + else { + const char *smask = luaL_checkstring(L, arg+2); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + count = luaL_optint(L, arg+3, 0); + func = hookf; mask = makemask(smask, count); + } + gethooktable(L); + lua_pushlightuserdata(L, L1); + lua_pushvalue(L, arg+1); + lua_rawset(L, -3); /* set new hook */ + lua_pop(L, 1); /* remove hook table */ + lua_sethook(L1, func, mask, count); /* set hooks */ + return 0; +} + + +static int db_gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + char buff[5]; + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); + if (hook != NULL && hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { + gethooktable(L); + lua_pushlightuserdata(L, L1); + lua_rawget(L, -2); /* get hook */ + lua_remove(L, -2); /* remove hook table */ + } + lua_pushstring(L, unmakemask(mask, buff)); + lua_pushinteger(L, lua_gethookcount(L1)); + return 3; +} + + +static int db_debug (lua_State *L) { + for (;;) { + char buffer[250]; + fputs("lua_debug> ", stderr); + if (fgets(buffer, sizeof(buffer), stdin) == 0 || + strcmp(buffer, "cont\n") == 0) + return 0; + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || + lua_pcall(L, 0, 0, 0)) { + fputs(lua_tostring(L, -1), stderr); + fputs("\n", stderr); + } + lua_settop(L, 0); /* remove eventual returns */ + } +} + + +#define LEVELS1 12 /* size of the first part of the stack */ +#define LEVELS2 10 /* size of the second part of the stack */ + +static int db_errorfb (lua_State *L) { + int level; + int firstpart = 1; /* still before eventual `...' */ + int arg; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + if (lua_isnumber(L, arg+2)) { + level = (int)lua_tointeger(L, arg+2); + lua_pop(L, 1); + } + else + level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ + if (lua_gettop(L) == arg) + lua_pushliteral(L, ""); + else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ + else lua_pushliteral(L, "\n"); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) { + if (level > LEVELS1 && firstpart) { + /* no more than `LEVELS2' more levels? */ + if (!lua_getstack(L1, level+LEVELS2, &ar)) + level--; /* keep going */ + else { + lua_pushliteral(L, "\n\t..."); /* too many levels */ + while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ + level++; + } + firstpart = 0; + continue; + } + lua_pushliteral(L, "\n\t"); + lua_getinfo(L1, "Snl", &ar); + lua_pushfstring(L, "%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + if (*ar.namewhat != '\0') /* is there a name? */ + lua_pushfstring(L, " in function " LUA_QS, ar.name); + else { + if (*ar.what == 'm') /* main? */ + lua_pushfstring(L, " in main chunk"); + else if (*ar.what == 'C' || *ar.what == 't') + lua_pushliteral(L, " ?"); /* C function or tail call */ + else + lua_pushfstring(L, " in function <%s:%d>", + ar.short_src, ar.linedefined); + } + lua_concat(L, lua_gettop(L) - arg); + } + lua_concat(L, lua_gettop(L) - arg); + return 1; +} + + +static const luaL_Reg dblib[] = { + {"debug", db_debug}, + {"getfenv", db_getfenv}, + {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, + {"getmetatable", db_getmetatable}, + {"getupvalue", db_getupvalue}, + {"setfenv", db_setfenv}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, + {"setupvalue", db_setupvalue}, + {"traceback", db_errorfb}, + {NULL, NULL} +}; + + +LUALIB_API int luaopen_debug (lua_State *L) { + luaL_register(L, LUA_DBLIBNAME, dblib); + return 1; +} + diff --git a/source/fceultra/lua/src/ldebug.c b/source/fceultra/lua/src/ldebug.c new file mode 100644 index 0000000..50ad3d3 --- /dev/null +++ b/source/fceultra/lua/src/ldebug.c @@ -0,0 +1,638 @@ +/* +** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $ +** Debug Interface +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + + +#define ldebug_c +#define LUA_CORE + +#include "lua.h" + +#include "lapi.h" +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + + +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); + + +static int currentpc (lua_State *L, CallInfo *ci) { + if (!isLua(ci)) return -1; /* function is not a Lua function? */ + if (ci == L->ci) + ci->savedpc = L->savedpc; + return pcRel(ci->savedpc, ci_func(ci)->l.p); +} + + +static int currentline (lua_State *L, CallInfo *ci) { + int pc = currentpc(L, ci); + if (pc < 0) + return -1; /* only active lua functions have current-line information */ + else + return getline(ci_func(ci)->l.p, pc); +} + + +/* +** this function can be called asynchronous (e.g. during a signal) +*/ +LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { + if (func == NULL || mask == 0) { /* turn off hooks? */ + mask = 0; + func = NULL; + } + L->hook = func; + L->basehookcount = count; + resethookcount(L); + L->hookmask = cast_byte(mask); + return 1; +} + + +LUA_API lua_Hook lua_gethook (lua_State *L) { + return L->hook; +} + + +LUA_API int lua_gethookmask (lua_State *L) { + return L->hookmask; +} + + +LUA_API int lua_gethookcount (lua_State *L) { + return L->basehookcount; +} + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { + int status; + CallInfo *ci; + lua_lock(L); + for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { + level--; + if (f_isLua(ci)) /* Lua function? */ + level -= ci->tailcalls; /* skip lost tail calls */ + } + if (level == 0 && ci > L->base_ci) { /* level found? */ + status = 1; + ar->i_ci = cast_int(ci - L->base_ci); + } + else if (level < 0) { /* level is of a lost tail call? */ + status = 1; + ar->i_ci = 0; + } + else status = 0; /* no such level */ + lua_unlock(L); + return status; +} + + +static Proto *getluaproto (CallInfo *ci) { + return (isLua(ci) ? ci_func(ci)->l.p : NULL); +} + + +static const char *findlocal (lua_State *L, CallInfo *ci, int n) { + const char *name; + Proto *fp = getluaproto(ci); + if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) + return name; /* is a local variable in a Lua function */ + else { + StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; + if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */ + return "(*temporary)"; + else + return NULL; + } +} + + +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { + CallInfo *ci = L->base_ci + ar->i_ci; + const char *name = findlocal(L, ci, n); + lua_lock(L); + if (name) + luaA_pushobject(L, ci->base + (n - 1)); + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { + CallInfo *ci = L->base_ci + ar->i_ci; + const char *name = findlocal(L, ci, n); + lua_lock(L); + if (name) + setobjs2s(L, ci->base + (n - 1), L->top - 1); + L->top--; /* pop value */ + lua_unlock(L); + return name; +} + + +static void funcinfo (lua_Debug *ar, Closure *cl) { + if (cl->c.isC) { + ar->source = "=[C]"; + ar->linedefined = -1; + ar->lastlinedefined = -1; + ar->what = "C"; + } + else { + ar->source = getstr(cl->l.p->source); + ar->linedefined = cl->l.p->linedefined; + ar->lastlinedefined = cl->l.p->lastlinedefined; + ar->what = (ar->linedefined == 0) ? "main" : "Lua"; + } + luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); +} + + +static void info_tailcall (lua_Debug *ar) { + ar->name = ar->namewhat = ""; + ar->what = "tail"; + ar->lastlinedefined = ar->linedefined = ar->currentline = -1; + ar->source = "=(tail call)"; + luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); + ar->nups = 0; +} + + +static void collectvalidlines (lua_State *L, Closure *f) { + if (f == NULL || f->c.isC) { + setnilvalue(L->top); + } + else { + Table *t = luaH_new(L, 0, 0); + int *lineinfo = f->l.p->lineinfo; + int i; + for (i=0; il.p->sizelineinfo; i++) + setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); + sethvalue(L, L->top, t); + } + incr_top(L); +} + + +static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, + Closure *f, CallInfo *ci) { + int status = 1; + if (f == NULL) { + info_tailcall(ar); + return status; + } + for (; *what; what++) { + switch (*what) { + case 'S': { + funcinfo(ar, f); + break; + } + case 'l': { + ar->currentline = (ci) ? currentline(L, ci) : -1; + break; + } + case 'u': { + ar->nups = f->c.nupvalues; + break; + } + case 'n': { + ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL; + if (ar->namewhat == NULL) { + ar->namewhat = ""; /* not found */ + ar->name = NULL; + } + break; + } + case 'L': + case 'f': /* handled by lua_getinfo */ + break; + default: status = 0; /* invalid option */ + } + } + return status; +} + + +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { + int status; + Closure *f = NULL; + CallInfo *ci = NULL; + lua_lock(L); + if (*what == '>') { + StkId func = L->top - 1; + luai_apicheck(L, ttisfunction(func)); + what++; /* skip the '>' */ + f = clvalue(func); + L->top--; /* pop function */ + } + else if (ar->i_ci != 0) { /* no tail call? */ + ci = L->base_ci + ar->i_ci; + lua_assert(ttisfunction(ci->func)); + f = clvalue(ci->func); + } + status = auxgetinfo(L, what, ar, f, ci); + if (strchr(what, 'f')) { + if (f == NULL) setnilvalue(L->top); + else setclvalue(L, L->top, f); + incr_top(L); + } + if (strchr(what, 'L')) + collectvalidlines(L, f); + lua_unlock(L); + return status; +} + + +/* +** {====================================================== +** Symbolic Execution and code checker +** ======================================================= +*/ + +#define check(x) if (!(x)) return 0; + +#define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode) + +#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize) + + + +static int precheck (const Proto *pt) { + check(pt->maxstacksize <= MAXSTACK); + check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); + check(!(pt->is_vararg & VARARG_NEEDSARG) || + (pt->is_vararg & VARARG_HASARG)); + check(pt->sizeupvalues <= pt->nups); + check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); + check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); + return 1; +} + + +#define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1]) + +int luaG_checkopenop (Instruction i) { + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: + case OP_RETURN: + case OP_SETLIST: { + check(GETARG_B(i) == 0); + return 1; + } + default: return 0; /* invalid instruction after an open call */ + } +} + + +static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { + switch (mode) { + case OpArgN: check(r == 0); break; + case OpArgU: break; + case OpArgR: checkreg(pt, r); break; + case OpArgK: + check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); + break; + } + return 1; +} + + +static Instruction symbexec (const Proto *pt, int lastpc, int reg) { + int pc; + int last; /* stores position of last instruction that changed `reg' */ + last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ + check(precheck(pt)); + for (pc = 0; pc < lastpc; pc++) { + Instruction i = pt->code[pc]; + OpCode op = GET_OPCODE(i); + int a = GETARG_A(i); + int b = 0; + int c = 0; + check(op < NUM_OPCODES); + checkreg(pt, a); + switch (getOpMode(op)) { + case iABC: { + b = GETARG_B(i); + c = GETARG_C(i); + check(checkArgMode(pt, b, getBMode(op))); + check(checkArgMode(pt, c, getCMode(op))); + break; + } + case iABx: { + b = GETARG_Bx(i); + if (getBMode(op) == OpArgK) check(b < pt->sizek); + break; + } + case iAsBx: { + b = GETARG_sBx(i); + if (getBMode(op) == OpArgR) { + int dest = pc+1+b; + check(0 <= dest && dest < pt->sizecode); + if (dest > 0) { + int j; + /* check that it does not jump to a setlist count; this + is tricky, because the count from a previous setlist may + have the same value of an invalid setlist; so, we must + go all the way back to the first of them (if any) */ + for (j = 0; j < dest; j++) { + Instruction d = pt->code[dest-1-j]; + if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break; + } + /* if 'j' is even, previous value is not a setlist (even if + it looks like one) */ + check((j&1) == 0); + } + } + break; + } + } + if (testAMode(op)) { + if (a == reg) last = pc; /* change register `a' */ + } + if (testTMode(op)) { + check(pc+2 < pt->sizecode); /* check skip */ + check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); + } + switch (op) { + case OP_LOADBOOL: { + if (c == 1) { /* does it jump? */ + check(pc+2 < pt->sizecode); /* check its jump */ + check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST || + GETARG_C(pt->code[pc+1]) != 0); + } + break; + } + case OP_LOADNIL: { + if (a <= reg && reg <= b) + last = pc; /* set registers from `a' to `b' */ + break; + } + case OP_GETUPVAL: + case OP_SETUPVAL: { + check(b < pt->nups); + break; + } + case OP_GETGLOBAL: + case OP_SETGLOBAL: { + check(ttisstring(&pt->k[b])); + break; + } + case OP_SELF: { + checkreg(pt, a+1); + if (reg == a+1) last = pc; + break; + } + case OP_CONCAT: { + check(b < c); /* at least two operands */ + break; + } + case OP_TFORLOOP: { + check(c >= 1); /* at least one result (control variable) */ + checkreg(pt, a+2+c); /* space for results */ + if (reg >= a+2) last = pc; /* affect all regs above its base */ + break; + } + case OP_FORLOOP: + case OP_FORPREP: + checkreg(pt, a+3); + /* go through */ + case OP_JMP: { + int dest = pc+1+b; + /* not full check and jump is forward and do not skip `lastpc'? */ + if (reg != NO_REG && pc < dest && dest <= lastpc) + pc += b; /* do the jump */ + break; + } + case OP_CALL: + case OP_TAILCALL: { + if (b != 0) { + checkreg(pt, a+b-1); + } + c--; /* c = num. returns */ + if (c == LUA_MULTRET) { + check(checkopenop(pt, pc)); + } + else if (c != 0) + checkreg(pt, a+c-1); + if (reg >= a) last = pc; /* affect all registers above base */ + break; + } + case OP_RETURN: { + b--; /* b = num. returns */ + if (b > 0) checkreg(pt, a+b-1); + break; + } + case OP_SETLIST: { + if (b > 0) checkreg(pt, a + b); + if (c == 0) { + pc++; + check(pc < pt->sizecode - 1); + } + break; + } + case OP_CLOSURE: { + int nup, j; + check(b < pt->sizep); + nup = pt->p[b]->nups; + check(pc + nup < pt->sizecode); + for (j = 1; j <= nup; j++) { + OpCode op1 = GET_OPCODE(pt->code[pc + j]); + check(op1 == OP_GETUPVAL || op1 == OP_MOVE); + } + if (reg != NO_REG) /* tracing? */ + pc += nup; /* do not 'execute' these pseudo-instructions */ + break; + } + case OP_VARARG: { + check((pt->is_vararg & VARARG_ISVARARG) && + !(pt->is_vararg & VARARG_NEEDSARG)); + b--; + if (b == LUA_MULTRET) check(checkopenop(pt, pc)); + checkreg(pt, a+b-1); + break; + } + default: break; + } + } + return pt->code[last]; +} + +#undef check +#undef checkjump +#undef checkreg + +/* }====================================================== */ + + +int luaG_checkcode (const Proto *pt) { + return (symbexec(pt, pt->sizecode, NO_REG) != 0); +} + + +static const char *kname (Proto *p, int c) { + if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) + return svalue(&p->k[INDEXK(c)]); + else + return "?"; +} + + +static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, + const char **name) { + if (isLua(ci)) { /* a Lua function? */ + Proto *p = ci_func(ci)->l.p; + int pc = currentpc(L, ci); + Instruction i; + *name = luaF_getlocalname(p, stackpos+1, pc); + if (*name) /* is a local? */ + return "local"; + i = symbexec(p, pc, stackpos); /* try symbolic execution */ + lua_assert(pc != -1); + switch (GET_OPCODE(i)) { + case OP_GETGLOBAL: { + int g = GETARG_Bx(i); /* global index */ + lua_assert(ttisstring(&p->k[g])); + *name = svalue(&p->k[g]); + return "global"; + } + case OP_MOVE: { + int a = GETARG_A(i); + int b = GETARG_B(i); /* move from `b' to `a' */ + if (b < a) + return getobjname(L, ci, b, name); /* get name for `b' */ + break; + } + case OP_GETTABLE: { + int k = GETARG_C(i); /* key index */ + *name = kname(p, k); + return "field"; + } + case OP_GETUPVAL: { + int u = GETARG_B(i); /* upvalue index */ + *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; + return "upvalue"; + } + case OP_SELF: { + int k = GETARG_C(i); /* key index */ + *name = kname(p, k); + return "method"; + } + default: break; + } + } + return NULL; /* no useful name found */ +} + + +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { + Instruction i; + if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) + return NULL; /* calling function is not Lua (or is unknown) */ + ci--; /* calling function */ + i = ci_func(ci)->l.p->code[currentpc(L, ci)]; + if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || + GET_OPCODE(i) == OP_TFORLOOP) + return getobjname(L, ci, GETARG_A(i), name); + else + return NULL; /* no useful name can be found */ +} + + +/* only ANSI way to check whether a pointer points to an array */ +static int isinstack (CallInfo *ci, const TValue *o) { + StkId p; + for (p = ci->base; p < ci->top; p++) + if (o == p) return 1; + return 0; +} + + +void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + const char *name = NULL; + const char *t = luaT_typenames[ttype(o)]; + const char *kind = (isinstack(L->ci, o)) ? + getobjname(L, L->ci, cast_int(o - L->base), &name) : + NULL; + if (kind) + luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", + op, kind, name, t); + else + luaG_runerror(L, "attempt to %s a %s value", op, t); +} + + +void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { + if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; + lua_assert(!ttisstring(p1) && !ttisnumber(p1)); + luaG_typeerror(L, p1, "concatenate"); +} + + +void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { + TValue temp; + if (luaV_tonumber(p1, &temp) == NULL) + p2 = p1; /* first operand is wrong */ + luaG_typeerror(L, p2, "perform arithmetic on"); +} + + +int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { + const char *t1 = luaT_typenames[ttype(p1)]; + const char *t2 = luaT_typenames[ttype(p2)]; + if (t1[2] == t2[2]) + luaG_runerror(L, "attempt to compare two %s values", t1); + else + luaG_runerror(L, "attempt to compare %s with %s", t1, t2); + return 0; +} + + +static void addinfo (lua_State *L, const char *msg) { + CallInfo *ci = L->ci; + if (isLua(ci)) { /* is Lua code? */ + char buff[LUA_IDSIZE]; /* add file:line information */ + int line = currentline(L, ci); + luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); + luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); + } +} + + +void luaG_errormsg (lua_State *L) { + if (L->errfunc != 0) { /* is there an error handling function? */ + StkId errfunc = restorestack(L, L->errfunc); + if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); + setobjs2s(L, L->top, L->top - 1); /* move argument */ + setobjs2s(L, L->top - 1, errfunc); /* push function */ + incr_top(L); + luaD_call(L, L->top - 2, 1); /* call it */ + } + luaD_throw(L, LUA_ERRRUN); +} + + +void luaG_runerror (lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + addinfo(L, luaO_pushvfstring(L, fmt, argp)); + va_end(argp); + luaG_errormsg(L); +} + diff --git a/source/fceultra/lua/src/ldebug.h b/source/fceultra/lua/src/ldebug.h new file mode 100644 index 0000000..ba28a97 --- /dev/null +++ b/source/fceultra/lua/src/ldebug.h @@ -0,0 +1,33 @@ +/* +** $Id: ldebug.h,v 2.3.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions from Debug Interface module +** See Copyright Notice in lua.h +*/ + +#ifndef ldebug_h +#define ldebug_h + + +#include "lstate.h" + + +#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) + +#define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) + +#define resethookcount(L) (L->hookcount = L->basehookcount) + + +LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o, + const char *opname); +LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2); +LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaG_errormsg (lua_State *L); +LUAI_FUNC int luaG_checkcode (const Proto *pt); +LUAI_FUNC int luaG_checkopenop (Instruction i); + +#endif diff --git a/source/fceultra/lua/src/ldo.c b/source/fceultra/lua/src/ldo.c new file mode 100644 index 0000000..8de05f7 --- /dev/null +++ b/source/fceultra/lua/src/ldo.c @@ -0,0 +1,518 @@ +/* +** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +#define ldo_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" +#include "lzio.h" + + + + +/* +** {====================================================== +** Error-recovery functions +** ======================================================= +*/ + + +/* chain list of long jump buffers */ +struct lua_longjmp { + struct lua_longjmp *previous; + luai_jmpbuf b; + volatile int status; /* error code */ +}; + + +void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { + switch (errcode) { + case LUA_ERRMEM: { + setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); + break; + } + case LUA_ERRERR: { + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); + break; + } + case LUA_ERRSYNTAX: + case LUA_ERRRUN: { + setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ + break; + } + } + L->top = oldtop + 1; +} + + +static void restore_stack_limit (lua_State *L) { + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); + if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ + int inuse = cast_int(L->ci - L->base_ci); + if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ + luaD_reallocCI(L, LUAI_MAXCALLS); + } +} + + +static void resetstack (lua_State *L, int status) { + L->ci = L->base_ci; + L->base = L->ci->base; + luaF_close(L, L->base); /* close eventual pending closures */ + luaD_seterrorobj(L, status, L->base); + L->nCcalls = L->baseCcalls; + L->allowhook = 1; + restore_stack_limit(L); + L->errfunc = 0; + L->errorJmp = NULL; +} + + +void luaD_throw (lua_State *L, int errcode) { + if (L->errorJmp) { + L->errorJmp->status = errcode; + LUAI_THROW(L, L->errorJmp); + } + else { + L->status = cast_byte(errcode); + if (G(L)->panic) { + resetstack(L, errcode); + lua_unlock(L); + G(L)->panic(L); + } + exit(EXIT_FAILURE); + } +} + + +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + struct lua_longjmp lj; + lj.status = 0; + lj.previous = L->errorJmp; /* chain new error handler */ + L->errorJmp = &lj; + LUAI_TRY(L, &lj, + (*f)(L, ud); + ); + L->errorJmp = lj.previous; /* restore old error handler */ + return lj.status; +} + +/* }====================================================== */ + + +static void correctstack (lua_State *L, TValue *oldstack) { + CallInfo *ci; + GCObject *up; + L->top = (L->top - oldstack) + L->stack; + for (up = L->openupval; up != NULL; up = up->gch.next) + gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; + for (ci = L->base_ci; ci <= L->ci; ci++) { + ci->top = (ci->top - oldstack) + L->stack; + ci->base = (ci->base - oldstack) + L->stack; + ci->func = (ci->func - oldstack) + L->stack; + } + L->base = (L->base - oldstack) + L->stack; +} + + +void luaD_reallocstack (lua_State *L, int newsize) { + TValue *oldstack = L->stack; + int realsize = newsize + 1 + EXTRA_STACK; + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); + luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); + L->stacksize = realsize; + L->stack_last = L->stack+newsize; + correctstack(L, oldstack); +} + + +void luaD_reallocCI (lua_State *L, int newsize) { + CallInfo *oldci = L->base_ci; + luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); + L->size_ci = newsize; + L->ci = (L->ci - oldci) + L->base_ci; + L->end_ci = L->base_ci + L->size_ci - 1; +} + + +void luaD_growstack (lua_State *L, int n) { + if (n <= L->stacksize) /* double size is enough? */ + luaD_reallocstack(L, 2*L->stacksize); + else + luaD_reallocstack(L, L->stacksize + n); +} + + +static CallInfo *growCI (lua_State *L) { + if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ + luaD_throw(L, LUA_ERRERR); + else { + luaD_reallocCI(L, 2*L->size_ci); + if (L->size_ci > LUAI_MAXCALLS) + luaG_runerror(L, "stack overflow"); + } + return ++L->ci; +} + + +void luaD_callhook (lua_State *L, int event, int line) { + lua_Hook hook = L->hook; + if (hook && L->allowhook) { + ptrdiff_t top = savestack(L, L->top); + ptrdiff_t ci_top = savestack(L, L->ci->top); + lua_Debug ar; + ar.event = event; + ar.currentline = line; + if (event == LUA_HOOKTAILRET) + ar.i_ci = 0; /* tail call; no debug information about it */ + else + ar.i_ci = cast_int(L->ci - L->base_ci); + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + L->ci->top = L->top + LUA_MINSTACK; + lua_assert(L->ci->top <= L->stack_last); + L->allowhook = 0; /* cannot call hooks inside a hook */ + lua_unlock(L); + (*hook)(L, &ar); + lua_lock(L); + lua_assert(!L->allowhook); + L->allowhook = 1; + L->ci->top = restorestack(L, ci_top); + L->top = restorestack(L, top); + } +} + + +static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { + int i; + int nfixargs = p->numparams; + Table *htab = NULL; + StkId base, fixed; + for (; actual < nfixargs; ++actual) + setnilvalue(L->top++); +#if defined(LUA_COMPAT_VARARG) + if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ + int nvar = actual - nfixargs; /* number of extra arguments */ + lua_assert(p->is_vararg & VARARG_HASARG); + luaC_checkGC(L); + htab = luaH_new(L, nvar, 1); /* create `arg' table */ + for (i=0; itop - nvar + i); + /* store counter in field `n' */ + setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); + } +#endif + /* move fixed parameters to final position */ + fixed = L->top - actual; /* first fixed argument */ + base = L->top; /* final position of first argument */ + for (i=0; itop++, fixed+i); + setnilvalue(fixed+i); + } + /* add `arg' parameter */ + if (htab) { + sethvalue(L, L->top++, htab); + lua_assert(iswhite(obj2gco(htab))); + } + return base; +} + + +static StkId tryfuncTM (lua_State *L, StkId func) { + const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); + StkId p; + ptrdiff_t funcr = savestack(L, func); + if (!ttisfunction(tm)) + luaG_typeerror(L, func, "call"); + /* Open a hole inside the stack at `func' */ + for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); + incr_top(L); + func = restorestack(L, funcr); /* previous call may change stack */ + setobj2s(L, func, tm); /* tag method is the new function to be called */ + return func; +} + + + +#define inc_ci(L) \ + ((L->ci == L->end_ci) ? growCI(L) : \ + (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) + + +int luaD_precall (lua_State *L, StkId func, int nresults) { + LClosure *cl; + ptrdiff_t funcr; + if (!ttisfunction(func)) /* `func' is not a function? */ + func = tryfuncTM(L, func); /* check the `function' tag method */ + funcr = savestack(L, func); + cl = &clvalue(func)->l; + L->ci->savedpc = L->savedpc; + if (!cl->isC) { /* Lua function? prepare its call */ + CallInfo *ci; + StkId st, base; + Proto *p = cl->p; + luaD_checkstack(L, p->maxstacksize); + func = restorestack(L, funcr); + if (!p->is_vararg) { /* no varargs? */ + base = func + 1; + if (L->top > base + p->numparams) + L->top = base + p->numparams; + } + else { /* vararg function */ + int nargs = cast_int(L->top - func) - 1; + base = adjust_varargs(L, p, nargs); + func = restorestack(L, funcr); /* previous call may change the stack */ + } + ci = inc_ci(L); /* now `enter' new function */ + ci->func = func; + L->base = ci->base = base; + ci->top = L->base + p->maxstacksize; + lua_assert(ci->top <= L->stack_last); + L->savedpc = p->code; /* starting point */ + ci->tailcalls = 0; + ci->nresults = nresults; + for (st = L->top; st < ci->top; st++) + setnilvalue(st); + L->top = ci->top; + if (L->hookmask & LUA_MASKCALL) { + L->savedpc++; /* hooks assume 'pc' is already incremented */ + luaD_callhook(L, LUA_HOOKCALL, -1); + L->savedpc--; /* correct 'pc' */ + } + return PCRLUA; + } + else { /* if is a C function, call it */ + CallInfo *ci; + int n; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci = inc_ci(L); /* now `enter' new function */ + ci->func = restorestack(L, funcr); + L->base = ci->base = ci->func + 1; + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + ci->nresults = nresults; + if (L->hookmask & LUA_MASKCALL) + luaD_callhook(L, LUA_HOOKCALL, -1); + lua_unlock(L); + n = (*curr_func(L)->c.f)(L); /* do the actual call */ + lua_lock(L); + if (n < 0) /* yielding? */ + return PCRYIELD; + else { + luaD_poscall(L, L->top - n); + return PCRC; + } + } +} + + +static StkId callrethooks (lua_State *L, StkId firstResult) { + ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ + luaD_callhook(L, LUA_HOOKRET, -1); + if (f_isLua(L->ci)) { /* Lua function? */ + while ((L->hookmask & LUA_MASKRET) && L->ci->tailcalls--) /* tail calls */ + luaD_callhook(L, LUA_HOOKTAILRET, -1); + } + return restorestack(L, fr); +} + + +int luaD_poscall (lua_State *L, StkId firstResult) { + StkId res; + int wanted, i; + CallInfo *ci; + if (L->hookmask & LUA_MASKRET) + firstResult = callrethooks(L, firstResult); + ci = L->ci--; + res = ci->func; /* res == final position of 1st result */ + wanted = ci->nresults; + L->base = (ci - 1)->base; /* restore base */ + L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ + /* move results to correct place */ + for (i = wanted; i != 0 && firstResult < L->top; i--) + setobjs2s(L, res++, firstResult++); + while (i-- > 0) + setnilvalue(res++); + L->top = res; + return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ +} + + +/* +** Call a function (C or Lua). The function to be called is at *func. +** The arguments are on the stack, right after the function. +** When returns, all the results are on the stack, starting at the original +** function position. +*/ +void luaD_call (lua_State *L, StkId func, int nResults) { + if (++L->nCcalls >= LUAI_MAXCCALLS) { + if (L->nCcalls == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ + } + if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ + luaV_execute(L, 1); /* call it */ + L->nCcalls--; + luaC_checkGC(L); +} + + +static void resume (lua_State *L, void *ud) { + StkId firstArg = cast(StkId, ud); + CallInfo *ci = L->ci; + if (L->status == 0) { /* start coroutine? */ + lua_assert(ci == L->base_ci && firstArg > L->base); + if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) + return; + } + else { /* resuming from previous yield */ + lua_assert(L->status == LUA_YIELD); + L->status = 0; + if (!f_isLua(ci)) { /* `common' yield? */ + /* finish interrupted execution of `OP_CALL' */ + lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || + GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); + if (luaD_poscall(L, firstArg)) /* complete it... */ + L->top = L->ci->top; /* and correct top if not multiple results */ + } + else /* yielded inside a hook: just continue its execution */ + L->base = L->ci->base; + } + luaV_execute(L, cast_int(L->ci - L->base_ci)); +} + + +static int resume_error (lua_State *L, const char *msg) { + L->top = L->ci->base; + setsvalue2s(L, L->top, luaS_new(L, msg)); + incr_top(L); + lua_unlock(L); + return LUA_ERRRUN; +} + + +LUA_API int lua_resume (lua_State *L, int nargs) { + int status; + lua_lock(L); + if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci)) + return resume_error(L, "cannot resume non-suspended coroutine"); + if (L->nCcalls >= LUAI_MAXCCALLS) + return resume_error(L, "C stack overflow"); + luai_userstateresume(L, nargs); + lua_assert(L->errfunc == 0); + L->baseCcalls = ++L->nCcalls; + status = luaD_rawrunprotected(L, resume, L->top - nargs); + if (status != 0) { /* error? */ + L->status = cast_byte(status); /* mark thread as `dead' */ + luaD_seterrorobj(L, status, L->top); + L->ci->top = L->top; + } + else { + lua_assert(L->nCcalls == L->baseCcalls); + status = L->status; + } + --L->nCcalls; + lua_unlock(L); + return status; +} + + +LUA_API int lua_yield (lua_State *L, int nresults) { + luai_userstateyield(L, nresults); + lua_lock(L); + if (L->nCcalls > L->baseCcalls) + luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); + L->base = L->top - nresults; /* protect stack slots below */ + L->status = LUA_YIELD; + lua_unlock(L); + return -1; +} + + +int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t old_top, ptrdiff_t ef) { + int status; + unsigned short oldnCcalls = L->nCcalls; + ptrdiff_t old_ci = saveci(L, L->ci); + lu_byte old_allowhooks = L->allowhook; + ptrdiff_t old_errfunc = L->errfunc; + L->errfunc = ef; + status = luaD_rawrunprotected(L, func, u); + if (status != 0) { /* an error occurred? */ + StkId oldtop = restorestack(L, old_top); + luaF_close(L, oldtop); /* close eventual pending closures */ + luaD_seterrorobj(L, status, oldtop); + L->nCcalls = oldnCcalls; + L->ci = restoreci(L, old_ci); + L->base = L->ci->base; + L->savedpc = L->ci->savedpc; + L->allowhook = old_allowhooks; + restore_stack_limit(L); + } + L->errfunc = old_errfunc; + return status; +} + + + +/* +** Execute a protected parser. +*/ +struct SParser { /* data to `f_parser' */ + ZIO *z; + Mbuffer buff; /* buffer to be used by the scanner */ + const char *name; +}; + +static void f_parser (lua_State *L, void *ud) { + int i; + Proto *tf; + Closure *cl; + struct SParser *p = cast(struct SParser *, ud); + int c = luaZ_lookahead(p->z); + luaC_checkGC(L); + tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, + &p->buff, p->name); + cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); + cl->l.p = tf; + for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ + cl->l.upvals[i] = luaF_newupval(L); + setclvalue(L, L->top, cl); + incr_top(L); +} + + +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { + struct SParser p; + int status; + p.z = z; p.name = name; + luaZ_initbuffer(L, &p.buff); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); + luaZ_freebuffer(L, &p.buff); + return status; +} + + diff --git a/source/fceultra/lua/src/ldo.h b/source/fceultra/lua/src/ldo.h new file mode 100644 index 0000000..98fddac --- /dev/null +++ b/source/fceultra/lua/src/ldo.h @@ -0,0 +1,57 @@ +/* +** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#ifndef ldo_h +#define ldo_h + + +#include "lobject.h" +#include "lstate.h" +#include "lzio.h" + + +#define luaD_checkstack(L,n) \ + if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ + luaD_growstack(L, n); \ + else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); + + +#define incr_top(L) {luaD_checkstack(L,1); L->top++;} + +#define savestack(L,p) ((char *)(p) - (char *)L->stack) +#define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) + +#define saveci(L,p) ((char *)(p) - (char *)L->base_ci) +#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) + + +/* results from luaD_precall */ +#define PCRLUA 0 /* initiated a call to a Lua function */ +#define PCRC 1 /* did a call to a C function */ +#define PCRYIELD 2 /* C funtion yielded */ + + +/* type of protected functions, to be ran by `runprotected' */ +typedef void (*Pfunc) (lua_State *L, void *ud); + +LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); +LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); +LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t oldtop, ptrdiff_t ef); +LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); +LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); +LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); +LUAI_FUNC void luaD_growstack (lua_State *L, int n); + +LUAI_FUNC void luaD_throw (lua_State *L, int errcode); +LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); + +LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); + +#endif + diff --git a/source/fceultra/lua/src/ldump.c b/source/fceultra/lua/src/ldump.c new file mode 100644 index 0000000..c9d3d48 --- /dev/null +++ b/source/fceultra/lua/src/ldump.c @@ -0,0 +1,164 @@ +/* +** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** save precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#include + +#define ldump_c +#define LUA_CORE + +#include "lua.h" + +#include "lobject.h" +#include "lstate.h" +#include "lundump.h" + +typedef struct { + lua_State* L; + lua_Writer writer; + void* data; + int strip; + int status; +} DumpState; + +#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) +#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) + +static void DumpBlock(const void* b, size_t size, DumpState* D) +{ + if (D->status==0) + { + lua_unlock(D->L); + D->status=(*D->writer)(D->L,b,size,D->data); + lua_lock(D->L); + } +} + +static void DumpChar(int y, DumpState* D) +{ + char x=(char)y; + DumpVar(x,D); +} + +static void DumpInt(int x, DumpState* D) +{ + DumpVar(x,D); +} + +static void DumpNumber(lua_Number x, DumpState* D) +{ + DumpVar(x,D); +} + +static void DumpVector(const void* b, int n, size_t size, DumpState* D) +{ + DumpInt(n,D); + DumpMem(b,n,size,D); +} + +static void DumpString(const TString* s, DumpState* D) +{ + if (s==NULL || getstr(s)==NULL) + { + size_t size=0; + DumpVar(size,D); + } + else + { + size_t size=s->tsv.len+1; /* include trailing '\0' */ + DumpVar(size,D); + DumpBlock(getstr(s),size,D); + } +} + +#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) + +static void DumpFunction(const Proto* f, const TString* p, DumpState* D); + +static void DumpConstants(const Proto* f, DumpState* D) +{ + int i,n=f->sizek; + DumpInt(n,D); + for (i=0; ik[i]; + DumpChar(ttype(o),D); + switch (ttype(o)) + { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpChar(bvalue(o),D); + break; + case LUA_TNUMBER: + DumpNumber(nvalue(o),D); + break; + case LUA_TSTRING: + DumpString(rawtsvalue(o),D); + break; + default: + lua_assert(0); /* cannot happen */ + break; + } + } + n=f->sizep; + DumpInt(n,D); + for (i=0; ip[i],f->source,D); +} + +static void DumpDebug(const Proto* f, DumpState* D) +{ + int i,n; + n= (D->strip) ? 0 : f->sizelineinfo; + DumpVector(f->lineinfo,n,sizeof(int),D); + n= (D->strip) ? 0 : f->sizelocvars; + DumpInt(n,D); + for (i=0; ilocvars[i].varname,D); + DumpInt(f->locvars[i].startpc,D); + DumpInt(f->locvars[i].endpc,D); + } + n= (D->strip) ? 0 : f->sizeupvalues; + DumpInt(n,D); + for (i=0; iupvalues[i],D); +} + +static void DumpFunction(const Proto* f, const TString* p, DumpState* D) +{ + DumpString((f->source==p || D->strip) ? NULL : f->source,D); + DumpInt(f->linedefined,D); + DumpInt(f->lastlinedefined,D); + DumpChar(f->nups,D); + DumpChar(f->numparams,D); + DumpChar(f->is_vararg,D); + DumpChar(f->maxstacksize,D); + DumpCode(f,D); + DumpConstants(f,D); + DumpDebug(f,D); +} + +static void DumpHeader(DumpState* D) +{ + char h[LUAC_HEADERSIZE]; + luaU_header(h); + DumpBlock(h,LUAC_HEADERSIZE,D); +} + +/* +** dump Lua function as precompiled chunk +*/ +int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) +{ + DumpState D; + D.L=L; + D.writer=w; + D.data=data; + D.strip=strip; + D.status=0; + DumpHeader(&D); + DumpFunction(f,NULL,&D); + return D.status; +} diff --git a/source/fceultra/lua/src/lfunc.c b/source/fceultra/lua/src/lfunc.c new file mode 100644 index 0000000..813e88f --- /dev/null +++ b/source/fceultra/lua/src/lfunc.c @@ -0,0 +1,174 @@ +/* +** $Id: lfunc.c,v 2.12.1.2 2007/12/28 14:58:43 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + + +#include + +#define lfunc_c +#define LUA_CORE + +#include "lua.h" + +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { + Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); + c->c.isC = 1; + c->c.env = e; + c->c.nupvalues = cast_byte(nelems); + return c; +} + + +Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { + Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); + c->l.isC = 0; + c->l.env = e; + c->l.nupvalues = cast_byte(nelems); + while (nelems--) c->l.upvals[nelems] = NULL; + return c; +} + + +UpVal *luaF_newupval (lua_State *L) { + UpVal *uv = luaM_new(L, UpVal); + luaC_link(L, obj2gco(uv), LUA_TUPVAL); + uv->v = &uv->u.value; + setnilvalue(uv->v); + return uv; +} + + +UpVal *luaF_findupval (lua_State *L, StkId level) { + global_State *g = G(L); + GCObject **pp = &L->openupval; + UpVal *p; + UpVal *uv; + while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) { + lua_assert(p->v != &p->u.value); + if (p->v == level) { /* found a corresponding upvalue? */ + if (isdead(g, obj2gco(p))) /* is it dead? */ + changewhite(obj2gco(p)); /* ressurect it */ + return p; + } + pp = &p->next; + } + uv = luaM_new(L, UpVal); /* not found: create a new one */ + uv->tt = LUA_TUPVAL; + uv->marked = luaC_white(g); + uv->v = level; /* current value lives in the stack */ + uv->next = *pp; /* chain it in the proper position */ + *pp = obj2gco(uv); + uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ + uv->u.l.next = g->uvhead.u.l.next; + uv->u.l.next->u.l.prev = uv; + g->uvhead.u.l.next = uv; + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + return uv; +} + + +static void unlinkupval (UpVal *uv) { + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */ + uv->u.l.prev->u.l.next = uv->u.l.next; +} + + +void luaF_freeupval (lua_State *L, UpVal *uv) { + if (uv->v != &uv->u.value) /* is it open? */ + unlinkupval(uv); /* remove from open list */ + luaM_free(L, uv); /* free upvalue */ +} + + +void luaF_close (lua_State *L, StkId level) { + UpVal *uv; + global_State *g = G(L); + while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) { + GCObject *o = obj2gco(uv); + lua_assert(!isblack(o) && uv->v != &uv->u.value); + L->openupval = uv->next; /* remove from `open' list */ + if (isdead(g, o)) + luaF_freeupval(L, uv); /* free upvalue */ + else { + unlinkupval(uv); + setobj(L, &uv->u.value, uv->v); + uv->v = &uv->u.value; /* now current value lives here */ + luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ + } + } +} + + +Proto *luaF_newproto (lua_State *L) { + Proto *f = luaM_new(L, Proto); + luaC_link(L, obj2gco(f), LUA_TPROTO); + f->k = NULL; + f->sizek = 0; + f->p = NULL; + f->sizep = 0; + f->code = NULL; + f->sizecode = 0; + f->sizelineinfo = 0; + f->sizeupvalues = 0; + f->nups = 0; + f->upvalues = NULL; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->lineinfo = NULL; + f->sizelocvars = 0; + f->locvars = NULL; + f->linedefined = 0; + f->lastlinedefined = 0; + f->source = NULL; + return f; +} + + +void luaF_freeproto (lua_State *L, Proto *f) { + luaM_freearray(L, f->code, f->sizecode, Instruction); + luaM_freearray(L, f->p, f->sizep, Proto *); + luaM_freearray(L, f->k, f->sizek, TValue); + luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); + luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); + luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); + luaM_free(L, f); +} + + +void luaF_freeclosure (lua_State *L, Closure *c) { + int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : + sizeLclosure(c->l.nupvalues); + luaM_freemem(L, c, size); +} + + +/* +** Look for n-th local variable at line `line' in function `func'. +** Returns NULL if not found. +*/ +const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { + int i; + for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { + if (pc < f->locvars[i].endpc) { /* is variable active? */ + local_number--; + if (local_number == 0) + return getstr(f->locvars[i].varname); + } + } + return NULL; /* not found */ +} + diff --git a/source/fceultra/lua/src/lfunc.h b/source/fceultra/lua/src/lfunc.h new file mode 100644 index 0000000..a68cf51 --- /dev/null +++ b/source/fceultra/lua/src/lfunc.h @@ -0,0 +1,34 @@ +/* +** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#ifndef lfunc_h +#define lfunc_h + + +#include "lobject.h" + + +#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ + cast(int, sizeof(TValue)*((n)-1))) + +#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ + cast(int, sizeof(TValue *)*((n)-1))) + + +LUAI_FUNC Proto *luaF_newproto (lua_State *L); +LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); +LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); +LUAI_FUNC UpVal *luaF_newupval (lua_State *L); +LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_close (lua_State *L, StkId level); +LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); +LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c); +LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); +LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, + int pc); + + +#endif diff --git a/source/fceultra/lua/src/lgc.c b/source/fceultra/lua/src/lgc.c new file mode 100644 index 0000000..d9e0b78 --- /dev/null +++ b/source/fceultra/lua/src/lgc.c @@ -0,0 +1,711 @@ +/* +** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#include + +#define lgc_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +#define GCSTEPSIZE 1024u +#define GCSWEEPMAX 40 +#define GCSWEEPCOST 10 +#define GCFINALIZECOST 100 + + +#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) + +#define makewhite(g,x) \ + ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) + +#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) + +#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) + + +#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) +#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) + + +#define KEYWEAK bitmask(KEYWEAKBIT) +#define VALUEWEAK bitmask(VALUEWEAKBIT) + + + +#define markvalue(g,o) { checkconsistency(o); \ + if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } + +#define markobject(g,t) { if (iswhite(obj2gco(t))) \ + reallymarkobject(g, obj2gco(t)); } + + +#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) + + +static void removeentry (Node *n) { + lua_assert(ttisnil(gval(n))); + if (iscollectable(gkey(n))) + setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ +} + + +static void reallymarkobject (global_State *g, GCObject *o) { + lua_assert(iswhite(o) && !isdead(g, o)); + white2gray(o); + switch (o->gch.tt) { + case LUA_TSTRING: { + return; + } + case LUA_TUSERDATA: { + Table *mt = gco2u(o)->metatable; + gray2black(o); /* udata are never gray */ + if (mt) markobject(g, mt); + markobject(g, gco2u(o)->env); + return; + } + case LUA_TUPVAL: { + UpVal *uv = gco2uv(o); + markvalue(g, uv->v); + if (uv->v == &uv->u.value) /* closed? */ + gray2black(o); /* open upvalues are never black */ + return; + } + case LUA_TFUNCTION: { + gco2cl(o)->c.gclist = g->gray; + g->gray = o; + break; + } + case LUA_TTABLE: { + gco2h(o)->gclist = g->gray; + g->gray = o; + break; + } + case LUA_TTHREAD: { + gco2th(o)->gclist = g->gray; + g->gray = o; + break; + } + case LUA_TPROTO: { + gco2p(o)->gclist = g->gray; + g->gray = o; + break; + } + default: lua_assert(0); + } +} + + +static void marktmu (global_State *g) { + GCObject *u = g->tmudata; + if (u) { + do { + u = u->gch.next; + makewhite(g, u); /* may be marked, if left from previous GC */ + reallymarkobject(g, u); + } while (u != g->tmudata); + } +} + + +/* move `dead' udata that need finalization to list `tmudata' */ +size_t luaC_separateudata (lua_State *L, int all) { + global_State *g = G(L); + size_t deadmem = 0; + GCObject **p = &g->mainthread->next; + GCObject *curr; + while ((curr = *p) != NULL) { + if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) + p = &curr->gch.next; /* don't bother with them */ + else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { + markfinalized(gco2u(curr)); /* don't need finalization */ + p = &curr->gch.next; + } + else { /* must call its gc method */ + deadmem += sizeudata(gco2u(curr)); + markfinalized(gco2u(curr)); + *p = curr->gch.next; + /* link `curr' at the end of `tmudata' list */ + if (g->tmudata == NULL) /* list is empty? */ + g->tmudata = curr->gch.next = curr; /* creates a circular list */ + else { + curr->gch.next = g->tmudata->gch.next; + g->tmudata->gch.next = curr; + g->tmudata = curr; + } + } + } + return deadmem; +} + + +static int traversetable (global_State *g, Table *h) { + int i; + int weakkey = 0; + int weakvalue = 0; + const TValue *mode; + if (h->metatable) + markobject(g, h->metatable); + mode = gfasttm(g, h->metatable, TM_MODE); + if (mode && ttisstring(mode)) { /* is there a weak mode? */ + weakkey = (strchr(svalue(mode), 'k') != NULL); + weakvalue = (strchr(svalue(mode), 'v') != NULL); + if (weakkey || weakvalue) { /* is really weak? */ + h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ + h->marked |= cast_byte((weakkey << KEYWEAKBIT) | + (weakvalue << VALUEWEAKBIT)); + h->gclist = g->weak; /* must be cleared after GC, ... */ + g->weak = obj2gco(h); /* ... so put in the appropriate list */ + } + } + if (weakkey && weakvalue) return 1; + if (!weakvalue) { + i = h->sizearray; + while (i--) + markvalue(g, &h->array[i]); + } + i = sizenode(h); + while (i--) { + Node *n = gnode(h, i); + lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); + if (ttisnil(gval(n))) + removeentry(n); /* remove empty entries */ + else { + lua_assert(!ttisnil(gkey(n))); + if (!weakkey) markvalue(g, gkey(n)); + if (!weakvalue) markvalue(g, gval(n)); + } + } + return weakkey || weakvalue; +} + + +/* +** All marks are conditional because a GC may happen while the +** prototype is still being created +*/ +static void traverseproto (global_State *g, Proto *f) { + int i; + if (f->source) stringmark(f->source); + for (i=0; isizek; i++) /* mark literals */ + markvalue(g, &f->k[i]); + for (i=0; isizeupvalues; i++) { /* mark upvalue names */ + if (f->upvalues[i]) + stringmark(f->upvalues[i]); + } + for (i=0; isizep; i++) { /* mark nested protos */ + if (f->p[i]) + markobject(g, f->p[i]); + } + for (i=0; isizelocvars; i++) { /* mark local-variable names */ + if (f->locvars[i].varname) + stringmark(f->locvars[i].varname); + } +} + + + +static void traverseclosure (global_State *g, Closure *cl) { + markobject(g, cl->c.env); + if (cl->c.isC) { + int i; + for (i=0; ic.nupvalues; i++) /* mark its upvalues */ + markvalue(g, &cl->c.upvalue[i]); + } + else { + int i; + lua_assert(cl->l.nupvalues == cl->l.p->nups); + markobject(g, cl->l.p); + for (i=0; il.nupvalues; i++) /* mark its upvalues */ + markobject(g, cl->l.upvals[i]); + } +} + + +static void checkstacksizes (lua_State *L, StkId max) { + int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */ + int s_used = cast_int(max - L->stack); /* part of stack in use */ + if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ + return; /* do not touch the stacks */ + if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) + luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ + condhardstacktests(luaD_reallocCI(L, ci_used + 1)); + if (4*s_used < L->stacksize && + 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) + luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ + condhardstacktests(luaD_reallocstack(L, s_used)); +} + + +static void traversestack (global_State *g, lua_State *l) { + StkId o, lim; + CallInfo *ci; + markvalue(g, gt(l)); + lim = l->top; + for (ci = l->base_ci; ci <= l->ci; ci++) { + lua_assert(ci->top <= l->stack_last); + if (lim < ci->top) lim = ci->top; + } + for (o = l->stack; o < l->top; o++) + markvalue(g, o); + for (; o <= lim; o++) + setnilvalue(o); + checkstacksizes(l, lim); +} + + +/* +** traverse one gray object, turning it to black. +** Returns `quantity' traversed. +*/ +static l_mem propagatemark (global_State *g) { + GCObject *o = g->gray; + lua_assert(isgray(o)); + gray2black(o); + switch (o->gch.tt) { + case LUA_TTABLE: { + Table *h = gco2h(o); + g->gray = h->gclist; + if (traversetable(g, h)) /* table is weak? */ + black2gray(o); /* keep it gray */ + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * sizenode(h); + } + case LUA_TFUNCTION: { + Closure *cl = gco2cl(o); + g->gray = cl->c.gclist; + traverseclosure(g, cl); + return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : + sizeLclosure(cl->l.nupvalues); + } + case LUA_TTHREAD: { + lua_State *th = gco2th(o); + g->gray = th->gclist; + th->gclist = g->grayagain; + g->grayagain = o; + black2gray(o); + traversestack(g, th); + return sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->size_ci; + } + case LUA_TPROTO: { + Proto *p = gco2p(o); + g->gray = p->gclist; + traverseproto(g, p); + return sizeof(Proto) + sizeof(Instruction) * p->sizecode + + sizeof(Proto *) * p->sizep + + sizeof(TValue) * p->sizek + + sizeof(int) * p->sizelineinfo + + sizeof(LocVar) * p->sizelocvars + + sizeof(TString *) * p->sizeupvalues; + } + default: lua_assert(0); return 0; + } +} + + +static size_t propagateall (global_State *g) { + size_t m = 0; + while (g->gray) m += propagatemark(g); + return m; +} + + +/* +** The next function tells whether a key or value can be cleared from +** a weak table. Non-collectable objects are never removed from weak +** tables. Strings behave as `values', so are never removed too. for +** other objects: if really collected, cannot keep them; for userdata +** being finalized, keep them in keys, but not in values +*/ +static int iscleared (const TValue *o, int iskey) { + if (!iscollectable(o)) return 0; + if (ttisstring(o)) { + stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ + return 0; + } + return iswhite(gcvalue(o)) || + (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); +} + + +/* +** clear collected entries from weaktables +*/ +static void cleartable (GCObject *l) { + while (l) { + Table *h = gco2h(l); + int i = h->sizearray; + lua_assert(testbit(h->marked, VALUEWEAKBIT) || + testbit(h->marked, KEYWEAKBIT)); + if (testbit(h->marked, VALUEWEAKBIT)) { + while (i--) { + TValue *o = &h->array[i]; + if (iscleared(o, 0)) /* value was collected? */ + setnilvalue(o); /* remove value */ + } + } + i = sizenode(h); + while (i--) { + Node *n = gnode(h, i); + if (!ttisnil(gval(n)) && /* non-empty entry? */ + (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* remove entry from table */ + } + } + l = h->gclist; + } +} + + +static void freeobj (lua_State *L, GCObject *o) { + switch (o->gch.tt) { + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; + case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; + case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; + case LUA_TTABLE: luaH_free(L, gco2h(o)); break; + case LUA_TTHREAD: { + lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); + luaE_freethread(L, gco2th(o)); + break; + } + case LUA_TSTRING: { + G(L)->strt.nuse--; + luaM_freemem(L, o, sizestring(gco2ts(o))); + break; + } + case LUA_TUSERDATA: { + luaM_freemem(L, o, sizeudata(gco2u(o))); + break; + } + default: lua_assert(0); + } +} + + + +#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) + + +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { + GCObject *curr; + global_State *g = G(L); + int deadmask = otherwhite(g); + while ((curr = *p) != NULL && count-- > 0) { + if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ + sweepwholelist(L, &gco2th(curr)->openupval); + if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ + lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); + makewhite(g, curr); /* make it white (for next cycle) */ + p = &curr->gch.next; + } + else { /* must erase `curr' */ + lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); + *p = curr->gch.next; + if (curr == g->rootgc) /* is the first element of the list? */ + g->rootgc = curr->gch.next; /* adjust first */ + freeobj(L, curr); + } + } + return p; +} + + +static void checkSizes (lua_State *L) { + global_State *g = G(L); + /* check size of string hash */ + if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && + g->strt.size > MINSTRTABSIZE*2) + luaS_resize(L, g->strt.size/2); /* table is too big */ + /* check size of buffer */ + if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ + size_t newsize = luaZ_sizebuffer(&g->buff) / 2; + luaZ_resizebuffer(L, &g->buff, newsize); + } +} + + +static void GCTM (lua_State *L) { + global_State *g = G(L); + GCObject *o = g->tmudata->gch.next; /* get first element */ + Udata *udata = rawgco2u(o); + const TValue *tm; + /* remove udata from `tmudata' */ + if (o == g->tmudata) /* last element? */ + g->tmudata = NULL; + else + g->tmudata->gch.next = udata->uv.next; + udata->uv.next = g->mainthread->next; /* return it to `root' list */ + g->mainthread->next = o; + makewhite(g, o); + tm = fasttm(L, udata->uv.metatable, TM_GC); + if (tm != NULL) { + lu_byte oldah = L->allowhook; + lu_mem oldt = g->GCthreshold; + L->allowhook = 0; /* stop debug hooks during GC tag method */ + g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ + setobj2s(L, L->top, tm); + setuvalue(L, L->top+1, udata); + L->top += 2; + luaD_call(L, L->top - 2, 0); + L->allowhook = oldah; /* restore hooks */ + g->GCthreshold = oldt; /* restore threshold */ + } +} + + +/* +** Call all GC tag methods +*/ +void luaC_callGCTM (lua_State *L) { + while (G(L)->tmudata) + GCTM(L); +} + + +void luaC_freeall (lua_State *L) { + global_State *g = G(L); + int i; + g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ + sweepwholelist(L, &g->rootgc); + for (i = 0; i < g->strt.size; i++) /* free all string lists */ + sweepwholelist(L, &g->strt.hash[i]); +} + + +static void markmt (global_State *g) { + int i; + for (i=0; imt[i]) markobject(g, g->mt[i]); +} + + +/* mark root set */ +static void markroot (lua_State *L) { + global_State *g = G(L); + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + markobject(g, g->mainthread); + /* make global table be traversed before main stack */ + markvalue(g, gt(g->mainthread)); + markvalue(g, registry(L)); + markmt(g); + g->gcstate = GCSpropagate; +} + + +static void remarkupvals (global_State *g) { + UpVal *uv; + for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + if (isgray(obj2gco(uv))) + markvalue(g, uv->v); + } +} + + +static void atomic (lua_State *L) { + global_State *g = G(L); + size_t udsize; /* total size of userdata to be finalized */ + /* remark occasional upvalues of (maybe) dead threads */ + remarkupvals(g); + /* traverse objects cautch by write barrier and by 'remarkupvals' */ + propagateall(g); + /* remark weak tables */ + g->gray = g->weak; + g->weak = NULL; + lua_assert(!iswhite(obj2gco(g->mainthread))); + markobject(g, L); /* mark running thread */ + markmt(g); /* mark basic metatables (again) */ + propagateall(g); + /* remark gray again */ + g->gray = g->grayagain; + g->grayagain = NULL; + propagateall(g); + udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ + marktmu(g); /* mark `preserved' userdata */ + udsize += propagateall(g); /* remark, to propagate `preserveness' */ + cleartable(g->weak); /* remove collected objects from weak tables */ + /* flip current white */ + g->currentwhite = cast_byte(otherwhite(g)); + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + g->gcstate = GCSsweepstring; + g->estimate = g->totalbytes - udsize; /* first estimate */ +} + + +static l_mem singlestep (lua_State *L) { + global_State *g = G(L); + /*lua_checkmemory(L);*/ + switch (g->gcstate) { + case GCSpause: { + markroot(L); /* start a new collection */ + return 0; + } + case GCSpropagate: { + if (g->gray) + return propagatemark(g); + else { /* no more `gray' objects */ + atomic(L); /* finish mark phase */ + return 0; + } + } + case GCSsweepstring: { + lu_mem old = g->totalbytes; + sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); + if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ + g->gcstate = GCSsweep; /* end sweep-string phase */ + lua_assert(old >= g->totalbytes); + g->estimate -= old - g->totalbytes; + return GCSWEEPCOST; + } + case GCSsweep: { + lu_mem old = g->totalbytes; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + if (*g->sweepgc == NULL) { /* nothing more to sweep? */ + checkSizes(L); + g->gcstate = GCSfinalize; /* end sweep phase */ + } + lua_assert(old >= g->totalbytes); + g->estimate -= old - g->totalbytes; + return GCSWEEPMAX*GCSWEEPCOST; + } + case GCSfinalize: { + if (g->tmudata) { + GCTM(L); + if (g->estimate > GCFINALIZECOST) + g->estimate -= GCFINALIZECOST; + return GCFINALIZECOST; + } + else { + g->gcstate = GCSpause; /* end collection */ + g->gcdept = 0; + return 0; + } + } + default: lua_assert(0); return 0; + } +} + + +void luaC_step (lua_State *L) { + global_State *g = G(L); + l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; + if (lim == 0) + lim = (MAX_LUMEM-1)/2; /* no limit */ + g->gcdept += g->totalbytes - g->GCthreshold; + do { + lim -= singlestep(L); + if (g->gcstate == GCSpause) + break; + } while (lim > 0); + if (g->gcstate != GCSpause) { + if (g->gcdept < GCSTEPSIZE) + g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/ + else { + g->gcdept -= GCSTEPSIZE; + g->GCthreshold = g->totalbytes; + } + } + else { + lua_assert(g->totalbytes >= g->estimate); + setthreshold(g); + } +} + + +void luaC_fullgc (lua_State *L) { + global_State *g = G(L); + if (g->gcstate <= GCSpropagate) { + /* reset sweep marks to sweep all elements (returning them to white) */ + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + /* reset other collector lists */ + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + g->gcstate = GCSsweepstring; + } + lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); + /* finish any pending sweep phase */ + while (g->gcstate != GCSfinalize) { + lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); + singlestep(L); + } + markroot(L); + while (g->gcstate != GCSpause) { + singlestep(L); + } + setthreshold(g); +} + + +void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + lua_assert(ttype(&o->gch) != LUA_TTABLE); + /* must keep invariant? */ + if (g->gcstate == GCSpropagate) + reallymarkobject(g, v); /* restore invariant */ + else /* don't mind */ + makewhite(g, o); /* mark as white just to avoid other barriers */ +} + + +void luaC_barrierback (lua_State *L, Table *t) { + global_State *g = G(L); + GCObject *o = obj2gco(t); + lua_assert(isblack(o) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + black2gray(o); /* make table gray (again) */ + t->gclist = g->grayagain; + g->grayagain = o; +} + + +void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { + global_State *g = G(L); + o->gch.next = g->rootgc; + g->rootgc = o; + o->gch.marked = luaC_white(g); + o->gch.tt = tt; +} + + +void luaC_linkupval (lua_State *L, UpVal *uv) { + global_State *g = G(L); + GCObject *o = obj2gco(uv); + o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ + g->rootgc = o; + if (isgray(o)) { + if (g->gcstate == GCSpropagate) { + gray2black(o); /* closed upvalues need barrier */ + luaC_barrier(L, uv, uv->v); + } + else { /* sweep phase: sweep it (turning it into white) */ + makewhite(g, o); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + } + } +} + diff --git a/source/fceultra/lua/src/lgc.h b/source/fceultra/lua/src/lgc.h new file mode 100644 index 0000000..5a8dc60 --- /dev/null +++ b/source/fceultra/lua/src/lgc.h @@ -0,0 +1,110 @@ +/* +** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#ifndef lgc_h +#define lgc_h + + +#include "lobject.h" + + +/* +** Possible states of the Garbage Collector +*/ +#define GCSpause 0 +#define GCSpropagate 1 +#define GCSsweepstring 2 +#define GCSsweep 3 +#define GCSfinalize 4 + + +/* +** some userful bit tricks +*/ +#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define l_setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) +#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) +#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) +#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) + + + +/* +** Layout for bit use in `marked' field: +** bit 0 - object is white (type 0) +** bit 1 - object is white (type 1) +** bit 2 - object is black +** bit 3 - for userdata: has been finalized +** bit 3 - for tables: has weak keys +** bit 4 - for tables: has weak values +** bit 5 - object is fixed (should not be collected) +** bit 6 - object is "super" fixed (only the main thread) +*/ + + +#define WHITE0BIT 0 +#define WHITE1BIT 1 +#define BLACKBIT 2 +#define FINALIZEDBIT 3 +#define KEYWEAKBIT 3 +#define VALUEWEAKBIT 4 +#define FIXEDBIT 5 +#define SFIXEDBIT 6 +#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) + + +#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define isblack(x) testbit((x)->gch.marked, BLACKBIT) +#define isgray(x) (!isblack(x) && !iswhite(x)) + +#define otherwhite(g) (g->currentwhite ^ WHITEBITS) +#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS) + +#define changewhite(x) ((x)->gch.marked ^= WHITEBITS) +#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) + +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) + +#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) + + +#define luaC_checkGC(L) { \ + condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ + if (G(L)->totalbytes >= G(L)->GCthreshold) \ + luaC_step(L); } + + +#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),gcvalue(v)); } + +#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \ + luaC_barrierback(L,t); } + +#define luaC_objbarrier(L,p,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),obj2gco(o)); } + +#define luaC_objbarriert(L,t,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } + +LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); +LUAI_FUNC void luaC_callGCTM (lua_State *L); +LUAI_FUNC void luaC_freeall (lua_State *L); +LUAI_FUNC void luaC_step (lua_State *L); +LUAI_FUNC void luaC_fullgc (lua_State *L); +LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); +LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); +LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); +LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); + + +#endif diff --git a/source/fceultra/lua/src/linit.c b/source/fceultra/lua/src/linit.c new file mode 100644 index 0000000..c1f90df --- /dev/null +++ b/source/fceultra/lua/src/linit.c @@ -0,0 +1,38 @@ +/* +** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $ +** Initialization of libraries for lua.c +** See Copyright Notice in lua.h +*/ + + +#define linit_c +#define LUA_LIB + +#include "lua.h" + +#include "lualib.h" +#include "lauxlib.h" + + +static const luaL_Reg lualibs[] = { + {"", luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_DBLIBNAME, luaopen_debug}, + {NULL, NULL} +}; + + +LUALIB_API void luaL_openlibs (lua_State *L) { + const luaL_Reg *lib = lualibs; + for (; lib->func; lib++) { + lua_pushcfunction(L, lib->func); + lua_pushstring(L, lib->name); + lua_call(L, 1, 0); + } +} + diff --git a/source/fceultra/lua/src/liolib.c b/source/fceultra/lua/src/liolib.c new file mode 100644 index 0000000..e79ed1c --- /dev/null +++ b/source/fceultra/lua/src/liolib.c @@ -0,0 +1,553 @@ +/* +** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $ +** Standard I/O (and system) library +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define liolib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +#define IO_INPUT 1 +#define IO_OUTPUT 2 + + +static const char *const fnames[] = {"input", "output"}; + + +static int pushresult (lua_State *L, int i, const char *filename) { + int en = errno; /* calls to Lua API may change this value */ + if (i) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + if (filename) + lua_pushfstring(L, "%s: %s", filename, strerror(en)); + else + lua_pushfstring(L, "%s", strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +static void fileerror (lua_State *L, int arg, const char *filename) { + lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + luaL_argerror(L, arg, lua_tostring(L, -1)); +} + + +#define tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + + +static int io_type (lua_State *L) { + void *ud; + luaL_checkany(L, 1); + ud = lua_touserdata(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); + if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) + lua_pushnil(L); /* not a file */ + else if (*((FILE **)ud) == NULL) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; +} + + +static FILE *tofile (lua_State *L) { + FILE **f = tofilep(L); + if (*f == NULL) + luaL_error(L, "attempt to use a closed file"); + return *f; +} + + + +/* +** When creating file handles, always creates a `closed' file handle +** before opening the actual file; so, if there is a memory error, the +** file is not left opened. +*/ +static FILE **newfile (lua_State *L) { + FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); + *pf = NULL; /* file handle is currently `closed' */ + luaL_getmetatable(L, LUA_FILEHANDLE); + lua_setmetatable(L, -2); + return pf; +} + + +/* +** function to (not) close the standard files stdin, stdout, and stderr +*/ +static int io_noclose (lua_State *L) { + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; +} + + +/* +** function to close 'popen' files +*/ +static int io_pclose (lua_State *L) { + FILE **p = tofilep(L); + int ok = lua_pclose(L, *p); + *p = NULL; + return pushresult(L, ok, NULL); +} + + +/* +** function to close regular files +*/ +static int io_fclose (lua_State *L) { + FILE **p = tofilep(L); + int ok = (fclose(*p) == 0); + *p = NULL; + return pushresult(L, ok, NULL); +} + + +static int aux_close (lua_State *L) { + lua_getfenv(L, 1); + lua_getfield(L, -1, "__close"); + return (lua_tocfunction(L, -1))(L); +} + + +static int io_close (lua_State *L) { + if (lua_isnone(L, 1)) + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); + tofile(L); /* make sure argument is a file */ + return aux_close(L); +} + + +static int io_gc (lua_State *L) { + FILE *f = *tofilep(L); + /* ignore closed files */ + if (f != NULL) + aux_close(L); + return 0; +} + + +static int io_tostring (lua_State *L) { + FILE *f = *tofilep(L); + if (f == NULL) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", f); + return 1; +} + + +static int io_open (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + FILE **pf = newfile(L); + *pf = fopen(filename, mode); + return (*pf == NULL) ? pushresult(L, 0, filename) : 1; +} + + +/* +** this function has a separated environment, which defines the +** correct __close for 'popen' files +*/ +static int io_popen (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + FILE **pf = newfile(L); + *pf = lua_popen(L, filename, mode); + return (*pf == NULL) ? pushresult(L, 0, filename) : 1; +} + + +static int io_tmpfile (lua_State *L) { + FILE **pf = newfile(L); + *pf = tmpfile(); + return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; +} + + +static FILE *getiofile (lua_State *L, int findex) { + FILE *f; + lua_rawgeti(L, LUA_ENVIRONINDEX, findex); + f = *(FILE **)lua_touserdata(L, -1); + if (f == NULL) + luaL_error(L, "standard %s file is closed", fnames[findex - 1]); + return f; +} + + +static int g_iofile (lua_State *L, int f, const char *mode) { + if (!lua_isnoneornil(L, 1)) { + const char *filename = lua_tostring(L, 1); + if (filename) { + FILE **pf = newfile(L); + *pf = fopen(filename, mode); + if (*pf == NULL) + fileerror(L, 1, filename); + } + else { + tofile(L); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_rawseti(L, LUA_ENVIRONINDEX, f); + } + /* return current value */ + lua_rawgeti(L, LUA_ENVIRONINDEX, f); + return 1; +} + + +static int io_input (lua_State *L) { + return g_iofile(L, IO_INPUT, "r"); +} + + +static int io_output (lua_State *L) { + return g_iofile(L, IO_OUTPUT, "w"); +} + + +static int io_readline (lua_State *L); + + +static void aux_lines (lua_State *L, int idx, int toclose) { + lua_pushvalue(L, idx); + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_pushcclosure(L, io_readline, 2); +} + + +static int f_lines (lua_State *L) { + tofile(L); /* check that it's a valid file handle */ + aux_lines(L, 1, 0); + return 1; +} + + +static int io_lines (lua_State *L) { + if (lua_isnoneornil(L, 1)) { /* no arguments? */ + /* will iterate over default input */ + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); + return f_lines(L); + } + else { + const char *filename = luaL_checkstring(L, 1); + FILE **pf = newfile(L); + *pf = fopen(filename, "r"); + if (*pf == NULL) + fileerror(L, 1, filename); + aux_lines(L, lua_gettop(L), 1); + return 1; + } +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +static int read_number (lua_State *L, FILE *f) { + lua_Number d; + if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { + lua_pushnumber(L, d); + return 1; + } + else return 0; /* read fails */ +} + + +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); + ungetc(c, f); + lua_pushlstring(L, NULL, 0); + return (c != EOF); +} + + +static int read_line (lua_State *L, FILE *f) { + luaL_Buffer b; + luaL_buffinit(L, &b); + for (;;) { + size_t l; + char *p = luaL_prepbuffer(&b); + if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ + luaL_pushresult(&b); /* close buffer */ + return (lua_objlen(L, -1) > 0); /* check whether read something */ + } + l = strlen(p); + if (l == 0 || p[l-1] != '\n') + luaL_addsize(&b, l); + else { + luaL_addsize(&b, l - 1); /* do not include `eol' */ + luaL_pushresult(&b); /* close buffer */ + return 1; /* read at least an `eol' */ + } + } +} + + +static int read_chars (lua_State *L, FILE *f, size_t n) { + size_t rlen; /* how much to read */ + size_t nr; /* number of chars actually read */ + luaL_Buffer b; + luaL_buffinit(L, &b); + rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ + do { + char *p = luaL_prepbuffer(&b); + if (rlen > n) rlen = n; /* cannot read more than asked */ + nr = fread(p, sizeof(char), rlen, f); + luaL_addsize(&b, nr); + n -= nr; /* still have to read `n' chars */ + } while (n > 0 && nr == rlen); /* until end of count or eof */ + luaL_pushresult(&b); /* close buffer */ + return (n == 0 || lua_objlen(L, -1) > 0); +} + + +static int g_read (lua_State *L, FILE *f, int first) { + int nargs = lua_gettop(L) - 1; + int success; + int n; + clearerr(f); + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f); + n = first+1; /* to return 1 result */ + } + else { /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)lua_tointeger(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } + else { + const char *p = lua_tostring(L, n); + luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); + switch (p[1]) { + case 'n': /* number */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f); + break; + case 'a': /* file */ + read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return pushresult(L, 0, NULL); + if (!success) { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - first; +} + + +static int io_read (lua_State *L) { + return g_read(L, getiofile(L, IO_INPUT), 1); +} + + +static int f_read (lua_State *L) { + return g_read(L, tofile(L), 2); +} + + +static int io_readline (lua_State *L) { + FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); + int sucess; + if (f == NULL) /* file is already closed? */ + luaL_error(L, "file is already closed"); + sucess = read_line(L, f); + if (ferror(f)) + return luaL_error(L, "%s", strerror(errno)); + if (sucess) return 1; + else { /* EOF */ + if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(1)); + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - 1; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + status = status && + fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + return pushresult(L, status, NULL); +} + + +static int io_write (lua_State *L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); +} + + +static int f_write (lua_State *L) { + return g_write(L, tofile(L), 2); +} + + +static int f_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char *const modenames[] = {"set", "cur", "end", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); + long offset = luaL_optlong(L, 3, 0); + op = fseek(f, offset, mode[op]); + if (op) + return pushresult(L, 0, NULL); /* error */ + else { + lua_pushinteger(L, ftell(f)); + return 1; + } +} + + +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, NULL, mode[op], sz); + return pushresult(L, res == 0, NULL); +} + + + +static int io_flush (lua_State *L) { + return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return pushresult(L, fflush(tofile(L)) == 0, NULL); +} + + +static const luaL_Reg iolib[] = { + {"close", io_close}, + {"flush", io_flush}, + {"input", io_input}, + {"lines", io_lines}, + {"open", io_open}, + {"output", io_output}, + {"popen", io_popen}, + {"read", io_read}, + {"tmpfile", io_tmpfile}, + {"type", io_type}, + {"write", io_write}, + {NULL, NULL} +}; + + +static const luaL_Reg flib[] = { + {"close", io_close}, + {"flush", f_flush}, + {"lines", f_lines}, + {"read", f_read}, + {"seek", f_seek}, + {"setvbuf", f_setvbuf}, + {"write", f_write}, + {"__gc", io_gc}, + {"__tostring", io_tostring}, + {NULL, NULL} +}; + + +static void createmeta (lua_State *L) { + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_register(L, NULL, flib); /* file methods */ +} + + +static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { + *newfile(L) = f; + if (k > 0) { + lua_pushvalue(L, -1); + lua_rawseti(L, LUA_ENVIRONINDEX, k); + } + lua_pushvalue(L, -2); /* copy environment */ + lua_setfenv(L, -2); /* set it */ + lua_setfield(L, -3, fname); +} + + +static void newfenv (lua_State *L, lua_CFunction cls) { + lua_createtable(L, 0, 1); + lua_pushcfunction(L, cls); + lua_setfield(L, -2, "__close"); +} + + +LUALIB_API int luaopen_io (lua_State *L) { + createmeta(L); + /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ + newfenv(L, io_fclose); + lua_replace(L, LUA_ENVIRONINDEX); + /* open library */ + luaL_register(L, LUA_IOLIBNAME, iolib); + /* create (and set) default files */ + newfenv(L, io_noclose); /* close function for default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, 0, "stderr"); + lua_pop(L, 1); /* pop environment for default files */ + lua_getfield(L, -1, "popen"); + newfenv(L, io_pclose); /* create environment for 'popen' */ + lua_setfenv(L, -2); /* set fenv for 'popen' */ + lua_pop(L, 1); /* pop 'popen' */ + return 1; +} + diff --git a/source/fceultra/lua/src/llex.c b/source/fceultra/lua/src/llex.c new file mode 100644 index 0000000..6dc3193 --- /dev/null +++ b/source/fceultra/lua/src/llex.c @@ -0,0 +1,461 @@ +/* +** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +#define llex_c +#define LUA_CORE + +#include "lua.h" + +#include "ldo.h" +#include "llex.h" +#include "lobject.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lzio.h" + + + +#define next(ls) (ls->current = zgetc(ls->z)) + + + + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + + +/* ORDER RESERVED */ +const char *const luaX_tokens [] = { + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", + "..", "...", "==", ">=", "<=", "~=", + "", "", "", "", + NULL +}; + + +#define save_and_next(ls) (save(ls, ls->current), next(ls)) + + +static void save (LexState *ls, int c) { + Mbuffer *b = ls->buff; + if (b->n + 1 > b->buffsize) { + size_t newsize; + if (b->buffsize >= MAX_SIZET/2) + luaX_lexerror(ls, "lexical element too long", 0); + newsize = b->buffsize * 2; + luaZ_resizebuffer(ls->L, b, newsize); + } + b->buffer[b->n++] = cast(char, c); +} + + +void luaX_init (lua_State *L) { + int i; + for (i=0; itsv.reserved = cast_byte(i+1); /* reserved word */ + } +} + + +#define MAXSRC 80 + + +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { + lua_assert(token == cast(unsigned char, token)); + return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : + luaO_pushfstring(ls->L, "%c", token); + } + else + return luaX_tokens[token-FIRST_RESERVED]; +} + + +static const char *txtToken (LexState *ls, int token) { + switch (token) { + case TK_NAME: + case TK_STRING: + case TK_NUMBER: + save(ls, '\0'); + return luaZ_buffer(ls->buff); + default: + return luaX_token2str(ls, token); + } +} + + +void luaX_lexerror (LexState *ls, const char *msg, int token) { + char buff[MAXSRC]; + luaO_chunkid(buff, getstr(ls->source), MAXSRC); + msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); + if (token) + luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); +} + + +void luaX_syntaxerror (LexState *ls, const char *msg) { + luaX_lexerror(ls, msg, ls->t.token); +} + + +TString *luaX_newstring (LexState *ls, const char *str, size_t l) { + lua_State *L = ls->L; + TString *ts = luaS_newlstr(L, str, l); + TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ + if (ttisnil(o)) + setbvalue(o, 1); /* make sure `str' will not be collected */ + return ts; +} + + +static void inclinenumber (LexState *ls) { + int old = ls->current; + lua_assert(currIsNewline(ls)); + next(ls); /* skip `\n' or `\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip `\n\r' or `\r\n' */ + if (++ls->linenumber >= MAX_INT) + luaX_syntaxerror(ls, "chunk has too many lines"); +} + + +void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { + ls->decpoint = '.'; + ls->L = L; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->z = z; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ + next(ls); /* read first char */ +} + + + +/* +** ======================================================= +** LEXICAL ANALYZER +** ======================================================= +*/ + + + +static int check_next (LexState *ls, const char *set) { + if (!strchr(set, ls->current)) + return 0; + save_and_next(ls); + return 1; +} + + +static void buffreplace (LexState *ls, char from, char to) { + size_t n = luaZ_bufflen(ls->buff); + char *p = luaZ_buffer(ls->buff); + while (n--) + if (p[n] == from) p[n] = to; +} + + +static void trydecpoint (LexState *ls, SemInfo *seminfo) { + /* format error: try to update decimal point separator */ + struct lconv *cv = localeconv(); + char old = ls->decpoint; + ls->decpoint = (cv ? cv->decimal_point[0] : '.'); + buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ + if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { + /* format error with correct decimal point: no more options */ + buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ + luaX_lexerror(ls, "malformed number", TK_NUMBER); + } +} + + +/* LUA_NUMBER */ +static void read_numeral (LexState *ls, SemInfo *seminfo) { + lua_assert(isdigit(ls->current)); + do { + save_and_next(ls); + } while (isdigit(ls->current) || ls->current == '.'); + if (check_next(ls, "Ee")) /* `E'? */ + check_next(ls, "+-"); /* optional exponent sign */ + while (isalnum(ls->current) || ls->current == '_') + save_and_next(ls); + save(ls, '\0'); + buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ + if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ + trydecpoint(ls, seminfo); /* try to update decimal point separator */ +} + + +static int skip_sep (LexState *ls) { + int count = 0; + int s = ls->current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '=') { + save_and_next(ls); + count++; + } + return (ls->current == s) ? count : (-count) - 1; +} + + +static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { + int cont = 0; + (void)(cont); /* avoid warnings when `cont' is not used */ + save_and_next(ls); /* skip 2nd `[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ + for (;;) { + switch (ls->current) { + case EOZ: + luaX_lexerror(ls, (seminfo) ? "unfinished long string" : + "unfinished long comment", TK_EOS); + break; /* to avoid warnings */ +#if defined(LUA_COMPAT_LSTR) + case '[': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `[' */ + cont++; +#if LUA_COMPAT_LSTR == 1 + if (sep == 0) + luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); +#endif + } + break; + } +#endif + case ']': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `]' */ +#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 + cont--; + if (sep == 0 && cont >= 0) break; +#endif + goto endloop; + } + break; + } + case '\n': + case '\r': { + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ + break; + } + default: { + if (seminfo) save_and_next(ls); + else next(ls); + } + } + } endloop: + if (seminfo) + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), + luaZ_bufflen(ls->buff) - 2*(2 + sep)); +} + + +static void read_string (LexState *ls, int del, SemInfo *seminfo) { + save_and_next(ls); + while (ls->current != del) { + switch (ls->current) { + case EOZ: + luaX_lexerror(ls, "unfinished string", TK_EOS); + continue; /* to avoid warnings */ + case '\n': + case '\r': + luaX_lexerror(ls, "unfinished string", TK_STRING); + continue; /* to avoid warnings */ + case '\\': { + int c; + next(ls); /* do not save the `\' */ + switch (ls->current) { + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case '\n': /* go through */ + case '\r': save(ls, '\n'); inclinenumber(ls); continue; + case EOZ: continue; /* will raise an error next loop */ + default: { + if (!isdigit(ls->current)) + save_and_next(ls); /* handles \\, \", \', and \? */ + else { /* \xxx */ + int i = 0; + c = 0; + do { + c = 10*c + (ls->current-'0'); + next(ls); + } while (++i<3 && isdigit(ls->current)); + if (c > UCHAR_MAX) + luaX_lexerror(ls, "escape sequence too large", TK_STRING); + save(ls, c); + } + continue; + } + } + save(ls, c); + next(ls); + continue; + } + default: + save_and_next(ls); + } + } + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); +} + + +static int llex (LexState *ls, SemInfo *seminfo) { + luaZ_resetbuffer(ls->buff); + for (;;) { + switch (ls->current) { + case '\n': + case '\r': { + inclinenumber(ls); + continue; + } + case '-': { + next(ls); + if (ls->current != '-') return '-'; + /* else is a comment */ + next(ls); + if (ls->current == '[') { + int sep = skip_sep(ls); + luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ + if (sep >= 0) { + read_long_string(ls, NULL, sep); /* long comment */ + luaZ_resetbuffer(ls->buff); + continue; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); + continue; + } + case '[': { + int sep = skip_sep(ls); + if (sep >= 0) { + read_long_string(ls, seminfo, sep); + return TK_STRING; + } + else if (sep == -1) return '['; + else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); + } + case '=': { + next(ls); + if (ls->current != '=') return '='; + else { next(ls); return TK_EQ; } + } + case '<': { + next(ls); + if (ls->current != '=') return '<'; + else { next(ls); return TK_LE; } + } + case '>': { + next(ls); + if (ls->current != '=') return '>'; + else { next(ls); return TK_GE; } + } + case '~': { + next(ls); + if (ls->current != '=') return '~'; + else { next(ls); return TK_NE; } + } + case '"': + case '\'': { + read_string(ls, ls->current, seminfo); + return TK_STRING; + } + case '.': { + save_and_next(ls); + if (check_next(ls, ".")) { + if (check_next(ls, ".")) + return TK_DOTS; /* ... */ + else return TK_CONCAT; /* .. */ + } + else if (!isdigit(ls->current)) return '.'; + else { + read_numeral(ls, seminfo); + return TK_NUMBER; + } + } + case EOZ: { + return TK_EOS; + } + default: { + if (isspace(ls->current)) { + lua_assert(!currIsNewline(ls)); + next(ls); + continue; + } + else if (isdigit(ls->current)) { + read_numeral(ls, seminfo); + return TK_NUMBER; + } + else if (isalpha(ls->current) || ls->current == '_') { + /* identifier or reserved word */ + TString *ts; + do { + save_and_next(ls); + } while (isalnum(ls->current) || ls->current == '_'); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); + if (ts->tsv.reserved > 0) /* reserved word? */ + return ts->tsv.reserved - 1 + FIRST_RESERVED; + else { + seminfo->ts = ts; + return TK_NAME; + } + } + else { + int c = ls->current; + next(ls); + return c; /* single-char tokens (+ - / ...) */ + } + } + } + } +} + + +void luaX_next (LexState *ls) { + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ + } + else + ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ +} + + +void luaX_lookahead (LexState *ls) { + lua_assert(ls->lookahead.token == TK_EOS); + ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); +} + diff --git a/source/fceultra/lua/src/llex.h b/source/fceultra/lua/src/llex.h new file mode 100644 index 0000000..a9201ce --- /dev/null +++ b/source/fceultra/lua/src/llex.h @@ -0,0 +1,81 @@ +/* +** $Id: llex.h,v 1.58.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#ifndef llex_h +#define llex_h + +#include "lobject.h" +#include "lzio.h" + + +#define FIRST_RESERVED 257 + +/* maximum length of a reserved word */ +#define TOKEN_LEN (sizeof("function")/sizeof(char)) + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER RESERVED" +*/ +enum RESERVED { + /* terminal symbols denoted by reserved words */ + TK_AND = FIRST_RESERVED, TK_BREAK, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, + TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, + TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, + /* other terminal symbols */ + TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, + TK_NAME, TK_STRING, TK_EOS +}; + +/* number of reserved words */ +#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) + + +/* array with token `names' */ +LUAI_DATA const char *const luaX_tokens []; + + +typedef union { + lua_Number r; + TString *ts; +} SemInfo; /* semantics information */ + + +typedef struct Token { + int token; + SemInfo seminfo; +} Token; + + +typedef struct LexState { + int current; /* current character (charint) */ + int linenumber; /* input line counter */ + int lastline; /* line of last token `consumed' */ + Token t; /* current token */ + Token lookahead; /* look ahead token */ + struct FuncState *fs; /* `FuncState' is private to the parser */ + struct lua_State *L; + ZIO *z; /* input stream */ + Mbuffer *buff; /* buffer for tokens */ + TString *source; /* current source name */ + char decpoint; /* locale decimal point */ +} LexState; + + +LUAI_FUNC void luaX_init (lua_State *L); +LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, + TString *source); +LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); +LUAI_FUNC void luaX_next (LexState *ls); +LUAI_FUNC void luaX_lookahead (LexState *ls); +LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token); +LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s); +LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); + + +#endif diff --git a/source/fceultra/lua/src/llimits.h b/source/fceultra/lua/src/llimits.h new file mode 100644 index 0000000..ca8dcb7 --- /dev/null +++ b/source/fceultra/lua/src/llimits.h @@ -0,0 +1,128 @@ +/* +** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $ +** Limits, basic types, and some other `installation-dependent' definitions +** See Copyright Notice in lua.h +*/ + +#ifndef llimits_h +#define llimits_h + + +#include +#include + + +#include "lua.h" + + +typedef LUAI_UINT32 lu_int32; + +typedef LUAI_UMEM lu_mem; + +typedef LUAI_MEM l_mem; + + + +/* chars used as small naturals (so that `char' is reserved for characters) */ +typedef unsigned char lu_byte; + + +#define MAX_SIZET ((size_t)(~(size_t)0)-2) + +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) + + +#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ + +/* +** conversion of pointer to integer +** this is for hashing only; there is no problem if the integer +** cannot hold the whole pointer value +*/ +#define IntPoint(p) ((unsigned int)(lu_mem)(p)) + + + +/* type to ensure maximum alignment */ +typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; + + +/* result of a `usual argument conversion' over lua_Number */ +typedef LUAI_UACNUMBER l_uacNumber; + + +/* internal assertions for in-house debugging */ +#ifdef lua_assert + +#define check_exp(c,e) (lua_assert(c), (e)) +#define api_check(l,e) lua_assert(e) + +#else + +#define lua_assert(c) ((void)0) +#define check_exp(c,e) (e) +#define api_check luai_apicheck + +#endif + + +#ifndef UNUSED +#define UNUSED(x) ((void)(x)) /* to avoid warnings */ +#endif + + +#ifndef cast +#define cast(t, exp) ((t)(exp)) +#endif + +#define cast_byte(i) cast(lu_byte, (i)) +#define cast_num(i) cast(lua_Number, (i)) +#define cast_int(i) cast(int, (i)) + + + +/* +** type for virtual-machine instructions +** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) +*/ +typedef lu_int32 Instruction; + + + +/* maximum stack for a Lua function */ +#define MAXSTACK 250 + + + +/* minimum size for the string table (must be power of 2) */ +#ifndef MINSTRTABSIZE +#define MINSTRTABSIZE 32 +#endif + + +/* minimum size for string buffer */ +#ifndef LUA_MINBUFFER +#define LUA_MINBUFFER 32 +#endif + + +#ifndef lua_lock +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) +#endif + +#ifndef luai_threadyield +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} +#endif + + +/* +** macro to control inclusion of some hard tests on stack reallocation +*/ +#ifndef HARDSTACKTESTS +#define condhardstacktests(x) ((void)0) +#else +#define condhardstacktests(x) x +#endif + +#endif diff --git a/source/fceultra/lua/src/lmathlib.c b/source/fceultra/lua/src/lmathlib.c new file mode 100644 index 0000000..441fbf7 --- /dev/null +++ b/source/fceultra/lua/src/lmathlib.c @@ -0,0 +1,263 @@ +/* +** $Id: lmathlib.c,v 1.67.1.1 2007/12/27 13:02:25 roberto Exp $ +** Standard mathematical library +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#define lmathlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#undef PI +#define PI (3.14159265358979323846) +#define RADIANS_PER_DEGREE (PI/180.0) + + + +static int math_abs (lua_State *L) { + lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sin (lua_State *L) { + lua_pushnumber(L, sin(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sinh (lua_State *L) { + lua_pushnumber(L, sinh(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cos (lua_State *L) { + lua_pushnumber(L, cos(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cosh (lua_State *L) { + lua_pushnumber(L, cosh(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tan (lua_State *L) { + lua_pushnumber(L, tan(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tanh (lua_State *L) { + lua_pushnumber(L, tanh(luaL_checknumber(L, 1))); + return 1; +} + +static int math_asin (lua_State *L) { + lua_pushnumber(L, asin(luaL_checknumber(L, 1))); + return 1; +} + +static int math_acos (lua_State *L) { + lua_pushnumber(L, acos(luaL_checknumber(L, 1))); + return 1; +} + +static int math_atan (lua_State *L) { + lua_pushnumber(L, atan(luaL_checknumber(L, 1))); + return 1; +} + +static int math_atan2 (lua_State *L) { + lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +static int math_ceil (lua_State *L) { + lua_pushnumber(L, ceil(luaL_checknumber(L, 1))); + return 1; +} + +static int math_floor (lua_State *L) { + lua_pushnumber(L, floor(luaL_checknumber(L, 1))); + return 1; +} + +static int math_fmod (lua_State *L) { + lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +static int math_modf (lua_State *L) { + double ip; + double fp = modf(luaL_checknumber(L, 1), &ip); + lua_pushnumber(L, ip); + lua_pushnumber(L, fp); + return 2; +} + +static int math_sqrt (lua_State *L) { + lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); + return 1; +} + +static int math_pow (lua_State *L) { + lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + return 1; +} + +static int math_log (lua_State *L) { + lua_pushnumber(L, log(luaL_checknumber(L, 1))); + return 1; +} + +static int math_log10 (lua_State *L) { + lua_pushnumber(L, log10(luaL_checknumber(L, 1))); + return 1; +} + +static int math_exp (lua_State *L) { + lua_pushnumber(L, exp(luaL_checknumber(L, 1))); + return 1; +} + +static int math_deg (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); + return 1; +} + +static int math_rad (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); + return 1; +} + +static int math_frexp (lua_State *L) { + int e; + lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); + lua_pushinteger(L, e); + return 2; +} + +static int math_ldexp (lua_State *L) { + lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); + return 1; +} + + + +static int math_min (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + lua_Number dmin = luaL_checknumber(L, 1); + int i; + for (i=2; i<=n; i++) { + lua_Number d = luaL_checknumber(L, i); + if (d < dmin) + dmin = d; + } + lua_pushnumber(L, dmin); + return 1; +} + + +static int math_max (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + lua_Number dmax = luaL_checknumber(L, 1); + int i; + for (i=2; i<=n; i++) { + lua_Number d = luaL_checknumber(L, i); + if (d > dmax) + dmax = d; + } + lua_pushnumber(L, dmax); + return 1; +} + + +static int math_random (lua_State *L) { + /* the `%' avoids the (rare) case of r==1, and is needed also because on + some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ + lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; + switch (lua_gettop(L)) { /* check number of arguments */ + case 0: { /* no arguments */ + lua_pushnumber(L, r); /* Number between 0 and 1 */ + break; + } + case 1: { /* only upper limit */ + int u = luaL_checkint(L, 1); + luaL_argcheck(L, 1<=u, 1, "interval is empty"); + lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */ + break; + } + case 2: { /* lower and upper limits */ + int l = luaL_checkint(L, 1); + int u = luaL_checkint(L, 2); + luaL_argcheck(L, l<=u, 2, "interval is empty"); + lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ + break; + } + default: return luaL_error(L, "wrong number of arguments"); + } + return 1; +} + + +static int math_randomseed (lua_State *L) { + srand(luaL_checkint(L, 1)); + return 0; +} + + +static const luaL_Reg mathlib[] = { + {"abs", math_abs}, + {"acos", math_acos}, + {"asin", math_asin}, + {"atan2", math_atan2}, + {"atan", math_atan}, + {"ceil", math_ceil}, + {"cosh", math_cosh}, + {"cos", math_cos}, + {"deg", math_deg}, + {"exp", math_exp}, + {"floor", math_floor}, + {"fmod", math_fmod}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, + {"log10", math_log10}, + {"log", math_log}, + {"max", math_max}, + {"min", math_min}, + {"modf", math_modf}, + {"pow", math_pow}, + {"rad", math_rad}, + {"random", math_random}, + {"randomseed", math_randomseed}, + {"sinh", math_sinh}, + {"sin", math_sin}, + {"sqrt", math_sqrt}, + {"tanh", math_tanh}, + {"tan", math_tan}, + {NULL, NULL} +}; + + +/* +** Open math library +*/ +LUALIB_API int luaopen_math (lua_State *L) { + luaL_register(L, LUA_MATHLIBNAME, mathlib); + lua_pushnumber(L, PI); + lua_setfield(L, -2, "pi"); + lua_pushnumber(L, HUGE_VAL); + lua_setfield(L, -2, "huge"); +#if defined(LUA_COMPAT_MOD) + lua_getfield(L, -1, "fmod"); + lua_setfield(L, -2, "mod"); +#endif + return 1; +} + diff --git a/source/fceultra/lua/src/lmem.c b/source/fceultra/lua/src/lmem.c new file mode 100644 index 0000000..ae7d8c9 --- /dev/null +++ b/source/fceultra/lua/src/lmem.c @@ -0,0 +1,86 @@ +/* +** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + + +#include + +#define lmem_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +/* +** About the realloc function: +** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); +** (`osize' is the old size, `nsize' is the new size) +** +** Lua ensures that (ptr == NULL) iff (osize == 0). +** +** * frealloc(ud, NULL, 0, x) creates a new block of size `x' +** +** * frealloc(ud, p, x, 0) frees the block `p' +** (in this specific case, frealloc must return NULL). +** particularly, frealloc(ud, NULL, 0, 0) does nothing +** (which is equivalent to free(NULL) in ANSI C) +** +** frealloc returns NULL if it cannot create or reallocate the area +** (any reallocation to an equal or smaller size cannot fail!) +*/ + + + +#define MINSIZEARRAY 4 + + +void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, + int limit, const char *errormsg) { + void *newblock; + int newsize; + if (*size >= limit/2) { /* cannot double it? */ + if (*size >= limit) /* cannot grow even a little? */ + luaG_runerror(L, errormsg); + newsize = limit; /* still have at least one free place */ + } + else { + newsize = (*size)*2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ + } + newblock = luaM_reallocv(L, block, *size, newsize, size_elems); + *size = newsize; /* update only when everything else is OK */ + return newblock; +} + + +void *luaM_toobig (lua_State *L) { + luaG_runerror(L, "memory allocation error: block too big"); + return NULL; /* to avoid warnings */ +} + + + +/* +** generic allocation routine. +*/ +void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + global_State *g = G(L); + lua_assert((osize == 0) == (block == NULL)); + block = (*g->frealloc)(g->ud, block, osize, nsize); + if (block == NULL && nsize > 0) + luaD_throw(L, LUA_ERRMEM); + lua_assert((nsize == 0) == (block == NULL)); + g->totalbytes = (g->totalbytes - osize) + nsize; + return block; +} + diff --git a/source/fceultra/lua/src/lmem.h b/source/fceultra/lua/src/lmem.h new file mode 100644 index 0000000..7c2dcb3 --- /dev/null +++ b/source/fceultra/lua/src/lmem.h @@ -0,0 +1,49 @@ +/* +** $Id: lmem.h,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#ifndef lmem_h +#define lmem_h + + +#include + +#include "llimits.h" +#include "lua.h" + +#define MEMERRMSG "not enough memory" + + +#define luaM_reallocv(L,b,on,n,e) \ + ((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ + luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \ + luaM_toobig(L)) + +#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) +#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) +#define luaM_freearray(L, b, n, t) luaM_reallocv(L, (b), n, 0, sizeof(t)) + +#define luaM_malloc(L,t) luaM_realloc_(L, NULL, 0, (t)) +#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) +#define luaM_newvector(L,n,t) \ + cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) + +#define luaM_growvector(L,v,nelems,size,t,limit,e) \ + if ((nelems)+1 > (size)) \ + ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) + +#define luaM_reallocvector(L, v,oldn,n,t) \ + ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) + + +LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, + size_t size); +LUAI_FUNC void *luaM_toobig (lua_State *L); +LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, + size_t size_elem, int limit, + const char *errormsg); + +#endif + diff --git a/source/fceultra/lua/src/loadlib.c b/source/fceultra/lua/src/loadlib.c new file mode 100644 index 0000000..0d401eb --- /dev/null +++ b/source/fceultra/lua/src/loadlib.c @@ -0,0 +1,666 @@ +/* +** $Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp $ +** Dynamic library loader for Lua +** See Copyright Notice in lua.h +** +** This module contains an implementation of loadlib for Unix systems +** that have dlfcn, an implementation for Darwin (Mac OS X), an +** implementation for Windows, and a stub for other systems. +*/ + + +#include +#include + + +#define loadlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* prefix for open functions in C libraries */ +#define LUA_POF "luaopen_" + +/* separator for open functions in C libraries */ +#define LUA_OFSEP "_" + + +#define LIBPREFIX "LOADLIB: " + +#define POF LUA_POF +#define LIB_FAIL "open" + + +/* error codes for ll_loadfunc */ +#define ERRLIB 1 +#define ERRFUNC 2 + +#define setprogdir(L) ((void)0) + + +static void ll_unloadlib (void *lib); +static void *ll_load (lua_State *L, const char *path); +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); + + + +#if defined(LUA_DL_DLOPEN) +/* +** {======================================================================== +** This is an implementation of loadlib based on the dlfcn interface. +** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, +** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least +** as an emulation layer on top of native functions. +** ========================================================================= +*/ + +#include + +static void ll_unloadlib (void *lib) { + dlclose(lib); +} + + +static void *ll_load (lua_State *L, const char *path) { + void *lib = dlopen(path, RTLD_NOW); + if (lib == NULL) lua_pushstring(L, dlerror()); + return lib; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)dlsym(lib, sym); + if (f == NULL) lua_pushstring(L, dlerror()); + return f; +} + +/* }====================================================== */ + + + +#elif defined(LUA_DL_DLL) +/* +** {====================================================================== +** This is an implementation of loadlib for Windows using native functions. +** ======================================================================= +*/ + +#include + + +#undef setprogdir + +static void setprogdir (lua_State *L) { + char buff[MAX_PATH + 1]; + char *lb; + DWORD nsize = sizeof(buff)/sizeof(char); + DWORD n = GetModuleFileNameA(NULL, buff, nsize); + if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) + luaL_error(L, "unable to get ModuleFileName"); + else { + *lb = '\0'; + luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); + lua_remove(L, -2); /* remove original string */ + } +} + + +static void pusherror (lua_State *L) { + int error = GetLastError(); + char buffer[128]; + if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, buffer, sizeof(buffer), NULL)) + lua_pushstring(L, buffer); + else + lua_pushfstring(L, "system error %d\n", error); +} + +static void ll_unloadlib (void *lib) { + FreeLibrary((HINSTANCE)lib); +} + + +static void *ll_load (lua_State *L, const char *path) { + HINSTANCE lib = LoadLibraryA(path); + if (lib == NULL) pusherror(L); + return lib; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); + if (f == NULL) pusherror(L); + return f; +} + +/* }====================================================== */ + + + +#elif defined(LUA_DL_DYLD) +/* +** {====================================================================== +** Native Mac OS X / Darwin Implementation +** ======================================================================= +*/ + +#include + + +/* Mac appends a `_' before C function names */ +#undef POF +#define POF "_" LUA_POF + + +static void pusherror (lua_State *L) { + const char *err_str; + const char *err_file; + NSLinkEditErrors err; + int err_num; + NSLinkEditError(&err, &err_num, &err_file, &err_str); + lua_pushstring(L, err_str); +} + + +static const char *errorfromcode (NSObjectFileImageReturnCode ret) { + switch (ret) { + case NSObjectFileImageInappropriateFile: + return "file is not a bundle"; + case NSObjectFileImageArch: + return "library is for wrong CPU type"; + case NSObjectFileImageFormat: + return "bad format"; + case NSObjectFileImageAccess: + return "cannot access file"; + case NSObjectFileImageFailure: + default: + return "unable to load library"; + } +} + + +static void ll_unloadlib (void *lib) { + NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); +} + + +static void *ll_load (lua_State *L, const char *path) { + NSObjectFileImage img; + NSObjectFileImageReturnCode ret; + /* this would be a rare case, but prevents crashing if it happens */ + if(!_dyld_present()) { + lua_pushliteral(L, "dyld not present"); + return NULL; + } + ret = NSCreateObjectFileImageFromFile(path, &img); + if (ret == NSObjectFileImageSuccess) { + NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | + NSLINKMODULE_OPTION_RETURN_ON_ERROR); + NSDestroyObjectFileImage(img); + if (mod == NULL) pusherror(L); + return mod; + } + lua_pushstring(L, errorfromcode(ret)); + return NULL; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); + if (nss == NULL) { + lua_pushfstring(L, "symbol " LUA_QS " not found", sym); + return NULL; + } + return (lua_CFunction)NSAddressOfSymbol(nss); +} + +/* }====================================================== */ + + + +#else +/* +** {====================================================== +** Fallback for other systems +** ======================================================= +*/ + +#undef LIB_FAIL +#define LIB_FAIL "absent" + + +#define DLMSG "dynamic libraries not enabled; check your Lua installation" + + +static void ll_unloadlib (void *lib) { + (void)lib; /* to avoid warnings */ +} + + +static void *ll_load (lua_State *L, const char *path) { + (void)path; /* to avoid warnings */ + lua_pushliteral(L, DLMSG); + return NULL; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + (void)lib; (void)sym; /* to avoid warnings */ + lua_pushliteral(L, DLMSG); + return NULL; +} + +/* }====================================================== */ +#endif + + + +static void **ll_register (lua_State *L, const char *path) { + void **plib; + lua_pushfstring(L, "%s%s", LIBPREFIX, path); + lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ + if (!lua_isnil(L, -1)) /* is there an entry? */ + plib = (void **)lua_touserdata(L, -1); + else { /* no entry yet; create one */ + lua_pop(L, 1); + plib = (void **)lua_newuserdata(L, sizeof(const void *)); + *plib = NULL; + luaL_getmetatable(L, "_LOADLIB"); + lua_setmetatable(L, -2); + lua_pushfstring(L, "%s%s", LIBPREFIX, path); + lua_pushvalue(L, -2); + lua_settable(L, LUA_REGISTRYINDEX); + } + return plib; +} + + +/* +** __gc tag method: calls library's `ll_unloadlib' function with the lib +** handle +*/ +static int gctm (lua_State *L) { + void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); + if (*lib) ll_unloadlib(*lib); + *lib = NULL; /* mark library as closed */ + return 0; +} + + +static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { + void **reg = ll_register(L, path); + if (*reg == NULL) *reg = ll_load(L, path); + if (*reg == NULL) + return ERRLIB; /* unable to load library */ + else { + lua_CFunction f = ll_sym(L, *reg, sym); + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); + return 0; /* return function */ + } +} + + +static int ll_loadlib (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + const char *init = luaL_checkstring(L, 2); + int stat = ll_loadfunc(L, path, init); + if (stat == 0) /* no errors? */ + return 1; /* return the loaded function */ + else { /* error; error message is on stack top */ + lua_pushnil(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return nil, error message, and where */ + } +} + + + +/* +** {====================================================== +** 'require' function +** ======================================================= +*/ + + +static int readable (const char *filename) { + FILE *f = fopen(filename, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + fclose(f); + return 1; +} + + +static const char *pushnexttemplate (lua_State *L, const char *path) { + const char *l; + while (*path == *LUA_PATHSEP) path++; /* skip separators */ + if (*path == '\0') return NULL; /* no more templates */ + l = strchr(path, *LUA_PATHSEP); /* find next separator */ + if (l == NULL) l = path + strlen(path); + lua_pushlstring(L, path, l - path); /* template */ + return l; +} + + +static const char *findfile (lua_State *L, const char *name, + const char *pname) { + const char *path; + name = luaL_gsub(L, name, ".", LUA_DIRSEP); + lua_getfield(L, LUA_ENVIRONINDEX, pname); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, LUA_QL("package.%s") " must be a string", pname); + lua_pushliteral(L, ""); /* error accumulator */ + while ((path = pushnexttemplate(L, path)) != NULL) { + const char *filename; + filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); + lua_remove(L, -2); /* remove path template */ + if (readable(filename)) /* does file exist and is readable? */ + return filename; /* return that file name */ + lua_pushfstring(L, "\n\tno file " LUA_QS, filename); + lua_remove(L, -2); /* remove file name */ + lua_concat(L, 2); /* add entry to possible error message */ + } + return NULL; /* not found */ +} + + +static void loaderror (lua_State *L, const char *filename) { + luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); +} + + +static int loader_Lua (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path"); + if (filename == NULL) return 1; /* library not found in this path */ + if (luaL_loadfile(L, filename) != 0) + loaderror(L, filename); + return 1; /* library loaded successfully */ +} + + +static const char *mkfuncname (lua_State *L, const char *modname) { + const char *funcname; + const char *mark = strchr(modname, *LUA_IGMARK); + if (mark) modname = mark + 1; + funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); + funcname = lua_pushfstring(L, POF"%s", funcname); + lua_remove(L, -2); /* remove 'gsub' result */ + return funcname; +} + + +static int loader_C (lua_State *L) { + const char *funcname; + const char *name = luaL_checkstring(L, 1); + const char *filename = findfile(L, name, "cpath"); + if (filename == NULL) return 1; /* library not found in this path */ + funcname = mkfuncname(L, name); + if (ll_loadfunc(L, filename, funcname) != 0) + loaderror(L, filename); + return 1; /* library loaded successfully */ +} + + +static int loader_Croot (lua_State *L) { + const char *funcname; + const char *filename; + const char *name = luaL_checkstring(L, 1); + const char *p = strchr(name, '.'); + int stat; + if (p == NULL) return 0; /* is root */ + lua_pushlstring(L, name, p - name); + filename = findfile(L, lua_tostring(L, -1), "cpath"); + if (filename == NULL) return 1; /* root not found */ + funcname = mkfuncname(L, name); + if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { + if (stat != ERRFUNC) loaderror(L, filename); /* real error */ + lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, + name, filename); + return 1; /* function not found */ + } + return 1; +} + + +static int loader_preload (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_ENVIRONINDEX, "preload"); + if (!lua_istable(L, -1)) + luaL_error(L, LUA_QL("package.preload") " must be a table"); + lua_getfield(L, -1, name); + if (lua_isnil(L, -1)) /* not found? */ + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); + return 1; +} + + +static const int sentinel_ = 0; +#define sentinel ((void *)&sentinel_) + + +static int ll_require (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + int i; + lua_settop(L, 1); /* _LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, 2, name); + if (lua_toboolean(L, -1)) { /* is it there? */ + if (lua_touserdata(L, -1) == sentinel) /* check loops */ + luaL_error(L, "loop or previous error loading module " LUA_QS, name); + return 1; /* package is already loaded */ + } + /* else must load it; iterate over available loaders */ + lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); + if (!lua_istable(L, -1)) + luaL_error(L, LUA_QL("package.loaders") " must be a table"); + lua_pushliteral(L, ""); /* error message accumulator */ + for (i=1; ; i++) { + lua_rawgeti(L, -2, i); /* get a loader */ + if (lua_isnil(L, -1)) + luaL_error(L, "module " LUA_QS " not found:%s", + name, lua_tostring(L, -2)); + lua_pushstring(L, name); + lua_call(L, 1, 1); /* call it */ + if (lua_isfunction(L, -1)) /* did it find module? */ + break; /* module loaded successfully */ + else if (lua_isstring(L, -1)) /* loader returned error message? */ + lua_concat(L, 2); /* accumulate it */ + else + lua_pop(L, 1); + } + lua_pushlightuserdata(L, sentinel); + lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ + lua_pushstring(L, name); /* pass name as argument to module */ + lua_call(L, 1, 1); /* run loaded module */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ + lua_getfield(L, 2, name); + if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_pushvalue(L, -1); /* extra copy to be returned */ + lua_setfield(L, 2, name); /* _LOADED[name] = true */ + } + return 1; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** 'module' function +** ======================================================= +*/ + + +static void setfenv (lua_State *L) { + lua_Debug ar; + if (lua_getstack(L, 1, &ar) == 0 || + lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ + lua_iscfunction(L, -1)) + luaL_error(L, LUA_QL("module") " not called from a Lua function"); + lua_pushvalue(L, -2); + lua_setfenv(L, -2); + lua_pop(L, 1); +} + + +static void dooptions (lua_State *L, int n) { + int i; + for (i = 2; i <= n; i++) { + lua_pushvalue(L, i); /* get option (a function) */ + lua_pushvalue(L, -2); /* module */ + lua_call(L, 1, 0); + } +} + + +static void modinit (lua_State *L, const char *modname) { + const char *dot; + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_M"); /* module._M = module */ + lua_pushstring(L, modname); + lua_setfield(L, -2, "_NAME"); + dot = strrchr(modname, '.'); /* look for last dot in module name */ + if (dot == NULL) dot = modname; + else dot++; + /* set _PACKAGE as package name (full module name minus last part) */ + lua_pushlstring(L, modname, dot - modname); + lua_setfield(L, -2, "_PACKAGE"); +} + + +static int ll_module (lua_State *L) { + const char *modname = luaL_checkstring(L, 1); + int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ + if (!lua_istable(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) + return luaL_error(L, "name conflict for module " LUA_QS, modname); + lua_pushvalue(L, -1); + lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ + } + /* check whether table already has a _NAME field */ + lua_getfield(L, -1, "_NAME"); + if (!lua_isnil(L, -1)) /* is table an initialized module? */ + lua_pop(L, 1); + else { /* no; initialize it */ + lua_pop(L, 1); + modinit(L, modname); + } + lua_pushvalue(L, -1); + setfenv(L); + dooptions(L, loaded - 1); + return 0; +} + + +static int ll_seeall (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + if (!lua_getmetatable(L, 1)) { + lua_createtable(L, 0, 1); /* create new metatable */ + lua_pushvalue(L, -1); + lua_setmetatable(L, 1); + } + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setfield(L, -2, "__index"); /* mt.__index = _G */ + return 0; +} + + +/* }====================================================== */ + + + +/* auxiliary mark (for internal use) */ +#define AUXMARK "\1" + +static void setpath (lua_State *L, const char *fieldname, const char *envname, + const char *def) { + const char *path = getenv(envname); + if (path == NULL) /* no environment variable? */ + lua_pushstring(L, def); /* use default */ + else { + /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ + path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, + LUA_PATHSEP AUXMARK LUA_PATHSEP); + luaL_gsub(L, path, AUXMARK, def); + lua_remove(L, -2); + } + setprogdir(L); + lua_setfield(L, -2, fieldname); +} + + +static const luaL_Reg pk_funcs[] = { + {"loadlib", ll_loadlib}, + {"seeall", ll_seeall}, + {NULL, NULL} +}; + + +static const luaL_Reg ll_funcs[] = { + {"module", ll_module}, + {"require", ll_require}, + {NULL, NULL} +}; + + +static const lua_CFunction loaders[] = + {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; + + +LUALIB_API int luaopen_package (lua_State *L) { + int i; + /* create new type _LOADLIB */ + luaL_newmetatable(L, "_LOADLIB"); + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); + /* create `package' table */ + luaL_register(L, LUA_LOADLIBNAME, pk_funcs); +#if defined(LUA_COMPAT_LOADLIB) + lua_getfield(L, -1, "loadlib"); + lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); +#endif + lua_pushvalue(L, -1); + lua_replace(L, LUA_ENVIRONINDEX); + /* create `loaders' table */ + lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); + /* fill it with pre-defined loaders */ + for (i=0; loaders[i] != NULL; i++) { + lua_pushcfunction(L, loaders[i]); + lua_rawseti(L, -2, i+1); + } + lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ + setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ + setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ + /* store config information */ + lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" + LUA_EXECDIR "\n" LUA_IGMARK); + lua_setfield(L, -2, "config"); + /* set field `loaded' */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); + lua_setfield(L, -2, "loaded"); + /* set field `preload' */ + lua_newtable(L); + lua_setfield(L, -2, "preload"); + lua_pushvalue(L, LUA_GLOBALSINDEX); + luaL_register(L, NULL, ll_funcs); /* open lib into global table */ + lua_pop(L, 1); + return 1; /* return 'package' table */ +} + diff --git a/source/fceultra/lua/src/lobject.c b/source/fceultra/lua/src/lobject.c new file mode 100644 index 0000000..4ff5073 --- /dev/null +++ b/source/fceultra/lua/src/lobject.c @@ -0,0 +1,214 @@ +/* +** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $ +** Some generic functions over Lua objects +** See Copyright Notice in lua.h +*/ + +#include +#include +#include +#include +#include + +#define lobject_c +#define LUA_CORE + +#include "lua.h" + +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "lvm.h" + + + +const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; + + +/* +** converts an integer to a "floating point byte", represented as +** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if +** eeeee != 0 and (xxx) otherwise. +*/ +int luaO_int2fb (unsigned int x) { + int e = 0; /* expoent */ + while (x >= 16) { + x = (x+1) >> 1; + e++; + } + if (x < 8) return x; + else return ((e+1) << 3) | (cast_int(x) - 8); +} + + +/* converts back */ +int luaO_fb2int (int x) { + int e = (x >> 3) & 31; + if (e == 0) return x; + else return ((x & 7)+8) << (e - 1); +} + + +int luaO_log2 (unsigned int x) { + static const lu_byte log_2[256] = { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + int l = -1; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; + +} + + +int luaO_rawequalObj (const TValue *t1, const TValue *t2) { + if (ttype(t1) != ttype(t2)) return 0; + else switch (ttype(t1)) { + case LUA_TNIL: + return 1; + case LUA_TNUMBER: + return luai_numeq(nvalue(t1), nvalue(t2)); + case LUA_TBOOLEAN: + return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ + case LUA_TLIGHTUSERDATA: + return pvalue(t1) == pvalue(t2); + default: + lua_assert(iscollectable(t1)); + return gcvalue(t1) == gcvalue(t2); + } +} + + +int luaO_str2d (const char *s, lua_Number *result) { + char *endptr; + *result = lua_str2number(s, &endptr); + if (endptr == s) return 0; /* conversion failed */ + if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ + *result = cast_num(strtoul(s, &endptr, 16)); + if (*endptr == '\0') return 1; /* most common case */ + while (isspace(cast(unsigned char, *endptr))) endptr++; + if (*endptr != '\0') return 0; /* invalid trailing characters? */ + return 1; +} + + + +static void pushstr (lua_State *L, const char *str) { + setsvalue2s(L, L->top, luaS_new(L, str)); + incr_top(L); +} + + +/* this function handles only `%d', `%c', %f, %p, and `%s' formats */ +const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { + int n = 1; + pushstr(L, ""); + for (;;) { + const char *e = strchr(fmt, '%'); + if (e == NULL) break; + setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); + incr_top(L); + switch (*(e+1)) { + case 's': { + const char *s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + pushstr(L, s); + break; + } + case 'c': { + char buff[2]; + buff[0] = cast(char, va_arg(argp, int)); + buff[1] = '\0'; + pushstr(L, buff); + break; + } + case 'd': { + setnvalue(L->top, cast_num(va_arg(argp, int))); + incr_top(L); + break; + } + case 'f': { + setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); + incr_top(L); + break; + } + case 'p': { + char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ + sprintf(buff, "%p", va_arg(argp, void *)); + pushstr(L, buff); + break; + } + case '%': { + pushstr(L, "%"); + break; + } + default: { + char buff[3]; + buff[0] = '%'; + buff[1] = *(e+1); + buff[2] = '\0'; + pushstr(L, buff); + break; + } + } + n += 2; + fmt = e+2; + } + pushstr(L, fmt); + luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); + L->top -= n; + return svalue(L->top - 1); +} + + +const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { + const char *msg; + va_list argp; + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + return msg; +} + + +void luaO_chunkid (char *out, const char *source, size_t bufflen) { + if (*source == '=') { + strncpy(out, source+1, bufflen); /* remove first char */ + out[bufflen-1] = '\0'; /* ensures null termination */ + } + else { /* out = "source", or "...source" */ + if (*source == '@') { + size_t l; + source++; /* skip the `@' */ + bufflen -= sizeof(" '...' "); + l = strlen(source); + strcpy(out, ""); + if (l > bufflen) { + source += (l-bufflen); /* get last part of file name */ + strcat(out, "..."); + } + strcat(out, source); + } + else { /* out = [string "string"] */ + size_t len = strcspn(source, "\n\r"); /* stop at first newline */ + bufflen -= sizeof(" [string \"...\"] "); + if (len > bufflen) len = bufflen; + strcpy(out, "[string \""); + if (source[len] != '\0') { /* must truncate? */ + strncat(out, source, len); + strcat(out, "..."); + } + else + strcat(out, source); + strcat(out, "\"]"); + } + } +} diff --git a/source/fceultra/lua/src/lobject.h b/source/fceultra/lua/src/lobject.h new file mode 100644 index 0000000..f1e447e --- /dev/null +++ b/source/fceultra/lua/src/lobject.h @@ -0,0 +1,381 @@ +/* +** $Id: lobject.h,v 2.20.1.2 2008/08/06 13:29:48 roberto Exp $ +** Type definitions for Lua objects +** See Copyright Notice in lua.h +*/ + + +#ifndef lobject_h +#define lobject_h + + +#include + + +#include "llimits.h" +#include "lua.h" + + +/* tags for values visible from Lua */ +#define LAST_TAG LUA_TTHREAD + +#define NUM_TAGS (LAST_TAG+1) + + +/* +** Extra tags for non-values +*/ +#define LUA_TPROTO (LAST_TAG+1) +#define LUA_TUPVAL (LAST_TAG+2) +#define LUA_TDEADKEY (LAST_TAG+3) + + +/* +** Union of all collectable objects +*/ +typedef union GCObject GCObject; + + +/* +** Common Header for all collectable objects (in macro form, to be +** included in other objects) +*/ +#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked + + +/* +** Common header in struct form +*/ +typedef struct GCheader { + CommonHeader; +} GCheader; + + + + +/* +** Union of all Lua values +*/ +typedef union { + GCObject *gc; + void *p; + lua_Number n; + int b; +} Value; + + +/* +** Tagged Values +*/ + +#define TValuefields Value value; int tt + +typedef struct lua_TValue { + TValuefields; +} TValue; + + +/* Macros to test type */ +#define ttisnil(o) (ttype(o) == LUA_TNIL) +#define ttisnumber(o) (ttype(o) == LUA_TNUMBER) +#define ttisstring(o) (ttype(o) == LUA_TSTRING) +#define ttistable(o) (ttype(o) == LUA_TTABLE) +#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION) +#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) +#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) +#define ttisthread(o) (ttype(o) == LUA_TTHREAD) +#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) + +/* Macros to access values */ +#define ttype(o) ((o)->tt) +#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc) +#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p) +#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n) +#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) +#define tsvalue(o) (&rawtsvalue(o)->tsv) +#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) +#define uvalue(o) (&rawuvalue(o)->uv) +#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) +#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) +#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) +#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th) + +#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) + +/* +** for internal debug only +*/ +#define checkconsistency(obj) \ + lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) + +#define checkliveness(g,obj) \ + lua_assert(!iscollectable(obj) || \ + ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) + + +/* Macros to set values */ +#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) + +#define setnvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } + +#define setpvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } + +#define setbvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } + +#define setsvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ + checkliveness(G(L),i_o); } + +#define setuvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ + checkliveness(G(L),i_o); } + +#define setthvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ + checkliveness(G(L),i_o); } + +#define setclvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ + checkliveness(G(L),i_o); } + +#define sethvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ + checkliveness(G(L),i_o); } + +#define setptvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ + checkliveness(G(L),i_o); } + + + + +#define setobj(L,obj1,obj2) \ + { const TValue *o2=(obj2); TValue *o1=(obj1); \ + o1->value = o2->value; o1->tt=o2->tt; \ + checkliveness(G(L),o1); } + + +/* +** different types of sets, according to destination +*/ + +/* from stack to (same) stack */ +#define setobjs2s setobj +/* to stack (not from same stack) */ +#define setobj2s setobj +#define setsvalue2s setsvalue +#define sethvalue2s sethvalue +#define setptvalue2s setptvalue +/* from table to same table */ +#define setobjt2t setobj +/* to table */ +#define setobj2t setobj +/* to new object */ +#define setobj2n setobj +#define setsvalue2n setsvalue + +#define setttype(obj, tt) (ttype(obj) = (tt)) + + +#define iscollectable(o) (ttype(o) >= LUA_TSTRING) + + + +typedef TValue *StkId; /* index to stack elements */ + + +/* +** String headers for string table +*/ +typedef union TString { + L_Umaxalign dummy; /* ensures maximum alignment for strings */ + struct { + CommonHeader; + lu_byte reserved; + unsigned int hash; + size_t len; + } tsv; +} TString; + + +#define getstr(ts) cast(const char *, (ts) + 1) +#define svalue(o) getstr(rawtsvalue(o)) + + + +typedef union Udata { + L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ + struct { + CommonHeader; + struct Table *metatable; + struct Table *env; + size_t len; + } uv; +} Udata; + + + + +/* +** Function Prototypes +*/ +typedef struct Proto { + CommonHeader; + TValue *k; /* constants used by the function */ + Instruction *code; + struct Proto **p; /* functions defined inside the function */ + int *lineinfo; /* map from opcodes to source lines */ + struct LocVar *locvars; /* information about local variables */ + TString **upvalues; /* upvalue names */ + TString *source; + int sizeupvalues; + int sizek; /* size of `k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of `p' */ + int sizelocvars; + int linedefined; + int lastlinedefined; + GCObject *gclist; + lu_byte nups; /* number of upvalues */ + lu_byte numparams; + lu_byte is_vararg; + lu_byte maxstacksize; +} Proto; + + +/* masks for new-style vararg */ +#define VARARG_HASARG 1 +#define VARARG_ISVARARG 2 +#define VARARG_NEEDSARG 4 + + +typedef struct LocVar { + TString *varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ +} LocVar; + + + +/* +** Upvalues +*/ + +typedef struct UpVal { + CommonHeader; + TValue *v; /* points to stack or to its own value */ + union { + TValue value; /* the value (when closed) */ + struct { /* double linked list (when open) */ + struct UpVal *prev; + struct UpVal *next; + } l; + } u; +} UpVal; + + +/* +** Closures +*/ + +#define ClosureHeader \ + CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \ + struct Table *env + +typedef struct CClosure { + ClosureHeader; + lua_CFunction f; + TValue upvalue[1]; +} CClosure; + + +typedef struct LClosure { + ClosureHeader; + struct Proto *p; + UpVal *upvals[1]; +} LClosure; + + +typedef union Closure { + CClosure c; + LClosure l; +} Closure; + + +#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC) +#define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC) + + +/* +** Tables +*/ + +typedef union TKey { + struct { + TValuefields; + struct Node *next; /* for chaining */ + } nk; + TValue tvk; +} TKey; + + +typedef struct Node { + TValue i_val; + TKey i_key; +} Node; + + +typedef struct Table { + CommonHeader; + lu_byte flags; /* 1<

lsizenode)) + + +#define luaO_nilobject (&luaO_nilobject_) + +LUAI_DATA const TValue luaO_nilobject_; + +#define ceillog2(x) (luaO_log2((x)-1) + 1) + +LUAI_FUNC int luaO_log2 (unsigned int x); +LUAI_FUNC int luaO_int2fb (unsigned int x); +LUAI_FUNC int luaO_fb2int (int x); +LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2); +LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result); +LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, + va_list argp); +LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); + + +#endif + diff --git a/source/fceultra/lua/src/lopcodes.c b/source/fceultra/lua/src/lopcodes.c new file mode 100644 index 0000000..4cc7452 --- /dev/null +++ b/source/fceultra/lua/src/lopcodes.c @@ -0,0 +1,102 @@ +/* +** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ +** See Copyright Notice in lua.h +*/ + + +#define lopcodes_c +#define LUA_CORE + + +#include "lopcodes.h" + + +/* ORDER OP */ + +const char *const luaP_opnames[NUM_OPCODES+1] = { + "MOVE", + "LOADK", + "LOADBOOL", + "LOADNIL", + "GETUPVAL", + "GETGLOBAL", + "GETTABLE", + "SETGLOBAL", + "SETUPVAL", + "SETTABLE", + "NEWTABLE", + "SELF", + "ADD", + "SUB", + "MUL", + "DIV", + "MOD", + "POW", + "UNM", + "NOT", + "LEN", + "CONCAT", + "JMP", + "EQ", + "LT", + "LE", + "TEST", + "TESTSET", + "CALL", + "TAILCALL", + "RETURN", + "FORLOOP", + "FORPREP", + "TFORLOOP", + "SETLIST", + "CLOSE", + "CLOSURE", + "VARARG", + NULL +}; + + +#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) + +const lu_byte luaP_opmodes[NUM_OPCODES] = { +/* T A B C mode opcode */ + opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETGLOBAL */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ + ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ + ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ + ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ + ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */ + ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ + ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ + ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ +}; + diff --git a/source/fceultra/lua/src/lopcodes.h b/source/fceultra/lua/src/lopcodes.h new file mode 100644 index 0000000..41224d6 --- /dev/null +++ b/source/fceultra/lua/src/lopcodes.h @@ -0,0 +1,268 @@ +/* +** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 roberto Exp $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lopcodes_h +#define lopcodes_h + +#include "llimits.h" + + +/*=========================================================================== + We assume that instructions are unsigned numbers. + All instructions have an opcode in the first 6 bits. + Instructions can have the following fields: + `A' : 8 bits + `B' : 9 bits + `C' : 9 bits + `Bx' : 18 bits (`B' and `C' together) + `sBx' : signed Bx + + A signed argument is represented in excess K; that is, the number + value is the unsigned value minus K. K is exactly the maximum value + for that argument (so that -max is represented by 0, and +max is + represented by 2*max), which is half the maximum for the corresponding + unsigned argument. +===========================================================================*/ + + +enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ + + +/* +** size and position of opcode arguments. +*/ +#define SIZE_C 9 +#define SIZE_B 9 +#define SIZE_Bx (SIZE_C + SIZE_B) +#define SIZE_A 8 + +#define SIZE_OP 6 + +#define POS_OP 0 +#define POS_A (POS_OP + SIZE_OP) +#define POS_C (POS_A + SIZE_A) +#define POS_B (POS_C + SIZE_C) +#define POS_Bx POS_C + + +/* +** limits for opcode arguments. +** we use (signed) int to manipulate most arguments, +** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) +*/ +#if SIZE_Bx < LUAI_BITSINT-1 +#define MAXARG_Bx ((1<>1) /* `sBx' is signed */ +#else +#define MAXARG_Bx MAX_INT +#define MAXARG_sBx MAX_INT +#endif + + +#define MAXARG_A ((1<>POS_OP) & MASK1(SIZE_OP,0))) +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ + ((cast(Instruction, o)<>POS_A) & MASK1(SIZE_A,0))) +#define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ + ((cast(Instruction, u)<>POS_B) & MASK1(SIZE_B,0))) +#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ + ((cast(Instruction, b)<>POS_C) & MASK1(SIZE_C,0))) +#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \ + ((cast(Instruction, b)<>POS_Bx) & MASK1(SIZE_Bx,0))) +#define SETARG_Bx(i,b) ((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \ + ((cast(Instruction, b)< C) then pc++ */ +OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ + +OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ + +OP_FORLOOP,/* A sBx R(A)+=R(A+2); + if R(A) =) R(A)*/ +OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ + +OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ +} OpCode; + + +#define NUM_OPCODES (cast(int, OP_VARARG) + 1) + + + +/*=========================================================================== + Notes: + (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, + and can be 0: OP_CALL then sets `top' to last_result+1, so + next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. + + (*) In OP_VARARG, if (B == 0) then use actual number of varargs and + set top (like in OP_CALL with C == 0). + + (*) In OP_RETURN, if (B == 0) then return up to `top' + + (*) In OP_SETLIST, if (B == 0) then B = `top'; + if (C == 0) then next `instruction' is real C + + (*) For comparisons, A specifies what condition the test should accept + (true or false). + + (*) All `skips' (pc++) assume that next instruction is a jump +===========================================================================*/ + + +/* +** masks for instruction properties. The format is: +** bits 0-1: op mode +** bits 2-3: C arg mode +** bits 4-5: B arg mode +** bit 6: instruction set register A +** bit 7: operator is a test +*/ + +enum OpArgMask { + OpArgN, /* argument is not used */ + OpArgU, /* argument is used */ + OpArgR, /* argument is a register or a jump offset */ + OpArgK /* argument is a constant or register/constant */ +}; + +LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; + +#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) +#define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) +#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) +#define testAMode(m) (luaP_opmodes[m] & (1 << 6)) +#define testTMode(m) (luaP_opmodes[m] & (1 << 7)) + + +LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ + + +/* number of list items to accumulate before a SETLIST instruction */ +#define LFIELDS_PER_FLUSH 50 + + +#endif diff --git a/source/fceultra/lua/src/loslib.c b/source/fceultra/lua/src/loslib.c new file mode 100644 index 0000000..da06a57 --- /dev/null +++ b/source/fceultra/lua/src/loslib.c @@ -0,0 +1,243 @@ +/* +** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include +#include + +#define loslib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int os_pushresult (lua_State *L, int i, const char *filename) { + int en = errno; /* calls to Lua API may change this value */ + if (i) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + lua_pushfstring(L, "%s: %s", filename, strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +static int os_execute (lua_State *L) { + lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); + return 1; +} + + +static int os_remove (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + return os_pushresult(L, remove(filename) == 0, filename); +} + + +static int os_rename (lua_State *L) { + const char *fromname = luaL_checkstring(L, 1); + const char *toname = luaL_checkstring(L, 2); + return os_pushresult(L, rename(fromname, toname) == 0, fromname); +} + + +static int os_tmpname (lua_State *L) { + char buff[LUA_TMPNAMBUFSIZE]; + int err; + lua_tmpnam(buff, err); + if (err) + return luaL_error(L, "unable to generate a unique filename"); + lua_pushstring(L, buff); + return 1; +} + + +static int os_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ + return 1; +} + + +static int os_clock (lua_State *L) { + lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); + return 1; +} + + +/* +** {====================================================== +** Time/Date operations +** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, +** wday=%w+1, yday=%j, isdst=? } +** ======================================================= +*/ + +static void setfield (lua_State *L, const char *key, int value) { + lua_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +static void setboolfield (lua_State *L, const char *key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ + lua_pushboolean(L, value); + lua_setfield(L, -2, key); +} + +static int getboolfield (lua_State *L, const char *key) { + int res; + lua_getfield(L, -1, key); + res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +static int getfield (lua_State *L, const char *key, int d) { + int res; + lua_getfield(L, -1, key); + if (lua_isnumber(L, -1)) + res = (int)lua_tointeger(L, -1); + else { + if (d < 0) + return luaL_error(L, "field " LUA_QS " missing in date table", key); + res = d; + } + lua_pop(L, 1); + return res; +} + + +static int os_date (lua_State *L) { + const char *s = luaL_optstring(L, 1, "%c"); + time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); + struct tm *stm; + if (*s == '!') { /* UTC? */ + stm = gmtime(&t); + s++; /* skip `!' */ + } + else + stm = localtime(&t); + if (stm == NULL) /* invalid date? */ + lua_pushnil(L); + else if (strcmp(s, "*t") == 0) { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setfield(L, "sec", stm->tm_sec); + setfield(L, "min", stm->tm_min); + setfield(L, "hour", stm->tm_hour); + setfield(L, "day", stm->tm_mday); + setfield(L, "month", stm->tm_mon+1); + setfield(L, "year", stm->tm_year+1900); + setfield(L, "wday", stm->tm_wday+1); + setfield(L, "yday", stm->tm_yday+1); + setboolfield(L, "isdst", stm->tm_isdst); + } + else { + char cc[3]; + luaL_Buffer b; + cc[0] = '%'; cc[2] = '\0'; + luaL_buffinit(L, &b); + for (; *s; s++) { + if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ + luaL_addchar(&b, *s); + else { + size_t reslen; + char buff[200]; /* should be big enough for any conversion result */ + cc[1] = *(++s); + reslen = strftime(buff, sizeof(buff), cc, stm); + luaL_addlstring(&b, buff, reslen); + } + } + luaL_pushresult(&b); + } + return 1; +} + + +static int os_time (lua_State *L) { + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ + else { + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_sec = getfield(L, "sec", 0); + ts.tm_min = getfield(L, "min", 0); + ts.tm_hour = getfield(L, "hour", 12); + ts.tm_mday = getfield(L, "day", -1); + ts.tm_mon = getfield(L, "month", -1) - 1; + ts.tm_year = getfield(L, "year", -1) - 1900; + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + } + if (t == (time_t)(-1)) + lua_pushnil(L); + else + lua_pushnumber(L, (lua_Number)t); + return 1; +} + + +static int os_difftime (lua_State *L) { + lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), + (time_t)(luaL_optnumber(L, 2, 0)))); + return 1; +} + +/* }====================================================== */ + + +static int os_setlocale (lua_State *L) { + static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static const char *const catnames[] = {"all", "collate", "ctype", "monetary", + "numeric", "time", NULL}; + const char *l = luaL_optstring(L, 1, NULL); + int op = luaL_checkoption(L, 2, "all", catnames); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; +} + + +static int os_exit (lua_State *L) { + exit(luaL_optint(L, 1, EXIT_SUCCESS)); +} + +static const luaL_Reg syslib[] = { + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"execute", os_execute}, + {"exit", os_exit}, + {"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, + {"setlocale", os_setlocale}, + {"time", os_time}, + {"tmpname", os_tmpname}, + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUALIB_API int luaopen_os (lua_State *L) { + luaL_register(L, LUA_OSLIBNAME, syslib); + return 1; +} + diff --git a/source/fceultra/lua/src/lparser.c b/source/fceultra/lua/src/lparser.c new file mode 100644 index 0000000..1e2a9a8 --- /dev/null +++ b/source/fceultra/lua/src/lparser.c @@ -0,0 +1,1339 @@ +/* +** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + + +#include + +#define lparser_c +#define LUA_CORE + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" + + + +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) + +#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) + +#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) + + +/* +** nodes for block list (list of active blocks) +*/ +typedef struct BlockCnt { + struct BlockCnt *previous; /* chain */ + int breaklist; /* list of jumps out of this loop */ + lu_byte nactvar; /* # active locals outside the breakable structure */ + lu_byte upval; /* true if some variable in the block is an upvalue */ + lu_byte isbreakable; /* true if `block' is a loop */ +} BlockCnt; + + + +/* +** prototypes for recursive non-terminal functions +*/ +static void chunk (LexState *ls); +static void expr (LexState *ls, expdesc *v); + + +static void anchor_token (LexState *ls) { + if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { + TString *ts = ls->t.seminfo.ts; + luaX_newstring(ls, getstr(ts), ts->tsv.len); + } +} + + +static void error_expected (LexState *ls, int token) { + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token))); +} + + +static void errorlimit (FuncState *fs, int limit, const char *what) { + const char *msg = (fs->f->linedefined == 0) ? + luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : + luaO_pushfstring(fs->L, "function at line %d has more than %d %s", + fs->f->linedefined, limit, what); + luaX_lexerror(fs->ls, msg, 0); +} + + +static int testnext (LexState *ls, int c) { + if (ls->t.token == c) { + luaX_next(ls); + return 1; + } + else return 0; +} + + +static void check (LexState *ls, int c) { + if (ls->t.token != c) + error_expected(ls, c); +} + +static void checknext (LexState *ls, int c) { + check(ls, c); + luaX_next(ls); +} + + +#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } + + + +static void check_match (LexState *ls, int what, int who, int where) { + if (!testnext(ls, what)) { + if (where == ls->linenumber) + error_expected(ls, what); + else { + luaX_syntaxerror(ls, luaO_pushfstring(ls->L, + LUA_QS " expected (to close " LUA_QS " at line %d)", + luaX_token2str(ls, what), luaX_token2str(ls, who), where)); + } + } +} + + +static TString *str_checkname (LexState *ls) { + TString *ts; + check(ls, TK_NAME); + ts = ls->t.seminfo.ts; + luaX_next(ls); + return ts; +} + + +static void init_exp (expdesc *e, expkind k, int i) { + e->f = e->t = NO_JUMP; + e->k = k; + e->u.s.info = i; +} + + +static void codestring (LexState *ls, expdesc *e, TString *s) { + init_exp(e, VK, luaK_stringK(ls->fs, s)); +} + + +static void checkname(LexState *ls, expdesc *e) { + codestring(ls, e, str_checkname(ls)); +} + + +static int registerlocalvar (LexState *ls, TString *varname) { + FuncState *fs = ls->fs; + Proto *f = fs->f; + int oldsize = f->sizelocvars; + luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, + LocVar, SHRT_MAX, "too many local variables"); + while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; + f->locvars[fs->nlocvars].varname = varname; + luaC_objbarrier(ls->L, f, varname); + return fs->nlocvars++; +} + + +#define new_localvarliteral(ls,v,n) \ + new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) + + +static void new_localvar (LexState *ls, TString *name, int n) { + FuncState *fs = ls->fs; + luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables"); + fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); +} + + +static void adjustlocalvars (LexState *ls, int nvars) { + FuncState *fs = ls->fs; + fs->nactvar = cast_byte(fs->nactvar + nvars); + for (; nvars; nvars--) { + getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; + } +} + + +static void removevars (LexState *ls, int tolevel) { + FuncState *fs = ls->fs; + while (fs->nactvar > tolevel) + getlocvar(fs, --fs->nactvar).endpc = fs->pc; +} + + +static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { + int i; + Proto *f = fs->f; + int oldsize = f->sizeupvalues; + for (i=0; inups; i++) { + if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) { + lua_assert(f->upvalues[i] == name); + return i; + } + } + /* new one */ + luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues"); + luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, + TString *, MAX_INT, ""); + while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; + f->upvalues[f->nups] = name; + luaC_objbarrier(fs->L, f, name); + lua_assert(v->k == VLOCAL || v->k == VUPVAL); + fs->upvalues[f->nups].k = cast_byte(v->k); + fs->upvalues[f->nups].info = cast_byte(v->u.s.info); + return f->nups++; +} + + +static int searchvar (FuncState *fs, TString *n) { + int i; + for (i=fs->nactvar-1; i >= 0; i--) { + if (n == getlocvar(fs, i).varname) + return i; + } + return -1; /* not found */ +} + + +static void markupval (FuncState *fs, int level) { + BlockCnt *bl = fs->bl; + while (bl && bl->nactvar > level) bl = bl->previous; + if (bl) bl->upval = 1; +} + + +static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { + if (fs == NULL) { /* no more levels? */ + init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ + return VGLOBAL; + } + else { + int v = searchvar(fs, n); /* look up at current level */ + if (v >= 0) { + init_exp(var, VLOCAL, v); + if (!base) + markupval(fs, v); /* local will be used as an upval */ + return VLOCAL; + } + else { /* not found at current level; try upper one */ + if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) + return VGLOBAL; + var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ + var->k = VUPVAL; /* upvalue in this level */ + return VUPVAL; + } + } +} + + +static void singlevar (LexState *ls, expdesc *var) { + TString *varname = str_checkname(ls); + FuncState *fs = ls->fs; + if (singlevaraux(fs, varname, var, 1) == VGLOBAL) + var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ +} + + +static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { + FuncState *fs = ls->fs; + int extra = nvars - nexps; + if (hasmultret(e->k)) { + extra++; /* includes call itself */ + if (extra < 0) extra = 0; + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + if (extra > 1) luaK_reserveregs(fs, extra-1); + } + else { + if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ + if (extra > 0) { + int reg = fs->freereg; + luaK_reserveregs(fs, extra); + luaK_nil(fs, reg, extra); + } + } +} + + +static void enterlevel (LexState *ls) { + if (++ls->L->nCcalls > LUAI_MAXCCALLS) + luaX_lexerror(ls, "chunk has too many syntax levels", 0); +} + + +#define leavelevel(ls) ((ls)->L->nCcalls--) + + +static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { + bl->breaklist = NO_JUMP; + bl->isbreakable = isbreakable; + bl->nactvar = fs->nactvar; + bl->upval = 0; + bl->previous = fs->bl; + fs->bl = bl; + lua_assert(fs->freereg == fs->nactvar); +} + + +static void leaveblock (FuncState *fs) { + BlockCnt *bl = fs->bl; + fs->bl = bl->previous; + removevars(fs->ls, bl->nactvar); + if (bl->upval) + luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); + /* a block either controls scope or breaks (never both) */ + lua_assert(!bl->isbreakable || !bl->upval); + lua_assert(bl->nactvar == fs->nactvar); + fs->freereg = fs->nactvar; /* free registers */ + luaK_patchtohere(fs, bl->breaklist); +} + + +static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { + FuncState *fs = ls->fs; + Proto *f = fs->f; + int oldsize = f->sizep; + int i; + luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, + MAXARG_Bx, "constant table overflow"); + while (oldsize < f->sizep) f->p[oldsize++] = NULL; + f->p[fs->np++] = func->f; + luaC_objbarrier(ls->L, f, func->f); + init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); + for (i=0; if->nups; i++) { + OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; + luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); + } +} + + +static void open_func (LexState *ls, FuncState *fs) { + lua_State *L = ls->L; + Proto *f = luaF_newproto(L); + fs->f = f; + fs->prev = ls->fs; /* linked list of funcstates */ + fs->ls = ls; + fs->L = L; + ls->fs = fs; + fs->pc = 0; + fs->lasttarget = -1; + fs->jpc = NO_JUMP; + fs->freereg = 0; + fs->nk = 0; + fs->np = 0; + fs->nlocvars = 0; + fs->nactvar = 0; + fs->bl = NULL; + f->source = ls->source; + f->maxstacksize = 2; /* registers 0/1 are always valid */ + fs->h = luaH_new(L, 0, 0); + /* anchor table of constants and prototype (to avoid being collected) */ + sethvalue2s(L, L->top, fs->h); + incr_top(L); + setptvalue2s(L, L->top, f); + incr_top(L); +} + + +static void close_func (LexState *ls) { + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; + removevars(ls, 0); + luaK_ret(fs, 0, 0); /* final return */ + luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); + f->sizecode = fs->pc; + luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); + f->sizelineinfo = fs->pc; + luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); + f->sizek = fs->nk; + luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); + f->sizep = fs->np; + luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); + f->sizelocvars = fs->nlocvars; + luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *); + f->sizeupvalues = f->nups; + lua_assert(luaG_checkcode(f)); + lua_assert(fs->bl == NULL); + ls->fs = fs->prev; + L->top -= 2; /* remove table and prototype from the stack */ + /* last token read was anchored in defunct function; must reanchor it */ + if (fs) anchor_token(ls); +} + + +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { + struct LexState lexstate; + struct FuncState funcstate; + lexstate.buff = buff; + luaX_setinput(L, &lexstate, z, luaS_new(L, name)); + open_func(&lexstate, &funcstate); + funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ + luaX_next(&lexstate); /* read first token */ + chunk(&lexstate); + check(&lexstate, TK_EOS); + close_func(&lexstate); + lua_assert(funcstate.prev == NULL); + lua_assert(funcstate.f->nups == 0); + lua_assert(lexstate.fs == NULL); + return funcstate.f; +} + + + +/*============================================================*/ +/* GRAMMAR RULES */ +/*============================================================*/ + + +static void field (LexState *ls, expdesc *v) { + /* field -> ['.' | ':'] NAME */ + FuncState *fs = ls->fs; + expdesc key; + luaK_exp2anyreg(fs, v); + luaX_next(ls); /* skip the dot or colon */ + checkname(ls, &key); + luaK_indexed(fs, v, &key); +} + + +static void yindex (LexState *ls, expdesc *v) { + /* index -> '[' expr ']' */ + luaX_next(ls); /* skip the '[' */ + expr(ls, v); + luaK_exp2val(ls->fs, v); + checknext(ls, ']'); +} + + +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ + + +struct ConsControl { + expdesc v; /* last list item read */ + expdesc *t; /* table descriptor */ + int nh; /* total number of `record' elements */ + int na; /* total number of array elements */ + int tostore; /* number of array elements pending to be stored */ +}; + + +static void recfield (LexState *ls, struct ConsControl *cc) { + /* recfield -> (NAME | `['exp1`]') = exp1 */ + FuncState *fs = ls->fs; + int reg = ls->fs->freereg; + expdesc key, val; + int rkkey; + if (ls->t.token == TK_NAME) { + luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + checkname(ls, &key); + } + else /* ls->t.token == '[' */ + yindex(ls, &key); + cc->nh++; + checknext(ls, '='); + rkkey = luaK_exp2RK(fs, &key); + expr(ls, &val); + luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val)); + fs->freereg = reg; /* free registers */ +} + + +static void closelistfield (FuncState *fs, struct ConsControl *cc) { + if (cc->v.k == VVOID) return; /* there is no list item */ + luaK_exp2nextreg(fs, &cc->v); + cc->v.k = VVOID; + if (cc->tostore == LFIELDS_PER_FLUSH) { + luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); /* flush */ + cc->tostore = 0; /* no more items pending */ + } +} + + +static void lastlistfield (FuncState *fs, struct ConsControl *cc) { + if (cc->tostore == 0) return; + if (hasmultret(cc->v.k)) { + luaK_setmultret(fs, &cc->v); + luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET); + cc->na--; /* do not count last expression (unknown number of elements) */ + } + else { + if (cc->v.k != VVOID) + luaK_exp2nextreg(fs, &cc->v); + luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); + } +} + + +static void listfield (LexState *ls, struct ConsControl *cc) { + expr(ls, &cc->v); + luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); + cc->na++; + cc->tostore++; +} + + +static void constructor (LexState *ls, expdesc *t) { + /* constructor -> ?? */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); + struct ConsControl cc; + cc.na = cc.nh = cc.tostore = 0; + cc.t = t; + init_exp(t, VRELOCABLE, pc); + init_exp(&cc.v, VVOID, 0); /* no value (yet) */ + luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ + checknext(ls, '{'); + do { + lua_assert(cc.v.k == VVOID || cc.tostore > 0); + if (ls->t.token == '}') break; + closelistfield(fs, &cc); + switch(ls->t.token) { + case TK_NAME: { /* may be listfields or recfields */ + luaX_lookahead(ls); + if (ls->lookahead.token != '=') /* expression? */ + listfield(ls, &cc); + else + recfield(ls, &cc); + break; + } + case '[': { /* constructor_item -> recfield */ + recfield(ls, &cc); + break; + } + default: { /* constructor_part -> listfield */ + listfield(ls, &cc); + break; + } + } + } while (testnext(ls, ',') || testnext(ls, ';')); + check_match(ls, '}', '{', line); + lastlistfield(fs, &cc); + SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ + SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ +} + +/* }====================================================================== */ + + + +static void parlist (LexState *ls) { + /* parlist -> [ param { `,' param } ] */ + FuncState *fs = ls->fs; + Proto *f = fs->f; + int nparams = 0; + f->is_vararg = 0; + if (ls->t.token != ')') { /* is `parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_NAME: { /* param -> NAME */ + new_localvar(ls, str_checkname(ls), nparams++); + break; + } + case TK_DOTS: { /* param -> `...' */ + luaX_next(ls); +#if defined(LUA_COMPAT_VARARG) + /* use `arg' as default name */ + new_localvarliteral(ls, "arg", nparams++); + f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG; +#endif + f->is_vararg |= VARARG_ISVARARG; + break; + } + default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); + } + } while (!f->is_vararg && testnext(ls, ',')); + } + adjustlocalvars(ls, nparams); + f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ +} + + +static void body (LexState *ls, expdesc *e, int needself, int line) { + /* body -> `(' parlist `)' chunk END */ + FuncState new_fs; + open_func(ls, &new_fs); + new_fs.f->linedefined = line; + checknext(ls, '('); + if (needself) { + new_localvarliteral(ls, "self", 0); + adjustlocalvars(ls, 1); + } + parlist(ls); + checknext(ls, ')'); + chunk(ls); + new_fs.f->lastlinedefined = ls->linenumber; + check_match(ls, TK_END, TK_FUNCTION, line); + close_func(ls); + pushclosure(ls, &new_fs, e); +} + + +static int explist1 (LexState *ls, expdesc *v) { + /* explist1 -> expr { `,' expr } */ + int n = 1; /* at least one expression */ + expr(ls, v); + while (testnext(ls, ',')) { + luaK_exp2nextreg(ls->fs, v); + expr(ls, v); + n++; + } + return n; +} + + +static void funcargs (LexState *ls, expdesc *f) { + FuncState *fs = ls->fs; + expdesc args; + int base, nparams; + int line = ls->linenumber; + switch (ls->t.token) { + case '(': { /* funcargs -> `(' [ explist1 ] `)' */ + if (line != ls->lastline) + luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); + luaX_next(ls); + if (ls->t.token == ')') /* arg list is empty? */ + args.k = VVOID; + else { + explist1(ls, &args); + luaK_setmultret(fs, &args); + } + check_match(ls, ')', '(', line); + break; + } + case '{': { /* funcargs -> constructor */ + constructor(ls, &args); + break; + } + case TK_STRING: { /* funcargs -> STRING */ + codestring(ls, &args, ls->t.seminfo.ts); + luaX_next(ls); /* must use `seminfo' before `next' */ + break; + } + default: { + luaX_syntaxerror(ls, "function arguments expected"); + return; + } + } + lua_assert(f->k == VNONRELOC); + base = f->u.s.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = LUA_MULTRET; /* open call */ + else { + if (args.k != VVOID) + luaK_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); + } + init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); + luaK_fixline(fs, line); + fs->freereg = base+1; /* call remove function and arguments and leaves + (unless changed) one result */ +} + + + + +/* +** {====================================================================== +** Expression parsing +** ======================================================================= +*/ + + +static void prefixexp (LexState *ls, expdesc *v) { + /* prefixexp -> NAME | '(' expr ')' */ + switch (ls->t.token) { + case '(': { + int line = ls->linenumber; + luaX_next(ls); + expr(ls, v); + check_match(ls, ')', '(', line); + luaK_dischargevars(ls->fs, v); + return; + } + case TK_NAME: { + singlevar(ls, v); + return; + } + default: { + luaX_syntaxerror(ls, "unexpected symbol"); + return; + } + } +} + + +static void primaryexp (LexState *ls, expdesc *v) { + /* primaryexp -> + prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ + FuncState *fs = ls->fs; + prefixexp(ls, v); + for (;;) { + switch (ls->t.token) { + case '.': { /* field */ + field(ls, v); + break; + } + case '[': { /* `[' exp1 `]' */ + expdesc key; + luaK_exp2anyreg(fs, v); + yindex(ls, &key); + luaK_indexed(fs, v, &key); + break; + } + case ':': { /* `:' NAME funcargs */ + expdesc key; + luaX_next(ls); + checkname(ls, &key); + luaK_self(fs, v, &key); + funcargs(ls, v); + break; + } + case '(': case TK_STRING: case '{': { /* funcargs */ + luaK_exp2nextreg(fs, v); + funcargs(ls, v); + break; + } + default: return; + } + } +} + + +static void simpleexp (LexState *ls, expdesc *v) { + /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | + constructor | FUNCTION body | primaryexp */ + switch (ls->t.token) { + case TK_NUMBER: { + init_exp(v, VKNUM, 0); + v->u.nval = ls->t.seminfo.r; + break; + } + case TK_STRING: { + codestring(ls, v, ls->t.seminfo.ts); + break; + } + case TK_NIL: { + init_exp(v, VNIL, 0); + break; + } + case TK_TRUE: { + init_exp(v, VTRUE, 0); + break; + } + case TK_FALSE: { + init_exp(v, VFALSE, 0); + break; + } + case TK_DOTS: { /* vararg */ + FuncState *fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use " LUA_QL("...") " outside a vararg function"); + fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); + break; + } + case '{': { /* constructor */ + constructor(ls, v); + return; + } + case TK_FUNCTION: { + luaX_next(ls); + body(ls, v, 0, ls->linenumber); + return; + } + default: { + primaryexp(ls, v); + return; + } + } + luaX_next(ls); +} + + +static UnOpr getunopr (int op) { + switch (op) { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + case '#': return OPR_LEN; + default: return OPR_NOUNOPR; + } +} + + +static BinOpr getbinopr (int op) { + switch (op) { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MUL; + case '/': return OPR_DIV; + case '%': return OPR_MOD; + case '^': return OPR_POW; + case TK_CONCAT: return OPR_CONCAT; + case TK_NE: return OPR_NE; + case TK_EQ: return OPR_EQ; + case '<': return OPR_LT; + case TK_LE: return OPR_LE; + case '>': return OPR_GT; + case TK_GE: return OPR_GE; + case TK_AND: return OPR_AND; + case TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; + } +} + + +static const struct { + lu_byte left; /* left priority for each binary operator */ + lu_byte right; /* right priority */ +} priority[] = { /* ORDER OPR */ + {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ + {10, 9}, {5, 4}, /* power and concat (right associative) */ + {3, 3}, {3, 3}, /* equality and inequality */ + {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ + {2, 2}, {1, 1} /* logical (and/or) */ +}; + +#define UNARY_PRIORITY 8 /* priority for unary operators */ + + +/* +** subexpr -> (simpleexp | unop subexpr) { binop subexpr } +** where `binop' is any binary operator with a priority higher than `limit' +*/ +static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { + BinOpr op; + UnOpr uop; + enterlevel(ls); + uop = getunopr(ls->t.token); + if (uop != OPR_NOUNOPR) { + luaX_next(ls); + subexpr(ls, v, UNARY_PRIORITY); + luaK_prefix(ls->fs, uop, v); + } + else simpleexp(ls, v); + /* expand while operators have priorities higher than `limit' */ + op = getbinopr(ls->t.token); + while (op != OPR_NOBINOPR && priority[op].left > limit) { + expdesc v2; + BinOpr nextop; + luaX_next(ls); + luaK_infix(ls->fs, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, &v2, priority[op].right); + luaK_posfix(ls->fs, op, v, &v2); + op = nextop; + } + leavelevel(ls); + return op; /* return first untreated operator */ +} + + +static void expr (LexState *ls, expdesc *v) { + subexpr(ls, v, 0); +} + +/* }==================================================================== */ + + + +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ + + +static int block_follow (int token) { + switch (token) { + case TK_ELSE: case TK_ELSEIF: case TK_END: + case TK_UNTIL: case TK_EOS: + return 1; + default: return 0; + } +} + + +static void block (LexState *ls) { + /* block -> chunk */ + FuncState *fs = ls->fs; + BlockCnt bl; + enterblock(fs, &bl, 0); + chunk(ls); + lua_assert(bl.breaklist == NO_JUMP); + leaveblock(fs); +} + + +/* +** structure to chain all variables in the left-hand side of an +** assignment +*/ +struct LHS_assign { + struct LHS_assign *prev; + expdesc v; /* variable (global, local, upvalue, or indexed) */ +}; + + +/* +** check whether, in an assignment to a local variable, the local variable +** is needed in a previous assignment (to a table). If so, save original +** local value in a safe place and use this safe copy in the previous +** assignment. +*/ +static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { + FuncState *fs = ls->fs; + int extra = fs->freereg; /* eventual position to save local variable */ + int conflict = 0; + for (; lh; lh = lh->prev) { + if (lh->v.k == VINDEXED) { + if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ + conflict = 1; + lh->v.u.s.info = extra; /* previous assignment will use safe copy */ + } + if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */ + conflict = 1; + lh->v.u.s.aux = extra; /* previous assignment will use safe copy */ + } + } + } + if (conflict) { + luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */ + luaK_reserveregs(fs, 1); + } +} + + +static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { + expdesc e; + check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, + "syntax error"); + if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ + struct LHS_assign nv; + nv.prev = lh; + primaryexp(ls, &nv.v); + if (nv.v.k == VLOCAL) + check_conflict(ls, lh, &nv.v); + luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, + "variables in assignment"); + assignment(ls, &nv, nvars+1); + } + else { /* assignment -> `=' explist1 */ + int nexps; + checknext(ls, '='); + nexps = explist1(ls, &e); + if (nexps != nvars) { + adjust_assign(ls, nvars, nexps, &e); + if (nexps > nvars) + ls->fs->freereg -= nexps - nvars; /* remove extra values */ + } + else { + luaK_setoneret(ls->fs, &e); /* close last expression */ + luaK_storevar(ls->fs, &lh->v, &e); + return; /* avoid default */ + } + } + init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ + luaK_storevar(ls->fs, &lh->v, &e); +} + + +static int cond (LexState *ls) { + /* cond -> exp */ + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + return v.f; +} + + +static void breakstat (LexState *ls) { + FuncState *fs = ls->fs; + BlockCnt *bl = fs->bl; + int upval = 0; + while (bl && !bl->isbreakable) { + upval |= bl->upval; + bl = bl->previous; + } + if (!bl) + luaX_syntaxerror(ls, "no loop to break"); + if (upval) + luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); + luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); +} + + +static void whilestat (LexState *ls, int line) { + /* whilestat -> WHILE cond DO block END */ + FuncState *fs = ls->fs; + int whileinit; + int condexit; + BlockCnt bl; + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); + enterblock(fs, &bl, 1); + checknext(ls, TK_DO); + block(ls); + luaK_patchlist(fs, luaK_jump(fs), whileinit); + check_match(ls, TK_END, TK_WHILE, line); + leaveblock(fs); + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ +} + + +static void repeatstat (LexState *ls, int line) { + /* repeatstat -> REPEAT block UNTIL cond */ + int condexit; + FuncState *fs = ls->fs; + int repeat_init = luaK_getlabel(fs); + BlockCnt bl1, bl2; + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + luaX_next(ls); /* skip REPEAT */ + chunk(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + condexit = cond(ls); /* read condition (inside scope block) */ + if (!bl2.upval) { /* no upvalues? */ + leaveblock(fs); /* finish scope */ + luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ + } + else { /* complete semantics when there are upvalues */ + breakstat(ls); /* if condition then break */ + luaK_patchtohere(ls->fs, condexit); /* else... */ + leaveblock(fs); /* finish scope... */ + luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ + } + leaveblock(fs); /* finish loop */ +} + + +static int exp1 (LexState *ls) { + expdesc e; + int k; + expr(ls, &e); + k = e.k; + luaK_exp2nextreg(ls->fs, &e); + return k; +} + + +static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { + /* forbody -> DO block */ + BlockCnt bl; + FuncState *fs = ls->fs; + int prep, endfor; + adjustlocalvars(ls, 3); /* control variables */ + checknext(ls, TK_DO); + prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); + block(ls); + leaveblock(fs); /* end of scope for declared variables */ + luaK_patchtohere(fs, prep); + endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : + luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); + luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ + luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); +} + + +static void fornum (LexState *ls, TString *varname, int line) { + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ + FuncState *fs = ls->fs; + int base = fs->freereg; + new_localvarliteral(ls, "(for index)", 0); + new_localvarliteral(ls, "(for limit)", 1); + new_localvarliteral(ls, "(for step)", 2); + new_localvar(ls, varname, 3); + checknext(ls, '='); + exp1(ls); /* initial value */ + checknext(ls, ','); + exp1(ls); /* limit */ + if (testnext(ls, ',')) + exp1(ls); /* optional step */ + else { /* default step = 1 */ + luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); + luaK_reserveregs(fs, 1); + } + forbody(ls, base, line, 1, 1); +} + + +static void forlist (LexState *ls, TString *indexname) { + /* forlist -> NAME {,NAME} IN explist1 forbody */ + FuncState *fs = ls->fs; + expdesc e; + int nvars = 0; + int line; + int base = fs->freereg; + /* create control variables */ + new_localvarliteral(ls, "(for generator)", nvars++); + new_localvarliteral(ls, "(for state)", nvars++); + new_localvarliteral(ls, "(for control)", nvars++); + /* create declared variables */ + new_localvar(ls, indexname, nvars++); + while (testnext(ls, ',')) + new_localvar(ls, str_checkname(ls), nvars++); + checknext(ls, TK_IN); + line = ls->linenumber; + adjust_assign(ls, 3, explist1(ls, &e), &e); + luaK_checkstack(fs, 3); /* extra space to call generator */ + forbody(ls, base, line, nvars - 3, 0); +} + + +static void forstat (LexState *ls, int line) { + /* forstat -> FOR (fornum | forlist) END */ + FuncState *fs = ls->fs; + TString *varname; + BlockCnt bl; + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip `for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) { + case '=': fornum(ls, varname, line); break; + case ',': case TK_IN: forlist(ls, varname); break; + default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); + } + check_match(ls, TK_END, TK_FOR, line); + leaveblock(fs); /* loop scope (`break' jumps to this point) */ +} + + +static int test_then_block (LexState *ls) { + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + int condexit; + luaX_next(ls); /* skip IF or ELSEIF */ + condexit = cond(ls); + checknext(ls, TK_THEN); + block(ls); /* `then' part */ + return condexit; +} + + +static void ifstat (LexState *ls, int line) { + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState *fs = ls->fs; + int flist; + int escapelist = NO_JUMP; + flist = test_then_block(ls); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) { + luaK_concat(fs, &escapelist, luaK_jump(fs)); + luaK_patchtohere(fs, flist); + flist = test_then_block(ls); /* ELSEIF cond THEN block */ + } + if (ls->t.token == TK_ELSE) { + luaK_concat(fs, &escapelist, luaK_jump(fs)); + luaK_patchtohere(fs, flist); + luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ + block(ls); /* `else' part */ + } + else + luaK_concat(fs, &escapelist, flist); + luaK_patchtohere(fs, escapelist); + check_match(ls, TK_END, TK_IF, line); +} + + +static void localfunc (LexState *ls) { + expdesc v, b; + FuncState *fs = ls->fs; + new_localvar(ls, str_checkname(ls), 0); + init_exp(&v, VLOCAL, fs->freereg); + luaK_reserveregs(fs, 1); + adjustlocalvars(ls, 1); + body(ls, &b, 0, ls->linenumber); + luaK_storevar(fs, &v, &b); + /* debug information will only see the variable after this point! */ + getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; +} + + +static void localstat (LexState *ls) { + /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */ + int nvars = 0; + int nexps; + expdesc e; + do { + new_localvar(ls, str_checkname(ls), nvars++); + } while (testnext(ls, ',')); + if (testnext(ls, '=')) + nexps = explist1(ls, &e); + else { + e.k = VVOID; + nexps = 0; + } + adjust_assign(ls, nvars, nexps, &e); + adjustlocalvars(ls, nvars); +} + + +static int funcname (LexState *ls, expdesc *v) { + /* funcname -> NAME {field} [`:' NAME] */ + int needself = 0; + singlevar(ls, v); + while (ls->t.token == '.') + field(ls, v); + if (ls->t.token == ':') { + needself = 1; + field(ls, v); + } + return needself; +} + + +static void funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int needself; + expdesc v, b; + luaX_next(ls); /* skip FUNCTION */ + needself = funcname(ls, &v); + body(ls, &b, needself, line); + luaK_storevar(ls->fs, &v, &b); + luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ +} + + +static void exprstat (LexState *ls) { + /* stat -> func | assignment */ + FuncState *fs = ls->fs; + struct LHS_assign v; + primaryexp(ls, &v.v); + if (v.v.k == VCALL) /* stat -> func */ + SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ + else { /* stat -> assignment */ + v.prev = NULL; + assignment(ls, &v, 1); + } +} + + +static void retstat (LexState *ls) { + /* stat -> RETURN explist */ + FuncState *fs = ls->fs; + expdesc e; + int first, nret; /* registers with returned values */ + luaX_next(ls); /* skip RETURN */ + if (block_follow(ls->t.token) || ls->t.token == ';') + first = nret = 0; /* return no values */ + else { + nret = explist1(ls, &e); /* optional return values */ + if (hasmultret(e.k)) { + luaK_setmultret(fs, &e); + if (e.k == VCALL && nret == 1) { /* tail call? */ + SET_OPCODE(getcode(fs,&e), OP_TAILCALL); + lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); + } + first = fs->nactvar; + nret = LUA_MULTRET; /* return all values */ + } + else { + if (nret == 1) /* only one single value? */ + first = luaK_exp2anyreg(fs, &e); + else { + luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ + first = fs->nactvar; /* return all `active' values */ + lua_assert(nret == fs->freereg - first); + } + } + } + luaK_ret(fs, first, nret); +} + + +static int statement (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + switch (ls->t.token) { + case TK_IF: { /* stat -> ifstat */ + ifstat(ls, line); + return 0; + } + case TK_WHILE: { /* stat -> whilestat */ + whilestat(ls, line); + return 0; + } + case TK_DO: { /* stat -> DO block END */ + luaX_next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + return 0; + } + case TK_FOR: { /* stat -> forstat */ + forstat(ls, line); + return 0; + } + case TK_REPEAT: { /* stat -> repeatstat */ + repeatstat(ls, line); + return 0; + } + case TK_FUNCTION: { + funcstat(ls, line); /* stat -> funcstat */ + return 0; + } + case TK_LOCAL: { /* stat -> localstat */ + luaX_next(ls); /* skip LOCAL */ + if (testnext(ls, TK_FUNCTION)) /* local function? */ + localfunc(ls); + else + localstat(ls); + return 0; + } + case TK_RETURN: { /* stat -> retstat */ + retstat(ls); + return 1; /* must be last statement */ + } + case TK_BREAK: { /* stat -> breakstat */ + luaX_next(ls); /* skip BREAK */ + breakstat(ls); + return 1; /* must be last statement */ + } + default: { + exprstat(ls); + return 0; /* to avoid warnings */ + } + } +} + + +static void chunk (LexState *ls) { + /* chunk -> { stat [`;'] } */ + int islast = 0; + enterlevel(ls); + while (!islast && !block_follow(ls->t.token)) { + islast = statement(ls); + testnext(ls, ';'); + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= ls->fs->nactvar); + ls->fs->freereg = ls->fs->nactvar; /* free registers */ + } + leavelevel(ls); +} + +/* }====================================================================== */ diff --git a/source/fceultra/lua/src/lparser.h b/source/fceultra/lua/src/lparser.h new file mode 100644 index 0000000..18836af --- /dev/null +++ b/source/fceultra/lua/src/lparser.h @@ -0,0 +1,82 @@ +/* +** $Id: lparser.h,v 1.57.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#ifndef lparser_h +#define lparser_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* +** Expression descriptor +*/ + +typedef enum { + VVOID, /* no value */ + VNIL, + VTRUE, + VFALSE, + VK, /* info = index of constant in `k' */ + VKNUM, /* nval = numerical value */ + VLOCAL, /* info = local register */ + VUPVAL, /* info = index of upvalue in `upvalues' */ + VGLOBAL, /* info = index of table; aux = index of global name in `k' */ + VINDEXED, /* info = table register; aux = index register (or `k') */ + VJMP, /* info = instruction pc */ + VRELOCABLE, /* info = instruction pc */ + VNONRELOC, /* info = result register */ + VCALL, /* info = instruction pc */ + VVARARG /* info = instruction pc */ +} expkind; + +typedef struct expdesc { + expkind k; + union { + struct { int info, aux; } s; + lua_Number nval; + } u; + int t; /* patch list of `exit when true' */ + int f; /* patch list of `exit when false' */ +} expdesc; + + +typedef struct upvaldesc { + lu_byte k; + lu_byte info; +} upvaldesc; + + +struct BlockCnt; /* defined in lparser.c */ + + +/* state needed to generate code for a given function */ +typedef struct FuncState { + Proto *f; /* current function header */ + Table *h; /* table to find (and reuse) elements in `k' */ + struct FuncState *prev; /* enclosing function */ + struct LexState *ls; /* lexical state */ + struct lua_State *L; /* copy of the Lua state */ + struct BlockCnt *bl; /* chain of current blocks */ + int pc; /* next position to code (equivalent to `ncode') */ + int lasttarget; /* `pc' of last `jump target' */ + int jpc; /* list of pending jumps to `pc' */ + int freereg; /* first free register */ + int nk; /* number of elements in `k' */ + int np; /* number of elements in `p' */ + short nlocvars; /* number of elements in `locvars' */ + lu_byte nactvar; /* number of active local variables */ + upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */ + unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */ +} FuncState; + + +LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + const char *name); + + +#endif diff --git a/source/fceultra/lua/src/lstate.c b/source/fceultra/lua/src/lstate.c new file mode 100644 index 0000000..4313b83 --- /dev/null +++ b/source/fceultra/lua/src/lstate.c @@ -0,0 +1,214 @@ +/* +** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + + +#include + +#define lstate_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +#define state_size(x) (sizeof(x) + LUAI_EXTRASPACE) +#define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE) +#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE)) + + +/* +** Main thread combines a thread state and the global state +*/ +typedef struct LG { + lua_State l; + global_State g; +} LG; + + + +static void stack_init (lua_State *L1, lua_State *L) { + /* initialize CallInfo array */ + L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); + L1->ci = L1->base_ci; + L1->size_ci = BASIC_CI_SIZE; + L1->end_ci = L1->base_ci + L1->size_ci - 1; + /* initialize stack array */ + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); + L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; + L1->top = L1->stack; + L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; + /* initialize first ci */ + L1->ci->func = L1->top; + setnilvalue(L1->top++); /* `function' entry for this `ci' */ + L1->base = L1->ci->base = L1->top; + L1->ci->top = L1->top + LUA_MINSTACK; +} + + +static void freestack (lua_State *L, lua_State *L1) { + luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); + luaM_freearray(L, L1->stack, L1->stacksize, TValue); +} + + +/* +** open parts that may cause memory-allocation errors +*/ +static void f_luaopen (lua_State *L, void *ud) { + global_State *g = G(L); + UNUSED(ud); + stack_init(L, L); /* init stack */ + sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ + sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ + luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + luaT_init(L); + luaX_init(L); + luaS_fix(luaS_newliteral(L, MEMERRMSG)); + g->GCthreshold = 4*g->totalbytes; +} + + +static void preinit_state (lua_State *L, global_State *g) { + G(L) = g; + L->stack = NULL; + L->stacksize = 0; + L->errorJmp = NULL; + L->hook = NULL; + L->hookmask = 0; + L->basehookcount = 0; + L->allowhook = 1; + resethookcount(L); + L->openupval = NULL; + L->size_ci = 0; + L->nCcalls = L->baseCcalls = 0; + L->status = 0; + L->base_ci = L->ci = NULL; + L->savedpc = NULL; + L->errfunc = 0; + setnilvalue(gt(L)); +} + + +static void close_state (lua_State *L) { + global_State *g = G(L); + luaF_close(L, L->stack); /* close all upvalues for this thread */ + luaC_freeall(L); /* collect all objects */ + lua_assert(g->rootgc == obj2gco(L)); + lua_assert(g->strt.nuse == 0); + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); + luaZ_freebuffer(L, &g->buff); + freestack(L, L); + lua_assert(g->totalbytes == sizeof(LG)); + (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); +} + + +lua_State *luaE_newthread (lua_State *L) { + lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); + luaC_link(L, obj2gco(L1), LUA_TTHREAD); + preinit_state(L1, G(L)); + stack_init(L1, L); /* init stack */ + setobj2n(L, gt(L1), gt(L)); /* share table of globals */ + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); + lua_assert(iswhite(obj2gco(L1))); + return L1; +} + + +void luaE_freethread (lua_State *L, lua_State *L1) { + luaF_close(L1, L1->stack); /* close all upvalues for this thread */ + lua_assert(L1->openupval == NULL); + luai_userstatefree(L1); + freestack(L, L1); + luaM_freemem(L, fromstate(L1), state_size(lua_State)); +} + + +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + int i; + lua_State *L; + global_State *g; + void *l = (*f)(ud, NULL, 0, state_size(LG)); + if (l == NULL) return NULL; + L = tostate(l); + g = &((LG *)L)->g; + L->next = NULL; + L->tt = LUA_TTHREAD; + g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); + L->marked = luaC_white(g); + set2bits(L->marked, FIXEDBIT, SFIXEDBIT); + preinit_state(L, g); + g->frealloc = f; + g->ud = ud; + g->mainthread = L; + g->uvhead.u.l.prev = &g->uvhead; + g->uvhead.u.l.next = &g->uvhead; + g->GCthreshold = 0; /* mark it as unfinished state */ + g->strt.size = 0; + g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(registry(L)); + luaZ_initbuffer(L, &g->buff); + g->panic = NULL; + g->gcstate = GCSpause; + g->rootgc = obj2gco(L); + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + g->tmudata = NULL; + g->totalbytes = sizeof(LG); + g->gcpause = LUAI_GCPAUSE; + g->gcstepmul = LUAI_GCMUL; + g->gcdept = 0; + for (i=0; imt[i] = NULL; + if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; + } + else + luai_userstateopen(L); + return L; +} + + +static void callallgcTM (lua_State *L, void *ud) { + UNUSED(ud); + luaC_callGCTM(L); /* call GC metamethods for all udata */ +} + + +LUA_API void lua_close (lua_State *L) { + L = G(L)->mainthread; /* only the main thread can be closed */ + lua_lock(L); + luaF_close(L, L->stack); /* close all upvalues for this thread */ + luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ + L->errfunc = 0; /* no error function during GC metamethods */ + do { /* repeat until no more errors */ + L->ci = L->base_ci; + L->base = L->top = L->ci->base; + L->nCcalls = L->baseCcalls = 0; + } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); + lua_assert(G(L)->tmudata == NULL); + luai_userstateclose(L); + close_state(L); +} + diff --git a/source/fceultra/lua/src/lstate.h b/source/fceultra/lua/src/lstate.h new file mode 100644 index 0000000..3bc575b --- /dev/null +++ b/source/fceultra/lua/src/lstate.h @@ -0,0 +1,169 @@ +/* +** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + +#ifndef lstate_h +#define lstate_h + +#include "lua.h" + +#include "lobject.h" +#include "ltm.h" +#include "lzio.h" + + + +struct lua_longjmp; /* defined in ldo.c */ + + +/* table of globals */ +#define gt(L) (&L->l_gt) + +/* registry */ +#define registry(L) (&G(L)->l_registry) + + +/* extra stack space to handle TM calls and some other extras */ +#define EXTRA_STACK 5 + + +#define BASIC_CI_SIZE 8 + +#define BASIC_STACK_SIZE (2*LUA_MINSTACK) + + + +typedef struct stringtable { + GCObject **hash; + lu_int32 nuse; /* number of elements */ + int size; +} stringtable; + + +/* +** informations about a call +*/ +typedef struct CallInfo { + StkId base; /* base for this function */ + StkId func; /* function index in the stack */ + StkId top; /* top for this function */ + const Instruction *savedpc; + int nresults; /* expected number of results from this function */ + int tailcalls; /* number of tail calls lost under this entry */ +} CallInfo; + + + +#define curr_func(L) (clvalue(L->ci->func)) +#define ci_func(ci) (clvalue((ci)->func)) +#define f_isLua(ci) (!ci_func(ci)->c.isC) +#define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci)) + + +/* +** `global state', shared by all threads of this state +*/ +typedef struct global_State { + stringtable strt; /* hash table for strings */ + lua_Alloc frealloc; /* function to reallocate memory */ + void *ud; /* auxiliary data to `frealloc' */ + lu_byte currentwhite; + lu_byte gcstate; /* state of garbage collector */ + int sweepstrgc; /* position of sweep in `strt' */ + GCObject *rootgc; /* list of all collectable objects */ + GCObject **sweepgc; /* position of sweep in `rootgc' */ + GCObject *gray; /* list of gray objects */ + GCObject *grayagain; /* list of objects to be traversed atomically */ + GCObject *weak; /* list of weak tables (to be cleared) */ + GCObject *tmudata; /* last element of list of userdata to be GC */ + Mbuffer buff; /* temporary buffer for string concatentation */ + lu_mem GCthreshold; + lu_mem totalbytes; /* number of bytes currently allocated */ + lu_mem estimate; /* an estimate of number of bytes actually in use */ + lu_mem gcdept; /* how much GC is `behind schedule' */ + int gcpause; /* size of pause between successive GCs */ + int gcstepmul; /* GC `granularity' */ + lua_CFunction panic; /* to be called in unprotected errors */ + TValue l_registry; + struct lua_State *mainthread; + UpVal uvhead; /* head of double-linked list of all open upvalues */ + struct Table *mt[NUM_TAGS]; /* metatables for basic types */ + TString *tmname[TM_N]; /* array with tag-method names */ +} global_State; + + +/* +** `per thread' state +*/ +struct lua_State { + CommonHeader; + lu_byte status; + StkId top; /* first free slot in the stack */ + StkId base; /* base of current function */ + global_State *l_G; + CallInfo *ci; /* call info for current function */ + const Instruction *savedpc; /* `savedpc' of current function */ + StkId stack_last; /* last free slot in the stack */ + StkId stack; /* stack base */ + CallInfo *end_ci; /* points after end of ci array*/ + CallInfo *base_ci; /* array of CallInfo's */ + int stacksize; + int size_ci; /* size of array `base_ci' */ + unsigned short nCcalls; /* number of nested C calls */ + unsigned short baseCcalls; /* nested C calls when resuming coroutine */ + lu_byte hookmask; + lu_byte allowhook; + int basehookcount; + int hookcount; + lua_Hook hook; + TValue l_gt; /* table of globals */ + TValue env; /* temporary place for environments */ + GCObject *openupval; /* list of open upvalues in this stack */ + GCObject *gclist; + struct lua_longjmp *errorJmp; /* current error recover point */ + ptrdiff_t errfunc; /* current error handling function (stack index) */ +}; + + +#define G(L) (L->l_G) + + +/* +** Union of all collectable objects +*/ +union GCObject { + GCheader gch; + union TString ts; + union Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct UpVal uv; + struct lua_State th; /* thread */ +}; + + +/* macros to convert a GCObject into a specific value */ +#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) +#define gco2ts(o) (&rawgco2ts(o)->tsv) +#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) +#define gco2u(o) (&rawgco2u(o)->uv) +#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) +#define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) +#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) +#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) +#define ngcotouv(o) \ + check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) +#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) + +/* macro to convert any Lua object into a GCObject */ +#define obj2gco(v) (cast(GCObject *, (v))) + + +LUAI_FUNC lua_State *luaE_newthread (lua_State *L); +LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); + +#endif + diff --git a/source/fceultra/lua/src/lstring.c b/source/fceultra/lua/src/lstring.c new file mode 100644 index 0000000..4911315 --- /dev/null +++ b/source/fceultra/lua/src/lstring.c @@ -0,0 +1,111 @@ +/* +** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** String table (keeps all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + + +#include + +#define lstring_c +#define LUA_CORE + +#include "lua.h" + +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" + + + +void luaS_resize (lua_State *L, int newsize) { + GCObject **newhash; + stringtable *tb; + int i; + if (G(L)->gcstate == GCSsweepstring) + return; /* cannot resize during GC traverse */ + newhash = luaM_newvector(L, newsize, GCObject *); + tb = &G(L)->strt; + for (i=0; isize; i++) { + GCObject *p = tb->hash[i]; + while (p) { /* for each node in the list */ + GCObject *next = p->gch.next; /* save next */ + unsigned int h = gco2ts(p)->hash; + int h1 = lmod(h, newsize); /* new position */ + lua_assert(cast_int(h%newsize) == lmod(h, newsize)); + p->gch.next = newhash[h1]; /* chain it */ + newhash[h1] = p; + p = next; + } + } + luaM_freearray(L, tb->hash, tb->size, TString *); + tb->size = newsize; + tb->hash = newhash; +} + + +static TString *newlstr (lua_State *L, const char *str, size_t l, + unsigned int h) { + TString *ts; + stringtable *tb; + if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) + luaM_toobig(L); + ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); + ts->tsv.len = l; + ts->tsv.hash = h; + ts->tsv.marked = luaC_white(G(L)); + ts->tsv.tt = LUA_TSTRING; + ts->tsv.reserved = 0; + memcpy(ts+1, str, l*sizeof(char)); + ((char *)(ts+1))[l] = '\0'; /* ending 0 */ + tb = &G(L)->strt; + h = lmod(h, tb->size); + ts->tsv.next = tb->hash[h]; /* chain new entry */ + tb->hash[h] = obj2gco(ts); + tb->nuse++; + if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) + luaS_resize(L, tb->size*2); /* too crowded */ + return ts; +} + + +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + GCObject *o; + unsigned int h = cast(unsigned int, l); /* seed */ + size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ + size_t l1; + for (l1=l; l1>=step; l1-=step) /* compute hash */ + h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); + for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; + o != NULL; + o = o->gch.next) { + TString *ts = rawgco2ts(o); + if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { + /* string may be dead */ + if (isdead(G(L), o)) changewhite(o); + return ts; + } + } + return newlstr(L, str, l, h); /* not found */ +} + + +Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { + Udata *u; + if (s > MAX_SIZET - sizeof(Udata)) + luaM_toobig(L); + u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); + u->uv.marked = luaC_white(G(L)); /* is not finalized */ + u->uv.tt = LUA_TUSERDATA; + u->uv.len = s; + u->uv.metatable = NULL; + u->uv.env = e; + /* chain it on udata list (after main thread) */ + u->uv.next = G(L)->mainthread->next; + G(L)->mainthread->next = obj2gco(u); + return u; +} + diff --git a/source/fceultra/lua/src/lstring.h b/source/fceultra/lua/src/lstring.h new file mode 100644 index 0000000..73a2ff8 --- /dev/null +++ b/source/fceultra/lua/src/lstring.h @@ -0,0 +1,31 @@ +/* +** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $ +** String table (keep all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#ifndef lstring_h +#define lstring_h + + +#include "lgc.h" +#include "lobject.h" +#include "lstate.h" + + +#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) + +#define sizeudata(u) (sizeof(union Udata)+(u)->len) + +#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s))) +#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ + (sizeof(s)/sizeof(char))-1)) + +#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) + +LUAI_FUNC void luaS_resize (lua_State *L, int newsize); +LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); +LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); + + +#endif diff --git a/source/fceultra/lua/src/lstrlib.c b/source/fceultra/lua/src/lstrlib.c new file mode 100644 index 0000000..1b4763d --- /dev/null +++ b/source/fceultra/lua/src/lstrlib.c @@ -0,0 +1,869 @@ +/* +** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $ +** Standard library for string operations and pattern-matching +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include +#include + +#define lstrlib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* macro to `unsign' a character */ +#define uchar(c) ((unsigned char)(c)) + + + +static int str_len (lua_State *L) { + size_t l; + luaL_checklstring(L, 1, &l); + lua_pushinteger(L, l); + return 1; +} + + +static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { + /* relative string position: negative means back from end */ + if (pos < 0) pos += (ptrdiff_t)len + 1; + return (pos >= 0) ? pos : 0; +} + + +static int str_sub (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); + ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); + if (start < 1) start = 1; + if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; + if (start <= end) + lua_pushlstring(L, s+start-1, end-start+1); + else lua_pushliteral(L, ""); + return 1; +} + + +static int str_reverse (lua_State *L) { + size_t l; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + luaL_buffinit(L, &b); + while (l--) luaL_addchar(&b, s[l]); + luaL_pushresult(&b); + return 1; +} + + +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + luaL_buffinit(L, &b); + for (i=0; i 0) + luaL_addlstring(&b, s, l); + luaL_pushresult(&b); + return 1; +} + + +static int str_byte (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); + ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); + int n, i; + if (posi <= 0) posi = 1; + if ((size_t)pose > l) pose = l; + if (posi > pose) return 0; /* empty interval; return no values */ + n = (int)(pose - posi + 1); + if (posi + n <= pose) /* overflow? */ + luaL_error(L, "string slice too long"); + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) + return luaL_error(ms->L, "invalid capture index"); + return l; +} + + +static int capture_to_close (MatchState *ms) { + int level = ms->level; + for (level--; level>=0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); +} + + +static const char *classend (MatchState *ms, const char *p) { + switch (*p++) { + case L_ESC: { + if (*p == '\0') + luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); + return p+1; + } + case '[': { + if (*p == '^') p++; + do { /* look for a `]' */ + if (*p == '\0') + luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); + if (*(p++) == L_ESC && *p != '\0') + p++; /* skip escapes (e.g. `%]') */ + } while (*p != ']'); + return p+1; + } + default: { + return p; + } + } +} + + +static int match_class (int c, int cl) { + int res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; + case 'z' : res = (c == 0); break; + default: return (cl == c); + } + return (islower(cl) ? res : !res); +} + + +static int matchbracketclass (int c, const char *p, const char *ec) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the `^' */ + } + while (++p < ec) { + if (*p == L_ESC) { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < ec)) { + p+=2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; +} + + +static int singlematch (int c, const char *p, const char *ep) { + switch (*p) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } +} + + +static const char *match (MatchState *ms, const char *s, const char *p); + + +static const char *matchbalance (MatchState *ms, const char *s, + const char *p) { + if (*p == 0 || *(p+1) == 0) + luaL_error(ms->L, "unbalanced pattern"); + if (*s != *p) return NULL; + else { + int b = *p; + int e = *(p+1); + int cont = 1; + while (++s < ms->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} + + +static const char *max_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + ptrdiff_t i = 0; /* counts maximum expand for item */ + while ((s+i)src_end && singlematch(uchar(*(s+i)), p, ep)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + const char *res = match(ms, (s+i), ep+1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; +} + + +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + for (;;) { + const char *res = match(ms, s, ep+1); + if (res != NULL) + return res; + else if (ssrc_end && singlematch(uchar(*s), p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { + const char *res; + int level = ms->level; + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level+1; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; +} + + +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); + const char *res; + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; +} + + +static const char *match_capture (MatchState *ms, const char *s, int l) { + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end-s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} + + +static const char *match (MatchState *ms, const char *s, const char *p) { + init: /* using goto's to optimize tail recursion */ + switch (*p) { + case '(': { /* start capture */ + if (*(p+1) == ')') /* position capture? */ + return start_capture(ms, s, p+2, CAP_POSITION); + else + return start_capture(ms, s, p+1, CAP_UNFINISHED); + } + case ')': { /* end capture */ + return end_capture(ms, s, p+1); + } + case L_ESC: { + switch (*(p+1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p+2); + if (s == NULL) return NULL; + p+=4; goto init; /* else return match(ms, s, p+4); */ + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (*p != '[') + luaL_error(ms->L, "missing " LUA_QL("[") " after " + LUA_QL("%%f") " in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s-1); + if (matchbracketclass(uchar(previous), p, ep-1) || + !matchbracketclass(uchar(*s), p, ep-1)) return NULL; + p=ep; goto init; /* else return match(ms, s, ep); */ + } + default: { + if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p+1))); + if (s == NULL) return NULL; + p+=2; goto init; /* else return match(ms, s, p+2) */ + } + goto dflt; /* case default */ + } + } + } + case '\0': { /* end of pattern */ + return s; /* match succeeded */ + } + case '$': { + if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ + return (s == ms->src_end) ? s : NULL; /* check end of string */ + else goto dflt; + } + default: dflt: { /* it is a pattern item */ + const char *ep = classend(ms, p); /* points to what is next */ + int m = ssrc_end && singlematch(uchar(*s), p, ep); + switch (*ep) { + case '?': { /* optional */ + const char *res; + if (m && ((res=match(ms, s+1, ep+1)) != NULL)) + return res; + p=ep+1; goto init; /* else return match(ms, s, ep+1); */ + } + case '*': { /* 0 or more repetitions */ + return max_expand(ms, s, p, ep); + } + case '+': { /* 1 or more repetitions */ + return (m ? max_expand(ms, s+1, p, ep) : NULL); + } + case '-': { /* 0 or more repetitions (minimum) */ + return min_expand(ms, s, p, ep); + } + default: { + if (!m) return NULL; + s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ + } + } + } + } +} + + + +static const char *lmemfind (const char *s1, size_t l1, + const char *s2, size_t l2) { + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative `l1' */ + else { + const char *init; /* to search for a `*s2' inside `s1' */ + l2--; /* 1st char will be checked by `memchr' */ + l1 = l1-l2; /* `s2' cannot be found after that */ + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { + init++; /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct `l1' and `s1' to try again */ + l1 -= init-s1; + s1 = init; + } + } + return NULL; /* not found */ + } +} + + +static void push_onecapture (MatchState *ms, int i, const char *s, + const char *e) { + if (i >= ms->level) { + if (i == 0) /* ms->level == 0, too */ + lua_pushlstring(ms->L, s, e - s); /* add whole match */ + else + luaL_error(ms->L, "invalid capture index"); + } + else { + ptrdiff_t l = ms->capture[i].len; + if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); + if (l == CAP_POSITION) + lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); + else + lua_pushlstring(ms->L, ms->capture[i].init, l); + } +} + + +static int push_captures (MatchState *ms, const char *s, const char *e) { + int i; + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + luaL_checkstack(ms->L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ +} + + +static int str_find_aux (lua_State *L, int find) { + size_t l1, l2; + const char *s = luaL_checklstring(L, 1, &l1); + const char *p = luaL_checklstring(L, 2, &l2); + ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; + if (init < 0) init = 0; + else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; + if (find && (lua_toboolean(L, 4) || /* explicit request? */ + strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ + /* do a plain search */ + const char *s2 = lmemfind(s+init, l1-init, p, l2); + if (s2) { + lua_pushinteger(L, s2-s+1); + lua_pushinteger(L, s2-s+l2); + return 2; + } + } + else { + MatchState ms; + int anchor = (*p == '^') ? (p++, 1) : 0; + const char *s1=s+init; + ms.L = L; + ms.src_init = s; + ms.src_end = s+l1; + do { + const char *res; + ms.level = 0; + if ((res=match(&ms, s1, p)) != NULL) { + if (find) { + lua_pushinteger(L, s1-s+1); /* start */ + lua_pushinteger(L, res-s); /* end */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); + } + } while (s1++ < ms.src_end && !anchor); + } + lua_pushnil(L); /* not found */ + return 1; +} + + +static int str_find (lua_State *L) { + return str_find_aux(L, 1); +} + + +static int str_match (lua_State *L) { + return str_find_aux(L, 0); +} + + +static int gmatch_aux (lua_State *L) { + MatchState ms; + size_t ls; + const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); + const char *p = lua_tostring(L, lua_upvalueindex(2)); + const char *src; + ms.L = L; + ms.src_init = s; + ms.src_end = s+ls; + for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); + src <= ms.src_end; + src++) { + const char *e; + ms.level = 0; + if ((e = match(&ms, src, p)) != NULL) { + lua_Integer newstart = e-s; + if (e == src) newstart++; /* empty match? go at least one position */ + lua_pushinteger(L, newstart); + lua_replace(L, lua_upvalueindex(3)); + return push_captures(&ms, src, e); + } + } + return 0; /* not found */ +} + + +static int gmatch (lua_State *L) { + luaL_checkstring(L, 1); + luaL_checkstring(L, 2); + lua_settop(L, 2); + lua_pushinteger(L, 0); + lua_pushcclosure(L, gmatch_aux, 3); + return 1; +} + + +static int gfind_nodef (lua_State *L) { + return luaL_error(L, LUA_QL("string.gfind") " was renamed to " + LUA_QL("string.gmatch")); +} + + +static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + size_t l, i; + const char *news = lua_tolstring(ms->L, 3, &l); + for (i = 0; i < l; i++) { + if (news[i] != L_ESC) + luaL_addchar(b, news[i]); + else { + i++; /* skip ESC */ + if (!isdigit(uchar(news[i]))) + luaL_addchar(b, news[i]); + else if (news[i] == '0') + luaL_addlstring(b, s, e - s); + else { + push_onecapture(ms, news[i] - '1', s, e); + luaL_addvalue(b); /* add capture to accumulated result */ + } + } + } +} + + +static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + lua_State *L = ms->L; + switch (lua_type(L, 3)) { + case LUA_TNUMBER: + case LUA_TSTRING: { + add_s(ms, b, s, e); + return; + } + case LUA_TFUNCTION: { + int n; + lua_pushvalue(L, 3); + n = push_captures(ms, s, e); + lua_call(L, n, 1); + break; + } + case LUA_TTABLE: { + push_onecapture(ms, 0, s, e); + lua_gettable(L, 3); + break; + } + } + if (!lua_toboolean(L, -1)) { /* nil or false? */ + lua_pop(L, 1); + lua_pushlstring(L, s, e - s); /* keep original text */ + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_addvalue(b); /* add result to accumulator */ +} + + +static int str_gsub (lua_State *L) { + size_t srcl; + const char *src = luaL_checklstring(L, 1, &srcl); + const char *p = luaL_checkstring(L, 2); + int tr = lua_type(L, 3); + int max_s = luaL_optint(L, 4, srcl+1); + int anchor = (*p == '^') ? (p++, 1) : 0; + int n = 0; + MatchState ms; + luaL_Buffer b; + luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, + "string/function/table expected"); + luaL_buffinit(L, &b); + ms.L = L; + ms.src_init = src; + ms.src_end = src+srcl; + while (n < max_s) { + const char *e; + ms.level = 0; + e = match(&ms, src, p); + if (e) { + n++; + add_value(&ms, &b, src, e); + } + if (e && e>src) /* non empty match? */ + src = e; /* skip it */ + else if (src < ms.src_end) + luaL_addchar(&b, *src++); + else break; + if (anchor) break; + } + luaL_addlstring(&b, src, ms.src_end-src); + luaL_pushresult(&b); + lua_pushinteger(L, n); /* number of substitutions */ + return 2; +} + +/* }====================================================== */ + + +/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ +#define MAX_ITEM 512 +/* valid flags in a format specification */ +#define FLAGS "-+ #0" +/* +** maximum size of each format specification (such as '%-099.99d') +** (+10 accounts for %99.99x plus margin of error) +*/ +#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) + + +static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + luaL_addchar(b, '"'); + while (l--) { + switch (*s) { + case '"': case '\\': case '\n': { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); + break; + } + case '\r': { + luaL_addlstring(b, "\\r", 2); + break; + } + case '\0': { + luaL_addlstring(b, "\\000", 4); + break; + } + default: { + luaL_addchar(b, *s); + break; + } + } + s++; + } + luaL_addchar(b, '"'); +} + +static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { + const char *p = strfrmt; + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) + luaL_error(L, "invalid format (repeated flags)"); + if (isdigit(uchar(*p))) p++; /* skip width */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + if (*p == '.') { + p++; + if (isdigit(uchar(*p))) p++; /* skip precision */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + } + if (isdigit(uchar(*p))) + luaL_error(L, "invalid format (width or precision too long)"); + *(form++) = '%'; + strncpy(form, strfrmt, p - strfrmt + 1); + form += p - strfrmt + 1; + *form = '\0'; + return p; +} + + +static void addintlen (char *form) { + size_t l = strlen(form); + char spec = form[l - 1]; + strcpy(form + l - 1, LUA_INTFRMLEN); + form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; + form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; +} + + +static int str_format (lua_State *L) { + int arg = 1; + size_t sfl; + const char *strfrmt = luaL_checklstring(L, arg, &sfl); + const char *strfrmt_end = strfrmt+sfl; + luaL_Buffer b; + luaL_buffinit(L, &b); + while (strfrmt < strfrmt_end) { + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&b, *strfrmt++); /* %% */ + else { /* format item */ + char form[MAX_FORMAT]; /* to store the format (`%...') */ + char buff[MAX_ITEM]; /* to store the formatted item */ + arg++; + strfrmt = scanformat(L, strfrmt, form); + switch (*strfrmt++) { + case 'c': { + sprintf(buff, form, (int)luaL_checknumber(L, arg)); + break; + } + case 'd': case 'i': { + addintlen(form); + sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); + break; + } + case 'o': case 'u': case 'x': case 'X': { + addintlen(form); + sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); + break; + } + case 'e': case 'E': case 'f': + case 'g': case 'G': { + sprintf(buff, form, (double)luaL_checknumber(L, arg)); + break; + } + case 'q': { + addquoted(L, &b, arg); + continue; /* skip the 'addsize' at the end */ + } + case 's': { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + if (!strchr(form, '.') && l >= 100) { + /* no precision and string is too long to be formatted; + keep original string */ + lua_pushvalue(L, arg); + luaL_addvalue(&b); + continue; /* skip the `addsize' at the end */ + } + else { + sprintf(buff, form, s); + break; + } + } + default: { /* also treat cases `pnLlh' */ + return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " + LUA_QL("format"), *(strfrmt - 1)); + } + } + luaL_addlstring(&b, buff, strlen(buff)); + } + } + luaL_pushresult(&b); + return 1; +} + + +static const luaL_Reg strlib[] = { + {"byte", str_byte}, + {"char", str_char}, + {"dump", str_dump}, + {"find", str_find}, + {"format", str_format}, + {"gfind", gfind_nodef}, + {"gmatch", gmatch}, + {"gsub", str_gsub}, + {"len", str_len}, + {"lower", str_lower}, + {"match", str_match}, + {"rep", str_rep}, + {"reverse", str_reverse}, + {"sub", str_sub}, + {"upper", str_upper}, + {NULL, NULL} +}; + + +static void createmetatable (lua_State *L) { + lua_createtable(L, 0, 1); /* create metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); + lua_setmetatable(L, -2); /* set string metatable */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* string library... */ + lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ + lua_pop(L, 1); /* pop metatable */ +} + + +/* +** Open string library +*/ +LUALIB_API int luaopen_string (lua_State *L) { + luaL_register(L, LUA_STRLIBNAME, strlib); +#if defined(LUA_COMPAT_GFIND) + lua_getfield(L, -1, "gmatch"); + lua_setfield(L, -2, "gfind"); +#endif + createmetatable(L); + return 1; +} + diff --git a/source/fceultra/lua/src/ltable.c b/source/fceultra/lua/src/ltable.c new file mode 100644 index 0000000..ec84f4f --- /dev/null +++ b/source/fceultra/lua/src/ltable.c @@ -0,0 +1,588 @@ +/* +** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + + +/* +** Implementation of tables (aka arrays, objects, or hash tables). +** Tables keep its elements in two parts: an array part and a hash part. +** Non-negative integer keys are all candidates to be kept in the array +** part. The actual size of the array is the largest `n' such that at +** least half the slots between 0 and n are in use. +** Hash uses a mix of chained scatter table with Brent's variation. +** A main invariant of these tables is that, if an element is not +** in its main position (i.e. the `original' position that its hash gives +** to it), then the colliding element is in its own main position. +** Hence even when the load factor reaches 100%, performance remains good. +*/ + +#include +#include + +#define ltable_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "ltable.h" + + +/* +** max size of array part is 2^MAXBITS +*/ +#if LUAI_BITSINT > 26 +#define MAXBITS 26 +#else +#define MAXBITS (LUAI_BITSINT-2) +#endif + +#define MAXASIZE (1 << MAXBITS) + + +#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) + +#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) +#define hashboolean(t,p) hashpow2(t, p) + + +/* +** for some types, it is better to avoid modulus by power of 2, as +** they tend to have many 2 factors. +*/ +#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) + + +#define hashpointer(t,p) hashmod(t, IntPoint(p)) + + +/* +** number of ints inside a lua_Number +*/ +#define numints cast_int(sizeof(lua_Number)/sizeof(int)) + + + +#define dummynode (&dummynode_) + +static const Node dummynode_ = { + {{NULL}, LUA_TNIL}, /* value */ + {{{NULL}, LUA_TNIL, NULL}} /* key */ +}; + + +/* +** hash for lua_Numbers +*/ +static Node *hashnum (const Table *t, lua_Number n) { + unsigned int a[numints]; + int i; + if (luai_numeq(n, 0)) /* avoid problems with -0 */ + return gnode(t, 0); + memcpy(a, &n, sizeof(a)); + for (i = 1; i < numints; i++) a[0] += a[i]; + return hashmod(t, a[0]); +} + + + +/* +** returns the `main' position of an element in a table (that is, the index +** of its hash value) +*/ +static Node *mainposition (const Table *t, const TValue *key) { + switch (ttype(key)) { + case LUA_TNUMBER: + return hashnum(t, nvalue(key)); + case LUA_TSTRING: + return hashstr(t, rawtsvalue(key)); + case LUA_TBOOLEAN: + return hashboolean(t, bvalue(key)); + case LUA_TLIGHTUSERDATA: + return hashpointer(t, pvalue(key)); + default: + return hashpointer(t, gcvalue(key)); + } +} + + +/* +** returns the index for `key' if `key' is an appropriate key to live in +** the array part of the table, -1 otherwise. +*/ +static int arrayindex (const TValue *key) { + if (ttisnumber(key)) { + lua_Number n = nvalue(key); + int k; + lua_number2int(k, n); + if (luai_numeq(cast_num(k), n)) + return k; + } + return -1; /* `key' did not match some condition */ +} + + +/* +** returns the index of a `key' for table traversals. First goes all +** elements in the array part, then elements in the hash part. The +** beginning of a traversal is signalled by -1. +*/ +static int findindex (lua_State *L, Table *t, StkId key) { + int i; + if (ttisnil(key)) return -1; /* first iteration */ + i = arrayindex(key); + if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ + return i-1; /* yes; that's the index (corrected to C) */ + else { + Node *n = mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in `next' */ + if (luaO_rawequalObj(key2tval(n), key) || + (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && + gcvalue(gkey(n)) == gcvalue(key))) { + i = cast_int(n - gnode(t, 0)); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return i + t->sizearray; + } + else n = gnext(n); + } while (n); + luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ + return 0; /* to avoid warnings */ + } +} + + +int luaH_next (lua_State *L, Table *t, StkId key) { + int i = findindex(L, t, key); /* find original element */ + for (i++; i < t->sizearray; i++) { /* try first array part */ + if (!ttisnil(&t->array[i])) { /* a non-nil value? */ + setnvalue(key, cast_num(i+1)); + setobj2s(L, key+1, &t->array[i]); + return 1; + } + } + for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ + if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ + setobj2s(L, key, key2tval(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); + return 1; + } + } + return 0; /* no more elements */ +} + + +/* +** {============================================================= +** Rehash +** ============================================================== +*/ + + +static int computesizes (int nums[], int *narray) { + int i; + int twotoi; /* 2^i */ + int a = 0; /* number of elements smaller than 2^i */ + int na = 0; /* number of elements to go to array part */ + int n = 0; /* optimal size for array part */ + for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { + if (nums[i] > 0) { + a += nums[i]; + if (a > twotoi/2) { /* more than half elements present? */ + n = twotoi; /* optimal size (till now) */ + na = a; /* all elements smaller than n will go to array part */ + } + } + if (a == *narray) break; /* all elements already counted */ + } + *narray = n; + lua_assert(*narray/2 <= na && na <= *narray); + return na; +} + + +static int countint (const TValue *key, int *nums) { + int k = arrayindex(key); + if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ + nums[ceillog2(k)]++; /* count as such */ + return 1; + } + else + return 0; +} + + +static int numusearray (const Table *t, int *nums) { + int lg; + int ttlg; /* 2^lg */ + int ause = 0; /* summation of `nums' */ + int i = 1; /* count to traverse all array keys */ + for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ + int lc = 0; /* counter */ + int lim = ttlg; + if (lim > t->sizearray) { + lim = t->sizearray; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ + } + /* count elements in range (2^(lg-1), 2^lg] */ + for (; i <= lim; i++) { + if (!ttisnil(&t->array[i-1])) + lc++; + } + nums[lg] += lc; + ause += lc; + } + return ause; +} + + +static int numusehash (const Table *t, int *nums, int *pnasize) { + int totaluse = 0; /* total number of elements */ + int ause = 0; /* summation of `nums' */ + int i = sizenode(t); + while (i--) { + Node *n = &t->node[i]; + if (!ttisnil(gval(n))) { + ause += countint(key2tval(n), nums); + totaluse++; + } + } + *pnasize += ause; + return totaluse; +} + + +static void setarrayvector (lua_State *L, Table *t, int size) { + int i; + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); + for (i=t->sizearray; iarray[i]); + t->sizearray = size; +} + + +static void setnodevector (lua_State *L, Table *t, int size) { + int lsize; + if (size == 0) { /* no elements to hash part? */ + t->node = cast(Node *, dummynode); /* use common `dummynode' */ + lsize = 0; + } + else { + int i; + lsize = ceillog2(size); + if (lsize > MAXBITS) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); + t->node = luaM_newvector(L, size, Node); + for (i=0; ilsizenode = cast_byte(lsize); + t->lastfree = gnode(t, size); /* all positions are free */ +} + + +static void resize (lua_State *L, Table *t, int nasize, int nhsize) { + int i; + int oldasize = t->sizearray; + int oldhsize = t->lsizenode; + Node *nold = t->node; /* save old hash ... */ + if (nasize > oldasize) /* array part must grow? */ + setarrayvector(L, t, nasize); + /* create new hash part with appropriate size */ + setnodevector(L, t, nhsize); + if (nasize < oldasize) { /* array part must shrink? */ + t->sizearray = nasize; + /* re-insert elements from vanishing slice */ + for (i=nasize; iarray[i])) + setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); + } + /* shrink array */ + luaM_reallocvector(L, t->array, oldasize, nasize, TValue); + } + /* re-insert elements from hash part */ + for (i = twoto(oldhsize) - 1; i >= 0; i--) { + Node *old = nold+i; + if (!ttisnil(gval(old))) + setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); + } + if (nold != dummynode) + luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ +} + + +void luaH_resizearray (lua_State *L, Table *t, int nasize) { + int nsize = (t->node == dummynode) ? 0 : sizenode(t); + resize(L, t, nasize, nsize); +} + + +static void rehash (lua_State *L, Table *t, const TValue *ek) { + int nasize, na; + int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ + int i; + int totaluse; + for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ + nasize = numusearray(t, nums); /* count keys in array part */ + totaluse = nasize; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ + /* count extra key */ + nasize += countint(ek, nums); + totaluse++; + /* compute new size for array part */ + na = computesizes(nums, &nasize); + /* resize the table to new computed sizes */ + resize(L, t, nasize, totaluse - na); +} + + + +/* +** }============================================================= +*/ + + +Table *luaH_new (lua_State *L, int narray, int nhash) { + Table *t = luaM_new(L, Table); + luaC_link(L, obj2gco(t), LUA_TTABLE); + t->metatable = NULL; + t->flags = cast_byte(~0); + /* temporary values (kept only if some malloc fails) */ + t->array = NULL; + t->sizearray = 0; + t->lsizenode = 0; + t->node = cast(Node *, dummynode); + setarrayvector(L, t, narray); + setnodevector(L, t, nhash); + return t; +} + + +void luaH_free (lua_State *L, Table *t) { + if (t->node != dummynode) + luaM_freearray(L, t->node, sizenode(t), Node); + luaM_freearray(L, t->array, t->sizearray, TValue); + luaM_free(L, t); +} + + +static Node *getfreepos (Table *t) { + while (t->lastfree-- > t->node) { + if (ttisnil(gkey(t->lastfree))) + return t->lastfree; + } + return NULL; /* could not find a free place */ +} + + + +/* +** inserts a new key into a hash table; first, check whether key's main +** position is free. If not, check whether colliding node is in its main +** position or not: if it is not, move colliding node to an empty place and +** put new key in its main position; otherwise (colliding node is in its main +** position), new key goes to an empty position. +*/ +static TValue *newkey (lua_State *L, Table *t, const TValue *key) { + Node *mp = mainposition(t, key); + if (!ttisnil(gval(mp)) || mp == dummynode) { + Node *othern; + Node *n = getfreepos(t); /* get a free place */ + if (n == NULL) { /* cannot find a free place? */ + rehash(L, t, key); /* grow table */ + return luaH_set(L, t, key); /* re-insert key into grown table */ + } + lua_assert(n != dummynode); + othern = mainposition(t, key2tval(mp)); + if (othern != mp) { /* is colliding node out of its main position? */ + /* yes; move colliding node into free position */ + while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ + gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ + *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + gnext(mp) = NULL; /* now `mp' is free */ + setnilvalue(gval(mp)); + } + else { /* colliding node is in its own main position */ + /* new node will go into free position */ + gnext(n) = gnext(mp); /* chain new position */ + gnext(mp) = n; + mp = n; + } + } + gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; + luaC_barriert(L, t, key); + lua_assert(ttisnil(gval(mp))); + return gval(mp); +} + + +/* +** search function for integers +*/ +const TValue *luaH_getnum (Table *t, int key) { + /* (1 <= key && key <= t->sizearray) */ + if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) + return &t->array[key-1]; + else { + lua_Number nk = cast_num(key); + Node *n = hashnum(t, nk); + do { /* check whether `key' is somewhere in the chain */ + if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n); + return luaO_nilobject; + } +} + + +/* +** search function for strings +*/ +const TValue *luaH_getstr (Table *t, TString *key) { + Node *n = hashstr(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n); + return luaO_nilobject; +} + + +/* +** main search function +*/ +const TValue *luaH_get (Table *t, const TValue *key) { + switch (ttype(key)) { + case LUA_TNIL: return luaO_nilobject; + case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); + case LUA_TNUMBER: { + int k; + lua_Number n = nvalue(key); + lua_number2int(k, n); + if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ + return luaH_getnum(t, k); /* use specialized version */ + /* else go through */ + } + default: { + Node *n = mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (luaO_rawequalObj(key2tval(n), key)) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n); + return luaO_nilobject; + } + } +} + + +TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { + const TValue *p = luaH_get(t, key); + t->flags = 0; + if (p != luaO_nilobject) + return cast(TValue *, p); + else { + if (ttisnil(key)) luaG_runerror(L, "table index is nil"); + else if (ttisnumber(key) && luai_numisnan(nvalue(key))) + luaG_runerror(L, "table index is NaN"); + return newkey(L, t, key); + } +} + + +TValue *luaH_setnum (lua_State *L, Table *t, int key) { + const TValue *p = luaH_getnum(t, key); + if (p != luaO_nilobject) + return cast(TValue *, p); + else { + TValue k; + setnvalue(&k, cast_num(key)); + return newkey(L, t, &k); + } +} + + +TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { + const TValue *p = luaH_getstr(t, key); + if (p != luaO_nilobject) + return cast(TValue *, p); + else { + TValue k; + setsvalue(L, &k, key); + return newkey(L, t, &k); + } +} + + +static int unbound_search (Table *t, unsigned int j) { + unsigned int i = j; /* i is zero or a present index */ + j++; + /* find `i' and `j' such that i is present and j is not */ + while (!ttisnil(luaH_getnum(t, j))) { + i = j; + j *= 2; + if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ + /* table was built with bad purposes: resort to linear search */ + i = 1; + while (!ttisnil(luaH_getnum(t, i))) i++; + return i - 1; + } + } + /* now do a binary search between them */ + while (j - i > 1) { + unsigned int m = (i+j)/2; + if (ttisnil(luaH_getnum(t, m))) j = m; + else i = m; + } + return i; +} + + +/* +** Try to find a boundary in table `t'. A `boundary' is an integer index +** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). +*/ +int luaH_getn (Table *t) { + unsigned int j = t->sizearray; + if (j > 0 && ttisnil(&t->array[j - 1])) { + /* there is a boundary in the array part: (binary) search for it */ + unsigned int i = 0; + while (j - i > 1) { + unsigned int m = (i+j)/2; + if (ttisnil(&t->array[m - 1])) j = m; + else i = m; + } + return i; + } + /* else must find a boundary in hash part */ + else if (t->node == dummynode) /* hash part is empty? */ + return j; /* that is easy... */ + else return unbound_search(t, j); +} + + + +#if defined(LUA_DEBUG) + +Node *luaH_mainposition (const Table *t, const TValue *key) { + return mainposition(t, key); +} + +int luaH_isdummy (Node *n) { return n == dummynode; } + +#endif diff --git a/source/fceultra/lua/src/ltable.h b/source/fceultra/lua/src/ltable.h new file mode 100644 index 0000000..f5b9d5e --- /dev/null +++ b/source/fceultra/lua/src/ltable.h @@ -0,0 +1,40 @@ +/* +** $Id: ltable.h,v 2.10.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#ifndef ltable_h +#define ltable_h + +#include "lobject.h" + + +#define gnode(t,i) (&(t)->node[i]) +#define gkey(n) (&(n)->i_key.nk) +#define gval(n) (&(n)->i_val) +#define gnext(n) ((n)->i_key.nk.next) + +#define key2tval(n) (&(n)->i_key.tvk) + + +LUAI_FUNC const TValue *luaH_getnum (Table *t, int key); +LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key); +LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); +LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key); +LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); +LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); +LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash); +LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); +LUAI_FUNC void luaH_free (lua_State *L, Table *t); +LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); +LUAI_FUNC int luaH_getn (Table *t); + + +#if defined(LUA_DEBUG) +LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); +LUAI_FUNC int luaH_isdummy (Node *n); +#endif + + +#endif diff --git a/source/fceultra/lua/src/ltablib.c b/source/fceultra/lua/src/ltablib.c new file mode 100644 index 0000000..b6d9cb4 --- /dev/null +++ b/source/fceultra/lua/src/ltablib.c @@ -0,0 +1,287 @@ +/* +** $Id: ltablib.c,v 1.38.1.3 2008/02/14 16:46:58 roberto Exp $ +** Library for Table Manipulation +** See Copyright Notice in lua.h +*/ + + +#include + +#define ltablib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) + + +static int foreachi (lua_State *L) { + int i; + int n = aux_getn(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + for (i=1; i <= n; i++) { + lua_pushvalue(L, 2); /* function */ + lua_pushinteger(L, i); /* 1st argument */ + lua_rawgeti(L, 1, i); /* 2nd argument */ + lua_call(L, 2, 1); + if (!lua_isnil(L, -1)) + return 1; + lua_pop(L, 1); /* remove nil result */ + } + return 0; +} + + +static int foreach (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_pushnil(L); /* first key */ + while (lua_next(L, 1)) { + lua_pushvalue(L, 2); /* function */ + lua_pushvalue(L, -3); /* key */ + lua_pushvalue(L, -3); /* value */ + lua_call(L, 2, 1); + if (!lua_isnil(L, -1)) + return 1; + lua_pop(L, 2); /* remove value and result */ + } + return 0; +} + + +static int maxn (lua_State *L) { + lua_Number max = 0; + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushnil(L); /* first key */ + while (lua_next(L, 1)) { + lua_pop(L, 1); /* remove value */ + if (lua_type(L, -1) == LUA_TNUMBER) { + lua_Number v = lua_tonumber(L, -1); + if (v > max) max = v; + } + } + lua_pushnumber(L, max); + return 1; +} + + +static int getn (lua_State *L) { + lua_pushinteger(L, aux_getn(L, 1)); + return 1; +} + + +static int setn (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); +#ifndef luaL_setn + luaL_setn(L, 1, luaL_checkint(L, 2)); +#else + luaL_error(L, LUA_QL("setn") " is obsolete"); +#endif + lua_pushvalue(L, 1); + return 1; +} + + +static int tinsert (lua_State *L) { + int e = aux_getn(L, 1) + 1; /* first empty element */ + int pos; /* where to insert new element */ + switch (lua_gettop(L)) { + case 2: { /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: { + int i; + pos = luaL_checkint(L, 2); /* 2nd argument is the position */ + if (pos > e) e = pos; /* `grow' array if necessary */ + for (i = e; i > pos; i--) { /* move up elements */ + lua_rawgeti(L, 1, i-1); + lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ + } + break; + } + default: { + return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); + } + } + luaL_setn(L, 1, e); /* new size */ + lua_rawseti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int tremove (lua_State *L) { + int e = aux_getn(L, 1); + int pos = luaL_optint(L, 2, e); + if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ + return 0; /* nothing to remove */ + luaL_setn(L, 1, e - 1); /* t.n = n-1 */ + lua_rawgeti(L, 1, pos); /* result = t[pos] */ + for ( ;pos= P */ + while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i>u) luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* repeat --j until a[j] <= P */ + while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j + +#define ltm_c +#define LUA_CORE + +#include "lua.h" + +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + + +const char *const luaT_typenames[] = { + "nil", "boolean", "userdata", "number", + "string", "table", "function", "userdata", "thread", + "proto", "upval" +}; + + +void luaT_init (lua_State *L) { + static const char *const luaT_eventname[] = { /* ORDER TM */ + "__index", "__newindex", + "__gc", "__mode", "__eq", + "__add", "__sub", "__mul", "__div", "__mod", + "__pow", "__unm", "__len", "__lt", "__le", + "__concat", "__call" + }; + int i; + for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); + luaS_fix(G(L)->tmname[i]); /* never collect these names */ + } +} + + +/* +** function to be used with macro "fasttm": optimized for absence of +** tag methods +*/ +const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { + const TValue *tm = luaH_getstr(events, ename); + lua_assert(event <= TM_EQ); + if (ttisnil(tm)) { /* no tag method? */ + events->flags |= cast_byte(1u<metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(o)->metatable; + break; + default: + mt = G(L)->mt[ttype(o)]; + } + return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); +} + diff --git a/source/fceultra/lua/src/ltm.h b/source/fceultra/lua/src/ltm.h new file mode 100644 index 0000000..64343b7 --- /dev/null +++ b/source/fceultra/lua/src/ltm.h @@ -0,0 +1,54 @@ +/* +** $Id: ltm.h,v 2.6.1.1 2007/12/27 13:02:25 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#ifndef ltm_h +#define ltm_h + + +#include "lobject.h" + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER TM" +*/ +typedef enum { + TM_INDEX, + TM_NEWINDEX, + TM_GC, + TM_MODE, + TM_EQ, /* last tag method with `fast' access */ + TM_ADD, + TM_SUB, + TM_MUL, + TM_DIV, + TM_MOD, + TM_POW, + TM_UNM, + TM_LEN, + TM_LT, + TM_LE, + TM_CONCAT, + TM_CALL, + TM_N /* number of elements in the enum */ +} TMS; + + + +#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ + ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) + +#define fasttm(l,et,e) gfasttm(G(l), et, e) + +LUAI_DATA const char *const luaT_typenames[]; + + +LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); +LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, + TMS event); +LUAI_FUNC void luaT_init (lua_State *L); + +#endif diff --git a/source/fceultra/lua/src/lua.c b/source/fceultra/lua/src/lua.c new file mode 100644 index 0000000..3a46609 --- /dev/null +++ b/source/fceultra/lua/src/lua.c @@ -0,0 +1,392 @@ +/* +** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $ +** Lua stand-alone interpreter +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define lua_c + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +static lua_State *globalL = NULL; + +static const char *progname = LUA_PROGNAME; + + + +static void lstop (lua_State *L, lua_Debug *ar) { + (void)ar; /* unused arg. */ + lua_sethook(L, NULL, 0, 0); + luaL_error(L, "interrupted!"); +} + + +static void laction (int i) { + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, + terminate process (default action) */ + lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); +} + + +static void print_usage (void) { + fprintf(stderr, + "usage: %s [options] [script [args]].\n" + "Available options are:\n" + " -e stat execute string " LUA_QL("stat") "\n" + " -l name require library " LUA_QL("name") "\n" + " -i enter interactive mode after executing " LUA_QL("script") "\n" + " -v show version information\n" + " -- stop handling options\n" + " - execute stdin and stop handling options\n" + , + progname); + fflush(stderr); +} + + +static void l_message (const char *pname, const char *msg) { + if (pname) fprintf(stderr, "%s: ", pname); + fprintf(stderr, "%s\n", msg); + fflush(stderr); +} + + +static int report (lua_State *L, int status) { + if (status && !lua_isnil(L, -1)) { + const char *msg = lua_tostring(L, -1); + if (msg == NULL) msg = "(error object is not a string)"; + l_message(progname, msg); + lua_pop(L, 1); + } + return status; +} + + +static int traceback (lua_State *L) { + if (!lua_isstring(L, 1)) /* 'message' not a string? */ + return 1; /* keep it intact */ + lua_getfield(L, LUA_GLOBALSINDEX, "debug"); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + return 1; + } + lua_getfield(L, -1, "traceback"); + if (!lua_isfunction(L, -1)) { + lua_pop(L, 2); + return 1; + } + lua_pushvalue(L, 1); /* pass error message */ + lua_pushinteger(L, 2); /* skip this function and traceback */ + lua_call(L, 2, 1); /* call debug.traceback */ + return 1; +} + + +static int docall (lua_State *L, int narg, int clear) { + int status; + int base = lua_gettop(L) - narg; /* function index */ + lua_pushcfunction(L, traceback); /* push traceback function */ + lua_insert(L, base); /* put it under chunk and args */ + signal(SIGINT, laction); + status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); + signal(SIGINT, SIG_DFL); + lua_remove(L, base); /* remove traceback function */ + /* force a complete garbage collection in case of errors */ + if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); + return status; +} + + +static void print_version (void) { + l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT); +} + + +static int getargs (lua_State *L, char **argv, int n) { + int narg; + int i; + int argc = 0; + while (argv[argc]) argc++; /* count total number of arguments */ + narg = argc - (n + 1); /* number of arguments to the script */ + luaL_checkstack(L, narg + 3, "too many arguments to script"); + for (i=n+1; i < argc; i++) + lua_pushstring(L, argv[i]); + lua_createtable(L, narg, n + 1); + for (i=0; i < argc; i++) { + lua_pushstring(L, argv[i]); + lua_rawseti(L, -2, i - n); + } + return narg; +} + + +static int dofile (lua_State *L, const char *name) { + int status = luaL_loadfile(L, name) || docall(L, 0, 1); + return report(L, status); +} + + +static int dostring (lua_State *L, const char *s, const char *name) { + int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); + return report(L, status); +} + + +static int dolibrary (lua_State *L, const char *name) { + lua_getglobal(L, "require"); + lua_pushstring(L, name); + return report(L, docall(L, 1, 1)); +} + + +static const char *get_prompt (lua_State *L, int firstline) { + const char *p; + lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); + p = lua_tostring(L, -1); + if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); + lua_pop(L, 1); /* remove global */ + return p; +} + + +static int incomplete (lua_State *L, int status) { + if (status == LUA_ERRSYNTAX) { + size_t lmsg; + const char *msg = lua_tolstring(L, -1, &lmsg); + const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); + if (strstr(msg, LUA_QL("")) == tp) { + lua_pop(L, 1); + return 1; + } + } + return 0; /* else... */ +} + + +static int pushline (lua_State *L, int firstline) { + char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + if (lua_readline(L, b, prmt) == 0) + return 0; /* no input */ + l = strlen(b); + if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ + b[l-1] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* first line starts with `=' ? */ + lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ + else + lua_pushstring(L, b); + lua_freeline(L, b); + return 1; +} + + +static int loadline (lua_State *L) { + int status; + lua_settop(L, 0); + if (!pushline(L, 1)) + return -1; /* no input */ + for (;;) { /* repeat until gets a complete line */ + status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + if (!incomplete(L, status)) break; /* cannot try to add lines? */ + if (!pushline(L, 0)) /* no more input? */ + return -1; + lua_pushliteral(L, "\n"); /* add a new line... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } + lua_saveline(L, 1); + lua_remove(L, 1); /* remove line */ + return status; +} + + +static void dotty (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; + while ((status = loadline(L)) != -1) { + if (status == 0) status = docall(L, 0, 0); + report(L, status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(progname, lua_pushfstring(L, + "error calling " LUA_QL("print") " (%s)", + lua_tostring(L, -1))); + } + } + lua_settop(L, 0); /* clear stack */ + fputs("\n", stdout); + fflush(stdout); + progname = oldprogname; +} + + +static int handle_script (lua_State *L, char **argv, int n) { + int status; + const char *fname; + int narg = getargs(L, argv, n); /* collect arguments */ + lua_setglobal(L, "arg"); + fname = argv[n]; + if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + fname = NULL; /* stdin */ + status = luaL_loadfile(L, fname); + lua_insert(L, -(narg+1)); + if (status == 0) + status = docall(L, narg, 0); + else + lua_pop(L, narg); + return report(L, status); +} + + +/* check that argument has no extra characters at the end */ +#define notail(x) {if ((x)[2] != '\0') return -1;} + + +static int collectargs (char **argv, int *pi, int *pv, int *pe) { + int i; + for (i = 1; argv[i] != NULL; i++) { + if (argv[i][0] != '-') /* not an option? */ + return i; + switch (argv[i][1]) { /* option */ + case '-': + notail(argv[i]); + return (argv[i+1] != NULL ? i+1 : 0); + case '\0': + return i; + case 'i': + notail(argv[i]); + *pi = 1; /* go through */ + case 'v': + notail(argv[i]); + *pv = 1; + break; + case 'e': + *pe = 1; /* go through */ + case 'l': + if (argv[i][2] == '\0') { + i++; + if (argv[i] == NULL) return -1; + } + break; + default: return -1; /* invalid option */ + } + } + return 0; +} + + +static int runargs (lua_State *L, char **argv, int n) { + int i; + for (i = 1; i < n; i++) { + if (argv[i] == NULL) continue; + lua_assert(argv[i][0] == '-'); + switch (argv[i][1]) { /* option */ + case 'e': { + const char *chunk = argv[i] + 2; + if (*chunk == '\0') chunk = argv[++i]; + lua_assert(chunk != NULL); + if (dostring(L, chunk, "=(command line)") != 0) + return 1; + break; + } + case 'l': { + const char *filename = argv[i] + 2; + if (*filename == '\0') filename = argv[++i]; + lua_assert(filename != NULL); + if (dolibrary(L, filename)) + return 1; /* stop if file fails */ + break; + } + default: break; + } + } + return 0; +} + + +static int handle_luainit (lua_State *L) { + const char *init = getenv(LUA_INIT); + if (init == NULL) return 0; /* status OK */ + else if (init[0] == '@') + return dofile(L, init+1); + else + return dostring(L, init, "=" LUA_INIT); +} + + +struct Smain { + int argc; + char **argv; + int status; +}; + + +static int pmain (lua_State *L) { + struct Smain *s = (struct Smain *)lua_touserdata(L, 1); + char **argv = s->argv; + int script; + int has_i = 0, has_v = 0, has_e = 0; + globalL = L; + if (argv[0] && argv[0][0]) progname = argv[0]; + lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ + luaL_openlibs(L); /* open libraries */ + lua_gc(L, LUA_GCRESTART, 0); + s->status = handle_luainit(L); + if (s->status != 0) return 0; + script = collectargs(argv, &has_i, &has_v, &has_e); + if (script < 0) { /* invalid args? */ + print_usage(); + s->status = 1; + return 0; + } + if (has_v) print_version(); + s->status = runargs(L, argv, (script > 0) ? script : s->argc); + if (s->status != 0) return 0; + if (script) + s->status = handle_script(L, argv, script); + if (s->status != 0) return 0; + if (has_i) + dotty(L); + else if (script == 0 && !has_e && !has_v) { + if (lua_stdin_is_tty()) { + print_version(); + dotty(L); + } + else dofile(L, NULL); /* executes stdin as a file */ + } + return 0; +} + + +int main (int argc, char **argv) { + int status; + struct Smain s; + lua_State *L = lua_open(); /* create state */ + if (L == NULL) { + l_message(argv[0], "cannot create state: not enough memory"); + return EXIT_FAILURE; + } + s.argc = argc; + s.argv = argv; + status = lua_cpcall(L, &pmain, &s); + report(L, status); + lua_close(L); + return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; +} + diff --git a/source/fceultra/lua/src/lua.h b/source/fceultra/lua/src/lua.h new file mode 100644 index 0000000..e4bdfd3 --- /dev/null +++ b/source/fceultra/lua/src/lua.h @@ -0,0 +1,388 @@ +/* +** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $ +** Lua - An Extensible Extension Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ + + +#ifndef lua_h +#define lua_h + +#include +#include + + +#include "luaconf.h" + + +#define LUA_VERSION "Lua 5.1" +#define LUA_RELEASE "Lua 5.1.4" +#define LUA_VERSION_NUM 501 +#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" + + +/* mark for precompiled code (`Lua') */ +#define LUA_SIGNATURE "\033Lua" + +/* option for multiple returns in `lua_pcall' and `lua_call' */ +#define LUA_MULTRET (-1) + + +/* +** pseudo-indices +*/ +#define LUA_REGISTRYINDEX (-10000) +#define LUA_ENVIRONINDEX (-10001) +#define LUA_GLOBALSINDEX (-10002) +#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) + + +/* thread status; 0 is OK */ +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRERR 5 + + +typedef struct lua_State lua_State; + +typedef int (*lua_CFunction) (lua_State *L); + + +/* +** functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); + + +/* +** prototype for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + + +/* +** basic types +*/ +#define LUA_TNONE (-1) + +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +typedef LUA_INTEGER lua_Integer; + + + +/* +** state manipulation +*/ +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API void (lua_close) (lua_State *L); +LUA_API lua_State *(lua_newthread) (lua_State *L); + +LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + + +/* +** basic stack manipulation +*/ +LUA_API int (lua_gettop) (lua_State *L); +LUA_API void (lua_settop) (lua_State *L, int idx); +LUA_API void (lua_pushvalue) (lua_State *L, int idx); +LUA_API void (lua_remove) (lua_State *L, int idx); +LUA_API void (lua_insert) (lua_State *L, int idx); +LUA_API void (lua_replace) (lua_State *L, int idx); +LUA_API int (lua_checkstack) (lua_State *L, int sz); + +LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); + + +/* +** access functions (stack -> C) +*/ + +LUA_API int (lua_isnumber) (lua_State *L, int idx); +LUA_API int (lua_isstring) (lua_State *L, int idx); +LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isuserdata) (lua_State *L, int idx); +LUA_API int (lua_type) (lua_State *L, int idx); +LUA_API const char *(lua_typename) (lua_State *L, int tp); + +LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); + +LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); +LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); +LUA_API int (lua_toboolean) (lua_State *L, int idx); +LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); +LUA_API size_t (lua_objlen) (lua_State *L, int idx); +LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); +LUA_API void *(lua_touserdata) (lua_State *L, int idx); +LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); +LUA_API const void *(lua_topointer) (lua_State *L, int idx); + + +/* +** push functions (C -> stack) +*/ +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); +LUA_API void (lua_pushstring) (lua_State *L, const char *s); +LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); +LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean) (lua_State *L, int b); +LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); +LUA_API int (lua_pushthread) (lua_State *L); + + +/* +** get functions (Lua -> stack) +*/ +LUA_API void (lua_gettable) (lua_State *L, int idx); +LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawget) (lua_State *L, int idx); +LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); +LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); +LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); +LUA_API int (lua_getmetatable) (lua_State *L, int objindex); +LUA_API void (lua_getfenv) (lua_State *L, int idx); + + +/* +** set functions (stack -> Lua) +*/ +LUA_API void (lua_settable) (lua_State *L, int idx); +LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawset) (lua_State *L, int idx); +LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); +LUA_API int (lua_setmetatable) (lua_State *L, int objindex); +LUA_API int (lua_setfenv) (lua_State *L, int idx); + + +/* +** `load' and `call' functions (load and run Lua code) +*/ +LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); +LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); +LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); +LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname); + +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); + + +/* +** coroutine functions +*/ +LUA_API int (lua_yield) (lua_State *L, int nresults); +LUA_API int (lua_resume) (lua_State *L, int narg); +LUA_API int (lua_status) (lua_State *L); + +/* +** garbage-collection function and options +*/ + +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 +#define LUA_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 + +LUA_API int (lua_gc) (lua_State *L, int what, int data); + + +/* +** miscellaneous functions +*/ + +LUA_API int (lua_error) (lua_State *L); + +LUA_API int (lua_next) (lua_State *L, int idx); + +LUA_API void (lua_concat) (lua_State *L, int n); + +LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#define lua_newtable(L) lua_createtable(L, 0, 0) + +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) + +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) + +#define lua_strlen(L,i) lua_objlen(L, (i)) + +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) +#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) +#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) + +#define lua_pushliteral(L, s) \ + lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) + +#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) +#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) + +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + + + +/* +** compatibility macros and functions +*/ + +#define lua_open() luaL_newstate() + +#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) + +#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) + +#define lua_Chunkreader lua_Reader +#define lua_Chunkwriter lua_Writer + + +/* hack */ +LUA_API void lua_setlevel (lua_State *from, lua_State *to); + + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILRET 4 + + +/* +** Event masks +*/ +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) + +typedef struct lua_Debug lua_Debug; /* activation record */ + + +/* Functions to be called by the debuger in specific events */ +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); + +LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook lua_gethook (lua_State *L); +LUA_API int lua_gethookmask (lua_State *L); +LUA_API int lua_gethookcount (lua_State *L); + + +struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) `global', `local', `field', `method' */ + const char *what; /* (S) `Lua', `C', `main', `tail' */ + const char *source; /* (S) */ + int currentline; /* (l) */ + int nups; /* (u) number of upvalues */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + int i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. +* +* 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. +******************************************************************************/ + + +#endif diff --git a/source/fceultra/lua/src/luac.c b/source/fceultra/lua/src/luac.c new file mode 100644 index 0000000..d070173 --- /dev/null +++ b/source/fceultra/lua/src/luac.c @@ -0,0 +1,200 @@ +/* +** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $ +** Lua compiler (saves bytecodes to files; also list bytecodes) +** See Copyright Notice in lua.h +*/ + +#include +#include +#include +#include + +#define luac_c +#define LUA_CORE + +#include "lua.h" +#include "lauxlib.h" + +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstring.h" +#include "lundump.h" + +#define PROGNAME "luac" /* default program name */ +#define OUTPUT PROGNAME ".out" /* default output file */ + +static int listing=0; /* list bytecodes? */ +static int dumping=1; /* dump bytecodes? */ +static int stripping=0; /* strip debug information? */ +static char Output[]={ OUTPUT }; /* default output file name */ +static const char* output=Output; /* actual output file name */ +static const char* progname=PROGNAME; /* actual program name */ + +static void fatal(const char* message) +{ + fprintf(stderr,"%s: %s\n",progname,message); + exit(EXIT_FAILURE); +} + +static void cannot(const char* what) +{ + fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); + exit(EXIT_FAILURE); +} + +static void usage(const char* message) +{ + if (*message=='-') + fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); + else + fprintf(stderr,"%s: %s\n",progname,message); + fprintf(stderr, + "usage: %s [options] [filenames].\n" + "Available options are:\n" + " - process stdin\n" + " -l list\n" + " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" + " -p parse only\n" + " -s strip debug information\n" + " -v show version information\n" + " -- stop handling options\n", + progname,Output); + exit(EXIT_FAILURE); +} + +#define IS(s) (strcmp(argv[i],s)==0) + +static int doargs(int argc, char* argv[]) +{ + int i; + int version=0; + if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; + for (i=1; itop+(i))->l.p) + +static const Proto* combine(lua_State* L, int n) +{ + if (n==1) + return toproto(L,-1); + else + { + int i,pc; + Proto* f=luaF_newproto(L); + setptvalue2s(L,L->top,f); incr_top(L); + f->source=luaS_newliteral(L,"=(" PROGNAME ")"); + f->maxstacksize=1; + pc=2*n+1; + f->code=luaM_newvector(L,pc,Instruction); + f->sizecode=pc; + f->p=luaM_newvector(L,n,Proto*); + f->sizep=n; + pc=0; + for (i=0; ip[i]=toproto(L,i-n-1); + f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i); + f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1); + } + f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0); + return f; + } +} + +static int writer(lua_State* L, const void* p, size_t size, void* u) +{ + UNUSED(L); + return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); +} + +struct Smain { + int argc; + char** argv; +}; + +static int pmain(lua_State* L) +{ + struct Smain* s = (struct Smain*)lua_touserdata(L, 1); + int argc=s->argc; + char** argv=s->argv; + const Proto* f; + int i; + if (!lua_checkstack(L,argc)) fatal("too many input files"); + for (i=0; i1); + if (dumping) + { + FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); + if (D==NULL) cannot("open"); + lua_lock(L); + luaU_dump(L,f,writer,D,stripping); + lua_unlock(L); + if (ferror(D)) cannot("write"); + if (fclose(D)) cannot("close"); + } + return 0; +} + +int main(int argc, char* argv[]) +{ + lua_State* L; + struct Smain s; + int i=doargs(argc,argv); + argc-=i; argv+=i; + if (argc<=0) usage("no input files given"); + L=lua_open(); + if (L==NULL) fatal("not enough memory for state"); + s.argc=argc; + s.argv=argv; + if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1)); + lua_close(L); + return EXIT_SUCCESS; +} diff --git a/source/fceultra/lua/src/luaconf.h b/source/fceultra/lua/src/luaconf.h new file mode 100644 index 0000000..e2cb261 --- /dev/null +++ b/source/fceultra/lua/src/luaconf.h @@ -0,0 +1,763 @@ +/* +** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef lconfig_h +#define lconfig_h + +#include +#include + + +/* +** ================================================================== +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + + +/* +@@ LUA_ANSI controls the use of non-ansi features. +** CHANGE it (define it) if you want Lua to avoid the use of any +** non-ansi feature or library. +*/ +#if defined(__STRICT_ANSI__) +#define LUA_ANSI +#endif + + +#if !defined(LUA_ANSI) && defined(_WIN32) +#define LUA_WIN +#endif + +#if defined(LUA_USE_LINUX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ +#define LUA_USE_READLINE /* needs some extra libraries */ +#endif + +#if defined(LUA_USE_MACOSX) +#define LUA_USE_POSIX +#define LUA_DL_DYLD /* does not need extra library */ +#endif + + + +/* +@@ LUA_USE_POSIX includes all functionallity listed as X/Open System +@* Interfaces Extension (XSI). +** CHANGE it (define it) if your system is XSI compatible. +*/ +#if defined(LUA_USE_POSIX) +#define LUA_USE_MKSTEMP +#define LUA_USE_ISATTY +#define LUA_USE_POPEN +#define LUA_USE_ULONGJMP +#endif + + +/* +@@ LUA_PATH and LUA_CPATH are the names of the environment variables that +@* Lua check to set its paths. +@@ LUA_INIT is the name of the environment variable that Lua +@* checks for initialization code. +** CHANGE them if you want different names. +*/ +#define LUA_PATH "LUA_PATH" +#define LUA_CPATH "LUA_CPATH" +#define LUA_INIT "LUA_INIT" + + +/* +@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for +@* Lua libraries. +@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for +@* C libraries. +** CHANGE them if your machine has a non-conventional directory +** hierarchy or if you want to install your libraries in +** non-conventional directories. +*/ +#if defined(_WIN32) +/* +** In Windows, any exclamation mark ('!') in the path is replaced by the +** path of the directory of the executable file of the current process. +*/ +#define LUA_LDIR "!\\lua\\" +#define LUA_CDIR "!\\" +#define LUA_PATH_DEFAULT \ + ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua" +#define LUA_CPATH_DEFAULT \ + ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" + +#else +#define LUA_ROOT "/usr/local/" +#define LUA_LDIR LUA_ROOT "share/lua/5.1/" +#define LUA_CDIR LUA_ROOT "lib/lua/5.1/" +#define LUA_PATH_DEFAULT \ + "./?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua" +#define LUA_CPATH_DEFAULT \ + "./?.so;" LUA_CDIR"?.so;" LUA_CDIR"loadall.so" +#endif + + +/* +@@ LUA_DIRSEP is the directory separator (for submodules). +** CHANGE it if your machine does not use "/" as the directory separator +** and is not Windows. (On Windows Lua automatically uses "\".) +*/ +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else +#define LUA_DIRSEP "/" +#endif + + +/* +@@ LUA_PATHSEP is the character that separates templates in a path. +@@ LUA_PATH_MARK is the string that marks the substitution points in a +@* template. +@@ LUA_EXECDIR in a Windows path is replaced by the executable's +@* directory. +@@ LUA_IGMARK is a mark to ignore all before it when bulding the +@* luaopen_ function name. +** CHANGE them if for some reason your system cannot use those +** characters. (E.g., if one of those characters is a common character +** in file/directory names.) Probably you do not need to change them. +*/ +#define LUA_PATHSEP ";" +#define LUA_PATH_MARK "?" +#define LUA_EXECDIR "!" +#define LUA_IGMARK "-" + + +/* +@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. +** CHANGE that if ptrdiff_t is not adequate on your machine. (On most +** machines, ptrdiff_t gives a good choice between int or long.) +*/ +#define LUA_INTEGER ptrdiff_t + + +/* +@@ LUA_API is a mark for all core API functions. +@@ LUALIB_API is a mark for all standard library functions. +** CHANGE them if you need to define those functions in some special way. +** For instance, if you want to create one Windows DLL with the core and +** the libraries, you may want to use the following definition (define +** LUA_BUILD_AS_DLL to get it). +*/ +#if defined(LUA_BUILD_AS_DLL) + +#if defined(LUA_CORE) || defined(LUA_LIB) +#define LUA_API __declspec(dllexport) +#else +#define LUA_API __declspec(dllimport) +#endif + +#else + +#define LUA_API extern + +#endif + +/* more often than not the libs go together with the core */ +#define LUALIB_API LUA_API + + +/* +@@ LUAI_FUNC is a mark for all extern functions that are not to be +@* exported to outside modules. +@@ LUAI_DATA is a mark for all extern (const) variables that are not to +@* be exported to outside modules. +** CHANGE them if you need to mark them in some special way. Elf/gcc +** (versions 3.2 and later) mark them as "hidden" to optimize access +** when Lua is compiled as a shared library. +*/ +#if defined(luaall_c) +#define LUAI_FUNC static +#define LUAI_DATA /* empty */ + +#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) +#define LUAI_FUNC __attribute__((visibility("hidden"))) extern +#define LUAI_DATA LUAI_FUNC + +#else +#define LUAI_FUNC extern +#define LUAI_DATA extern +#endif + + + +/* +@@ LUA_QL describes how error messages quote program elements. +** CHANGE it if you want a different appearance. +*/ +#define LUA_QL(x) "'" x "'" +#define LUA_QS LUA_QL("%s") + + +/* +@@ LUA_IDSIZE gives the maximum size for the description of the source +@* of a function in debug information. +** CHANGE it if you want a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +** {================================================================== +** Stand-alone configuration +** =================================================================== +*/ + +#if defined(lua_c) || defined(luaall_c) + +/* +@@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that +@* is, whether we're running lua interactively). +** CHANGE it if you have a better definition for non-POSIX/non-Windows +** systems. +*/ +#if defined(LUA_USE_ISATTY) +#include +#define lua_stdin_is_tty() isatty(0) +#elif defined(LUA_WIN) +#include +#include +#define lua_stdin_is_tty() _isatty(_fileno(stdin)) +#else +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ +#endif + + +/* +@@ LUA_PROMPT is the default prompt used by stand-alone Lua. +@@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. +** CHANGE them if you want different prompts. (You can also change the +** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) +*/ +#define LUA_PROMPT "> " +#define LUA_PROMPT2 ">> " + + +/* +@@ LUA_PROGNAME is the default name for the stand-alone Lua program. +** CHANGE it if your stand-alone interpreter has a different name and +** your system is not able to detect that name automatically. +*/ +#define LUA_PROGNAME "lua" + + +/* +@@ LUA_MAXINPUT is the maximum length for an input line in the +@* stand-alone interpreter. +** CHANGE it if you need longer lines. +*/ +#define LUA_MAXINPUT 512 + + +/* +@@ lua_readline defines how to show a prompt and then read a line from +@* the standard input. +@@ lua_saveline defines how to "save" a read line in a "history". +@@ lua_freeline defines how to free a line read by lua_readline. +** CHANGE them if you want to improve this functionality (e.g., by using +** GNU readline and history facilities). +*/ +#if defined(LUA_USE_READLINE) +#include +#include +#include +#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_saveline(L,idx) \ + if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ + add_history(lua_tostring(L, idx)); /* add it to history */ +#define lua_freeline(L,b) ((void)L, free(b)) +#else +#define lua_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } +#endif + +#endif + +/* }================================================================== */ + + +/* +@@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles +@* as a percentage. +** CHANGE it if you want the GC to run faster or slower (higher values +** mean larger pauses which mean slower collection.) You can also change +** this value dynamically. +*/ +#define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */ + + +/* +@@ LUAI_GCMUL defines the default speed of garbage collection relative to +@* memory allocation as a percentage. +** CHANGE it if you want to change the granularity of the garbage +** collection. (Higher values mean coarser collections. 0 represents +** infinity, where each step performs a full collection.) You can also +** change this value dynamically. +*/ +#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ + + + +/* +@@ LUA_COMPAT_GETN controls compatibility with old getn behavior. +** CHANGE it (define it) if you want exact compatibility with the +** behavior of setn/getn in Lua 5.0. +*/ +#undef LUA_COMPAT_GETN + +/* +@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. +** CHANGE it to undefined as soon as you do not need a global 'loadlib' +** function (the function is still available as 'package.loadlib'). +*/ +#undef LUA_COMPAT_LOADLIB + +/* +@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. +** CHANGE it to undefined as soon as your programs use only '...' to +** access vararg parameters (instead of the old 'arg' table). +*/ +#define LUA_COMPAT_VARARG + +/* +@@ LUA_COMPAT_MOD controls compatibility with old math.mod function. +** CHANGE it to undefined as soon as your programs use 'math.fmod' or +** the new '%' operator instead of 'math.mod'. +*/ +#define LUA_COMPAT_MOD + +/* +@@ LUA_COMPAT_LSTR controls compatibility with old long string nesting +@* facility. +** CHANGE it to 2 if you want the old behaviour, or undefine it to turn +** off the advisory error when nesting [[...]]. +*/ +#define LUA_COMPAT_LSTR 1 + +/* +@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. +** CHANGE it to undefined as soon as you rename 'string.gfind' to +** 'string.gmatch'. +*/ +#define LUA_COMPAT_GFIND + +/* +@@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' +@* behavior. +** CHANGE it to undefined as soon as you replace to 'luaL_register' +** your uses of 'luaL_openlib' +*/ +#define LUA_COMPAT_OPENLIB + + + +/* +@@ luai_apicheck is the assert macro used by the Lua-C API. +** CHANGE luai_apicheck if you want Lua to perform some checks in the +** parameters it gets from API calls. This may slow down the interpreter +** a bit, but may be quite useful when debugging C code that interfaces +** with Lua. A useful redefinition is to use assert.h. +*/ +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(L,o) { (void)L; assert(o); } +#else +#define luai_apicheck(L,o) { (void)L; } +#endif + + +/* +@@ LUAI_BITSINT defines the number of bits in an int. +** CHANGE here if Lua cannot automatically detect the number of bits of +** your machine. Probably you do not need to change this. +*/ +/* avoid overflows in comparison */ +#if INT_MAX-20 < 32760 +#define LUAI_BITSINT 16 +#elif INT_MAX > 2147483640L +/* int has at least 32 bits */ +#define LUAI_BITSINT 32 +#else +#error "you must define LUA_BITSINT with number of bits in an integer" +#endif + + +/* +@@ LUAI_UINT32 is an unsigned integer with at least 32 bits. +@@ LUAI_INT32 is an signed integer with at least 32 bits. +@@ LUAI_UMEM is an unsigned integer big enough to count the total +@* memory used by Lua. +@@ LUAI_MEM is a signed integer big enough to count the total memory +@* used by Lua. +** CHANGE here if for some weird reason the default definitions are not +** good enough for your machine. (The definitions in the 'else' +** part always works, but may waste space on machines with 64-bit +** longs.) Probably you do not need to change this. +*/ +#if LUAI_BITSINT >= 32 +#define LUAI_UINT32 unsigned int +#define LUAI_INT32 int +#define LUAI_MAXINT32 INT_MAX +#define LUAI_UMEM size_t +#define LUAI_MEM ptrdiff_t +#else +/* 16-bit ints */ +#define LUAI_UINT32 unsigned long +#define LUAI_INT32 long +#define LUAI_MAXINT32 LONG_MAX +#define LUAI_UMEM unsigned long +#define LUAI_MEM long +#endif + + +/* +@@ LUAI_MAXCALLS limits the number of nested calls. +** CHANGE it if you need really deep recursive calls. This limit is +** arbitrary; its only purpose is to stop infinite recursion before +** exhausting memory. +*/ +#define LUAI_MAXCALLS 20000 + + +/* +@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function +@* can use. +** CHANGE it if you need lots of (Lua) stack space for your C +** functions. This limit is arbitrary; its only purpose is to stop C +** functions to consume unlimited stack space. (must be smaller than +** -LUA_REGISTRYINDEX) +*/ +#define LUAI_MAXCSTACK 8000 + + + +/* +** {================================================================== +** CHANGE (to smaller values) the following definitions if your system +** has a small C stack. (Or you may want to change them to larger +** values if your system has a large C stack and these limits are +** too rigid for you.) Some of these constants control the size of +** stack-allocated arrays used by the compiler or the interpreter, while +** others limit the maximum number of recursive calls that the compiler +** or the interpreter can perform. Values too large may cause a C stack +** overflow for some forms of deep constructs. +** =================================================================== +*/ + + +/* +@@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and +@* syntactical nested non-terminals in a program. +*/ +#define LUAI_MAXCCALLS 200 + + +/* +@@ LUAI_MAXVARS is the maximum number of local variables per function +@* (must be smaller than 250). +*/ +#define LUAI_MAXVARS 200 + + +/* +@@ LUAI_MAXUPVALUES is the maximum number of upvalues per function +@* (must be smaller than 250). +*/ +#define LUAI_MAXUPVALUES 60 + + +/* +@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. +*/ +#define LUAL_BUFFERSIZE BUFSIZ + +/* }================================================================== */ + + + + +/* +** {================================================================== +@@ LUA_NUMBER is the type of numbers in Lua. +** CHANGE the following definitions only if you want to build Lua +** with a number type different from double. You may also need to +** change lua_number2int & lua_number2integer. +** =================================================================== +*/ + +#define LUA_NUMBER_DOUBLE +#define LUA_NUMBER double + +/* +@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' +@* over a number. +*/ +#define LUAI_UACNUMBER double + + +/* +@@ LUA_NUMBER_SCAN is the format for reading numbers. +@@ LUA_NUMBER_FMT is the format for writing numbers. +@@ lua_number2str converts a number to a string. +@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. +@@ lua_str2number converts a string to a number. +*/ +#define LUA_NUMBER_SCAN "%lf" +#define LUA_NUMBER_FMT "%.14g" +#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) +#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ +#define lua_str2number(s,p) strtod((s), (p)) + + +/* +@@ The luai_num* macros define the primitive operations over numbers. +*/ +#if defined(LUA_CORE) +#include +#define luai_numadd(a,b) ((a)+(b)) +#define luai_numsub(a,b) ((a)-(b)) +#define luai_nummul(a,b) ((a)*(b)) +#define luai_numdiv(a,b) ((a)/(b)) +#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) +#define luai_numpow(a,b) (pow(a,b)) +#define luai_numunm(a) (-(a)) +#define luai_numeq(a,b) ((a)==(b)) +#define luai_numlt(a,b) ((a)<(b)) +#define luai_numle(a,b) ((a)<=(b)) +#define luai_numisnan(a) (!luai_numeq((a), (a))) +#endif + + +/* +@@ lua_number2int is a macro to convert lua_Number to int. +@@ lua_number2integer is a macro to convert lua_Number to lua_Integer. +** CHANGE them if you know a faster way to convert a lua_Number to +** int (with any rounding method and without throwing errors) in your +** system. In Pentium machines, a naive typecast from double to int +** in C is extremely slow, so any alternative is worth trying. +*/ + +/* On a Pentium, resort to a trick */ +#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ + (defined(__i386) || defined (_M_IX86) || defined(__i386__)) + +/* On a Microsoft compiler, use assembler */ +#if defined(_MSC_VER) + +#define lua_number2int(i,d) __asm fld d __asm fistp i +#define lua_number2integer(i,n) lua_number2int(i, n) + +/* the next trick should work on any Pentium, but sometimes clashes + with a DirectX idiosyncrasy */ +#else + +union luai_Cast { double l_d; long l_l; }; +#define lua_number2int(i,d) \ + { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } +#define lua_number2integer(i,n) lua_number2int(i, n) + +#endif + + +/* this option always works, but may be slow */ +#else +#define lua_number2int(i,d) ((i)=(int)(d)) +#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) + +#endif + +/* }================================================================== */ + + +/* +@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment. +** CHANGE it if your system requires alignments larger than double. (For +** instance, if your system supports long doubles and they must be +** aligned in 16-byte boundaries, then you should add long double in the +** union.) Probably you do not need to change this. +*/ +#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } + + +/* +@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. +** CHANGE them if you prefer to use longjmp/setjmp even with C++ +** or if want/don't to use _longjmp/_setjmp instead of regular +** longjmp/setjmp. By default, Lua handles errors with exceptions when +** compiling as C++ code, with _longjmp/_setjmp when asked to use them, +** and with longjmp/setjmp otherwise. +*/ +#if defined(__cplusplus) +/* C++ exceptions */ +#define LUAI_THROW(L,c) throw(c) +#define LUAI_TRY(L,c,a) try { a } catch(...) \ + { if ((c)->status == 0) (c)->status = -1; } +#define luai_jmpbuf int /* dummy variable */ + +#elif defined(LUA_USE_ULONGJMP) +/* in Unix, try _longjmp/_setjmp (more efficient) */ +#define LUAI_THROW(L,c) _longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#else +/* default handling with long jumps */ +#define LUAI_THROW(L,c) longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#endif + + +/* +@@ LUA_MAXCAPTURES is the maximum number of captures that a pattern +@* can do during pattern-matching. +** CHANGE it if you need more captures. This limit is arbitrary. +*/ +#define LUA_MAXCAPTURES 32 + + +/* +@@ lua_tmpnam is the function that the OS library uses to create a +@* temporary name. +@@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam. +** CHANGE them if you have an alternative to tmpnam (which is considered +** insecure) or if you want the original tmpnam anyway. By default, Lua +** uses tmpnam except when POSIX is available, where it uses mkstemp. +*/ +#if defined(loslib_c) || defined(luaall_c) + +#if defined(LUA_USE_MKSTEMP) +#include +#define LUA_TMPNAMBUFSIZE 32 +#define lua_tmpnam(b,e) { \ + strcpy(b, "/tmp/lua_XXXXXX"); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } + +#else +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } +#endif + +#endif + + +/* +@@ lua_popen spawns a new process connected to the current one through +@* the file streams. +** CHANGE it if you have a way to implement it in your system. +*/ +#if defined(LUA_USE_POPEN) + +#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) +#define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) + +#elif defined(LUA_WIN) + +#define lua_popen(L,c,m) ((void)L, _popen(c,m)) +#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) + +#else + +#define lua_popen(L,c,m) ((void)((void)c, m), \ + luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) +#define lua_pclose(L,file) ((void)((void)L, file), 0) + +#endif + +/* +@@ LUA_DL_* define which dynamic-library system Lua should use. +** CHANGE here if Lua has problems choosing the appropriate +** dynamic-library system for your platform (either Windows' DLL, Mac's +** dyld, or Unix's dlopen). If your system is some kind of Unix, there +** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for +** it. To use dlopen you also need to adapt the src/Makefile (probably +** adding -ldl to the linker options), so Lua does not select it +** automatically. (When you change the makefile to add -ldl, you must +** also add -DLUA_USE_DLOPEN.) +** If you do not want any kind of dynamic library, undefine all these +** options. +** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD. +*/ +#if defined(LUA_USE_DLOPEN) +#define LUA_DL_DLOPEN +#endif + +#if defined(LUA_WIN) +#define LUA_DL_DLL +#endif + + +/* +@@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State +@* (the data goes just *before* the lua_State pointer). +** CHANGE (define) this if you really need that. This value must be +** a multiple of the maximum alignment required for your machine. +*/ +#define LUAI_EXTRASPACE 0 + + +/* +@@ luai_userstate* allow user-specific actions on threads. +** CHANGE them if you defined LUAI_EXTRASPACE and need to do something +** extra when a thread is created/deleted/resumed/yielded. +*/ +#define luai_userstateopen(L) ((void)L) +#define luai_userstateclose(L) ((void)L) +#define luai_userstatethread(L,L1) ((void)L) +#define luai_userstatefree(L) ((void)L) +#define luai_userstateresume(L,n) ((void)L) +#define luai_userstateyield(L,n) ((void)L) + + +/* +@@ LUA_INTFRMLEN is the length modifier for integer conversions +@* in 'string.format'. +@@ LUA_INTFRM_T is the integer type correspoding to the previous length +@* modifier. +** CHANGE them if your system supports long long or does not support long. +*/ + +#if defined(LUA_USELONGLONG) + +#define LUA_INTFRMLEN "ll" +#define LUA_INTFRM_T long long + +#else + +#define LUA_INTFRMLEN "l" +#define LUA_INTFRM_T long + +#endif + + + +/* =================================================================== */ + +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ + + + +#endif + diff --git a/source/fceultra/lua/src/lualib.h b/source/fceultra/lua/src/lualib.h new file mode 100644 index 0000000..469417f --- /dev/null +++ b/source/fceultra/lua/src/lualib.h @@ -0,0 +1,53 @@ +/* +** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lualib_h +#define lualib_h + +#include "lua.h" + + +/* Key to file-handle type */ +#define LUA_FILEHANDLE "FILE*" + + +#define LUA_COLIBNAME "coroutine" +LUALIB_API int (luaopen_base) (lua_State *L); + +#define LUA_TABLIBNAME "table" +LUALIB_API int (luaopen_table) (lua_State *L); + +#define LUA_IOLIBNAME "io" +LUALIB_API int (luaopen_io) (lua_State *L); + +#define LUA_OSLIBNAME "os" +LUALIB_API int (luaopen_os) (lua_State *L); + +#define LUA_STRLIBNAME "string" +LUALIB_API int (luaopen_string) (lua_State *L); + +#define LUA_MATHLIBNAME "math" +LUALIB_API int (luaopen_math) (lua_State *L); + +#define LUA_DBLIBNAME "debug" +LUALIB_API int (luaopen_debug) (lua_State *L); + +#define LUA_LOADLIBNAME "package" +LUALIB_API int (luaopen_package) (lua_State *L); + + +/* open all previous libraries */ +LUALIB_API void (luaL_openlibs) (lua_State *L); + + + +#ifndef lua_assert +#define lua_assert(x) ((void)0) +#endif + + +#endif diff --git a/source/fceultra/lua/src/lundump.c b/source/fceultra/lua/src/lundump.c new file mode 100644 index 0000000..8010a45 --- /dev/null +++ b/source/fceultra/lua/src/lundump.c @@ -0,0 +1,227 @@ +/* +** $Id: lundump.c,v 2.7.1.4 2008/04/04 19:51:41 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#include + +#define lundump_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstring.h" +#include "lundump.h" +#include "lzio.h" + +typedef struct { + lua_State* L; + ZIO* Z; + Mbuffer* b; + const char* name; +} LoadState; + +#ifdef LUAC_TRUST_BINARIES +#define IF(c,s) +#define error(S,s) +#else +#define IF(c,s) if (c) error(S,s) + +static void error(LoadState* S, const char* why) +{ + luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why); + luaD_throw(S->L,LUA_ERRSYNTAX); +} +#endif + +#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) +#define LoadByte(S) (lu_byte)LoadChar(S) +#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) +#define LoadVector(S,b,n,size) LoadMem(S,b,n,size) + +static void LoadBlock(LoadState* S, void* b, size_t size) +{ + size_t r=luaZ_read(S->Z,b,size); + IF (r!=0, "unexpected end"); +} + +static int LoadChar(LoadState* S) +{ + char x; + LoadVar(S,x); + return x; +} + +static int LoadInt(LoadState* S) +{ + int x; + LoadVar(S,x); + IF (x<0, "bad integer"); + return x; +} + +static lua_Number LoadNumber(LoadState* S) +{ + lua_Number x; + LoadVar(S,x); + return x; +} + +static TString* LoadString(LoadState* S) +{ + size_t size; + LoadVar(S,size); + if (size==0) + return NULL; + else + { + char* s=luaZ_openspace(S->L,S->b,size); + LoadBlock(S,s,size); + return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ + } +} + +static void LoadCode(LoadState* S, Proto* f) +{ + int n=LoadInt(S); + f->code=luaM_newvector(S->L,n,Instruction); + f->sizecode=n; + LoadVector(S,f->code,n,sizeof(Instruction)); +} + +static Proto* LoadFunction(LoadState* S, TString* p); + +static void LoadConstants(LoadState* S, Proto* f) +{ + int i,n; + n=LoadInt(S); + f->k=luaM_newvector(S->L,n,TValue); + f->sizek=n; + for (i=0; ik[i]); + for (i=0; ik[i]; + int t=LoadChar(S); + switch (t) + { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o,LoadChar(S)!=0); + break; + case LUA_TNUMBER: + setnvalue(o,LoadNumber(S)); + break; + case LUA_TSTRING: + setsvalue2n(S->L,o,LoadString(S)); + break; + default: + error(S,"bad constant"); + break; + } + } + n=LoadInt(S); + f->p=luaM_newvector(S->L,n,Proto*); + f->sizep=n; + for (i=0; ip[i]=NULL; + for (i=0; ip[i]=LoadFunction(S,f->source); +} + +static void LoadDebug(LoadState* S, Proto* f) +{ + int i,n; + n=LoadInt(S); + f->lineinfo=luaM_newvector(S->L,n,int); + f->sizelineinfo=n; + LoadVector(S,f->lineinfo,n,sizeof(int)); + n=LoadInt(S); + f->locvars=luaM_newvector(S->L,n,LocVar); + f->sizelocvars=n; + for (i=0; ilocvars[i].varname=NULL; + for (i=0; ilocvars[i].varname=LoadString(S); + f->locvars[i].startpc=LoadInt(S); + f->locvars[i].endpc=LoadInt(S); + } + n=LoadInt(S); + f->upvalues=luaM_newvector(S->L,n,TString*); + f->sizeupvalues=n; + for (i=0; iupvalues[i]=NULL; + for (i=0; iupvalues[i]=LoadString(S); +} + +static Proto* LoadFunction(LoadState* S, TString* p) +{ + Proto* f; + if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code too deep"); + f=luaF_newproto(S->L); + setptvalue2s(S->L,S->L->top,f); incr_top(S->L); + f->source=LoadString(S); if (f->source==NULL) f->source=p; + f->linedefined=LoadInt(S); + f->lastlinedefined=LoadInt(S); + f->nups=LoadByte(S); + f->numparams=LoadByte(S); + f->is_vararg=LoadByte(S); + f->maxstacksize=LoadByte(S); + LoadCode(S,f); + LoadConstants(S,f); + LoadDebug(S,f); + IF (!luaG_checkcode(f), "bad code"); + S->L->top--; + S->L->nCcalls--; + return f; +} + +static void LoadHeader(LoadState* S) +{ + char h[LUAC_HEADERSIZE]; + char s[LUAC_HEADERSIZE]; + luaU_header(h); + LoadBlock(S,s,LUAC_HEADERSIZE); + IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); +} + +/* +** load precompiled chunk +*/ +Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) +{ + LoadState S; + if (*name=='@' || *name=='=') + S.name=name+1; + else if (*name==LUA_SIGNATURE[0]) + S.name="binary string"; + else + S.name=name; + S.L=L; + S.Z=Z; + S.b=buff; + LoadHeader(&S); + return LoadFunction(&S,luaS_newliteral(L,"=?")); +} + +/* +* make header +*/ +void luaU_header (char* h) +{ + int x=1; + memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); + h+=sizeof(LUA_SIGNATURE)-1; + *h++=(char)LUAC_VERSION; + *h++=(char)LUAC_FORMAT; + *h++=(char)*(char*)&x; /* endianness */ + *h++=(char)sizeof(int); + *h++=(char)sizeof(size_t); + *h++=(char)sizeof(Instruction); + *h++=(char)sizeof(lua_Number); + *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */ +} diff --git a/source/fceultra/lua/src/lundump.h b/source/fceultra/lua/src/lundump.h new file mode 100644 index 0000000..c80189d --- /dev/null +++ b/source/fceultra/lua/src/lundump.h @@ -0,0 +1,36 @@ +/* +** $Id: lundump.h,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#ifndef lundump_h +#define lundump_h + +#include "lobject.h" +#include "lzio.h" + +/* load one chunk; from lundump.c */ +LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); + +/* make header; from lundump.c */ +LUAI_FUNC void luaU_header (char* h); + +/* dump one chunk; from ldump.c */ +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); + +#ifdef luac_c +/* print one chunk; from print.c */ +LUAI_FUNC void luaU_print (const Proto* f, int full); +#endif + +/* for header of binary files -- this is Lua 5.1 */ +#define LUAC_VERSION 0x51 + +/* for header of binary files -- this is the official format */ +#define LUAC_FORMAT 0 + +/* size of header of binary files */ +#define LUAC_HEADERSIZE 12 + +#endif diff --git a/source/fceultra/lua/src/lvm.c b/source/fceultra/lua/src/lvm.c new file mode 100644 index 0000000..ee3256a --- /dev/null +++ b/source/fceultra/lua/src/lvm.c @@ -0,0 +1,763 @@ +/* +** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +#define lvm_c +#define LUA_CORE + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + + +/* limit for table tag-method chains (to avoid loops) */ +#define MAXTAGLOOP 100 + + +const TValue *luaV_tonumber (const TValue *obj, TValue *n) { + lua_Number num; + if (ttisnumber(obj)) return obj; + if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { + setnvalue(n, num); + return n; + } + else + return NULL; +} + + +int luaV_tostring (lua_State *L, StkId obj) { + if (!ttisnumber(obj)) + return 0; + else { + char s[LUAI_MAXNUMBER2STR]; + lua_Number n = nvalue(obj); + lua_number2str(s, n); + setsvalue2s(L, obj, luaS_new(L, s)); + return 1; + } +} + + +static void traceexec (lua_State *L, const Instruction *pc) { + lu_byte mask = L->hookmask; + const Instruction *oldpc = L->savedpc; + L->savedpc = pc; + if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { + resethookcount(L); + luaD_callhook(L, LUA_HOOKCOUNT, -1); + } + if (mask & LUA_MASKLINE) { + Proto *p = ci_func(L->ci)->l.p; + int npc = pcRel(pc, p); + int newline = getline(p, npc); + /* call linehook when enter a new function, when jump back (loop), + or when enter a new line */ + if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) + luaD_callhook(L, LUA_HOOKLINE, newline); + } +} + + +static void callTMres (lua_State *L, StkId res, const TValue *f, + const TValue *p1, const TValue *p2) { + ptrdiff_t result = savestack(L, res); + setobj2s(L, L->top, f); /* push function */ + setobj2s(L, L->top+1, p1); /* 1st argument */ + setobj2s(L, L->top+2, p2); /* 2nd argument */ + luaD_checkstack(L, 3); + L->top += 3; + luaD_call(L, L->top - 3, 1); + res = restorestack(L, result); + L->top--; + setobjs2s(L, res, L->top); +} + + + +static void callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, const TValue *p3) { + setobj2s(L, L->top, f); /* push function */ + setobj2s(L, L->top+1, p1); /* 1st argument */ + setobj2s(L, L->top+2, p2); /* 2nd argument */ + setobj2s(L, L->top+3, p3); /* 3th argument */ + luaD_checkstack(L, 4); + L->top += 4; + luaD_call(L, L->top - 4, 0); +} + + +void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { + int loop; + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; + if (ttistable(t)) { /* `t' is a table? */ + Table *h = hvalue(t); + const TValue *res = luaH_get(h, key); /* do a primitive get */ + if (!ttisnil(res) || /* result is no nil? */ + (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ + setobj2s(L, val, res); + return; + } + /* else will try the tag method */ + } + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) + luaG_typeerror(L, t, "index"); + if (ttisfunction(tm)) { + callTMres(L, val, tm, t, key); + return; + } + t = tm; /* else repeat with `tm' */ + } + luaG_runerror(L, "loop in gettable"); +} + + +void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { + int loop; + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; + if (ttistable(t)) { /* `t' is a table? */ + Table *h = hvalue(t); + TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ + if (!ttisnil(oldval) || /* result is no nil? */ + (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ + setobj2t(L, oldval, val); + luaC_barriert(L, h, val); + return; + } + /* else will try the tag method */ + } + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) + luaG_typeerror(L, t, "index"); + if (ttisfunction(tm)) { + callTM(L, tm, t, key, val); + return; + } + t = tm; /* else repeat with `tm' */ + } + luaG_runerror(L, "loop in settable"); +} + + +static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (ttisnil(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (ttisnil(tm)) return 0; + callTMres(L, res, tm, p1, p2); + return 1; +} + + +static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, + TMS event) { + const TValue *tm1 = fasttm(L, mt1, event); + const TValue *tm2; + if (tm1 == NULL) return NULL; /* no metamethod */ + if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ + tm2 = fasttm(L, mt2, event); + if (tm2 == NULL) return NULL; /* no metamethod */ + if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ + return tm1; + return NULL; +} + + +static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, + TMS event) { + const TValue *tm1 = luaT_gettmbyobj(L, p1, event); + const TValue *tm2; + if (ttisnil(tm1)) return -1; /* no metamethod? */ + tm2 = luaT_gettmbyobj(L, p2, event); + if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ + return -1; + callTMres(L, L->top, tm1, p1, p2); + return !l_isfalse(L->top); +} + + +static int l_strcmp (const TString *ls, const TString *rs) { + const char *l = getstr(ls); + size_t ll = ls->tsv.len; + const char *r = getstr(rs); + size_t lr = rs->tsv.len; + for (;;) { + int temp = strcoll(l, r); + if (temp != 0) return temp; + else { /* strings are equal up to a `\0' */ + size_t len = strlen(l); /* index of first `\0' in both strings */ + if (len == lr) /* r is finished? */ + return (len == ll) ? 0 : 1; + else if (len == ll) /* l is finished? */ + return -1; /* l is smaller than r (because r is not finished) */ + /* both strings longer than `len'; go on comparing (after the `\0') */ + len++; + l += len; ll -= len; r += len; lr -= len; + } + } +} + + +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { + int res; + if (ttype(l) != ttype(r)) + return luaG_ordererror(L, l, r); + else if (ttisnumber(l)) + return luai_numlt(nvalue(l), nvalue(r)); + else if (ttisstring(l)) + return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; + else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) + return res; + return luaG_ordererror(L, l, r); +} + + +static int lessequal (lua_State *L, const TValue *l, const TValue *r) { + int res; + if (ttype(l) != ttype(r)) + return luaG_ordererror(L, l, r); + else if (ttisnumber(l)) + return luai_numle(nvalue(l), nvalue(r)); + else if (ttisstring(l)) + return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; + else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ + return res; + else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ + return !res; + return luaG_ordererror(L, l, r); +} + + +int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { + const TValue *tm; + lua_assert(ttype(t1) == ttype(t2)); + switch (ttype(t1)) { + case LUA_TNIL: return 1; + case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); + case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ + case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TUSERDATA: { + if (uvalue(t1) == uvalue(t2)) return 1; + tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, + TM_EQ); + break; /* will try TM */ + } + case LUA_TTABLE: { + if (hvalue(t1) == hvalue(t2)) return 1; + tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + default: return gcvalue(t1) == gcvalue(t2); + } + if (tm == NULL) return 0; /* no TM? */ + callTMres(L, L->top, tm, t1, t2); /* call TM */ + return !l_isfalse(L->top); +} + + +void luaV_concat (lua_State *L, int total, int last) { + do { + StkId top = L->base + last + 1; + int n = 2; /* number of elements handled in this pass (at least 2) */ + if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { + if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) + luaG_concaterror(L, top-2, top-1); + } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ + (void)tostring(L, top - 2); /* result is first op (as string) */ + else { + /* at least two string values; get as many as possible */ + size_t tl = tsvalue(top-1)->len; + char *buffer; + int i; + /* collect total length */ + for (n = 1; n < total && tostring(L, top-n-1); n++) { + size_t l = tsvalue(top-n-1)->len; + if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); + tl += l; + } + buffer = luaZ_openspace(L, &G(L)->buff, tl); + tl = 0; + for (i=n; i>0; i--) { /* concat all strings */ + size_t l = tsvalue(top-i)->len; + memcpy(buffer+tl, svalue(top-i), l); + tl += l; + } + setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); + } + total -= n-1; /* got `n' strings to create 1 new */ + last -= n-1; + } while (total > 1); /* repeat until only 1 result left */ +} + + +static void Arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op) { + TValue tempb, tempc; + const TValue *b, *c; + if ((b = luaV_tonumber(rb, &tempb)) != NULL && + (c = luaV_tonumber(rc, &tempc)) != NULL) { + lua_Number nb = nvalue(b), nc = nvalue(c); + switch (op) { + case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; + case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; + case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; + case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; + case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; + case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; + case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; + default: lua_assert(0); break; + } + } + else if (!call_binTM(L, rb, rc, ra, op)) + luaG_aritherror(L, rb, rc); +} + + + +/* +** some macros for common tasks in `luaV_execute' +*/ + +#define runtime_check(L, c) { if (!(c)) break; } + +#define RA(i) (base+GETARG_A(i)) +/* to be used after possible stack reallocation */ +#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) +#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) +#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ + ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) +#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ + ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) +#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) + + +#define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} + + +#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } + + +#define arith_op(op,tm) { \ + TValue *rb = RKB(i); \ + TValue *rc = RKC(i); \ + if (ttisnumber(rb) && ttisnumber(rc)) { \ + lua_Number nb = nvalue(rb), nc = nvalue(rc); \ + setnvalue(ra, op(nb, nc)); \ + } \ + else \ + Protect(Arith(L, ra, rb, rc, tm)); \ + } + + + +void luaV_execute (lua_State *L, int nexeccalls) { + LClosure *cl; + StkId base; + TValue *k; + const Instruction *pc; + reentry: /* entry point */ + lua_assert(isLua(L->ci)); + pc = L->savedpc; + cl = &clvalue(L->ci->func)->l; + base = L->base; + k = cl->p->k; + /* main loop of interpreter */ + for (;;) { + const Instruction i = *pc++; + StkId ra; + if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && + (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { + traceexec(L, pc); + if (L->status == LUA_YIELD) { /* did hook yield? */ + L->savedpc = pc - 1; + return; + } + base = L->base; + } + /* warning!! several calls may realloc the stack and invalidate `ra' */ + ra = RA(i); + lua_assert(base == L->base && L->base == L->ci->base); + lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); + lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); + switch (GET_OPCODE(i)) { + case OP_MOVE: { + setobjs2s(L, ra, RB(i)); + continue; + } + case OP_LOADK: { + setobj2s(L, ra, KBx(i)); + continue; + } + case OP_LOADBOOL: { + setbvalue(ra, GETARG_B(i)); + if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ + continue; + } + case OP_LOADNIL: { + TValue *rb = RB(i); + do { + setnilvalue(rb--); + } while (rb >= ra); + continue; + } + case OP_GETUPVAL: { + int b = GETARG_B(i); + setobj2s(L, ra, cl->upvals[b]->v); + continue; + } + case OP_GETGLOBAL: { + TValue g; + TValue *rb = KBx(i); + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(rb)); + Protect(luaV_gettable(L, &g, rb, ra)); + continue; + } + case OP_GETTABLE: { + Protect(luaV_gettable(L, RB(i), RKC(i), ra)); + continue; + } + case OP_SETGLOBAL: { + TValue g; + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(KBx(i))); + Protect(luaV_settable(L, &g, KBx(i), ra)); + continue; + } + case OP_SETUPVAL: { + UpVal *uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v, ra); + luaC_barrier(L, uv, ra); + continue; + } + case OP_SETTABLE: { + Protect(luaV_settable(L, ra, RKB(i), RKC(i))); + continue; + } + case OP_NEWTABLE: { + int b = GETARG_B(i); + int c = GETARG_C(i); + sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); + Protect(luaC_checkGC(L)); + continue; + } + case OP_SELF: { + StkId rb = RB(i); + setobjs2s(L, ra+1, rb); + Protect(luaV_gettable(L, rb, RKC(i), ra)); + continue; + } + case OP_ADD: { + arith_op(luai_numadd, TM_ADD); + continue; + } + case OP_SUB: { + arith_op(luai_numsub, TM_SUB); + continue; + } + case OP_MUL: { + arith_op(luai_nummul, TM_MUL); + continue; + } + case OP_DIV: { + arith_op(luai_numdiv, TM_DIV); + continue; + } + case OP_MOD: { + arith_op(luai_nummod, TM_MOD); + continue; + } + case OP_POW: { + arith_op(luai_numpow, TM_POW); + continue; + } + case OP_UNM: { + TValue *rb = RB(i); + if (ttisnumber(rb)) { + lua_Number nb = nvalue(rb); + setnvalue(ra, luai_numunm(nb)); + } + else { + Protect(Arith(L, ra, rb, rb, TM_UNM)); + } + continue; + } + case OP_NOT: { + int res = l_isfalse(RB(i)); /* next assignment may change this value */ + setbvalue(ra, res); + continue; + } + case OP_LEN: { + const TValue *rb = RB(i); + switch (ttype(rb)) { + case LUA_TTABLE: { + setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); + break; + } + case LUA_TSTRING: { + setnvalue(ra, cast_num(tsvalue(rb)->len)); + break; + } + default: { /* try metamethod */ + Protect( + if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) + luaG_typeerror(L, rb, "get length of"); + ) + } + } + continue; + } + case OP_CONCAT: { + int b = GETARG_B(i); + int c = GETARG_C(i); + Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); + setobjs2s(L, RA(i), base+b); + continue; + } + case OP_JMP: { + dojump(L, pc, GETARG_sBx(i)); + continue; + } + case OP_EQ: { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + Protect( + if (equalobj(L, rb, rc) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; + } + case OP_LT: { + Protect( + if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; + } + case OP_LE: { + Protect( + if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; + continue; + } + case OP_TEST: { + if (l_isfalse(ra) != GETARG_C(i)) + dojump(L, pc, GETARG_sBx(*pc)); + pc++; + continue; + } + case OP_TESTSET: { + TValue *rb = RB(i); + if (l_isfalse(rb) != GETARG_C(i)) { + setobjs2s(L, ra, rb); + dojump(L, pc, GETARG_sBx(*pc)); + } + pc++; + continue; + } + case OP_CALL: { + int b = GETARG_B(i); + int nresults = GETARG_C(i) - 1; + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + L->savedpc = pc; + switch (luaD_precall(L, ra, nresults)) { + case PCRLUA: { + nexeccalls++; + goto reentry; /* restart luaV_execute over new Lua function */ + } + case PCRC: { + /* it was a C function (`precall' called it); adjust results */ + if (nresults >= 0) L->top = L->ci->top; + base = L->base; + continue; + } + default: { + return; /* yield */ + } + } + } + case OP_TAILCALL: { + int b = GETARG_B(i); + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + L->savedpc = pc; + lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); + switch (luaD_precall(L, ra, LUA_MULTRET)) { + case PCRLUA: { + /* tail call: put new frame in place of previous one */ + CallInfo *ci = L->ci - 1; /* previous frame */ + int aux; + StkId func = ci->func; + StkId pfunc = (ci+1)->func; /* previous function index */ + if (L->openupval) luaF_close(L, ci->base); + L->base = ci->base = ci->func + ((ci+1)->base - pfunc); + for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ + setobjs2s(L, func+aux, pfunc+aux); + ci->top = L->top = func+aux; /* correct top */ + lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); + ci->savedpc = L->savedpc; + ci->tailcalls++; /* one more call lost */ + L->ci--; /* remove new frame */ + goto reentry; + } + case PCRC: { /* it was a C function (`precall' called it) */ + base = L->base; + continue; + } + default: { + return; /* yield */ + } + } + } + case OP_RETURN: { + int b = GETARG_B(i); + if (b != 0) L->top = ra+b-1; + if (L->openupval) luaF_close(L, base); + L->savedpc = pc; + b = luaD_poscall(L, ra); + if (--nexeccalls == 0) /* was previous function running `here'? */ + return; /* no: return */ + else { /* yes: continue its execution */ + if (b) L->top = L->ci->top; + lua_assert(isLua(L->ci)); + lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); + goto reentry; + } + } + case OP_FORLOOP: { + lua_Number step = nvalue(ra+2); + lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ + lua_Number limit = nvalue(ra+1); + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { + dojump(L, pc, GETARG_sBx(i)); /* jump back */ + setnvalue(ra, idx); /* update internal index... */ + setnvalue(ra+3, idx); /* ...and external index */ + } + continue; + } + case OP_FORPREP: { + const TValue *init = ra; + const TValue *plimit = ra+1; + const TValue *pstep = ra+2; + L->savedpc = pc; /* next steps may throw errors */ + if (!tonumber(init, ra)) + luaG_runerror(L, LUA_QL("for") " initial value must be a number"); + else if (!tonumber(plimit, ra+1)) + luaG_runerror(L, LUA_QL("for") " limit must be a number"); + else if (!tonumber(pstep, ra+2)) + luaG_runerror(L, LUA_QL("for") " step must be a number"); + setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); + dojump(L, pc, GETARG_sBx(i)); + continue; + } + case OP_TFORLOOP: { + StkId cb = ra + 3; /* call base */ + setobjs2s(L, cb+2, ra+2); + setobjs2s(L, cb+1, ra+1); + setobjs2s(L, cb, ra); + L->top = cb+3; /* func. + 2 args (state and index) */ + Protect(luaD_call(L, cb, GETARG_C(i))); + L->top = L->ci->top; + cb = RA(i) + 3; /* previous call may change the stack */ + if (!ttisnil(cb)) { /* continue loop? */ + setobjs2s(L, cb-1, cb); /* save control variable */ + dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ + } + pc++; + continue; + } + case OP_SETLIST: { + int n = GETARG_B(i); + int c = GETARG_C(i); + int last; + Table *h; + if (n == 0) { + n = cast_int(L->top - ra) - 1; + L->top = L->ci->top; + } + if (c == 0) c = cast_int(*pc++); + runtime_check(L, ttistable(ra)); + h = hvalue(ra); + last = ((c-1)*LFIELDS_PER_FLUSH) + n; + if (last > h->sizearray) /* needs more space? */ + luaH_resizearray(L, h, last); /* pre-alloc it at once */ + for (; n > 0; n--) { + TValue *val = ra+n; + setobj2t(L, luaH_setnum(L, h, last--), val); + luaC_barriert(L, h, val); + } + continue; + } + case OP_CLOSE: { + luaF_close(L, ra); + continue; + } + case OP_CLOSURE: { + Proto *p; + Closure *ncl; + int nup, j; + p = cl->p->p[GETARG_Bx(i)]; + nup = p->nups; + ncl = luaF_newLclosure(L, nup, cl->env); + ncl->l.p = p; + for (j=0; jl.upvals[j] = cl->upvals[GETARG_B(*pc)]; + else { + lua_assert(GET_OPCODE(*pc) == OP_MOVE); + ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); + } + } + setclvalue(L, ra, ncl); + Protect(luaC_checkGC(L)); + continue; + } + case OP_VARARG: { + int b = GETARG_B(i) - 1; + int j; + CallInfo *ci = L->ci; + int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; + if (b == LUA_MULTRET) { + Protect(luaD_checkstack(L, n)); + ra = RA(i); /* previous call may change the stack */ + b = n; + L->top = ra + n; + } + for (j = 0; j < b; j++) { + if (j < n) { + setobjs2s(L, ra + j, ci->base - n + j); + } + else { + setnilvalue(ra + j); + } + } + continue; + } + } + } +} + diff --git a/source/fceultra/lua/src/lvm.h b/source/fceultra/lua/src/lvm.h new file mode 100644 index 0000000..bfe4f56 --- /dev/null +++ b/source/fceultra/lua/src/lvm.h @@ -0,0 +1,36 @@ +/* +** $Id: lvm.h,v 2.5.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lvm_h +#define lvm_h + + +#include "ldo.h" +#include "lobject.h" +#include "ltm.h" + + +#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o))) + +#define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \ + (((o) = luaV_tonumber(o,n)) != NULL)) + +#define equalobj(L,o1,o2) \ + (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) + + +LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); +LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); +LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); +LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, + StkId val); +LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, + StkId val); +LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls); +LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); + +#endif diff --git a/source/fceultra/lua/src/lzio.c b/source/fceultra/lua/src/lzio.c new file mode 100644 index 0000000..293edd5 --- /dev/null +++ b/source/fceultra/lua/src/lzio.c @@ -0,0 +1,82 @@ +/* +** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ +** a generic input stream interface +** See Copyright Notice in lua.h +*/ + + +#include + +#define lzio_c +#define LUA_CORE + +#include "lua.h" + +#include "llimits.h" +#include "lmem.h" +#include "lstate.h" +#include "lzio.h" + + +int luaZ_fill (ZIO *z) { + size_t size; + lua_State *L = z->L; + const char *buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); + if (buff == NULL || size == 0) return EOZ; + z->n = size - 1; + z->p = buff; + return char2int(*(z->p++)); +} + + +int luaZ_lookahead (ZIO *z) { + if (z->n == 0) { + if (luaZ_fill(z) == EOZ) + return EOZ; + else { + z->n++; /* luaZ_fill removed first byte; put back it */ + z->p--; + } + } + return char2int(*z->p); +} + + +void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { + z->L = L; + z->reader = reader; + z->data = data; + z->n = 0; + z->p = NULL; +} + + +/* --------------------------------------------------------------- read --- */ +size_t luaZ_read (ZIO *z, void *b, size_t n) { + while (n) { + size_t m; + if (luaZ_lookahead(z) == EOZ) + return n; /* return number of missing bytes */ + m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ + memcpy(b, z->p, m); + z->n -= m; + z->p += m; + b = (char *)b + m; + n -= m; + } + return 0; +} + +/* ------------------------------------------------------------------------ */ +char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { + if (n > buff->buffsize) { + if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; + luaZ_resizebuffer(L, buff, n); + } + return buff->buffer; +} + + diff --git a/source/fceultra/lua/src/lzio.h b/source/fceultra/lua/src/lzio.h new file mode 100644 index 0000000..51d695d --- /dev/null +++ b/source/fceultra/lua/src/lzio.h @@ -0,0 +1,67 @@ +/* +** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + + +#ifndef lzio_h +#define lzio_h + +#include "lua.h" + +#include "lmem.h" + + +#define EOZ (-1) /* end of stream */ + +typedef struct Zio ZIO; + +#define char2int(c) cast(int, cast(unsigned char, (c))) + +#define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) + +typedef struct Mbuffer { + char *buffer; + size_t n; + size_t buffsize; +} Mbuffer; + +#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) + +#define luaZ_buffer(buff) ((buff)->buffer) +#define luaZ_sizebuffer(buff) ((buff)->buffsize) +#define luaZ_bufflen(buff) ((buff)->n) + +#define luaZ_resetbuffer(buff) ((buff)->n = 0) + + +#define luaZ_resizebuffer(L, buff, size) \ + (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ + (buff)->buffsize = size) + +#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) + + +LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); +LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, + void *data); +LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ +LUAI_FUNC int luaZ_lookahead (ZIO *z); + + + +/* --------- Private Part ------------------ */ + +struct Zio { + size_t n; /* bytes still unread */ + const char *p; /* current position in buffer */ + lua_Reader reader; + void* data; /* additional data */ + lua_State *L; /* Lua state (for reader) */ +}; + + +LUAI_FUNC int luaZ_fill (ZIO *z); + +#endif diff --git a/source/fceultra/lua/src/print.c b/source/fceultra/lua/src/print.c new file mode 100644 index 0000000..e240cfc --- /dev/null +++ b/source/fceultra/lua/src/print.c @@ -0,0 +1,227 @@ +/* +** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $ +** print bytecodes +** See Copyright Notice in lua.h +*/ + +#include +#include + +#define luac_c +#define LUA_CORE + +#include "ldebug.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lundump.h" + +#define PrintFunction luaU_print + +#define Sizeof(x) ((int)sizeof(x)) +#define VOID(p) ((const void*)(p)) + +static void PrintString(const TString* ts) +{ + const char* s=getstr(ts); + size_t i,n=ts->tsv.len; + putchar('"'); + for (i=0; ik[i]; + switch (ttype(o)) + { + case LUA_TNIL: + printf("nil"); + break; + case LUA_TBOOLEAN: + printf(bvalue(o) ? "true" : "false"); + break; + case LUA_TNUMBER: + printf(LUA_NUMBER_FMT,nvalue(o)); + break; + case LUA_TSTRING: + PrintString(rawtsvalue(o)); + break; + default: /* cannot happen */ + printf("? type=%d",ttype(o)); + break; + } +} + +static void PrintCode(const Proto* f) +{ + const Instruction* code=f->code; + int pc,n=f->sizecode; + for (pc=0; pc0) printf("[%d]\t",line); else printf("[-]\t"); + printf("%-9s\t",luaP_opnames[o]); + switch (getOpMode(o)) + { + case iABC: + printf("%d",a); + if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); + if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); + break; + case iABx: + if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); + break; + case iAsBx: + if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); + break; + } + switch (o) + { + case OP_LOADK: + printf("\t; "); PrintConstant(f,bx); + break; + case OP_GETUPVAL: + case OP_SETUPVAL: + printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); + break; + case OP_GETGLOBAL: + case OP_SETGLOBAL: + printf("\t; %s",svalue(&f->k[bx])); + break; + case OP_GETTABLE: + case OP_SELF: + if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } + break; + case OP_SETTABLE: + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_DIV: + case OP_POW: + case OP_EQ: + case OP_LT: + case OP_LE: + if (ISK(b) || ISK(c)) + { + printf("\t; "); + if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); + printf(" "); + if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); + } + break; + case OP_JMP: + case OP_FORLOOP: + case OP_FORPREP: + printf("\t; to %d",sbx+pc+2); + break; + case OP_CLOSURE: + printf("\t; %p",VOID(f->p[bx])); + break; + case OP_SETLIST: + if (c==0) printf("\t; %d",(int)code[++pc]); + else printf("\t; %d",c); + break; + default: + break; + } + printf("\n"); + } +} + +#define SS(x) (x==1)?"":"s" +#define S(x) x,SS(x) + +static void PrintHeader(const Proto* f) +{ + const char* s=getstr(f->source); + if (*s=='@' || *s=='=') + s++; + else if (*s==LUA_SIGNATURE[0]) + s="(bstring)"; + else + s="(string)"; + printf("\n%s <%s:%d,%d> (%d instruction%s, %d bytes at %p)\n", + (f->linedefined==0)?"main":"function",s, + f->linedefined,f->lastlinedefined, + S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); + printf("%d%s param%s, %d slot%s, %d upvalue%s, ", + f->numparams,f->is_vararg?"+":"",SS(f->numparams), + S(f->maxstacksize),S(f->nups)); + printf("%d local%s, %d constant%s, %d function%s\n", + S(f->sizelocvars),S(f->sizek),S(f->sizep)); +} + +static void PrintConstants(const Proto* f) +{ + int i,n=f->sizek; + printf("constants (%d) for %p:\n",n,VOID(f)); + for (i=0; isizelocvars; + printf("locals (%d) for %p:\n",n,VOID(f)); + for (i=0; ilocvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); + } +} + +static void PrintUpvalues(const Proto* f) +{ + int i,n=f->sizeupvalues; + printf("upvalues (%d) for %p:\n",n,VOID(f)); + if (f->upvalues==NULL) return; + for (i=0; iupvalues[i])); + } +} + +void PrintFunction(const Proto* f, int full) +{ + int i,n=f->sizep; + PrintHeader(f); + PrintCode(f); + if (full) + { + PrintConstants(f); + PrintLocals(f); + PrintUpvalues(f); + } + for (i=0; ip[i],full); +} diff --git a/source/fceultra/movie.cpp b/source/fceultra/movie.cpp index f0a9394..4c20fa5 100644 --- a/source/fceultra/movie.cpp +++ b/source/fceultra/movie.cpp @@ -1,13 +1,3 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "emufile.h" #include "version.h" #include "types.h" @@ -22,6 +12,7 @@ #include "video.h" #include "movie.h" #include "fds.h" +#include "vsuni.h" #ifdef _S9XLUA_H #include "fceulua.h" #endif @@ -39,11 +30,20 @@ #include "./drivers/win/common.h" #include "./drivers/win/window.h" extern void AddRecentMovieFile(const char *filename); - #include "./drivers/win/taseditor.h" -extern bool emulator_must_run_taseditor; +extern bool mustEngageTaseditor; #endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + using namespace std; #define MOVIE_VERSION 3 @@ -103,7 +103,7 @@ SFORMAT FCEUMOV_STATEINFO[]={ char curMovieFilename[512] = {0}; MovieData currMovieData; MovieData defaultMovieData; -int currRerecordCount; +int currRerecordCount; // Keep the global value char lagcounterbuf[32] = {0}; @@ -411,10 +411,10 @@ void MovieRecord::dumpBinary(MovieData* md, EMUFILE* os, int index) void MovieRecord::dump(MovieData* md, EMUFILE* os, int index) { - //dump the misc commands + // dump the commands //*os << '|' << setw(1) << (int)commands; os->fputc('|'); - putdec(os,commands); + putdec(os, commands); // "variable length decimal integer" //a special case: if fourscore is enabled, dump four gamepads if(md->fourscore) @@ -968,7 +968,8 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) pauseframe = _pauseframe; movie_readonly = _read_only; movieMode = MOVIEMODE_PLAY; - currRerecordCount = currMovieData.rerecordCount; + if (movieMode != MOVIEMODE_TASEDITOR) + currRerecordCount = currMovieData.rerecordCount; if(movie_readonly) FCEU_DispMessage("Replay started Read-Only.",0); @@ -1039,7 +1040,8 @@ void FCEUI_SaveMovie(const char *fname, EMOVIE_FLAG flags, std::wstring author) movieMode = MOVIEMODE_RECORD; movie_readonly = false; - currRerecordCount = 0; + if (movieMode != MOVIEMODE_TASEDITOR) + currRerecordCount = 0; FCEU_DispMessage("Movie recording started.",0); } @@ -1057,41 +1059,42 @@ void FCEUMOV_AddInputState() currMovieData.insertEmpty(-1, (currFrameCounter + 1) - ((int)currMovieData.records.size() - 1)); MovieRecord* mr = &currMovieData.records[currFrameCounter]; - if (TaseditorIsRecording()) + if (isTaseditorRecording()) { // record commands and buttons mr->commands |= _currCommand; joyports[0].log(mr); joyports[1].log(mr); - Taseditor_RecordInput(); + recordInputByTaseditor(); } // replay buttons joyports[0].load(mr); joyports[1].load(mr); // replay commands - if(mr->command_power()) + if (mr->command_power()) PowerNES(); - if(mr->command_reset()) + if (mr->command_reset()) ResetNES(); - if(mr->command_fds_insert()) + if (mr->command_fds_insert()) FCEU_FDSInsert(); - if(mr->command_fds_select()) + if (mr->command_fds_select()) FCEU_FDSSelect(); + if (mr->command_vs_insertcoin()) + FCEU_VSUniCoin(); _currCommand = 0; } else #endif - if(movieMode == MOVIEMODE_PLAY) + if (movieMode == MOVIEMODE_PLAY) { //stop when we run out of frames - if(currFrameCounter >= (int)currMovieData.records.size()) + if (currFrameCounter >= (int)currMovieData.records.size()) { FinishPlayback(); //tell all drivers to poll input and set up their logical states for(int port=0;port<2;port++) joyports[port].driver->Update(port,joyports[port].ptr,joyports[port].attrib); portFC.driver->Update(portFC.ptr,portFC.attrib); - } - else + } else { MovieRecord* mr = &currMovieData.records[currFrameCounter]; @@ -1104,13 +1107,15 @@ void FCEUMOV_AddInputState() FCEU_FDSInsert(); if(mr->command_fds_select()) FCEU_FDSSelect(); + if (mr->command_vs_insertcoin()) + FCEU_VSUniCoin(); joyports[0].load(mr); joyports[1].load(mr); } //if we are on the last frame, then pause the emulator if the player requested it - if(currFrameCounter == currMovieData.records.size()-1) + if (currFrameCounter == currMovieData.records.size()-1) { if(FCEUD_PauseAfterPlayback()) { @@ -1119,14 +1124,13 @@ void FCEUMOV_AddInputState() } //pause the movie at a specified frame - if(FCEUMOV_ShouldPause() && FCEUI_EmulationPaused()==0) + if (FCEUMOV_ShouldPause() && FCEUI_EmulationPaused()==0) { FCEUI_ToggleEmulationPause(); FCEU_DispMessage("Paused at specified movie frame",0); } - } - else if(movieMode == MOVIEMODE_RECORD) + } else if (movieMode == MOVIEMODE_RECORD) { MovieRecord mr; @@ -1159,12 +1163,16 @@ void FCEUMOV_AddCommand(int cmd) if(movieMode != MOVIEMODE_RECORD && movieMode != MOVIEMODE_TASEDITOR) return; - //NOTE: EMOVIECMD matches FCEUNPCMD_RESET and FCEUNPCMD_POWER - //we are lucky (well, I planned it that way) - - switch(cmd) { + // translate "FCEU NetPlay" command to "FCEU Movie" command + switch (cmd) + { + case FCEUNPCMD_RESET: cmd = MOVIECMD_RESET; break; + case FCEUNPCMD_POWER: cmd = MOVIECMD_POWER; break; case FCEUNPCMD_FDSINSERT: cmd = MOVIECMD_FDS_INSERT; break; case FCEUNPCMD_FDSSELECT: cmd = MOVIECMD_FDS_SELECT; break; + case FCEUNPCMD_VSUNICOIN: cmd = MOVIECMD_VS_INSERTCOIN; break; + // all other netplay commands (e.g. FCEUNPCMD_VSUNIDIP0) are not supported by movie recorder for now + default: return; } _currCommand |= cmd; @@ -1177,12 +1185,12 @@ void FCEU_DrawMovies(uint8 *XBuf) char counterbuf[32] = {0}; int color = 0x20; if(movieMode == MOVIEMODE_PLAY) - sprintf(counterbuf,"%d/%d",currFrameCounter,currMovieData.records.size()); + sprintf(counterbuf,"%d/%d",currFrameCounter,(int)currMovieData.records.size()); else if(movieMode == MOVIEMODE_RECORD) sprintf(counterbuf,"%d",currFrameCounter); else if (movieMode == MOVIEMODE_FINISHED) { - sprintf(counterbuf,"%d/%d (finished)",currFrameCounter,currMovieData.records.size()); + sprintf(counterbuf,"%d/%d (finished)",currFrameCounter,(int)currMovieData.records.size()); color = 0x17; //Show red to get attention } else if(movieMode == MOVIEMODE_TASEDITOR) { @@ -1256,7 +1264,7 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size) #ifdef WIN32 int result = MessageBox(hAppWnd, "This movie is a TAS Editor project file.\nIt can be modified in TAS Editor only.\n\nOpen it in TAS Editor now?", "Movie Replay", MB_YESNO); if (result == IDYES) - emulator_must_run_taseditor = true; + mustEngageTaseditor = true; #else FCEUI_printf("This movie is a TAS Editor project file! It can be modified in TAS Editor only.\nMovie is now Read-Only.\n"); #endif @@ -1418,9 +1426,9 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size) // Finally, this is a savestate file for this movie movieMode = MOVIEMODE_PLAY; } - } - else //Read + write + } else { + //Read+Write mode if (currFrameCounter > (int)tempMovieData.records.size()) { //This is a post movie savestate, handle it differently @@ -1429,20 +1437,15 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size) openRecordingMovie(curMovieFilename); currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/); FinishPlayback(); - } - else + } else { //truncate before we copy, just to save some time, unless the user selects a full copy option if (!fullSaveStateLoads) - tempMovieData.truncateAt(currFrameCounter); //we can only assume this here since we have checked that the frame counter is not greater than the movie data + //we can only assume this here since we have checked that the frame counter is not greater than the movie data + tempMovieData.truncateAt(currFrameCounter); + currMovieData = tempMovieData; -#ifdef _S9XLUA_H - if(!FCEU_LuaRerecordCountSkip()) - currRerecordCount++; -#else - currRerecordCount++; -#endif - currMovieData.rerecordCount = currRerecordCount; + FCEUMOV_IncrementRerecordCount(); openRecordingMovie(curMovieFilename); currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/); movieMode = MOVIEMODE_RECORD; @@ -1469,6 +1472,24 @@ bool FCEUMOV_PostLoad(void) return load_successful; } +void FCEUMOV_IncrementRerecordCount() +{ +#ifdef _S9XLUA_H + if(!FCEU_LuaRerecordCountSkip()) + if (movieMode != MOVIEMODE_TASEDITOR) + currRerecordCount++; + else + currMovieData.rerecordCount++; +#else + if (movieMode != MOVIEMODE_TASEDITOR)currRerecordCount++; + currRerecordCount++; + else + currMovieData.rerecordCount++; +#endif + if (movieMode != MOVIEMODE_TASEDITOR) + currMovieData.rerecordCount = currRerecordCount; +} + void FCEUI_MovieToggleFrameDisplay(void) { frame_display=!frame_display; @@ -1543,11 +1564,9 @@ void FCEUI_MovieToggleReadOnly() if(movie_readonly) strcpy(message, "Movie is now Read+Write"); else - { strcpy(message, "Movie is now Read-Only"); - } - if(movieMode == MOVIEMODE_INACTIVE) + if (movieMode == MOVIEMODE_INACTIVE) strcat(message, " (no movie)"); else if (movieMode == MOVIEMODE_FINISHED) strcat(message, " (finished)"); @@ -1561,16 +1580,16 @@ void FCEUI_MoviePlayFromBeginning(void) if (movieMode == MOVIEMODE_TASEDITOR) { #ifdef WIN32 - Taseditor_EMUCMD(EMUCMD_MOVIE_PLAY_FROM_BEGINNING); + handleEmuCmdByTaseditor(EMUCMD_MOVIE_PLAY_FROM_BEGINNING); #endif } else if (movieMode != MOVIEMODE_INACTIVE) { if (currMovieData.savestate.empty()) { - movie_readonly=true; + movie_readonly = true; movieMode = MOVIEMODE_PLAY; poweron(true); - currFrameCounter=0; + currFrameCounter = 0; FCEU_DispMessage("Movie is now Read-Only. Playing from beginning.",0); } else diff --git a/source/fceultra/movie.h b/source/fceultra/movie.h index a7ab898..783e5b9 100644 --- a/source/fceultra/movie.h +++ b/source/fceultra/movie.h @@ -1,15 +1,15 @@ #ifndef __MOVIE_H_ #define __MOVIE_H_ +#include "input/zapper.h" +#include "utils/guid.h" +#include "utils/md5.h" + #include #include #include #include -#include - -#include "input/zapper.h" -#include "utils/guid.h" -#include "utils/md5.h" +#include struct FCEUFILE; @@ -67,7 +67,8 @@ enum EMOVIECMD MOVIECMD_RESET = 1, MOVIECMD_POWER = 2, MOVIECMD_FDS_INSERT = 4, - MOVIECMD_FDS_SELECT = 8 + MOVIECMD_FDS_SELECT = 8, + MOVIECMD_VS_INSERTCOIN = 16 }; EMOVIEMODE FCEUMOV_Mode(); @@ -88,6 +89,7 @@ int FCEUMOV_WriteState(EMUFILE* os); bool FCEUMOV_ReadState(EMUFILE* is, uint32 size); void FCEUMOV_PreLoad(); bool FCEUMOV_PostLoad(); +void FCEUMOV_IncrementRerecordCount(); bool FCEUMOV_FromPoweron(); @@ -111,10 +113,11 @@ public: //small now to save space; we might need to support more commands later. //the disk format will support up to 64bit if necessary uint8 commands; - bool command_reset() { return (commands&MOVIECMD_RESET)!=0; } - bool command_power() { return (commands&MOVIECMD_POWER)!=0; } - bool command_fds_insert() { return (commands&MOVIECMD_FDS_INSERT)!=0; } - bool command_fds_select() { return (commands&MOVIECMD_FDS_SELECT)!=0; } + bool command_reset() { return (commands & MOVIECMD_RESET) != 0; } + bool command_power() { return (commands & MOVIECMD_POWER) != 0; } + bool command_fds_insert() { return (commands & MOVIECMD_FDS_INSERT) != 0; } + bool command_fds_select() { return (commands & MOVIECMD_FDS_SELECT) != 0; } + bool command_vs_insertcoin() { return (commands & MOVIECMD_VS_INSERTCOIN) != 0; } void toggleBit(int joy, int bit) { diff --git a/source/fceultra/netplay.cpp b/source/fceultra/netplay.cpp index 6a0f7a1..ce6d9a3 100644 --- a/source/fceultra/netplay.cpp +++ b/source/fceultra/netplay.cpp @@ -19,15 +19,6 @@ */ -#include -#include -#include -#include -#include -//#include //mbg merge 7/17/06 removed - -#include - #include "types.h" #include "file.h" #include "utils/endian.h" @@ -39,6 +30,15 @@ #include "driver.h" #include "utils/memory.h" +#include +#include +#include +#include +#include +//#include //mbg merge 7/17/06 removed + +#include + int FCEUnetplay=0; static uint8 netjoy[4]; // Controller cache. diff --git a/source/fceultra/nsf.cpp b/source/fceultra/nsf.cpp index 0eb2dfc..d8c6b90 100644 --- a/source/fceultra/nsf.cpp +++ b/source/fceultra/nsf.cpp @@ -21,11 +21,6 @@ /// \file /// \brief implements a built-in NSF player. This is a perk--not a part of the emu core -#include -#include -#include -#include - #include "types.h" #include "x6502.h" #include "fceu.h" @@ -38,6 +33,7 @@ #include "fds.h" #include "cart.h" #include "input.h" +#include "state.h" #include "driver.h" #ifdef _S9XLUA_H #include "fceulua.h" @@ -47,13 +43,20 @@ #define M_PI 3.14159265358979323846 #endif +#include +#include +#include +#include + +static const int FIXED_EXWRAM_SIZE = 32768+8192; + static uint8 SongReload; -static int CurrentSong; +static int32 CurrentSong; static DECLFW(NSF_write); static DECLFR(NSF_read); -static int vismode=1; +static int vismode=1; //we cant consider this state, because the UI may be controlling it and wouldnt know we loadstated it //mbg 7/31/06 todo - no reason this couldnt be assembled on the fly from actual asm source code. thatd be less obscure. //here it is disassembled, for reference @@ -107,18 +110,18 @@ static DECLFR(NSFROMRead) return (NSFROM-0x3800)[A]; } -static int doreset=0; -static int NSFNMIFlags; -uint8 *NSFDATA=0; -int NSFMaxBank; +static uint8 doreset=0; //state +static uint8 NSFNMIFlags; //state +uint8 *NSFDATA=0; //configration, loaded from rom? +int NSFMaxBank; //configuration -static int NSFSize; -static uint8 BSon; -static uint8 BankCounter; +static int32 NSFSize; //configuration +static uint8 BSon; //configuration +static uint8 BankCounter; //configuration -static uint16 PlayAddr; -static uint16 InitAddr; -static uint16 LoadAddr; +static uint16 PlayAddr; //configuration +static uint16 InitAddr; //configuration +static uint16 LoadAddr; //configuration extern char LoadedRomFName[2048]; @@ -275,10 +278,13 @@ int NSFLoad(const char *name, FCEUFILE *fp) FCEU_printf(" %s\n",(NSFHeader.VideoSystem&1)?"PAL":"NTSC"); FCEU_printf(" Starting song: %d / %d\n\n",NSFHeader.StartingSong,NSFHeader.TotalSongs); + //choose exwram size and allocate + int exwram_size = 8192; if(NSFHeader.SoundChip&4) - ExWRAM=(uint8*)FCEU_gmalloc(32768+8192); //mbg merge 7/17/06 added cast - else - ExWRAM=(uint8*)FCEU_gmalloc(8192); //mbg merge 7/17/06 added cast + exwram_size = 32768+8192; + //lets just always use this size, for savestate simplicity + exwram_size = FIXED_EXWRAM_SIZE; + ExWRAM=(uint8*)FCEU_gmalloc(exwram_size); FCEUI_SetVidSystem(NSFHeader.VideoSystem); @@ -305,6 +311,15 @@ void NSFMMC5_Init(void); void NSFN106_Init(void); void NSFAY_Init(void); +//zero 17-apr-2013 - added +static SFORMAT StateRegs[] = { + {&SongReload, 1, "SREL"}, + {&CurrentSong, 4 | FCEUSTATE_RLSB, "CURS"}, + {&doreset, 1, "DORE"}, + {&NSFNMIFlags, 1, "NMIF"}, + { 0 } +}; + void NSF_init(void) { doreset=1; @@ -376,6 +391,10 @@ void NSF_init(void) CurrentSong=NSFHeader.StartingSong; SongReload=0xFF; NSFNMIFlags=0; + + //zero 17-apr-2013 - added + AddExState(StateRegs, ~0, 0, 0); + AddExState(ExWRAM, FIXED_EXWRAM_SIZE, 0, "ERAM"); } static DECLFW(NSF_write) diff --git a/source/fceultra/oldmovie.cpp b/source/fceultra/oldmovie.cpp new file mode 100644 index 0000000..4ed810e --- /dev/null +++ b/source/fceultra/oldmovie.cpp @@ -0,0 +1,677 @@ +#include "version.h" +#include "types.h" +#include "fceu.h" +#include "driver.h" +#include "netplay.h" + +#include "oldmovie.h" +#include "movie.h" +#include "utils/xstring.h" + +#include + +using namespace std; + +// FCM\x1a +#define MOVIE_MAGIC 0x1a4d4346 + +// still at 2 since the format itself is still compatible +// to detect which version the movie was made with, check the fceu version stored in the movie header +// (e.g against FCEU_VERSION_NUMERIC) +#define MOVIE_VERSION 2 + +//------- +//this is just supposed to be a comment describing the disk format +//--- +//struct MovieHeader +//{ +//uint32 magic; // +0 +//uint32 version=2; // +4 +//uint8 flags[4]; // +8 +//uint32 length_frames; // +12 +//uint32 rerecord_count; // +16 +//uint32 movie_data_size; // +20 +//uint32 offset_to_savestate; // +24, should be 4-byte-aligned +//uint32 offset_to_movie_data; // +28, should be 4-byte-aligned +//uint8 md5_of_rom_used[16]; // +32 +//uint32 version_of_emu_used // +48 +//char name_of_rom_used[] // +52, utf-8, null-terminated +//char metadata[]; // utf-8, null-terminated +//uint8 padding[]; +//uint8 savestate[]; // always present, even in a "from reset" recording +//uint8 padding[]; // used for byte-alignment +//uint8 movie_data[]; +//}; +//------- + +static uint8 joop[4]; +static uint8 joopcmd; +static uint32 framets = 0; +static uint32 frameptr = 0; +static uint8* moviedata = NULL; +static uint32 moviedatasize = 0; +static uint32 firstframeoffset = 0; +static uint32 savestate_offset = 0; + +//Cache variables used for playback. +static uint32 nextts = 0; +static int32 nextd = 0; + + // turn old ucs2 metadata into utf8 +void convert_metadata(char* metadata, int metadata_size, uint8* tmp, int metadata_length) +{ + char* ptr=metadata; + char* ptr_end=metadata+metadata_size-1; + int c_ptr=0; + while(ptr=ptr_end) + ptr_end=ptr; + else + { + *ptr++=(0xc0 | (c>>6)); + *ptr++=(0x80 | (c & 0x3f)); + } + else + if(ptr+2>=ptr_end) + ptr_end=ptr; + else + { + *ptr++=(0xe0 | (c>>12)); + *ptr++=(0x80 | ((c>>6) & 0x3f)); + *ptr++=(0x80 | (c & 0x3f)); + } + + c_ptr++; + } + *ptr='\0'; +} + +//backwards compat +static void FCEUI_LoadMovie_v1(char *fname, int _read_only); +//static int FCEUI_MovieGetInfo_v1(const char* fname, MOVIE_INFO* info); + +//int _old_FCEUI_MovieGetInfo(const char* fname, MOVIE_INFO* info) +//{ +// //mbg: wtf? +// //MovieFlushHeader(); +// +// // main get info part of function +// { +// uint32 magic; +// uint32 version; +// uint8 _flags[4]; +// +// FILE* fp = FCEUD_UTF8fopen(fname, "rb"); +// if(!fp) +// return 0; +// +// read32le(&magic, fp); +// if(magic != MOVIE_MAGIC) +// { +// fclose(fp); +// return 0; +// } +// +// read32le(&version, fp); +// if(version != MOVIE_VERSION) +// { +// fclose(fp); +// if(version == 1) +// return FCEUI_MovieGetInfo_v1(fname, info); +// else +// return 0; +// } +// +// info->movie_version = MOVIE_VERSION; +// +// fread(_flags, 1, 4, fp); +// +// info->flags = _flags[0]; +// read32le(&info->num_frames, fp); +// read32le(&info->rerecord_count, fp); +// +// if(access(fname, W_OK)) +// info->read_only = 1; +// else +// info->read_only = 0; +// +// fseek(fp, 12, SEEK_CUR); // skip movie_data_size, offset_to_savestate, and offset_to_movie_data +// +// fread(&info->md5_of_rom_used, 1, 16, fp); +// info->md5_of_rom_used_present = 1; +// +// read32le(&info->emu_version_used, fp); +// +// // I probably could have planned this better... +// { +// char str[256]; +// size_t r; +// uint32 p; //mbg merge 7/17/06 change to uint32 +// int p2=0; +// char last_c=32; +// +// if(info->name_of_rom_used && info->name_of_rom_used_size) +// info->name_of_rom_used[0]='\0'; +// +// r=fread(str, 1, 256, fp); +// while(r > 0) +// { +// for(p=0; pname_of_rom_used && info->name_of_rom_used_size && (p2 < info->name_of_rom_used_size-1)) +// { +// info->name_of_rom_used[p2]=str[p]; +// p2++; +// last_c=str[p]; +// } +// } +// if(pmetadata && info->metadata_size) +// info->metadata[0]='\0'; +// +// while(r > 0) +// { +// for(p=0; pmetadata && info->metadata_size && (p2 < info->metadata_size-1)) +// { +// info->metadata[p2]=str[p]; +// p2++; +// last_c=str[p]; +// } +// } +// if(p != r) +// break; +// r=fread(str, 1, 256, fp); +// } +// +// if(r<=0) +// { +// // somehow failed to read romname and metadata +// fclose(fp); +// return 0; +// } +// } +// +// // check what hacks are necessary +// fseek(fp, 24, SEEK_SET); // offset_to_savestate offset +// uint32 temp_savestate_offset; +// read32le(&temp_savestate_offset, fp); +// if(temp_savestate_offset != 0xFFFFFFFF) +// { +// if(fseek(fp, temp_savestate_offset, SEEK_SET)) +// { +// fclose(fp); +// return 0; +// } +// +// //don't really load, just load to find what's there then load backup +// if(!FCEUSS_LoadFP(fp,SSLOADPARAM_DUMMY)) return 0; +// } +// +// fclose(fp); +// return 1; +// } +//} +/* +Backwards compat +*/ + + +/* +struct MovieHeader_v1 +{ +uint32 magic; +uint32 version=1; +uint8 flags[4]; +uint32 length_frames; +uint32 rerecord_count; +uint32 movie_data_size; +uint32 offset_to_savestate; +uint32 offset_to_movie_data; +uint16 metadata_ucs2[]; // ucs-2, ick! sizeof(metadata) = offset_to_savestate - MOVIE_HEADER_SIZE +} +*/ + +#define MOVIE_V1_HEADER_SIZE 32 + +//static void FCEUI_LoadMovie_v1(char *fname, int _read_only) +//{ +// FILE *fp; +// char *fn = NULL; +// +// FCEUI_StopMovie(); +// +// if(!fname) +// fname = fn = FCEU_MakeFName(FCEUMKF_MOVIE,0,0); +// +// // check movie_readonly +// movie_readonly = _read_only; +// if(access(fname, W_OK)) +// movie_readonly = 2; +// +// fp = FCEUD_UTF8fopen(fname, (movie_readonly>=2) ? "rb" : "r+b"); +// +// if(fn) +// { +// free(fn); +// fname = NULL; +// } +// +// if(!fp) return; +// +// // read header +// { +// uint32 magic; +// uint32 version; +// uint8 flags[4]; +// uint32 fc; +// +// read32le(&magic, fp); +// if(magic != MOVIE_MAGIC) +// { +// fclose(fp); +// return; +// } +// +// read32le(&version, fp); +// if(version != 1) +// { +// fclose(fp); +// return; +// } +// +// fread(flags, 1, 4, fp); +// read32le(&fc, fp); +// read32le(&rerecord_count, fp); +// read32le(&moviedatasize, fp); +// read32le(&savestate_offset, fp); +// read32le(&firstframeoffset, fp); +// if(fseek(fp, savestate_offset, SEEK_SET)) +// { +// fclose(fp); +// return; +// } +// +// if(flags[0] & MOVIE_FLAG_NOSYNCHACK) +// movieSyncHackOn=0; +// else +// movieSyncHackOn=1; +// } +// +// // fully reload the game to reinitialize everything before playing any movie +// // to try fixing nondeterministic playback of some games +// { +// extern char lastLoadedGameName [2048]; +// extern int disableBatteryLoading, suppressAddPowerCommand; +// suppressAddPowerCommand=1; +// suppressMovieStop=true; +// { +// FCEUGI * gi = FCEUI_LoadGame(lastLoadedGameName, 0); +// if(!gi) +// PowerNES(); +// } +// suppressMovieStop=false; +// suppressAddPowerCommand=0; +// } +// +// if(!FCEUSS_LoadFP(fp,SSLOADPARAM_BACKUP)) return; +// +// ResetInputTypes(); +// +// fseek(fp, firstframeoffset, SEEK_SET); +// moviedata = (uint8*)realloc(moviedata, moviedatasize); +// fread(moviedata, 1, moviedatasize, fp); +// +// framecount = 0; // movies start at frame 0! +// frameptr = 0; +// current = 0; +// slots = fp; +// +// memset(joop,0,sizeof(joop)); +// current = -1 - current; +// framets=0; +// nextts=0; +// nextd = -1; +// FCEU_DispMessage("Movie playback started.",0); +//} +// +//static int FCEUI_MovieGetInfo_v1(const char* fname, MOVIE_INFO* info) +//{ +// uint32 magic; +// uint32 version; +// uint8 _flags[4]; +// uint32 savestateoffset; +// uint8 tmp[MOVIE_MAX_METADATA<<1]; +// int metadata_length; +// +// FILE* fp = FCEUD_UTF8fopen(fname, "rb"); +// if(!fp) +// return 0; +// +// read32le(&magic, fp); +// if(magic != MOVIE_MAGIC) +// { +// fclose(fp); +// return 0; +// } +// +// read32le(&version, fp); +// if(version != 1) +// { +// fclose(fp); +// return 0; +// } +// +// info->movie_version = 1; +// info->emu_version_used = 0; // unknown +// +// fread(_flags, 1, 4, fp); +// +// info->flags = _flags[0]; +// read32le(&info->num_frames, fp); +// read32le(&info->rerecord_count, fp); +// +// if(access(fname, W_OK)) +// info->read_only = 1; +// else +// info->read_only = 0; +// +// fseek(fp, 4, SEEK_CUR); +// read32le(&savestateoffset, fp); +// +// metadata_length = (int)savestateoffset - MOVIE_V1_HEADER_SIZE; +// if(metadata_length > 0) +// { +// //int i; //mbg merge 7/17/06 removed +// +// metadata_length >>= 1; +// if(metadata_length >= MOVIE_MAX_METADATA) +// metadata_length = MOVIE_MAX_METADATA-1; +// +// fseek(fp, MOVIE_V1_HEADER_SIZE, SEEK_SET); +// fread(tmp, 1, metadata_length<<1, fp); +// } +// +// // turn old ucs2 metadata into utf8 +// if(info->metadata && info->metadata_size) +// { +// char* ptr=info->metadata; +// char* ptr_end=info->metadata+info->metadata_size-1; +// int c_ptr=0; +// while(ptr=ptr_end) +// ptr_end=ptr; +// else +// { +// *ptr++=(0xc0 | (c>>6)); +// *ptr++=(0x80 | (c & 0x3f)); +// } +// else +// if(ptr+2>=ptr_end) +// ptr_end=ptr; +// else +// { +// *ptr++=(0xe0 | (c>>12)); +// *ptr++=(0x80 | ((c>>6) & 0x3f)); +// *ptr++=(0x80 | (c & 0x3f)); +// } +// +// c_ptr++; +// } +// *ptr='\0'; +// } +// +// // md5 info not available from v1 +// info->md5_of_rom_used_present = 0; +// // rom name used for the movie not available from v1 +// if(info->name_of_rom_used && info->name_of_rom_used_size) +// info->name_of_rom_used[0] = '\0'; +// +// // check what hacks are necessary +// fseek(fp, 24, SEEK_SET); // offset_to_savestate offset +// uint32 temp_savestate_offset; +// read32le(&temp_savestate_offset, fp); +// if(fseek(fp, temp_savestate_offset, SEEK_SET)) +// { +// fclose(fp); +// return 0; +// } +// if(!FCEUSS_LoadFP(fp,SSLOADPARAM_DUMMY)) return 0; // 2 -> don't really load, just load to find what's there then load backup +// +// +// fclose(fp); +// return 1; +//} + +static int movie_readchar() +{ + if(frameptr >= moviedatasize) + { + return -1; + } + return (int)(moviedata[frameptr++]); +} + + +static void _addjoy() +{ + while(nextts == framets || nextd == -1) + { + int tmp,ti; + uint8 d; + + if(nextd != -1) + { + if(nextd&0x80) + { + //FCEU_DoSimpleCommand(nextd&0x1F); + int command = nextd&0x1F; + if(command == FCEUNPCMD_RESET) + joopcmd = MOVIECMD_RESET; + if(command == FCEUNPCMD_POWER) + joopcmd = MOVIECMD_POWER; + } + else + joop[(nextd >> 3)&0x3] ^= 1 << (nextd&0x7); + } + + + tmp = movie_readchar(); + d = tmp; + + if(tmp < 0) + { + return; + } + + nextts = 0; + tmp >>= 5; + tmp &= 0x3; + ti=0; + + int tmpfix = tmp; + while(tmp--) { nextts |= movie_readchar() << (ti * 8); ti++; } + + // This fixes a bug in movies recorded before version 0.98.11 + // It's probably not necessary, but it may keep away CRAZY PEOPLE who recorded + // movies on <= 0.98.10 and don't work on playback. + if(tmpfix == 1 && !nextts) + {nextts |= movie_readchar()<<8; } + else if(tmpfix == 2 && !nextts) {nextts |= movie_readchar()<<16; } + + if(nextd != -1) + framets = 0; + nextd = d; + } + + framets++; +} + + +EFCM_CONVERTRESULT convert_fcm(MovieData& md, std::string fname) +{ + //convert EVEN OLDER movies to fcm + //fname = (char*)convertToFCM(fname,buffer); + + uint32 framecount; + uint32 rerecord_count; + int movieConvertOffset1=0, movieConvertOffset2=0,movieSyncHackOn=0; + + + EMUFILE* fp = FCEUD_UTF8_fstream(fname, "rb"); + if(!fp) return FCM_CONVERTRESULT_FAILOPEN; + + // read header + uint32 magic = 0; + uint32 version; + uint8 flags[4]; + + read32le(&magic, fp); + if(magic != MOVIE_MAGIC) + { + delete fp; + return FCM_CONVERTRESULT_FAILOPEN; + } + + read32le(&version, fp); + if(version == 1) + { + // attempt to load previous version's format + //TODO + delete fp; + //FCEUI_LoadMovie_v1(fname, _read_only); + return FCM_CONVERTRESULT_OLDVERSION; + } + else if(version == MOVIE_VERSION) + {} + else + { + // unsupported version + delete fp; + return FCM_CONVERTRESULT_UNSUPPORTEDVERSION; + } + + + fp->fread((char*)&flags,4); + read32le(&framecount, fp); + read32le(&rerecord_count, fp); + read32le(&moviedatasize, fp); + read32le(&savestate_offset, fp); + read32le(&firstframeoffset, fp); + + //read header values + fp->fread((char*)&md.romChecksum,16); + read32le((uint32*)&md.emuVersion,fp); + + md.romFilename = readNullTerminatedAscii(fp); + + md.comments.push_back(L"author " + mbstowcs(readNullTerminatedAscii(fp))); + + //int metadata_length = savestate_offset - MOVIE_V1_HEADER_SIZE; + //uint8* metadata = new uint8[metadata_length]; + //char* wcmetadata = new char[metadata_length*4]; //seems to me like we support the worst case + //fp->read((char*)metadata,metadata_length); + //convert_metadata(wcmetadata,metadata_length*4,metadata,metadata_length); + //md.comments.push_back(L"author " + (std::wstring)(wchar_t*)wcmetadata); + + // FCEU_PrintError("flags[0] & MOVIE_FLAG_NOSYNCHACK=%d",flags[0] & MOVIE_FLAG_NOSYNCHACK); + if(flags[0] & MOVIE_FLAG_NOSYNCHACK) + movieSyncHackOn=0; + else + movieSyncHackOn=1; + + if(flags[0] & MOVIE_FLAG_PAL) + md.palFlag = true; + + bool initreset = false; + if(flags[0] & MOVIE_FLAG_FROM_POWERON) + { + //don't need to load a savestate + } + else if(flags[0] & MOVIE_FLAG_FROM_RESET) + { + initreset = true; + } + else + { + delete fp; + return FCM_CONVERTRESULT_STARTFROMSAVESTATENOTSUPPORTED; + } + + //analyze input types? + //ResetInputTypes(); + + fp->fseek(firstframeoffset,SEEK_SET); + moviedata = (uint8*)realloc(moviedata, moviedatasize); + fp->fread((char*)moviedata,moviedatasize); + + frameptr = 0; + memset(joop,0,sizeof(joop)); + framets=0; + nextts=0; + nextd = -1; + + //prepare output structure + md.rerecordCount = rerecord_count; + md.records.resize(framecount); + md.guid.newGuid(); + + //begin decoding. + //joymask is used to look for any joystick that has input. + //if joysticks 3 or 4 have input then we will enable fourscore + uint8 joymask[4] = {0,0,0,0}; + for(uint32 i=0;i -#include -#include -#include - #include "types.h" #include "file.h" @@ -42,6 +37,11 @@ #define M_PI 3.14159265358979323846 #endif +#include +#include +#include +#include + static int ntsccol=0; static int ntsctint=46+10; static int ntschue=72; @@ -98,9 +98,34 @@ void FCEUI_SetNTSCTH(int n, int tint, int hue) static uint8 lastd=0; void SetNESDeemph(uint8 d, int force) { - static uint16 rtmul[7]={32768*1.239,32768*.794,32768*1.019,32768*.905,32768*1.023,32768*.741,32768*.75}; - static uint16 gtmul[7]={32768*.915,32768*1.086,32768*.98,32768*1.026,32768*.908,32768*.987,32768*.75}; - static uint16 btmul[7]={32768*.743,32768*.882,32768*.653,32768*1.277,32768*.979,32768*.101,32768*.75}; + static uint16 rtmul[]={ + static_cast(32768*1.239), + static_cast(32768*.794), + static_cast(32768*1.019), + static_cast(32768*.905), + static_cast(32768*1.023), + static_cast(32768*.741), + static_cast(32768*.75) + }; + static uint16 gtmul[]={ + static_cast(32768*.915), + static_cast(32768*1.086), + static_cast(32768*.98), + static_cast(32768*1.026), + static_cast(32768*.908), + static_cast(32768*.987), + static_cast(32768*.75) + }; + static uint16 btmul[]={ + static_cast(32768*.743), + static_cast(32768*.882), + static_cast(32768*.653), + static_cast(32768*1.277), + static_cast(32768*.979), + static_cast(32768*.101), + static_cast(32768*.75) + }; + uint32 r,g,b; int x; diff --git a/source/fceultra/palettes/SConscript b/source/fceultra/palettes/SConscript new file mode 100644 index 0000000..7e4aef5 --- /dev/null +++ b/source/fceultra/palettes/SConscript @@ -0,0 +1,6 @@ +import glob +source_list = glob.glob('*.c') + +for x in range(len(source_list)): + source_list[x] = 'palettes/' + source_list[x] +Return('source_list') diff --git a/source/fceultra/ppu.cpp b/source/fceultra/ppu.cpp index e1136a7..b291e66 100644 --- a/source/fceultra/ppu.cpp +++ b/source/fceultra/ppu.cpp @@ -1,64 +1,63 @@ /* FCE Ultra - NES/Famicom Emulator -* -* Copyright notice for this file: -* Copyright (C) 1998 BERO -* Copyright (C) 2003 Xodnizel -* -* 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 2 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, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ + * + * Copyright notice for this file: + * Copyright (C) 1998 BERO + * Copyright (C) 2003 Xodnizel + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ -#include -#include -#include +#include "types.h" +#include "x6502.h" +#include "fceu.h" +#include "ppu.h" +#include "nsf.h" +#include "sound.h" +#include "file.h" +#include "utils/endian.h" +#include "utils/memory.h" -#include "types.h" -#include "x6502.h" -#include "fceu.h" -#include "ppu.h" -#include "nsf.h" -#include "sound.h" -#include "file.h" -#include "utils/endian.h" -#include "utils/memory.h" +#include "cart.h" +#include "palette.h" +#include "state.h" +#include "video.h" +#include "input.h" +#include "driver.h" +#include "debug.h" -#include "cart.h" -#include "palette.h" -#include "state.h" -#include "video.h" -#include "input.h" -#include "driver.h" -#include "debug.h" +#include +#include +#include +#define VBlankON (PPU[0] & 0x80) //Generate VBlank NMI +#define Sprite16 (PPU[0] & 0x20) //Sprites 8x16/8x8 +#define BGAdrHI (PPU[0] & 0x10) //BG pattern adr $0000/$1000 +#define SpAdrHI (PPU[0] & 0x08) //Sprite pattern adr $0000/$1000 +#define INC32 (PPU[0] & 0x04) //auto increment 1/32 -#define VBlankON (PPU[0]&0x80) //Generate VBlank NMI -#define Sprite16 (PPU[0]&0x20) //Sprites 8x16/8x8 -#define BGAdrHI (PPU[0]&0x10) //BG pattern adr $0000/$1000 -#define SpAdrHI (PPU[0]&0x08) //Sprite pattern adr $0000/$1000 -#define INC32 (PPU[0]&0x04) //auto increment 1/32 +#define SpriteON (PPU[1] & 0x10) //Show Sprite +#define ScreenON (PPU[1] & 0x08) //Show screen +#define PPUON (PPU[1] & 0x18) //PPU should operate +#define GRAYSCALE (PPU[1] & 0x01) //Grayscale (AND palette entries with 0x30) -#define SpriteON (PPU[1]&0x10) //Show Sprite -#define ScreenON (PPU[1]&0x08) //Show screen -#define PPUON (PPU[1]&0x18) //PPU should operate -#define GRAYSCALE (PPU[1]&0x01) //Grayscale (AND palette entries with 0x30) - -#define SpriteLeft8 (PPU[1]&0x04) -#define BGLeft8 (PPU[1]&0x02) +#define SpriteLeft8 (PPU[1] & 0x04) +#define BGLeft8 (PPU[1] & 0x02) #define PPU_status (PPU[2]) -#define Pal (PALRAM) +#define Pal (PALRAM) static void FetchSpriteData(void); static void RefreshLine(int lastpixel); @@ -74,48 +73,47 @@ int test = 0; template struct BITREVLUT { - T* lut; BITREVLUT() { int bits = BITS; - int n = 1<>1; + int a = n >> 1; int j = 2; lut[0] = 0; lut[1] = a; - while(--bits) { + while (--bits) { m <<= 1; a >>= 1; - for(int i=0;i bitrevlut; +BITREVLUT bitrevlut; -struct PPUSTATUS -{ - int32 sl; - int32 cycle, end_cycle; +struct PPUSTATUS { + int32 sl; + int32 cycle, end_cycle; }; -struct SPRITE_READ -{ - int32 num; - int32 count; - int32 fetch; - int32 found; - int32 found_pos[8]; - int32 ret; - int32 last; - int32 mode; + +struct SPRITE_READ { + int32 num; + int32 count; + int32 fetch; + int32 found; + int32 found_pos[8]; + int32 ret; + int32 last; + int32 mode; void reset() { num = count = fetch = found = ret = last = mode = 0; @@ -123,14 +121,13 @@ struct SPRITE_READ found_pos[4] = found_pos[5] = found_pos[6] = found_pos[7] = 0; } - void start_scanline() - { + void start_scanline() { num = 1; - found = 0; - fetch = 1; - count = 0; - last = 64; - mode = 0; + found = 0; + fetch = 1; + count = 0; + last = 64; + mode = 0; found_pos[0] = found_pos[1] = found_pos[2] = found_pos[3] = 0; found_pos[4] = found_pos[5] = found_pos[6] = found_pos[7] = 0; } @@ -148,28 +145,27 @@ uint8 idleSynch = 1; //uses the internal counters concept at http://nesdev.icequake.net/PPU%20addressing.txt struct PPUREGS { //normal clocked regs. as the game can interfere with these at any time, they need to be savestated - uint32 fv;//3 - uint32 v;//1 - uint32 h;//1 - uint32 vt;//5 - uint32 ht;//5 + uint32 fv; //3 + uint32 v; //1 + uint32 h; //1 + uint32 vt; //5 + uint32 ht; //5 //temp unlatched regs (need savestating, can be written to at any time) - uint32 _fv, _v, _h, _vt, _ht; + uint32 _fv, _v, _h, _vt, _ht; //other regs that need savestating - uint32 fh;//3 (horz scroll) - uint32 s;//1 ($2000 bit 4: "Background pattern table address (0: $0000; 1: $1000)") + uint32 fh; //3 (horz scroll) + uint32 s; //1 ($2000 bit 4: "Background pattern table address (0: $0000; 1: $1000)") //other regs that don't need saving - uint32 par;//8 (sort of a hack, just stored in here, but not managed by this system) + uint32 par; //8 (sort of a hack, just stored in here, but not managed by this system) //cached state data. these are always reset at the beginning of a frame and don't need saving //but just to be safe, we're gonna save it - PPUSTATUS status; + PPUSTATUS status; - void reset() - { + void reset() { fv = v = h = vt = ht = 0; fh = par = s = 0; _fv = _v = _h = _vt = _ht = 0; @@ -201,7 +197,7 @@ struct PPUREGS { //made up by daisy-chaining the HT counter to the H counter. The HT counter is //then clocked every 8 pixel dot clocks (or every 8/3 CPU clock cycles). ht++; - h += (ht>>5); + h += (ht >> 5); ht &= 31; h &= 1; } @@ -210,22 +206,21 @@ struct PPUREGS { fv++; int fv_overflow = (fv >> 3); vt += fv_overflow; - vt &= 31; //fixed tecmo super bowl - if(vt == 30 && fv_overflow==1) //caution here (only do it at the exact instant of overflow) fixes p'radikus conflict - { + vt &= 31; //fixed tecmo super bowl + if (vt == 30 && fv_overflow == 1) { //caution here (only do it at the exact instant of overflow) fixes p'radikus conflict v++; - vt=0; + vt = 0; } fv &= 7; v &= 1; } uint32 get_ntread() { - return 0x2000 | (v<<0xB) | (h<<0xA) | (vt<<5) | ht; + return 0x2000 | (v << 0xB) | (h << 0xA) | (vt << 5) | ht; } uint32 get_2007access() { - return ((fv&3)<<0xC) | (v<<0xB) | (h<<0xA) | (vt<<5) | ht; + return ((fv & 3) << 0xC) | (v << 0xB) | (h << 0xA) | (vt << 5) | ht; } //The PPU has an internal 4-position, 2-bit shifter, which it uses for @@ -235,15 +230,25 @@ struct PPUREGS { //apply to the data read from the attribute data (a is always 0). This is why //you only see bits 0 and 1 used off the read attribute data in the diagram. uint32 get_atread() { - return 0x2000 | (v<<0xB) | (h<<0xA) | 0x3C0 | ((vt&0x1C)<<1) | ((ht&0x1C)>>2); + return 0x2000 | (v << 0xB) | (h << 0xA) | 0x3C0 | ((vt & 0x1C) << 1) | ((ht & 0x1C) >> 2); } //address line 3 relates to the pattern table fetch occuring (the PPU always makes them in pairs). uint32 get_ptread() { - return (s<<0xC) | (par<<0x4) | fv; + return (s << 0xC) | (par << 0x4) | fv; } - void increment2007(bool by32) { + void increment2007(bool rendering, bool by32) { + + if (rendering) + { + //don't do this: + //if (by32) increment_vs(); + //else increment_hsc(); + //do this instead: + increment_vs(); //yes, even if we're moving by 32 + return; + } //If the VRAM address increment bit (2000.2) is clear (inc. amt. = 1), all the //scroll counters are daisy-chained (in the order of HT, VT, H, V, FV) so that @@ -254,15 +259,15 @@ struct PPUREGS { //If the VRAM address increment bit is set (inc. amt. = 32), the only //difference is that the HT counter is no longer being clocked, and the VT //counter is now being clocked by access to 2007. - if(by32) { + if (by32) { vt++; } else { ht++; - vt+=(ht>>5)&1; + vt += (ht >> 5) & 1; } - h+=(vt>>5); - v+=(h>>1); - fv+=(v>>1); + h += (vt >> 5); + v += (h >> 1); + fv += (v >> 1); ht &= 31; vt &= 31; h &= 1; @@ -271,82 +276,70 @@ struct PPUREGS { } } ppur; - -static void makeppulut(void) -{ +static void makeppulut(void) { int x; int y; - int cc,xo,pixel; + int cc, xo, pixel; - for(x=0;x<256;x++) - { + for (x = 0; x < 256; x++) { ppulut1[x] = 0; - - for(y=0;y<8;y++) - { - ppulut1[x] |= ((x>>(7-y))&1)<<(y*4); - } - + for (y = 0; y < 8; y++) + ppulut1[x] |= ((x >> (7 - y)) & 1) << (y * 4); ppulut2[x] = ppulut1[x] << 1; } - for(cc=0;cc<16;cc++) - { - for(xo=0;xo<8;xo++) - { - ppulut3[ xo | ( cc << 3 ) ] = 0; - - for(pixel=0;pixel<8;pixel++) - { + for (cc = 0; cc < 16; cc++) { + for (xo = 0; xo < 8; xo++) { + ppulut3[xo | (cc << 3)] = 0; + for (pixel = 0; pixel < 8; pixel++) { int shiftr; - shiftr = ( pixel + xo ) / 8; + shiftr = (pixel + xo) / 8; shiftr *= 2; - ppulut3[ xo | (cc<<3) ] |= ( ( cc >> shiftr ) & 3 ) << ( 2 + pixel * 4 ); + ppulut3[xo | (cc << 3)] |= ((cc >> shiftr) & 3) << (2 + pixel * 4); } - // printf("%08x\n",ppulut3[xo|(cc<<3)]); } } } -static int ppudead=1; -static int kook=0; -int fceuindbg=0; +static int ppudead = 1; +static int kook = 0; +int fceuindbg = 0; //mbg 6/23/08 //make the no-bg fill color configurable //0xFF shall indicate to use palette[0] uint8 gNoBGFillColor = 0xFF; -int MMC5Hack=0; -uint32 MMC5HackVROMMask=0; -uint8 *MMC5HackExNTARAMPtr=0; -uint8 *MMC5HackVROMPTR=0; -uint8 MMC5HackCHRMode=0; -uint8 MMC5HackSPMode=0; -uint8 MMC50x5130=0; -uint8 MMC5HackSPScroll=0; -uint8 MMC5HackSPPage=0; +int MMC5Hack = 0, PEC586Hack = 0;; +uint32 MMC5HackVROMMask = 0; +uint8 *MMC5HackExNTARAMPtr = 0; +uint8 *MMC5HackVROMPTR = 0; +uint8 MMC5HackCHRMode = 0; +uint8 MMC5HackSPMode = 0; +uint8 MMC50x5130 = 0; +uint8 MMC5HackSPScroll = 0; +uint8 MMC5HackSPPage = 0; - -uint8 VRAMBuffer=0,PPUGenLatch=0; +uint8 VRAMBuffer = 0, PPUGenLatch = 0; uint8 *vnapage[4]; -uint8 PPUNTARAM=0; -uint8 PPUCHRRAM=0; +uint8 PPUNTARAM = 0; +uint8 PPUCHRRAM = 0; //Color deemphasis emulation. Joy... -static uint8 deemp=0; +static uint8 deemp = 0; static int deempcnt[8]; void (*GameHBIRQHook)(void), (*GameHBIRQHook2)(void); void (*PPU_hook)(uint32 A); -uint8 vtoggle=0; -uint8 XOffset=0; +uint8 vtoggle = 0; +uint8 XOffset = 0; +uint8 SpriteDMA = 0; // $4014 / Writing $xx copies 256 bytes by reading from $xx00-$xxFF and writing to $2004 (OAM data) -uint32 TempAddr=0,RefreshAddr=0,DummyRead=0; +uint32 TempAddr = 0, RefreshAddr = 0, DummyRead = 0; -static int maxsprites=8; +static int maxsprites = 8; //scanline is equal to the current visible scanline we're on. int scanline; @@ -355,25 +348,24 @@ static uint32 scanlines_per_frame; uint8 PPU[4]; uint8 PPUSPL; -uint8 NTARAM[0x800],PALRAM[0x20],SPRAM[0x100],SPRBUF[0x100]; -uint8 UPALRAM[0x03]; //for 0x4/0x8/0xC addresses in palette, the ones in - //0x20 are 0 to not break fceu rendering. +uint8 NTARAM[0x800], PALRAM[0x20], SPRAM[0x100], SPRBUF[0x100]; +uint8 UPALRAM[0x03];//for 0x4/0x8/0xC addresses in palette, the ones in + //0x20 are 0 to not break fceu rendering. - -#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)] -#define VRAMADR(V) &VPage[(V)>>10][(V)] +#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V) >> 10][(V)] +#define VRAMADR(V) &VPage[(V) >> 10][(V)] //mbg 8/6/08 - fix a bug relating to //"When in 8x8 sprite mode, only one set is used for both BG and sprites." //in mmc5 docs uint8 * MMC5BGVRAMADR(uint32 V) { - if(!Sprite16) { - extern uint8 mmc5ABMode; /* A=0, B=1 */ - if(mmc5ABMode==0) + if (!Sprite16) { + extern uint8 mmc5ABMode; /* A=0, B=1 */ + if (mmc5ABMode == 0) return MMC5SPRVRAMADR(V); else - return &MMC5BGVPage[(V)>>10][(V)]; - } else return &MMC5BGVPage[(V)>>10][(V)]; + return &MMC5BGVPage[(V) >> 10][(V)]; + } else return &MMC5BGVPage[(V) >> 10][(V)]; } //this duplicates logic which is embedded in the ppu rendering code @@ -381,117 +373,104 @@ uint8 * MMC5BGVRAMADR(uint32 V) { //mostly involving mmc5. //this might be incomplete. uint8* FCEUPPU_GetCHR(uint32 vadr, uint32 refreshaddr) { - if(MMC5Hack) { - if(MMC5HackCHRMode==1) { + if (MMC5Hack) { + if (MMC5HackCHRMode == 1) { uint8 *C = MMC5HackVROMPTR; C += (((MMC5HackExNTARAMPtr[refreshaddr & 0x3ff]) & 0x3f & MMC5HackVROMMask) << 12) + (vadr & 0xfff); - C += (MMC50x5130&0x3)<<18; //11-jun-2009 for kuja_killer + C += (MMC50x5130 & 0x3) << 18; //11-jun-2009 for kuja_killer return C; } else { return MMC5BGVRAMADR(vadr); } - } - else return VRAMADR(vadr); + } else return VRAMADR(vadr); } //likewise for ATTR int FCEUPPU_GetAttr(int ntnum, int xt, int yt) { - int attraddr = 0x3C0+((yt>>2)<<3)+(xt>>2); - int temp = (((yt&2)<<1)+(xt&2)); - int refreshaddr = xt+yt*32; - if(MMC5Hack && MMC5HackCHRMode==1) - return (MMC5HackExNTARAMPtr[refreshaddr & 0x3ff] & 0xC0)>>6; + int attraddr = 0x3C0 + ((yt >> 2) << 3) + (xt >> 2); + int temp = (((yt & 2) << 1) + (xt & 2)); + int refreshaddr = xt + yt * 32; + if (MMC5Hack && MMC5HackCHRMode == 1) + return (MMC5HackExNTARAMPtr[refreshaddr & 0x3ff] & 0xC0) >> 6; else - return (vnapage[ntnum][attraddr] & (3<> temp; + return (vnapage[ntnum][attraddr] & (3 << temp)) >> temp; } //new ppu----- inline void FFCEUX_PPUWrite_Default(uint32 A, uint8 V) { uint32 tmp = A; - if(PPU_hook) PPU_hook(A); + if (PPU_hook) PPU_hook(A); - if(tmp<0x2000) - { - if(PPUCHRRAM&(1<<(tmp>>10))) - VPage[tmp>>10][tmp]=V; - } - else if (tmp<0x3F00) - { - if(PPUNTARAM&(1<<((tmp&0xF00)>>10))) - vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V; - } - else - { - if (!(tmp & 3)) - { - if (!(tmp & 0xC)) - PALRAM[0x00] = PALRAM[0x04] = - PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F; - else - UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F; - } - else - PALRAM[tmp & 0x1F] = V & 0x3F; - } + if (tmp < 0x2000) { + if (PPUCHRRAM & (1 << (tmp >> 10))) + VPage[tmp >> 10][tmp] = V; + } else if (tmp < 0x3F00) { + if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10))) + vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V; + } else { + if (!(tmp & 3)) { + if (!(tmp & 0xC)) + PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F; + else + UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F; + } else + PALRAM[tmp & 0x1F] = V & 0x3F; + } } volatile int rendercount, vromreadcount, undefinedvromcount, LogAddress = -1; unsigned char *cdloggervdata; -extern uint32 VROM_size; +unsigned int cdloggerVideoDataSize = 0; -int GetCHRAddress(int A){ - int result; - if((A > 0x1fff))return -1; - if(!VROM_size)return -1; - result = &VPage[A>>10][A]-CHRptr[0]; - if((result > (int)CHRsize[0]) || (result < 0))return -1; - else return result; +int GetCHRAddress(int A) { + if (cdloggerVideoDataSize) { + int result = &VPage[A >> 10][A] - CHRptr[0]; + if ((result >= 0) && (result < (int)cdloggerVideoDataSize)) + return result; + } + return -1; +} + +#define RENDER_LOG(tmp) { \ + if (debug_loggingCD) \ + { \ + int addr = GetCHRAddress(tmp); \ + if (addr != -1) \ + { \ + if (!(cdloggervdata[addr] & 1)) \ + { \ + cdloggervdata[addr] |= 1; \ + if (!(cdloggervdata[addr] & 2)) undefinedvromcount--; \ + rendercount++; \ + } \ + } \ + } \ } uint8 FASTCALL FFCEUX_PPURead_Default(uint32 A) { uint32 tmp = A; - if(PPU_hook) PPU_hook(A); + if (PPU_hook) PPU_hook(A); - if(tmp<0x2000) - { - if(debug_loggingCD) - { - int addr = GetCHRAddress(tmp); - if(addr != -1) - { - if(!(cdloggervdata[addr] & 1)) - { - cdloggervdata[addr] |= 1; - if(!(cdloggervdata[addr] & 2))undefinedvromcount--; - rendercount++; - } - } - } - return VPage[tmp>>10][tmp]; - } - else if (tmp < 0x3F00) - { - return vnapage[(tmp>>10)&0x3][tmp&0x3FF]; - } - else - { - uint8 ret; - if (!(tmp & 3)) - { - if (!(tmp & 0xC)) - ret = PALRAM[0x00]; - else - ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; - } - else - ret = PALRAM[tmp & 0x1F]; + if (tmp < 0x2000) { + return VPage[tmp >> 10][tmp]; + } else if (tmp < 0x3F00) { + return vnapage[(tmp >> 10) & 0x3][tmp & 0x3FF]; + } else { + uint8 ret; + if (!(tmp & 3)) { + if (!(tmp & 0xC)) + ret = PALRAM[0x00]; + else + ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; + } else + ret = PALRAM[tmp & 0x1F]; - if (GRAYSCALE) - ret &= 0x30; - return ret; - } + if (GRAYSCALE) + ret &= 0x30; + return ret; + } } @@ -500,32 +479,26 @@ void (*FFCEUX_PPUWrite)(uint32 A, uint8 V) = 0; #define CALL_PPUREAD(A) (FFCEUX_PPURead(A)) -#define CALL_PPUWRITE(A,V) (FFCEUX_PPUWrite?FFCEUX_PPUWrite(A,V):FFCEUX_PPUWrite_Default(A,V)) +#define CALL_PPUWRITE(A, V) (FFCEUX_PPUWrite ? FFCEUX_PPUWrite(A, V) : FFCEUX_PPUWrite_Default(A, V)) //whether to use the new ppu (new PPU doesn't handle MMC5 extra nametables at all int newppu = 0; -void ppu_getScroll(int &xpos, int &ypos) -{ - if(newppu) - { - ypos = ppur._vt*8 + ppur._fv + ppur._v*256; - xpos = ppur._ht*8 + ppur.fh + ppur._h*256; - } - else - { +void ppu_getScroll(int &xpos, int &ypos) { + if (newppu) { + ypos = ppur._vt * 8 + ppur._fv + ppur._v * 256; + xpos = ppur._ht * 8 + ppur.fh + ppur._h * 256; + } else { xpos = ((RefreshAddr & 0x400) >> 2) | ((RefreshAddr & 0x1F) << 3) | XOffset; ypos = ((RefreshAddr & 0x3E0) >> 2) | ((RefreshAddr & 0x7000) >> 12); - if(RefreshAddr & 0x800) ypos += 240; + if (RefreshAddr & 0x800) ypos += 240; } } //--------------- -static DECLFR(A2002) -{ - if(newppu) - { +static DECLFR(A2002) { + if (newppu) { //once we thought we clear latches here, but that caused midframe glitches. //i think we should only reset the state machine for 2005/2006 //ppur.clear_latches(); @@ -535,649 +508,491 @@ static DECLFR(A2002) FCEUPPU_LineUpdate(); ret = PPU_status; - ret|=PPUGenLatch&0x1F; + ret |= PPUGenLatch & 0x1F; #ifdef FCEUDEF_DEBUGGER - if(!fceuindbg) + if (!fceuindbg) #endif { - vtoggle=0; - PPU_status&=0x7F; - PPUGenLatch=ret; + vtoggle = 0; + PPU_status &= 0x7F; + PPUGenLatch = ret; } return ret; } -static DECLFR(A2004) -{ - if (newppu) - { - if ((ppur.status.sl < 241) && PPUON) - { - /* from cycles 0 to 63, the - * 32 byte OAM buffer gets init - * to 0xFF */ - if (ppur.status.cycle < 64) - return spr_read.ret = 0xFF; - else - { - for (int i = spr_read.last; - i != ppur.status.cycle; ++i) - { - if (i < 256) - { - switch (spr_read.mode) - { - case 0: - if (spr_read.count < 2) - spr_read.ret = (PPU[3] & 0xF8) - + (spr_read.count << 2); - else - spr_read.ret = spr_read.count << 2; - spr_read.found_pos[spr_read.found] = - spr_read.ret; +static DECLFR(A2004) { + if (newppu) { + if ((ppur.status.sl < 241) && PPUON) { + // from cycles 0 to 63, the + // 32 byte OAM buffer gets init + // to 0xFF + if (ppur.status.cycle < 64) + return spr_read.ret = 0xFF; + else { + for (int i = spr_read.last; + i != ppur.status.cycle; ++i) { + if (i < 256) { + switch (spr_read.mode) { + case 0: + if (spr_read.count < 2) + spr_read.ret = (PPU[3] & 0xF8) + (spr_read.count << 2); + else + spr_read.ret = spr_read.count << 2; - spr_read.ret = SPRAM[spr_read.ret]; + spr_read.found_pos[spr_read.found] = spr_read.ret; + spr_read.ret = SPRAM[spr_read.ret]; - if (i & 1) //odd cycle - { - //see if in range - if ( !((ppur.status.sl - 1 - - spr_read.ret) - & ~(Sprite16 ? 0xF : 0x7)) ) + if (i & 1) { + //odd cycle + //see if in range + if (!((ppur.status.sl - 1 - spr_read.ret) & ~(Sprite16 ? 0xF : 0x7))) { + ++spr_read.found; + spr_read.fetch = 1; + spr_read.mode = 1; + } else { + if (++spr_read.count == 64) { + spr_read.mode = 4; + spr_read.count = 0; + } else if (spr_read.found == 8) { + spr_read.fetch = 0; + spr_read.mode = 2; + } + } + } + break; + case 1: //sprite is in range fetch next 3 bytes + if (i & 1) { + ++spr_read.fetch; + if (spr_read.fetch == 4) { + spr_read.fetch = 1; + if (++spr_read.count == 64) { + spr_read.count = 0; + spr_read.mode = 4; + } else if (spr_read.found == 8) { + spr_read.fetch = 0; + spr_read.mode = 2; + } else + spr_read.mode = 0; + } + } - { - ++spr_read.found; - spr_read.fetch = 1; - spr_read.mode = 1; - } - else - { - if (++spr_read.count == 64) - { - spr_read.mode = 4; - spr_read.count = 0; - } - else if (spr_read.found == 8) - { - spr_read.fetch = 0; - spr_read.mode = 2; - } - } - } - break; - case 1: //sprite is in range fetch next 3 bytes - if (i & 1) - { - ++spr_read.fetch; - if (spr_read.fetch == 4) - { - spr_read.fetch = 1; - if (++spr_read.count == 64) - { - spr_read.count = 0; - spr_read.mode = 4; - } - else if (spr_read.found == 8) - { - spr_read.fetch = 0; - spr_read.mode = 2; - } - else - spr_read.mode = 0; - } - } + if (spr_read.count < 2) + spr_read.ret = (PPU[3] & 0xF8) + (spr_read.count << 2); + else + spr_read.ret = spr_read.count << 2; - if (spr_read.count < 2) - spr_read.ret = (PPU[3] & 0xF8) - + (spr_read.count << 2); - else - spr_read.ret = spr_read.count << 2; - - spr_read.ret = SPRAM[spr_read.ret | - spr_read.fetch]; - break; - case 2: //8th sprite fetched - spr_read.ret = SPRAM[(spr_read.count << 2) - | spr_read.fetch]; - if (i & 1) - { - if ( !((ppur.status.sl - 1 - - SPRAM[((spr_read.count << 2) - | spr_read.fetch)]) - & ~((Sprite16) ? 0xF : 0x7)) ) - { - spr_read.fetch = 1; - spr_read.mode = 3; - } - else - { - if (++spr_read.count == 64) - { - spr_read.count = 0; - spr_read.mode = 4; - } - spr_read.fetch = - (spr_read.fetch + 1) & 3; - } - } - spr_read.ret = spr_read.count; - break; - case 3: //9th sprite overflow detected - spr_read.ret = SPRAM[spr_read.count - | spr_read.fetch]; - if (i & 1) - { - if (++spr_read.fetch == 4) - { - spr_read.count = (spr_read.count - + 1) & 63; - spr_read.mode = 4; - } - } - break; - case 4: //read OAM[n][0] until hblank - if (i & 1) - spr_read.count = - (spr_read.count + 1) & 63; - spr_read.fetch = 0; - spr_read.ret = SPRAM[spr_read.count << 2]; - break; - } - } - else if (i < 320) - { - spr_read.ret = (i & 0x38) >> 3; - if (spr_read.found < (spr_read.ret + 1)) - { - if (spr_read.num) - { - spr_read.ret = SPRAM[252]; - spr_read.num = 0; - } - else - spr_read.ret = 0xFF; - } - else if ((i & 7) < 4) - { - spr_read.ret = - SPRAM[spr_read.found_pos[spr_read.ret] - | spr_read.fetch++]; - if (spr_read.fetch == 4) - spr_read.fetch = 0; - } - else - spr_read.ret = SPRAM[spr_read.found_pos - [spr_read.ret | 3]]; - } - else - { - if (!spr_read.found) - spr_read.ret = SPRAM[252]; - else - spr_read.ret = SPRAM[spr_read.found_pos[0]]; - break; - } - } - spr_read.last = ppur.status.cycle; - return spr_read.ret; - } - } - else - return SPRAM[PPU[3]]; - } - else - { - FCEUPPU_LineUpdate(); - return PPUGenLatch; - } + spr_read.ret = SPRAM[spr_read.ret | spr_read.fetch]; + break; + case 2: //8th sprite fetched + spr_read.ret = SPRAM[(spr_read.count << 2) | spr_read.fetch]; + if (i & 1) { + if (!((ppur.status.sl - 1 - SPRAM[((spr_read.count << 2) | spr_read.fetch)]) & ~((Sprite16) ? 0xF : 0x7))) { + spr_read.fetch = 1; + spr_read.mode = 3; + } else { + if (++spr_read.count == 64) { + spr_read.count = 0; + spr_read.mode = 4; + } + spr_read.fetch = + (spr_read.fetch + 1) & 3; + } + } + spr_read.ret = spr_read.count; + break; + case 3: //9th sprite overflow detected + spr_read.ret = SPRAM[spr_read.count | spr_read.fetch]; + if (i & 1) { + if (++spr_read.fetch == 4) { + spr_read.count = (spr_read.count + 1) & 63; + spr_read.mode = 4; + } + } + break; + case 4: //read OAM[n][0] until hblank + if (i & 1) + spr_read.count = (spr_read.count + 1) & 63; + spr_read.fetch = 0; + spr_read.ret = SPRAM[spr_read.count << 2]; + break; + } + } else if (i < 320) { + spr_read.ret = (i & 0x38) >> 3; + if (spr_read.found < (spr_read.ret + 1)) { + if (spr_read.num) { + spr_read.ret = SPRAM[252]; + spr_read.num = 0; + } else + spr_read.ret = 0xFF; + } else if ((i & 7) < 4) { + spr_read.ret = + SPRAM[spr_read.found_pos[spr_read.ret] | spr_read.fetch++]; + if (spr_read.fetch == 4) + spr_read.fetch = 0; + } else + spr_read.ret = SPRAM[spr_read.found_pos [spr_read.ret | 3]]; + } else { + if (!spr_read.found) + spr_read.ret = SPRAM[252]; + else + spr_read.ret = SPRAM[spr_read.found_pos[0]]; + break; + } + } + spr_read.last = ppur.status.cycle; + return spr_read.ret; + } + } else + return SPRAM[PPU[3]]; + } else { + FCEUPPU_LineUpdate(); + return PPUGenLatch; + } } -static DECLFR(A200x) /* Not correct for $2004 reads. */ -{ +static DECLFR(A200x) { /* Not correct for $2004 reads. */ FCEUPPU_LineUpdate(); return PPUGenLatch; } -/* -static DECLFR(A2004) -{ -uint8 ret; - -FCEUPPU_LineUpdate(); -ret = SPRAM[PPU[3]]; - -if(PPUSPL>=8) -{ -if(PPU[3]>=8) -ret = SPRAM[PPU[3]]; -} -else -{ -//printf("$%02x:$%02x\n",PPUSPL,V); -ret = SPRAM[PPUSPL]; -} -PPU[3]++; -PPUSPL++; -PPUGenLatch = ret; -printf("%d, %02x\n",scanline,ret); -return(ret); -} -*/ -static DECLFR(A2007) -{ +static DECLFR(A2007) { uint8 ret; - uint32 tmp=RefreshAddr&0x3FFF; + uint32 tmp = RefreshAddr & 0x3FFF; - if(debug_loggingCD) - { - if(!DummyRead && (LogAddress != -1)) - { - if(!(cdloggervdata[LogAddress] & 2)) - { + if (debug_loggingCD) { + if (!DummyRead && (LogAddress != -1)) { + if (!(cdloggervdata[LogAddress] & 2)) { cdloggervdata[LogAddress] |= 2; - if(!(cdloggervdata[LogAddress] & 1))undefinedvromcount--; + if (!(cdloggervdata[LogAddress] & 1)) undefinedvromcount--; vromreadcount++; } - } - else + } else DummyRead = 0; } - if(newppu) { - ret = VRAMBuffer; + if (newppu) { + ret = VRAMBuffer; RefreshAddr = ppur.get_2007access() & 0x3FFF; - if ((RefreshAddr & 0x3F00) == 0x3F00) - { - //if it is in the palette range bypass the - //delayed read, and what gets filled in the temp - //buffer is the address - 0x1000, also - //if grayscale is set then the return is AND with 0x30 - //to get a gray color reading - if (!(tmp & 3)) - { - if (!(tmp & 0xC)) - ret = PALRAM[0x00]; - else - ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; - } - else - ret = PALRAM[tmp & 0x1F]; - if (GRAYSCALE) - ret &= 0x30; - VRAMBuffer = CALL_PPUREAD(RefreshAddr - 0x1000); - } - else { - if(debug_loggingCD) + if ((RefreshAddr & 0x3F00) == 0x3F00) { + //if it is in the palette range bypass the + //delayed read, and what gets filled in the temp + //buffer is the address - 0x1000, also + //if grayscale is set then the return is AND with 0x30 + //to get a gray color reading + if (!(tmp & 3)) { + if (!(tmp & 0xC)) + ret = PALRAM[0x00]; + else + ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; + } else + ret = PALRAM[tmp & 0x1F]; + if (GRAYSCALE) + ret &= 0x30; + VRAMBuffer = CALL_PPUREAD(RefreshAddr - 0x1000); + } else { + if (debug_loggingCD && (RefreshAddr < 0x2000)) LogAddress = GetCHRAddress(RefreshAddr); - VRAMBuffer = CALL_PPUREAD(RefreshAddr); + VRAMBuffer = CALL_PPUREAD(RefreshAddr); } - ppur.increment2007(INC32!=0); + ppur.increment2007(ppur.status.sl >= 0 && ppur.status.sl < 241 && PPUON, INC32 != 0); RefreshAddr = ppur.get_2007access(); - return ret; - } else { + return ret; + } else { FCEUPPU_LineUpdate(); - ret=VRAMBuffer; - - #ifdef FCEUDEF_DEBUGGER - if(!fceuindbg) - #endif - { - if(PPU_hook) PPU_hook(tmp); - PPUGenLatch=VRAMBuffer; - if(tmp<0x2000) + if (tmp >= 0x3F00) { // Palette RAM tied directly to the output data, without VRAM buffer + if (!(tmp & 3)) { + if (!(tmp & 0xC)) + ret = PALRAM[0x00]; + else + ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; + } else + ret = PALRAM[tmp & 0x1F]; + if (GRAYSCALE) + ret &= 0x30; + #ifdef FCEUDEF_DEBUGGER + if (!fceuindbg) + #endif { - if(debug_loggingCD) - LogAddress = GetCHRAddress(tmp); - VRAMBuffer=VPage[tmp>>10][tmp]; + if ((tmp - 0x1000) < 0x2000) + VRAMBuffer = VPage[(tmp - 0x1000) >> 10][tmp - 0x1000]; + else + VRAMBuffer = vnapage[((tmp - 0x1000) >> 10) & 0x3][(tmp - 0x1000) & 0x3FF]; + if (PPU_hook) PPU_hook(tmp); } - else if (tmp < 0x3F00) + } else { + ret = VRAMBuffer; + #ifdef FCEUDEF_DEBUGGER + if (!fceuindbg) + #endif { - VRAMBuffer=vnapage[(tmp>>10)&0x3][tmp&0x3FF]; + if (PPU_hook) PPU_hook(tmp); + PPUGenLatch = VRAMBuffer; + if (tmp < 0x2000) { + if (debug_loggingCD) + LogAddress = GetCHRAddress(tmp); + VRAMBuffer = VPage[tmp >> 10][tmp]; + } else if (tmp < 0x3F00) + VRAMBuffer = vnapage[(tmp >> 10) & 0x3][tmp & 0x3FF]; } } + #ifdef FCEUDEF_DEBUGGER - if(!fceuindbg) + if (!fceuindbg) #endif { - if((ScreenON || SpriteON) && (scanline < 240)) - { - uint32 rad=RefreshAddr; - - if((rad&0x7000)==0x7000) - { - rad^=0x7000; - if((rad&0x3E0)==0x3A0) - rad^=0xBA0; - else if((rad&0x3E0)==0x3e0) - rad^=0x3e0; + if ((ScreenON || SpriteON) && (scanline < 240)) { + uint32 rad = RefreshAddr; + if ((rad & 0x7000) == 0x7000) { + rad ^= 0x7000; + if ((rad & 0x3E0) == 0x3A0) + rad ^= 0xBA0; + else if ((rad & 0x3E0) == 0x3e0) + rad ^= 0x3e0; else - rad+=0x20; - } - else - rad+=0x1000; - RefreshAddr=rad; - } - else - { + rad += 0x20; + } else + rad += 0x1000; + RefreshAddr = rad; + } else { if (INC32) - RefreshAddr+=32; + RefreshAddr += 32; else RefreshAddr++; } - if(PPU_hook) PPU_hook(RefreshAddr&0x3fff); + if (PPU_hook) PPU_hook(RefreshAddr & 0x3fff); } - return ret; } } -static DECLFW(B2000) -{ - // FCEU_printf("%04x:%02x, (%d) %02x, %02x\n",A,V,scanline,PPU[0],PPU_status); - +static DECLFW(B2000) { FCEUPPU_LineUpdate(); - PPUGenLatch=V; - if(!(PPU[0]&0x80) && (V&0x80) && (PPU_status&0x80)) - { - // FCEU_printf("Trigger NMI, %d, %d\n",timestamp,ppudead); + PPUGenLatch = V; + + if (!(PPU[0] & 0x80) && (V & 0x80) && (PPU_status & 0x80)) TriggerNMI2(); - } - PPU[0]=V; - TempAddr&=0xF3FF; - TempAddr|=(V&3)<<10; - ppur._h = V&1; - ppur._v = (V>>1)&1; - ppur.s = (V>>4)&1; + PPU[0] = V; + TempAddr &= 0xF3FF; + TempAddr |= (V & 3) << 10; + + ppur._h = V & 1; + ppur._v = (V >> 1) & 1; + ppur.s = (V >> 4) & 1; } -static DECLFW(B2001) -{ - //printf("%04x:$%02x, %d\n",A,V,scanline); +static DECLFW(B2001) { FCEUPPU_LineUpdate(); - PPUGenLatch=V; - PPU[1]=V; - if(V&0xE0) - deemp=V>>5; -} -// -static DECLFW(B2002) -{ - PPUGenLatch=V; + PPUGenLatch = V; + PPU[1] = V; + if (V & 0xE0) + deemp = V >> 5; } -static DECLFW(B2003) -{ - //printf("$%04x:$%02x, %d, %d\n",A,V,timestamp,scanline); - PPUGenLatch=V; - PPU[3]=V; - PPUSPL=V&0x7; +static DECLFW(B2002) { + PPUGenLatch = V; } -static DECLFW(B2004) -{ - //printf("Wr: %04x:$%02x\n",A,V); - PPUGenLatch=V; - if (newppu) - { - //the attribute upper bits are not connected - //so AND them out on write, since reading them - //should return 0 in those bits. - if ((PPU[3] & 3) == 2) - V &= 0xE3; - SPRAM[PPU[3]] = V; - PPU[3] = (PPU[3] + 1) & 0xFF; - } - else - { - if(PPUSPL>=8) - { - if(PPU[3]>=8) - SPRAM[PPU[3]]=V; - } - else - { - //printf("$%02x:$%02x\n",PPUSPL,V); - SPRAM[PPUSPL]=V; - } - PPU[3]++; - PPUSPL++; - } +static DECLFW(B2003) { + PPUGenLatch = V; + PPU[3] = V; + PPUSPL = V & 0x7; } -static DECLFW(B2005) -{ - uint32 tmp=TempAddr; +static DECLFW(B2004) { + PPUGenLatch = V; + if (newppu) { + //the attribute upper bits are not connected + //so AND them out on write, since reading them + //should return 0 in those bits. + if ((PPU[3] & 3) == 2) + V &= 0xE3; + SPRAM[PPU[3]] = V; + PPU[3] = (PPU[3] + 1) & 0xFF; + } else { + if (PPUSPL >= 8) { + if (PPU[3] >= 8) + SPRAM[PPU[3]] = V; + } else { + SPRAM[PPUSPL] = V; + } + PPU[3]++; + PPUSPL++; + } +} + +static DECLFW(B2005) { + uint32 tmp = TempAddr; FCEUPPU_LineUpdate(); - PPUGenLatch=V; - if(!vtoggle) - { - tmp&=0xFFE0; - tmp|=V>>3; - XOffset=V&7; - ppur._ht = V>>3; - ppur.fh = V&7; + PPUGenLatch = V; + if (!vtoggle) { + tmp &= 0xFFE0; + tmp |= V >> 3; + XOffset = V & 7; + ppur._ht = V >> 3; + ppur.fh = V & 7; + } else { + tmp &= 0x8C1F; + tmp |= ((V & ~0x7) << 2); + tmp |= (V & 7) << 12; + ppur._vt = V >> 3; + ppur._fv = V & 7; } - else - { - tmp&=0x8C1F; - tmp|=((V&~0x7)<<2); - tmp|=(V&7)<<12; - ppur._vt = V>>3; - ppur._fv = V&7; - } - TempAddr=tmp; - vtoggle^=1; + TempAddr = tmp; + vtoggle ^= 1; } -static DECLFW(B2006) -{ +static DECLFW(B2006) { FCEUPPU_LineUpdate(); - PPUGenLatch=V; - if(!vtoggle) - { - TempAddr&=0x00FF; - TempAddr|=(V&0x3f)<<8; + PPUGenLatch = V; + if (!vtoggle) { + TempAddr &= 0x00FF; + TempAddr |= (V & 0x3f) << 8; ppur._vt &= 0x07; - ppur._vt |= (V&0x3)<<3; - ppur._h = (V>>2)&1; - ppur._v = (V>>3)&1; - ppur._fv = (V>>4)&3; - } - else - { - TempAddr&=0xFF00; - TempAddr|=V; + ppur._vt |= (V & 0x3) << 3; + ppur._h = (V >> 2) & 1; + ppur._v = (V >> 3) & 1; + ppur._fv = (V >> 4) & 3; + } else { + TempAddr &= 0xFF00; + TempAddr |= V; - RefreshAddr=TempAddr; - DummyRead=1; - if(PPU_hook) + RefreshAddr = TempAddr; + DummyRead = 1; + if (PPU_hook) PPU_hook(RefreshAddr); - //printf("%d, %04x\n",scanline,RefreshAddr); ppur._vt &= 0x18; - ppur._vt |= (V>>5); - ppur._ht = V&31; + ppur._vt |= (V >> 5); + ppur._ht = V & 31; ppur.install_latches(); } - vtoggle^=1; + vtoggle ^= 1; } -static DECLFW(B2007) -{ - uint32 tmp=RefreshAddr&0x3FFF; +static DECLFW(B2007) { + uint32 tmp = RefreshAddr & 0x3FFF; - if(newppu) { - PPUGenLatch=V; + if (newppu) { + PPUGenLatch = V; RefreshAddr = ppur.get_2007access() & 0x3FFF; - CALL_PPUWRITE(RefreshAddr,V); - //printf("%04x ",RefreshAddr); - ppur.increment2007(INC32!=0); + CALL_PPUWRITE(RefreshAddr, V); + ppur.increment2007(ppur.status.sl >= 0 && ppur.status.sl < 241 && PPUON, INC32 != 0); RefreshAddr = ppur.get_2007access(); - } - else - { - //printf("%04x ",tmp); - PPUGenLatch=V; - if(tmp>=0x3F00) - { - // hmmm.... - if(!(tmp&0xf)) - PALRAM[0x00]=PALRAM[0x04]=PALRAM[0x08]=PALRAM[0x0C]=V&0x3F; - else if(tmp&3) PALRAM[(tmp&0x1f)]=V&0x3f; - } - else if(tmp<0x2000) - { - if(PPUCHRRAM&(1<<(tmp>>10))) - VPage[tmp>>10][tmp]=V; + } else { + PPUGenLatch = V; + if (tmp < 0x2000) { + if (PPUCHRRAM & (1 << (tmp >> 10))) + VPage[tmp >> 10][tmp] = V; + } else if (tmp < 0x3F00) { + if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10))) + vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V; + } else { + if (!(tmp & 3)) { + if (!(tmp & 0xC)) + PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F; + else + UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F; + } else + PALRAM[tmp & 0x1F] = V & 0x3F; } + if (INC32) + RefreshAddr += 32; else - { - if(PPUNTARAM&(1<<((tmp&0xF00)>>10))) - vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V; - } - // FCEU_printf("ppu (%04x) %04x:%04x %d, %d\n",X.PC,RefreshAddr,PPUGenLatch,scanline,timestamp); - if(INC32) RefreshAddr+=32; - else RefreshAddr++; - if(PPU_hook) PPU_hook(RefreshAddr&0x3fff); + RefreshAddr++; + if (PPU_hook) + PPU_hook(RefreshAddr & 0x3fff); } } -static DECLFW(B4014) -{ - uint32 t=V<<8; +static DECLFW(B4014) { + uint32 t = V << 8; int x; - for(x=0;x<256;x++) - X6502_DMW(0x2004,X6502_DMR(t+x)); + for (x = 0; x < 256; x++) + X6502_DMW(0x2004, X6502_DMR(t + x)); + SpriteDMA = V; } -#define PAL(c) ((c)+cc) +#define PAL(c) ((c) + cc) -#define GETLASTPIXEL (PAL?((timestamp*48-linestartts)/15) : ((timestamp*48-linestartts)>>4) ) +#define GETLASTPIXEL (PAL ? ((timestamp * 48 - linestartts) / 15) : ((timestamp * 48 - linestartts) >> 4)) -static uint8 *Pline,*Plinef; +static uint8 *Pline, *Plinef; static int firsttile; int linestartts; //no longer static so the debugger can see it -static int tofix=0; +static int tofix = 0; -static void ResetRL(uint8 *target) -{ - memset(target,0xFF,256); - InputScanlineHook(0,0,0,0); - Plinef=target; - Pline=target; - firsttile=0; - linestartts=timestamp*48+X.count; - tofix=0; +static void ResetRL(uint8 *target) { + memset(target, 0xFF, 256); + InputScanlineHook(0, 0, 0, 0); + Plinef = target; + Pline = target; + firsttile = 0; + linestartts = timestamp * 48 + X.count; + tofix = 0; FCEUPPU_LineUpdate(); - tofix=1; + tofix = 1; } -static uint8 sprlinebuf[256+8]; +static uint8 sprlinebuf[256 + 8]; -void FCEUPPU_LineUpdate(void) -{ - if(newppu) +void FCEUPPU_LineUpdate(void) { + if (newppu) return; #ifdef FCEUDEF_DEBUGGER - if(!fceuindbg) + if (!fceuindbg) #endif - if(Pline) - { - int l=GETLASTPIXEL; - RefreshLine(l); - } + if (Pline) { + int l = GETLASTPIXEL; + RefreshLine(l); + } } -static bool rendersprites=true, renderbg=true; +static bool rendersprites = true, renderbg = true; -void FCEUI_SetRenderPlanes(bool sprites, bool bg) -{ +void FCEUI_SetRenderPlanes(bool sprites, bool bg) { rendersprites = sprites; renderbg = bg; } -void FCEUI_GetRenderPlanes(bool& sprites, bool& bg) -{ +void FCEUI_GetRenderPlanes(bool& sprites, bool& bg) { sprites = rendersprites; bg = renderbg; } -//mbg 6/21/08 - tileview is being ripped out since i dont know how long its been since it worked -//static int tileview=1; -//void FCEUI_ToggleTileView(void) -//{ -// tileview^=1; -//} - - -//mbg 6/21/08 - tileview is being ripped out since i dont know how long its been since it worked -//static void TileView(void) -//{ -// uint8 *P=XBuf+16*256; -// int bgh; -// int y; -// int X1; -// for(bgh=0;bgh<2;bgh++) -// for(y=0;y<16*8;y++) -// for(P=XBuf+bgh*128+(16+y)*256,X1=16;X1;X1--,P+=8) -// { -// uint8 *C; -// register uint8 cc; -// uint32 vadr; -// -// vadr=((((16-X1)|((y>>3)<<4))<<4)|(y&7))+bgh*0x1000; -// //C= ROM+vadr+turt*8192; -// C = VRAMADR(vadr); -// //if((vadr+turt*8192)>=524288) -// //printf("%d ",vadr+turt*8192); -// cc=0; -// //#include "pputile.inc" -// } -//} - static void CheckSpriteHit(int p); -static void EndRL(void) -{ +static void EndRL(void) { RefreshLine(272); - if(tofix) + if (tofix) Fixit1(); CheckSpriteHit(272); - Pline=0; + Pline = 0; } static int32 sphitx; static uint8 sphitdata; -static void CheckSpriteHit(int p) -{ - int l=p-16; +static void CheckSpriteHit(int p) { + int l = p - 16; int x; - if(sphitx==0x100) return; + if (sphitx == 0x100) return; - for(x=sphitx;x<(sphitx+8) && x>(x-sphitx))) && !(Plinef[x]&64) && x < 255) - { - PPU_status|=0x40; - //printf("Ha: %d, %d, Hita: %d, %d, %d, %d, %d\n",p,p&~7,scanline,GETLASTPIXEL-16,&Plinef[x],Pline,Pline-Plinef); - //printf("%d\n",GETLASTPIXEL-16); - //if(Plinef[x] == 0xFF) - //printf("PL: %d, %02x\n",scanline, Plinef[x]); - sphitx=0x100; + for (x = sphitx; x < (sphitx + 8) && x < l; x++) { + if ((sphitdata & (0x80 >> (x - sphitx))) && !(Plinef[x] & 64) && x < 255) { + PPU_status |= 0x40; + sphitx = 0x100; break; } } @@ -1185,154 +1000,144 @@ static void CheckSpriteHit(int p) //spork the world. Any sprites on this line? Then this will be set to 1. //Needed for zapper emulation and *gasp* sprite emulation. -static int spork=0; +static int spork = 0; // lasttile is really "second to last tile." -static void RefreshLine(int lastpixel) -{ +static void RefreshLine(int lastpixel) { static uint32 pshift[2]; static uint32 atlatch; - uint32 smorkus=RefreshAddr; + uint32 smorkus = RefreshAddr; -#define RefreshAddr smorkus + #define RefreshAddr smorkus uint32 vofs; int X1; - register uint8 *P=Pline; - int lasttile=lastpixel>>3; + register uint8 *P = Pline; + int lasttile = lastpixel >> 3; int numtiles; - static int norecurse=0; /* Yeah, recursion would be bad. - PPU_hook() functions can call - mirroring/chr bank switching functions, - which call FCEUPPU_LineUpdate, which call this - function. */ - if(norecurse) return; + static int norecurse = 0; // Yeah, recursion would be bad. + // PPU_hook() functions can call + // mirroring/chr bank switching functions, + // which call FCEUPPU_LineUpdate, which call this + // function. + if (norecurse) return; - if(sphitx != 0x100 && !(PPU_status&0x40)) - { - if((sphitx < (lastpixel-16)) && !(sphitx < ((lasttile - 2)*8))) - { - //printf("OK: %d\n",scanline); + if (sphitx != 0x100 && !(PPU_status & 0x40)) { + if ((sphitx < (lastpixel - 16)) && !(sphitx < ((lasttile - 2) * 8))) lasttile++; - } - } - if(lasttile>34) lasttile=34; - numtiles=lasttile-firsttile; + if (lasttile > 34) lasttile = 34; + numtiles = lasttile - firsttile; - if(numtiles<=0) return; + if (numtiles <= 0) return; - P=Pline; + P = Pline; - vofs=0; + vofs = 0; - vofs=((PPU[0]&0x10)<<8) | ((RefreshAddr>>12)&7); + if(PEC586Hack) + vofs = ((RefreshAddr & 0x200) << 3) | ((RefreshAddr >> 12) & 7); + else + vofs = ((PPU[0] & 0x10) << 8) | ((RefreshAddr >> 12) & 7); - if(!ScreenON && !SpriteON) - { + if (!ScreenON && !SpriteON) { uint32 tem; - tem=Pal[0]|(Pal[0]<<8)|(Pal[0]<<16)|(Pal[0]<<24); - tem|=0x40404040; - FCEU_dwmemset(Pline,tem,numtiles*8); - P+=numtiles*8; - Pline=P; + tem = Pal[0] | (Pal[0] << 8) | (Pal[0] << 16) | (Pal[0] << 24); + tem |= 0x40404040; + FCEU_dwmemset(Pline, tem, numtiles * 8); + P += numtiles * 8; + Pline = P; - firsttile=lasttile; + firsttile = lasttile; -#define TOFIXNUM (272-0x4) - if(lastpixel>=TOFIXNUM && tofix) - { + #define TOFIXNUM (272 - 0x4) + if (lastpixel >= TOFIXNUM && tofix) { Fixit1(); - tofix=0; + tofix = 0; } - if((lastpixel-16)>=0) - { - InputScanlineHook(Plinef,spork?sprlinebuf:0,linestartts,lasttile*8-16); + if ((lastpixel - 16) >= 0) { + InputScanlineHook(Plinef, spork ? sprlinebuf : 0, linestartts, lasttile * 8 - 16); } return; } //Priority bits, needed for sprite emulation. - Pal[0]|=64; - Pal[4]|=64; - Pal[8]|=64; - Pal[0xC]|=64; + Pal[0] |= 64; + Pal[4] |= 64; + Pal[8] |= 64; + Pal[0xC] |= 64; //This high-level graphics MMC5 emulation code was written for MMC5 carts in "CL" mode. //It's probably not totally correct for carts in "SL" mode. #define PPUT_MMC5 - if(MMC5Hack && geniestage!=1) - { - if(MMC5HackCHRMode==0 && (MMC5HackSPMode&0x80)) - { - int tochange=MMC5HackSPMode&0x1F; - tochange-=firsttile; - for(X1=firsttile;X10 && !(MMC5HackSPMode&0x40))) - { -#define PPUT_MMC5SP -#include "pputile.inc" -#undef PPUT_MMC5SP - } - else - { -#include "pputile.inc" + if (MMC5Hack && geniestage != 1) { + if (MMC5HackCHRMode == 0 && (MMC5HackSPMode & 0x80)) { + int tochange = MMC5HackSPMode & 0x1F; + tochange -= firsttile; + for (X1 = firsttile; X1 < lasttile; X1++) { + if ((tochange <= 0 && MMC5HackSPMode & 0x40) || (tochange > 0 && !(MMC5HackSPMode & 0x40))) { + #define PPUT_MMC5SP + #include "pputile.inc" + #undef PPUT_MMC5SP + } else { + #include "pputile.inc" } tochange--; } - } - else if(MMC5HackCHRMode==1 && (MMC5HackSPMode&0x80)) - { - int tochange=MMC5HackSPMode&0x1F; - tochange-=firsttile; + } else if (MMC5HackCHRMode == 1 && (MMC5HackSPMode & 0x80)) { + int tochange = MMC5HackSPMode & 0x1F; + tochange -= firsttile; -#define PPUT_MMC5SP -#define PPUT_MMC5CHR1 - for(X1=firsttile;X10) - FCEU_dwmemset(Plinef+tstart*8,tem,tcount*8); + if (tcount > 0) + FCEU_dwmemset(Plinef + tstart * 8, tem, tcount * 8); } - if(lastpixel>=TOFIXNUM && tofix) - { - //puts("Fixed"); + if (lastpixel >= TOFIXNUM && tofix) { Fixit1(); - tofix=0; + tofix = 0; } - //CheckSpriteHit(lasttile*8); //lasttile*8); //lastpixel); - //This only works right because of a hack earlier in this function. CheckSpriteHit(lastpixel); - if((lastpixel-16)>=0) - { - InputScanlineHook(Plinef,spork?sprlinebuf:0,linestartts,lasttile*8-16); + if ((lastpixel - 16) >= 0) { + InputScanlineHook(Plinef, spork ? sprlinebuf : 0, linestartts, lasttile * 8 - 16); } - Pline=P; - firsttile=lasttile; + Pline = P; + firsttile = lasttile; } -static INLINE void Fixit2(void) -{ - if(ScreenON || SpriteON) - { - uint32 rad=RefreshAddr; - rad&=0xFBE0; - rad|=TempAddr&0x041f; - RefreshAddr=rad; - //PPU_hook(RefreshAddr); - //PPU_hook(RefreshAddr,-1); +static INLINE void Fixit2(void) { + if (ScreenON || SpriteON) { + uint32 rad = RefreshAddr; + rad &= 0xFBE0; + rad |= TempAddr & 0x041f; + RefreshAddr = rad; } } -static void Fixit1(void) -{ - if(ScreenON || SpriteON) - { - uint32 rad=RefreshAddr; +static void Fixit1(void) { + if (ScreenON || SpriteON) { + uint32 rad = RefreshAddr; - if((rad & 0x7000) == 0x7000) - { + if ((rad & 0x7000) == 0x7000) { rad ^= 0x7000; - if((rad & 0x3E0) == 0x3A0) + if ((rad & 0x3E0) == 0x3A0) rad ^= 0xBA0; - else if((rad & 0x3E0) == 0x3e0) + else if ((rad & 0x3E0) == 0x3e0) rad ^= 0x3e0; else rad += 0x20; - } - else + } else rad += 0x1000; RefreshAddr = rad; } } -void MMC5_hb(int); //Ugh ugh ugh. -static void DoLine(void) -{ +void MMC5_hb(int); //Ugh ugh ugh. +static void DoLine(void) { int x; - uint8 *target=XBuf+(scanline<<8); + // scanlines after 239 are dummy for dendy, and Xbuf is capped at 0xffff bytes, don't let it overflow + // send all future writes to the invisible sanline. the easiest way to "skip" them altogether in old ppu + // todo: figure out what exactly should be skipped. it's known that there's no activity on PPU bus + uint8 *target = XBuf + ((scanline < 240 ? scanline : 240) << 8); - if(MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline); + if (MMC5Hack) MMC5_hb(scanline); X6502_Run(256); EndRL(); - if(!renderbg) // User asked to not display background data. - { + if (!renderbg) {// User asked to not display background data. uint32 tem; uint8 col; - if(gNoBGFillColor == 0xFF) + if (gNoBGFillColor == 0xFF) col = Pal[0]; else col = gNoBGFillColor; - tem=col|(col<<8)|(col<<16)|(col<<24); - tem|=0x40404040; - FCEU_dwmemset(target,tem,256); + tem = col | (col << 8) | (col << 16) | (col << 24); + tem |= 0x40404040; + FCEU_dwmemset(target, tem, 256); } - if(SpriteON) + if (SpriteON) CopySprites(target); - if(ScreenON || SpriteON) // Yes, very el-cheapo. - { - if(PPU[1]&0x01) - { - for(x=63;x>=0;x--) - *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])&0x30303030; + if (ScreenON || SpriteON) { // Yes, very el-cheapo. + if (PPU[1] & 0x01) { + for (x = 63; x >= 0; x--) + *(uint32*)&target[x << 2] = (*(uint32*)&target[x << 2]) & 0x30303030; } } - if((PPU[1]>>5)==0x7) - { - for(x=63;x>=0;x--) - *(uint32 *)&target[x<<2]=((*(uint32*)&target[x<<2])&0x3f3f3f3f)|0xc0c0c0c0; - } - else if(PPU[1]&0xE0) - for(x=63;x>=0;x--) - *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])|0x40404040; + if ((PPU[1] >> 5) == 0x7) { + for (x = 63; x >= 0; x--) + *(uint32*)&target[x << 2] = ((*(uint32*)&target[x << 2]) & 0x3f3f3f3f) | 0xc0c0c0c0; + } else if (PPU[1] & 0xE0) + for (x = 63; x >= 0; x--) + *(uint32*)&target[x << 2] = (*(uint32*)&target[x << 2]) | 0x40404040; else - for(x=63;x>=0;x--) - *(uint32 *)&target[x<<2]=((*(uint32*)&target[x<<2])&0x3f3f3f3f)|0x80808080; + for (x = 63; x >= 0; x--) + *(uint32*)&target[x << 2] = ((*(uint32*)&target[x << 2]) & 0x3f3f3f3f) | 0x80808080; - sphitx=0x100; + sphitx = 0x100; - if(ScreenON || SpriteON) + if (ScreenON || SpriteON) FetchSpriteData(); - if(GameHBIRQHook && (ScreenON || SpriteON) && ((PPU[0]&0x38)!=0x18)) - { + if (GameHBIRQHook && (ScreenON || SpriteON) && ((PPU[0] & 0x38) != 0x18)) { X6502_Run(6); Fixit2(); X6502_Run(4); GameHBIRQHook(); - X6502_Run(85-16-10); - } - else - { - X6502_Run(6); // Tried 65, caused problems with Slalom(maybe others) + X6502_Run(85 - 16 - 10); + } else { + X6502_Run(6); // Tried 65, caused problems with Slalom(maybe others) Fixit2(); - X6502_Run(85-6-16); + X6502_Run(85 - 6 - 16); // A semi-hack for Star Trek: 25th Anniversary - if(GameHBIRQHook && (ScreenON || SpriteON) && ((PPU[0]&0x38)!=0x18)) + if (GameHBIRQHook && (ScreenON || SpriteON) && ((PPU[0] & 0x38) != 0x18)) GameHBIRQHook(); } - DEBUG(FCEUD_UpdateNTView(scanline,0)); + DEBUG(FCEUD_UpdateNTView(scanline, 0)); - if(SpriteON) + if (SpriteON) RefreshSprites(); - if(GameHBIRQHook2 && (ScreenON || SpriteON)) + if (GameHBIRQHook2 && (ScreenON || SpriteON)) GameHBIRQHook2(); scanline++; - if(scanline<240) - { - ResetRL(XBuf+(scanline<<8)); + if (scanline < 240) { + ResetRL(XBuf + (scanline << 8)); } X6502_Run(16); } @@ -1516,581 +1298,521 @@ static void DoLine(void) #define SP_BACK 0x20 typedef struct { - uint8 y,no,atr,x; + uint8 y, no, atr, x; } SPR; typedef struct { - uint8 ca[2],atr,x; + uint8 ca[2], atr, x; } SPRB; -void FCEUI_DisableSpriteLimitation(int a) -{ - maxsprites=a?64:8; +void FCEUI_DisableSpriteLimitation(int a) { + maxsprites = a ? 64 : 8; } -static uint8 numsprites,SpriteBlurp; -static void FetchSpriteData(void) -{ - uint8 ns,sb; +static uint8 numsprites, SpriteBlurp; +static void FetchSpriteData(void) { + uint8 ns, sb; SPR *spr; uint8 H; int n; int vofs; - uint8 P0=PPU[0]; + uint8 P0 = PPU[0]; - spr=(SPR *)SPRAM; - H=8; + spr = (SPR*)SPRAM; + H = 8; - ns=sb=0; + ns = sb = 0; - vofs=(unsigned int)(P0&0x8&(((P0&0x20)^0x20)>>2))<<9; - H+=(P0&0x20)>>2; + vofs = (uint32)(P0 & 0x8 & (((P0 & 0x20) ^ 0x20) >> 2)) << 9; + H += (P0 & 0x20) >> 2; - if(!PPU_hook) - for(n=63;n>=0;n--,spr++) - { - if((unsigned int)(scanline-spr->y)>=H) continue; - //printf("%d, %u\n",scanline,(unsigned int)(scanline-spr->y)); - if(ns= 0; n--, spr++) { + if ((uint32)(scanline - spr->y) >= H) continue; + if (ns < maxsprites) { + if (n == 63) sb = 1; { SPRB dst; uint8 *C; int t; - unsigned int vadr; + uint32 vadr; - t = (int)scanline-(spr->y); + t = (int)scanline - (spr->y); - if(Sprite16) - vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4); + if (Sprite16) + vadr = ((spr->no & 1) << 12) + ((spr->no & 0xFE) << 4); else - vadr = (spr->no<<4)+vofs; + vadr = (spr->no << 4) + vofs; - if(spr->atr&V_FLIP) - { - vadr+=7; - vadr-=t; - vadr+=(P0&0x20)>>1; - vadr-=t&8; - } - else - { - vadr+=t; - vadr+=t&8; + if (spr->atr & V_FLIP) { + vadr += 7; + vadr -= t; + vadr += (P0 & 0x20) >> 1; + vadr -= t & 8; + } else { + vadr += t; + vadr += t & 8; } /* Fix this geniestage hack */ - if(MMC5Hack && geniestage!=1) C = MMC5SPRVRAMADR(vadr); - else C = VRAMADR(vadr); + if (MMC5Hack && geniestage != 1) + C = MMC5SPRVRAMADR(vadr); + else + C = VRAMADR(vadr); + if (SpriteON) + RENDER_LOG(vadr); + dst.ca[0] = C[0]; + if (SpriteON) + RENDER_LOG(vadr + 8); + dst.ca[1] = C[8]; + dst.x = spr->x; + dst.atr = spr->atr; - dst.ca[0]=C[0]; - dst.ca[1]=C[8]; - dst.x=spr->x; - dst.atr=spr->atr; - - *(uint32 *)&SPRBUF[ns<<2]=*(uint32 *)&dst; + *(uint32*)&SPRBUF[ns << 2] = *(uint32*)&dst; } ns++; - } - else - { - PPU_status|=0x20; + } else { + PPU_status |= 0x20; break; } } else - for(n=63;n>=0;n--,spr++) - { - if((unsigned int)(scanline-spr->y)>=H) continue; + for (n = 63; n >= 0; n--, spr++) { + if ((uint32)(scanline - spr->y) >= H) continue; - if(nsy); + t = (int)scanline - (spr->y); - if(Sprite16) - vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4); + if (Sprite16) + vadr = ((spr->no & 1) << 12) + ((spr->no & 0xFE) << 4); else - vadr = (spr->no<<4)+vofs; + vadr = (spr->no << 4) + vofs; - if(spr->atr&V_FLIP) - { - vadr+=7; - vadr-=t; - vadr+=(P0&0x20)>>1; - vadr-=t&8; - } - else - { - vadr+=t; - vadr+=t&8; + if (spr->atr & V_FLIP) { + vadr += 7; + vadr -= t; + vadr += (P0 & 0x20) >> 1; + vadr -= t & 8; + } else { + vadr += t; + vadr += t & 8; } - if(MMC5Hack) C = MMC5SPRVRAMADR(vadr); - else C = VRAMADR(vadr); - dst.ca[0]=C[0]; - if(ns<8) - { + if (MMC5Hack) + C = MMC5SPRVRAMADR(vadr); + else + C = VRAMADR(vadr); + if (SpriteON) + RENDER_LOG(vadr); + dst.ca[0] = C[0]; + if (ns < 8) { PPU_hook(0x2000); PPU_hook(vadr); } - dst.ca[1]=C[8]; - dst.x=spr->x; - dst.atr=spr->atr; + if (SpriteON) + RENDER_LOG(vadr + 8); + dst.ca[1] = C[8]; + dst.x = spr->x; + dst.atr = spr->atr; - *(uint32 *)&SPRBUF[ns<<2]=*(uint32 *)&dst; + *(uint32*)&SPRBUF[ns << 2] = *(uint32*)&dst; } ns++; - } - else - { - PPU_status|=0x20; + } else { + PPU_status |= 0x20; break; } } - //if(ns>=7) - //printf("%d %d\n",scanline,ns); - //Handle case when >8 sprites per scanline option is enabled. - if(ns>8) PPU_status|=0x20; - else if(PPU_hook) - { - for(n=0;n<(8-ns);n++) - { - PPU_hook(0x2000); - PPU_hook(vofs); - } + //Handle case when >8 sprites per scanline option is enabled. + if (ns > 8) PPU_status |= 0x20; + else if (PPU_hook) { + for (n = 0; n < (8 - ns); n++) { + PPU_hook(0x2000); + PPU_hook(vofs); } - numsprites=ns; - SpriteBlurp=sb; + } + numsprites = ns; + SpriteBlurp = sb; } -static void RefreshSprites(void) -{ +static void RefreshSprites(void) { int n; SPRB *spr; - spork=0; - if(!numsprites) return; + spork = 0; + if (!numsprites) return; - FCEU_dwmemset(sprlinebuf,0x80808080,256); + FCEU_dwmemset(sprlinebuf, 0x80808080, 256); numsprites--; - spr = (SPRB*)SPRBUF+numsprites; + spr = (SPRB*)SPRBUF + numsprites; - for(n=numsprites;n>=0;n--,spr--) - { + for (n = numsprites; n >= 0; n--, spr--) { uint32 pixdata; - uint8 J,atr; + uint8 J, atr; - int x=spr->x; + int x = spr->x; uint8 *C; uint8 *VB; - pixdata=ppulut1[spr->ca[0]]|ppulut2[spr->ca[1]]; - J=spr->ca[0]|spr->ca[1]; - atr=spr->atr; + pixdata = ppulut1[spr->ca[0]] | ppulut2[spr->ca[1]]; + J = spr->ca[0] | spr->ca[1]; + atr = spr->atr; - if(J) - { - if(n==0 && SpriteBlurp && !(PPU_status&0x40)) - { - sphitx=x; - sphitdata=J; - if(atr&H_FLIP) - sphitdata= ((J<<7)&0x80) | - ((J<<5)&0x40) | - ((J<<3)&0x20) | - ((J<<1)&0x10) | - ((J>>1)&0x08) | - ((J>>3)&0x04) | - ((J>>5)&0x02) | - ((J>>7)&0x01); + if (J) { + if (n == 0 && SpriteBlurp && !(PPU_status & 0x40)) { + sphitx = x; + sphitdata = J; + if (atr & H_FLIP) + sphitdata = ((J << 7) & 0x80) | + ((J << 5) & 0x40) | + ((J << 3) & 0x20) | + ((J << 1) & 0x10) | + ((J >> 1) & 0x08) | + ((J >> 3) & 0x04) | + ((J >> 5) & 0x02) | + ((J >> 7) & 0x01); } - C = sprlinebuf+x; - VB = (PALRAM+0x10)+((atr&3)<<2); + C = sprlinebuf + x; + VB = (PALRAM + 0x10) + ((atr & 3) << 2); - if(atr&SP_BACK) - { - if(atr&H_FLIP) - { - if(J&0x80) C[7]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x40) C[6]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x20) C[5]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x10) C[4]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x08) C[3]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x04) C[2]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x02) C[1]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x01) C[0]=VB[pixdata]|0x40; - } else { - if(J&0x80) C[0]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x40) C[1]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x20) C[2]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x10) C[3]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x08) C[4]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x04) C[5]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x02) C[6]=VB[pixdata&3]|0x40; - pixdata>>=4; - if(J&0x01) C[7]=VB[pixdata]|0x40; + if (atr & SP_BACK) { + if (atr & H_FLIP) { + if (J & 0x80) C[7] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x40) C[6] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x20) C[5] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x10) C[4] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x08) C[3] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x04) C[2] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x02) C[1] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x01) C[0] = VB[pixdata] | 0x40; + } else { + if (J & 0x80) C[0] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x40) C[1] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x20) C[2] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x10) C[3] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x08) C[4] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x04) C[5] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x02) C[6] = VB[pixdata & 3] | 0x40; + pixdata >>= 4; + if (J & 0x01) C[7] = VB[pixdata] | 0x40; } } else { - if(atr&H_FLIP) - { - if(J&0x80) C[7]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x40) C[6]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x20) C[5]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x10) C[4]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x08) C[3]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x04) C[2]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x02) C[1]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x01) C[0]=VB[pixdata]; - }else{ - if(J&0x80) C[0]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x40) C[1]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x20) C[2]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x10) C[3]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x08) C[4]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x04) C[5]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x02) C[6]=VB[pixdata&3]; - pixdata>>=4; - if(J&0x01) C[7]=VB[pixdata]; + if (atr & H_FLIP) { + if (J & 0x80) C[7] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x40) C[6] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x20) C[5] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x10) C[4] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x08) C[3] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x04) C[2] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x02) C[1] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x01) C[0] = VB[pixdata]; + } else { + if (J & 0x80) C[0] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x40) C[1] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x20) C[2] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x10) C[3] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x08) C[4] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x04) C[5] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x02) C[6] = VB[pixdata & 3]; + pixdata >>= 4; + if (J & 0x01) C[7] = VB[pixdata]; } } } } - SpriteBlurp=0; - spork=1; + SpriteBlurp = 0; + spork = 1; } -static void CopySprites(uint8 *target) -{ - uint8 n=((PPU[1]&4)^4)<<1; - uint8 *P=target; +static void CopySprites(uint8 *target) { + uint8 n = ((PPU[1] & 4) ^ 4) << 1; + uint8 *P = target; - if(!spork) return; - spork=0; + if (!spork) return; + spork = 0; - if(!rendersprites) return; //User asked to not display sprites. + if (!rendersprites) return; //User asked to not display sprites. -loopskie: + loopskie: { - uint32 t=*(uint32 *)(sprlinebuf+n); + uint32 t = *(uint32*)(sprlinebuf + n); - if(t!=0x80808080) - { -#ifdef LSB_FIRST - if(!(t&0x80)) - { - if(!(t&0x40) || (P[n]&0x40)) // Normal sprite || behind bg sprite - P[n]=sprlinebuf[n]; + if (t != 0x80808080) { + #ifdef LSB_FIRST + if (!(t & 0x80)) { + if (!(t & 0x40) || (P[n] & 0x40)) // Normal sprite || behind bg sprite + P[n] = sprlinebuf[n]; } - if(!(t&0x8000)) - { - if(!(t&0x4000) || (P[n+1]&0x40)) // Normal sprite || behind bg sprite - P[n+1]=(sprlinebuf+1)[n]; + if (!(t & 0x8000)) { + if (!(t & 0x4000) || (P[n + 1] & 0x40)) // Normal sprite || behind bg sprite + P[n + 1] = (sprlinebuf + 1)[n]; } - if(!(t&0x800000)) - { - if(!(t&0x400000) || (P[n+2]&0x40)) // Normal sprite || behind bg sprite - P[n+2]=(sprlinebuf+2)[n]; + if (!(t & 0x800000)) { + if (!(t & 0x400000) || (P[n + 2] & 0x40)) // Normal sprite || behind bg sprite + P[n + 2] = (sprlinebuf + 2)[n]; } - if(!(t&0x80000000)) - { - if(!(t&0x40000000) || (P[n+3]&0x40)) // Normal sprite || behind bg sprite - P[n+3]=(sprlinebuf+3)[n]; + if (!(t & 0x80000000)) { + if (!(t & 0x40000000) || (P[n + 3] & 0x40)) // Normal sprite || behind bg sprite + P[n + 3] = (sprlinebuf + 3)[n]; } -#else + #else /* TODO: Simplify */ - if(!(t&0x80000000)) - { - if(!(t&0x40000000)) // Normal sprite - P[n]=sprlinebuf[n]; - else if(P[n]&64) // behind bg sprite - P[n]=sprlinebuf[n]; + if (!(t & 0x80000000)) { + if (!(t & 0x40000000)) // Normal sprite + P[n] = sprlinebuf[n]; + else if (P[n] & 64) // behind bg sprite + P[n] = sprlinebuf[n]; } - if(!(t&0x800000)) - { - if(!(t&0x400000)) // Normal sprite - P[n+1]=(sprlinebuf+1)[n]; - else if(P[n+1]&64) // behind bg sprite - P[n+1]=(sprlinebuf+1)[n]; + if (!(t & 0x800000)) { + if (!(t & 0x400000)) // Normal sprite + P[n + 1] = (sprlinebuf + 1)[n]; + else if (P[n + 1] & 64) // behind bg sprite + P[n + 1] = (sprlinebuf + 1)[n]; } - if(!(t&0x8000)) - { - if(!(t&0x4000)) // Normal sprite - P[n+2]=(sprlinebuf+2)[n]; - else if(P[n+2]&64) // behind bg sprite - P[n+2]=(sprlinebuf+2)[n]; + if (!(t & 0x8000)) { + if (!(t & 0x4000)) // Normal sprite + P[n + 2] = (sprlinebuf + 2)[n]; + else if (P[n + 2] & 64) // behind bg sprite + P[n + 2] = (sprlinebuf + 2)[n]; } - if(!(t&0x80)) - { - if(!(t&0x40)) // Normal sprite - P[n+3]=(sprlinebuf+3)[n]; - else if(P[n+3]&64) // behind bg sprite - P[n+3]=(sprlinebuf+3)[n]; + if (!(t & 0x80)) { + if (!(t & 0x40)) // Normal sprite + P[n + 3] = (sprlinebuf + 3)[n]; + else if (P[n + 3] & 64) // behind bg sprite + P[n + 3] = (sprlinebuf + 3)[n]; } -#endif + #endif } } - n+=4; - if(n) goto loopskie; + n += 4; + if (n) goto loopskie; } -void FCEUPPU_SetVideoSystem(int w) -{ - if(w) - { - scanlines_per_frame=312; - FSettings.FirstSLine=FSettings.UsrFirstSLine[1]; - FSettings.LastSLine=FSettings.UsrLastSLine[1]; - } - else - { - scanlines_per_frame=262; - FSettings.FirstSLine=FSettings.UsrFirstSLine[0]; - FSettings.LastSLine=FSettings.UsrLastSLine[0]; +void FCEUPPU_SetVideoSystem(int w) { + if (w) { + scanlines_per_frame = dendy ? 262: 312; + FSettings.FirstSLine = FSettings.UsrFirstSLine[1]; + FSettings.LastSLine = FSettings.UsrLastSLine[1]; + } else { + scanlines_per_frame = 262; + FSettings.FirstSLine = FSettings.UsrFirstSLine[0]; + FSettings.LastSLine = FSettings.UsrLastSLine[0]; } } //Initializes the PPU -void FCEUPPU_Init(void) -{ +void FCEUPPU_Init(void) { makeppulut(); } -void PPU_ResetHooks() -{ +void PPU_ResetHooks() { FFCEUX_PPURead = FFCEUX_PPURead_Default; } -void FCEUPPU_Reset(void) -{ - VRAMBuffer=PPU[0]=PPU[1]=PPU_status=PPU[3]=0; - PPUSPL=0; - PPUGenLatch=0; - RefreshAddr=TempAddr=0; +void FCEUPPU_Reset(void) { + VRAMBuffer = PPU[0] = PPU[1] = PPU_status = PPU[3] = 0; + PPUSPL = 0; + PPUGenLatch = 0; + RefreshAddr = TempAddr = 0; vtoggle = 0; ppudead = 2; kook = 0; idleSynch = 1; - // XOffset=0; ppur.reset(); spr_read.reset(); } -void FCEUPPU_Power(void) -{ +void FCEUPPU_Power(void) { int x; - memset(NTARAM,0x00,0x800); - memset(PALRAM,0x00,0x20); - memset(UPALRAM,0x00,0x03); - memset(SPRAM,0x00,0x100); + memset(NTARAM, 0x00, 0x800); + memset(PALRAM, 0x00, 0x20); + memset(UPALRAM, 0x00, 0x03); + memset(SPRAM, 0x00, 0x100); FCEUPPU_Reset(); - for(x=0x2000;x<0x4000;x+=8) - { - ARead[x]=A200x; - BWrite[x]=B2000; - ARead[x+1]=A200x; - BWrite[x+1]=B2001; - ARead[x+2]=A2002; - BWrite[x+2]=B2002; - ARead[x+3]=A200x; - BWrite[x+3]=B2003; - ARead[x+4]=A2004; //A2004; - BWrite[x+4]=B2004; - ARead[x+5]=A200x; - BWrite[x+5]=B2005; - ARead[x+6]=A200x; - BWrite[x+6]=B2006; - ARead[x+7]=A2007; - BWrite[x+7]=B2007; + for (x = 0x2000; x < 0x4000; x += 8) { + ARead[x] = A200x; + BWrite[x] = B2000; + ARead[x + 1] = A200x; + BWrite[x + 1] = B2001; + ARead[x + 2] = A2002; + BWrite[x + 2] = B2002; + ARead[x + 3] = A200x; + BWrite[x + 3] = B2003; + ARead[x + 4] = A2004; + BWrite[x + 4] = B2004; + ARead[x + 5] = A200x; + BWrite[x + 5] = B2005; + ARead[x + 6] = A200x; + BWrite[x + 6] = B2006; + ARead[x + 7] = A2007; + BWrite[x + 7] = B2007; } - BWrite[0x4014]=B4014; + BWrite[0x4014] = B4014; } -int FCEUPPU_Loop(int skip) -{ - if((newppu) && (GameInfo->type!=GIT_NSF)) { +int FCEUPPU_Loop(int skip) { + if ((newppu) && (GameInfo->type != GIT_NSF)) { int FCEUX_PPU_Loop(int skip); return FCEUX_PPU_Loop(skip); } //Needed for Knight Rider, possibly others. - if(ppudead) - { - memset(XBuf, 0x80, 256*240); - X6502_Run(scanlines_per_frame*(256+85)); + if (ppudead) { + memset(XBuf, 0x80, 256 * 240); + X6502_Run(scanlines_per_frame * (256 + 85)); ppudead--; - } - else - { - X6502_Run(256+85); + } else { + X6502_Run(256 + 85); PPU_status |= 0x80; //Not sure if this is correct. According to Matt Conte and my own tests, it is. //Timing is probably off, though. //NOTE: Not having this here breaks a Super Donkey Kong game. - PPU[3]=PPUSPL=0; + PPU[3] = PPUSPL = 0; //I need to figure out the true nature and length of this delay. X6502_Run(12); - if(GameInfo->type==GIT_NSF) + if (GameInfo->type == GIT_NSF) DoNSFFrame(); - else - { - if(VBlankON) + else { + if (VBlankON) TriggerNMI(); } - X6502_Run((scanlines_per_frame-242)*(256+85)-12); //-12); - PPU_status&=0x1f; + X6502_Run((scanlines_per_frame - 242) * (256 + 85) - 12); + PPU_status &= 0x1f; X6502_Run(256); { int x; - if(ScreenON || SpriteON) - { - if(GameHBIRQHook && ((PPU[0]&0x38)!=0x18)) + if (ScreenON || SpriteON) { + if (GameHBIRQHook && ((PPU[0] & 0x38) != 0x18)) GameHBIRQHook(); - if(PPU_hook) - for(x=0;x<42;x++) {PPU_hook(0x2000); PPU_hook(0);} - if(GameHBIRQHook2) - GameHBIRQHook2(); + if (PPU_hook) + for (x = 0; x < 42; x++) { + PPU_hook(0x2000); PPU_hook(0); + } + if (GameHBIRQHook2) + GameHBIRQHook2(); } - X6502_Run(85-16); - if(ScreenON || SpriteON) - { - RefreshAddr=TempAddr; - if(PPU_hook) PPU_hook(RefreshAddr&0x3fff); + X6502_Run(85 - 16); + if (ScreenON || SpriteON) { + RefreshAddr = TempAddr; + if (PPU_hook) PPU_hook(RefreshAddr & 0x3fff); } //Clean this stuff up later. - spork=numsprites=0; + spork = numsprites = 0; ResetRL(XBuf); - X6502_Run(16-kook); + X6502_Run(16 - kook); kook ^= 1; } - if(GameInfo->type==GIT_NSF) - X6502_Run((256+85)*240); -#ifdef FRAMESKIP - else if(skip) - { + if (GameInfo->type == GIT_NSF) + X6502_Run((256 + 85) * (dendy ? 290 : 240)); + #ifdef FRAMESKIP + else if (skip) { int y; - y=SPRAM[0]; + y = SPRAM[0]; y++; - PPU_status|=0x20; // Fixes "Bee 52". Does it break anything? - if(GameHBIRQHook) - { + PPU_status |= 0x20; // Fixes "Bee 52". Does it break anything? + if (GameHBIRQHook) { X6502_Run(256); - for(scanline=0;scanline<240;scanline++) - { - if(ScreenON || SpriteON) + for (scanline = 0; scanline < 240; scanline++) { + if (ScreenON || SpriteON) GameHBIRQHook(); - if(scanline==y && SpriteON) PPU_status|=0x40; - X6502_Run((scanline==239)?85:(256+85)); + if (scanline == y && SpriteON) PPU_status |= 0x40; + X6502_Run((scanline == 239) ? 85 : (256 + 85)); } - } - else if(y<240) - { - X6502_Run((256+85)*y); - if(SpriteON) PPU_status|=0x40; // Quick and very dirty hack. - X6502_Run((256+85)*(240-y)); - } - else - X6502_Run((256+85)*240); + } else if (y < 240) { + X6502_Run((256 + 85) * y); + if (SpriteON) PPU_status |= 0x40; // Quick and very dirty hack. + X6502_Run((256 + 85) * (240 - y)); + } else + X6502_Run((256 + 85) * 240); } -#endif - else - { - int x,max,maxref; + #endif + else { + int x, max, maxref; - deemp=PPU[1]>>5; - for(scanline=0;scanline<240;) //scanline is incremented in DoLine. Evil. :/ - { + deemp = PPU[1] >> 5; + for (scanline = 0; scanline < (dendy ? 290 : 240); ) { //scanline is incremented in DoLine. Evil. :/ deempcnt[deemp]++; - DEBUG(FCEUD_UpdatePPUView(scanline, 1)); + if (scanline < 240) + DEBUG(FCEUD_UpdatePPUView(scanline, 1)); DoLine(); } - - if(MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline); - for(x=1,max=0,maxref=0;x<7;x++) - { - - if(deempcnt[x]>max) - { - max=deempcnt[x]; - maxref=x; + if (MMC5Hack) MMC5_hb(scanline); + for (x = 1, max = 0, maxref = 0; x < 7; x++) { + if (deempcnt[x] > max) { + max = deempcnt[x]; + maxref = x; } - deempcnt[x]=0; + deempcnt[x] = 0; } - //FCEU_DispMessage("%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x %d",0,deempcnt[0],deempcnt[1],deempcnt[2],deempcnt[3],deempcnt[4],deempcnt[5],deempcnt[6],deempcnt[7],maxref); - //memset(deempcnt,0,sizeof(deempcnt)); - SetNESDeemph(maxref,0); + SetNESDeemph(maxref, 0); } - } //else... to if(ppudead) + } //else... to if(ppudead) -#ifdef FRAMESKIP - if(skip) - { + #ifdef FRAMESKIP + if (skip) { FCEU_PutImageDummy(); return(0); - } - else -#endif + } else + #endif { - //mbg 6/21/08 - tileview is being ripped out since i dont know how long its been since it worked - //if(tileview) TileView(); FCEU_PutImage(); return(1); } @@ -2098,162 +1820,176 @@ int FCEUPPU_Loop(int skip) int (*PPU_MASTER)(int skip) = FCEUPPU_Loop; -static uint16 TempAddrT,RefreshAddrT; +static uint16 TempAddrT, RefreshAddrT; -void FCEUPPU_LoadState(int version) -{ - TempAddr=TempAddrT; - RefreshAddr=RefreshAddrT; +void FCEUPPU_LoadState(int version) { + TempAddr = TempAddrT; + RefreshAddr = RefreshAddrT; } -SFORMAT FCEUPPU_STATEINFO[]={ - { NTARAM, 0x800, "NTAR"}, - { PALRAM, 0x20, "PRAM"}, - { SPRAM, 0x100, "SPRA"}, - { PPU, 0x4, "PPUR"}, - { &kook, 1, "KOOK"}, - { &ppudead, 1, "DEAD"}, - { &PPUSPL, 1, "PSPL"}, - { &XOffset, 1, "XOFF"}, - { &vtoggle, 1, "VTOG"}, - { &RefreshAddrT, 2|FCEUSTATE_RLSB, "RADD"}, - { &TempAddrT, 2|FCEUSTATE_RLSB, "TADD"}, - { &VRAMBuffer, 1, "VBUF"}, - { &PPUGenLatch, 1, "PGEN"}, +SFORMAT FCEUPPU_STATEINFO[] = { + { NTARAM, 0x800, "NTAR" }, + { PALRAM, 0x20, "PRAM" }, + { SPRAM, 0x100, "SPRA" }, + { PPU, 0x4, "PPUR" }, + { &kook, 1, "KOOK" }, + { &ppudead, 1, "DEAD" }, + { &PPUSPL, 1, "PSPL" }, + { &XOffset, 1, "XOFF" }, + { &vtoggle, 1, "VTGL" }, + { &RefreshAddrT, 2 | FCEUSTATE_RLSB, "RADD" }, + { &TempAddrT, 2 | FCEUSTATE_RLSB, "TADD" }, + { &VRAMBuffer, 1, "VBUF" }, + { &PPUGenLatch, 1, "PGEN" }, { 0 } }; SFORMAT FCEU_NEWPPU_STATEINFO[] = { { &idleSynch, 1, "IDLS" }, - { &spr_read.num, 4|FCEUSTATE_RLSB, "SR_0" }, - { &spr_read.count, 4|FCEUSTATE_RLSB, "SR_1" }, - { &spr_read.fetch, 4|FCEUSTATE_RLSB, "SR_2" }, - { &spr_read.found, 4|FCEUSTATE_RLSB, "SR_3" }, - { &spr_read.found_pos[0], 4|FCEUSTATE_RLSB, "SRx0" }, - { &spr_read.found_pos[0], 4|FCEUSTATE_RLSB, "SRx1" }, - { &spr_read.found_pos[0], 4|FCEUSTATE_RLSB, "SRx2" }, - { &spr_read.found_pos[0], 4|FCEUSTATE_RLSB, "SRx3" }, - { &spr_read.found_pos[0], 4|FCEUSTATE_RLSB, "SRx4" }, - { &spr_read.found_pos[0], 4|FCEUSTATE_RLSB, "SRx5" }, - { &spr_read.found_pos[0], 4|FCEUSTATE_RLSB, "SRx6" }, - { &spr_read.found_pos[0], 4|FCEUSTATE_RLSB, "SRx7" }, - { &spr_read.ret, 4|FCEUSTATE_RLSB, "SR_4" }, - { &spr_read.last, 4|FCEUSTATE_RLSB, "SR_5" }, - { &spr_read.mode, 4|FCEUSTATE_RLSB, "SR_6" }, - { &ppur.fv, 4|FCEUSTATE_RLSB, "PFVx" }, - { &ppur.v, 4|FCEUSTATE_RLSB, "PVxx" }, - { &ppur.h, 4|FCEUSTATE_RLSB, "PHxx" }, - { &ppur.vt, 4|FCEUSTATE_RLSB, "PVTx" }, - { &ppur.ht, 4|FCEUSTATE_RLSB, "PHTx" }, - { &ppur._fv, 4|FCEUSTATE_RLSB, "P_FV" }, - { &ppur._v, 4|FCEUSTATE_RLSB, "P_Vx" }, - { &ppur._h, 4|FCEUSTATE_RLSB, "P_Hx" }, - { &ppur._vt, 4|FCEUSTATE_RLSB, "P_VT" }, - { &ppur._ht, 4|FCEUSTATE_RLSB, "P_HT" }, - { &ppur.fh, 4|FCEUSTATE_RLSB, "PFHx" }, - { &ppur.s, 4|FCEUSTATE_RLSB, "PSxx" }, - { &ppur.status.sl, 4|FCEUSTATE_RLSB, "PST0" }, - { &ppur.status.cycle, 4|FCEUSTATE_RLSB, "PST1" }, - { &ppur.status.end_cycle, 4|FCEUSTATE_RLSB, "PST2" }, + { &spr_read.num, 4 | FCEUSTATE_RLSB, "SR_0" }, + { &spr_read.count, 4 | FCEUSTATE_RLSB, "SR_1" }, + { &spr_read.fetch, 4 | FCEUSTATE_RLSB, "SR_2" }, + { &spr_read.found, 4 | FCEUSTATE_RLSB, "SR_3" }, + { &spr_read.found_pos[0], 4 | FCEUSTATE_RLSB, "SRx0" }, + { &spr_read.found_pos[0], 4 | FCEUSTATE_RLSB, "SRx1" }, + { &spr_read.found_pos[0], 4 | FCEUSTATE_RLSB, "SRx2" }, + { &spr_read.found_pos[0], 4 | FCEUSTATE_RLSB, "SRx3" }, + { &spr_read.found_pos[0], 4 | FCEUSTATE_RLSB, "SRx4" }, + { &spr_read.found_pos[0], 4 | FCEUSTATE_RLSB, "SRx5" }, + { &spr_read.found_pos[0], 4 | FCEUSTATE_RLSB, "SRx6" }, + { &spr_read.found_pos[0], 4 | FCEUSTATE_RLSB, "SRx7" }, + { &spr_read.ret, 4 | FCEUSTATE_RLSB, "SR_4" }, + { &spr_read.last, 4 | FCEUSTATE_RLSB, "SR_5" }, + { &spr_read.mode, 4 | FCEUSTATE_RLSB, "SR_6" }, + { &ppur.fv, 4 | FCEUSTATE_RLSB, "PFVx" }, + { &ppur.v, 4 | FCEUSTATE_RLSB, "PVxx" }, + { &ppur.h, 4 | FCEUSTATE_RLSB, "PHxx" }, + { &ppur.vt, 4 | FCEUSTATE_RLSB, "PVTx" }, + { &ppur.ht, 4 | FCEUSTATE_RLSB, "PHTx" }, + { &ppur._fv, 4 | FCEUSTATE_RLSB, "P_FV" }, + { &ppur._v, 4 | FCEUSTATE_RLSB, "P_Vx" }, + { &ppur._h, 4 | FCEUSTATE_RLSB, "P_Hx" }, + { &ppur._vt, 4 | FCEUSTATE_RLSB, "P_VT" }, + { &ppur._ht, 4 | FCEUSTATE_RLSB, "P_HT" }, + { &ppur.fh, 4 | FCEUSTATE_RLSB, "PFHx" }, + { &ppur.s, 4 | FCEUSTATE_RLSB, "PSxx" }, + { &ppur.status.sl, 4 | FCEUSTATE_RLSB, "PST0" }, + { &ppur.status.cycle, 4 | FCEUSTATE_RLSB, "PST1" }, + { &ppur.status.end_cycle, 4 | FCEUSTATE_RLSB, "PST2" }, { 0 } }; -void FCEUPPU_SaveState(void) -{ - TempAddrT=TempAddr; - RefreshAddrT=RefreshAddr; +void FCEUPPU_SaveState(void) { + TempAddrT = TempAddr; + RefreshAddrT = RefreshAddr; } +uint32 FCEUPPU_PeekAddress() +{ + if (newppu) + { + return ppur.get_2007access() & 0x3FFF; + } + + return RefreshAddr & 0x3FFF; +} //--------------------- -int pputime=0; -int totpputime=0; -const int kLineTime=341; -const int kFetchTime=2; +int pputime = 0; +int totpputime = 0; +const int kLineTime = 341; +const int kFetchTime = 2; void runppu(int x) { - //pputime+=x; - //if(cputodo<200) return; - - ppur.status.cycle = (ppur.status.cycle + x) % - ppur.status.end_cycle; - + ppur.status.cycle = (ppur.status.cycle + x) % ppur.status.end_cycle; X6502_Run(x); - //pputime -= cputodo<<2; } //todo - consider making this a 3 or 4 slot fifo to keep from touching so much memory struct BGData { - struct Record { - uint8 nt, at, pt[2]; + struct Record { + uint8 nt, pecnt, at, pt[2]; - INLINE void Read() { - RefreshAddr = ppur.get_ntread(); - nt = CALL_PPUREAD(RefreshAddr); + INLINE void Read() { + RefreshAddr = ppur.get_ntread(); + if (PEC586Hack) + ppur.s = (RefreshAddr & 0x200) >> 9; + pecnt = (RefreshAddr & 1) << 3; + nt = CALL_PPUREAD(RefreshAddr); + runppu(kFetchTime); + + RefreshAddr = ppur.get_atread(); + at = CALL_PPUREAD(RefreshAddr); + + //modify at to get appropriate palette shift + if (ppur.vt & 2) at >>= 4; + if (ppur.ht & 2) at >>= 2; + at &= 0x03; + at <<= 2; + //horizontal scroll clocked at cycle 3 and then + //vertical scroll at 251 + runppu(1); + if (PPUON) { + ppur.increment_hsc(); + if (ppur.status.cycle == 251) + ppur.increment_vs(); + } + runppu(1); + + ppur.par = nt; + RefreshAddr = ppur.get_ptread(); + if (PEC586Hack) { + if (ScreenON) + RENDER_LOG(RefreshAddr | pecnt); + pt[0] = CALL_PPUREAD(RefreshAddr | pecnt); runppu(kFetchTime); - - RefreshAddr = ppur.get_atread(); - at = CALL_PPUREAD(RefreshAddr); - - //modify at to get appropriate palette shift - if(ppur.vt&2) at >>= 4; - if(ppur.ht&2) at >>= 2; - at &= 0x03; - at <<= 2; - //horizontal scroll clocked at cycle 3 and then - //vertical scroll at 251 - runppu(1); - if (PPUON) - { - ppur.increment_hsc(); - if (ppur.status.cycle == 251) - ppur.increment_vs(); - } - runppu(1); - - ppur.par = nt; - RefreshAddr = ppur.get_ptread(); + pt[1] = CALL_PPUREAD(RefreshAddr | pecnt); + runppu(kFetchTime); + } else { + if (ScreenON) + RENDER_LOG(RefreshAddr); pt[0] = CALL_PPUREAD(RefreshAddr); runppu(kFetchTime); RefreshAddr |= 8; + if (ScreenON) + RENDER_LOG(RefreshAddr); pt[1] = CALL_PPUREAD(RefreshAddr); runppu(kFetchTime); } - }; + } + }; - Record main[34]; //one at the end is junk, it can never be rendered - } bgdata; + Record main[34]; //one at the end is junk, it can never be rendered +} bgdata; -static inline int PaletteAdjustPixel(int pixel) -{ - if((PPU[1]>>5)==0x7) - return (pixel&0x3f)|0xc0; - else if(PPU[1]&0xE0) +static inline int PaletteAdjustPixel(int pixel) { + if ((PPU[1] >> 5) == 0x7) + return (pixel & 0x3f) | 0xc0; + else if (PPU[1] & 0xE0) return pixel | 0x40; else - return (pixel&0x3F)|0x80; + return (pixel & 0x3F) | 0x80; } -int framectr=0; +int framectr = 0; int FCEUX_PPU_Loop(int skip) { //262 scanlines - if (ppudead) - { - /* not quite emulating all the NES power up behavior - * since it is known that the NES ignores writes to some - * register before around a full frame, but no games - * should write to those regs during that time, it needs - * to wait for vblank */ - ppur.status.sl = 241; - if (PAL) - runppu(70*kLineTime); - else - runppu(20*kLineTime); - ppur.status.sl = 0; - runppu(242*kLineTime); - --ppudead; - goto finish; - } + if (ppudead) { + // not quite emulating all the NES power up behavior + // since it is known that the NES ignores writes to some + // register before around a full frame, but no games + // should write to those regs during that time, it needs + // to wait for vblank + ppur.status.sl = 241; + if (PAL) + runppu(70 * kLineTime); + else + runppu(20 * kLineTime); + ppur.status.sl = 0; + runppu(242 * kLineTime); + --ppudead; + goto finish; + } { PPU_status |= 0x80; @@ -2262,17 +1998,17 @@ int FCEUX_PPU_Loop(int skip) { //Not sure if this is correct. According to Matt Conte and my own tests, it is. //Timing is probably off, though. //NOTE: Not having this here breaks a Super Donkey Kong game. - PPU[3]=PPUSPL=0; - const int delay = 20; //fceu used 12 here but I couldnt get it to work in marble madness and pirates. + PPU[3] = PPUSPL = 0; + const int delay = 20; //fceu used 12 here but I couldnt get it to work in marble madness and pirates. - ppur.status.sl = 241; //for sprite reads + ppur.status.sl = 241; //for sprite reads - runppu(delay); //X6502_Run(12); - if(VBlankON) TriggerNMI(); - if (PAL) - runppu(70*(kLineTime)-delay); - else - runppu(20*(kLineTime)-delay); + runppu(delay); //X6502_Run(12); + if (VBlankON) TriggerNMI(); + if (PAL) + runppu(70 * (kLineTime) - delay); + else + runppu(20 * (kLineTime) - delay); //this seems to run just before the dummy scanline begins PPU_status = 0; @@ -2288,33 +2024,35 @@ int FCEUX_PPU_Loop(int skip) { //if(PPUON) // ppur.install_latches(); - static uint8 oams[2][64][8]; //[7] turned to [8] for faster indexing - static int oamcounts[2]={0,0}; - static int oamslot=0; + static uint8 oams[2][64][8];//[7] turned to [8] for faster indexing + static int oamcounts[2] = { 0, 0 }; + static int oamslot = 0; static int oamcount; //capture the initial xscroll //int xscroll = ppur.fh; - //render 241 scanlines (including 1 dummy at beginning) - for(int sl=0;sl<241;sl++) { + //render 241/291 scanlines (1 dummy at beginning, dendy's 50 at the end) + for (int sl = 0; sl < (dendy ? 291 : 241); sl++) { spr_read.start_scanline(); g_rasterpos = 0; ppur.status.sl = sl; - const int yp = sl-1; + linestartts = timestamp * 48 + X.count; // pixel timestamp for debugger + + const int yp = sl - 1; ppuphase = PPUPHASE_BG; - if(sl != 0) { - DEBUG(FCEUD_UpdatePPUView(scanline=yp,1)); - DEBUG(FCEUD_UpdateNTView(scanline=yp,1)); + if (sl != 0 && sl < 241) { // ignore the invisible + DEBUG(FCEUD_UpdatePPUView(scanline = yp, 1)); + DEBUG(FCEUD_UpdateNTView(scanline = yp, 1)); } - if(sl != 0) if(MMC5Hack && PPUON) MMC5_hb(yp); + if (MMC5Hack) MMC5_hb(yp); //twiddle the oam buffers - const int scanslot = oamslot^1; + const int scanslot = oamslot ^ 1; const int renderslot = oamslot; oamslot ^= 1; @@ -2323,82 +2061,79 @@ int FCEUX_PPU_Loop(int skip) { //the main scanline rendering loop: //32 times, we will fetch a tile and then render 8 pixels. //two of those tiles were read in the last scanline. - for(int xt=0;xt<32;xt++) { - bgdata.main[xt+2].Read(); + for (int xt = 0; xt < 32; xt++) { + bgdata.main[xt + 2].Read(); - //ok, we're also going to draw here. + //ok, we're also going to draw here. //unless we're on the first dummy scanline - if(sl != 0) { - int xstart = xt<<3; + if (sl != 0 && sl < 241) { // cape at 240 for dendy, its PPU does nothing afterwards + int xstart = xt << 3; oamcount = oamcounts[renderslot]; - uint8 * const target=XBuf+(yp<<8)+xstart; + uint8 * const target = XBuf + (yp << 8) + xstart; uint8 *ptr = target; int rasterpos = xstart; //check all the conditions that can cause things to render in these 8px - const bool renderspritenow = SpriteON && rendersprites && (xt>0 || SpriteLeft8); - const bool renderbgnow = ScreenON && renderbg && (xt>0 || BGLeft8); - for(int xp=0;xp<8;xp++,rasterpos++,g_rasterpos++) { - + const bool renderspritenow = SpriteON && rendersprites && (xt > 0 || SpriteLeft8); + const bool renderbgnow = ScreenON && renderbg && (xt > 0 || BGLeft8); + for (int xp = 0; xp < 8; xp++, rasterpos++, g_rasterpos++) { //bg pos is different from raster pos due to its offsetability. //so adjust for that here const int bgpos = rasterpos + ppur.fh; - const int bgpx = bgpos&7; - const int bgtile = bgpos>>3; + const int bgpx = bgpos & 7; + const int bgtile = bgpos >> 3; - uint8 pixel=0, pixelcolor; + uint8 pixel = 0, pixelcolor; //generate the BG data - if(renderbgnow) - { + if (renderbgnow) { uint8* pt = bgdata.main[bgtile].pt; - pixel = ((pt[0]>>(7-bgpx))&1) | (((pt[1]>>(7-bgpx))&1)<<1) | bgdata.main[bgtile].at; + pixel = ((pt[0] >> (7 - bgpx)) & 1) | (((pt[1] >> (7 - bgpx)) & 1) << 1) | bgdata.main[bgtile].at; } pixelcolor = PALRAM[pixel]; //look for a sprite to be drawn bool havepixel = false; - for(int s=0;s=x && rasterpos= x && rasterpos < x + 8) { //build the pixel. //fetch the LSB of the patterns - uint8 spixel = oam[4]&1; - spixel |= (oam[5]&1)<<1; + uint8 spixel = oam[4] & 1; + spixel |= (oam[5] & 1) << 1; //shift down the patterns so the next pixel is in the LSB oam[4] >>= 1; oam[5] >>= 1; - if(!renderspritenow) continue; + if (!renderspritenow) continue; //bail out if we already have a pixel from a higher priority sprite - if(havepixel) continue; + if (havepixel) continue; //transparent pixel bailout - if(spixel==0) continue; + if (spixel == 0) continue; //spritehit: //1. is it sprite#0? //2. is the bg pixel nonzero? //then, it is spritehit. - if(oam[6] == 0 && (pixel & 3) != 0 && - rasterpos < 255) - { - PPU_status |= 0x40; - } + if (oam[6] == 0 && (pixel & 3) != 0 && + rasterpos < 255) { + PPU_status |= 0x40; + } havepixel = true; //priority handling - if(oam[2]&0x20) { + if (oam[2] & 0x20) { //behind background: - if((pixel&3)!=0) continue; + if ((pixel & 3) != 0) continue; } //bring in the palette bits and palettize - spixel |= (oam[2]&3)<<2; - pixelcolor = PALRAM[0x10+spixel]; + spixel |= (oam[2] & 3) << 2; + pixelcolor = PALRAM[0x10 + spixel]; } } @@ -2409,22 +2144,22 @@ int FCEUX_PPU_Loop(int skip) { //look for sprites (was supposed to run concurrent with bg rendering) oamcounts[scanslot] = 0; - oamcount=0; - const int spriteHeight = Sprite16?16:8; - for(int i=0;i<64;i++) { + oamcount = 0; + const int spriteHeight = Sprite16 ? 16 : 8; + for (int i = 0; i < 64; i++) { oams[scanslot][oamcount][7] = 0; - uint8* spr = SPRAM+i*4; - if(yp >= spr[0] && yp < spr[0]+spriteHeight) { + uint8* spr = SPRAM + i * 4; + if (yp >= spr[0] && yp < spr[0] + spriteHeight) { //if we already have maxsprites, then this new one causes an overflow, //set the flag and bail out. - if(oamcount >= 8 && PPUON) { + if (oamcount >= 8 && PPUON) { PPU_status |= 0x20; if (maxsprites == 8) break; } //just copy some bytes into the internal sprite buffer - for(int j=0;j<4;j++) + for (int j = 0; j < 4; j++) oams[scanslot][oamcount][j] = spr[j]; oams[scanslot][oamcount][7] = 1; @@ -2440,113 +2175,113 @@ int FCEUX_PPU_Loop(int skip) { //well, according to (which?) tests, maybe at the end of hblank. //but, according to what it took to get crystalis working, it is at the beginning of hblank. - //this is done at cycle 251 - //rendering scanline, it doesn't need to be scanline 0, - //because on the first scanline when the increment is 0, the vs_scroll is reloaded. + //this is done at cycle 251 + //rendering scanline, it doesn't need to be scanline 0, + //because on the first scanline when the increment is 0, the vs_scroll is reloaded. //if(PPUON && sl != 0) // ppur.increment_vs(); //todo - think about clearing oams to a predefined value to force deterministic behavior - //so.. this is the end of hblank. latch horizontal scroll values - //do it cycle at 251 - if(PPUON && sl != 0) - ppur.install_h_latches(); - ppuphase = PPUPHASE_OBJ; //fetch sprite patterns - for(int s=0;s=8) + if (s == oamcount && s >= 8) break; //if this is a real sprite sprite, then it is not above the 8 sprite limit. //this is how we support the no 8 sprite limit feature. //not that at some point we may need a virtual CALL_PPUREAD which just peeks and doesnt increment any counters //this could be handy for the debugging tools also - const bool realSprite = (s<8); + const bool realSprite = (s < 8); uint8* const oam = oams[scanslot][s]; uint32 line = yp - oam[0]; - if(oam[2]&0x80) //vflip - line = spriteHeight-line-1; + if (oam[2] & 0x80) //vflip + line = spriteHeight - line - 1; uint32 patternNumber = oam[1]; uint32 patternAddress; //create deterministic dummy fetch pattern - if(!oam[7]) - { + if (!oam[7]) { patternNumber = 0; line = 0; } //8x16 sprite handling: - if(Sprite16) { - uint32 bank = (patternNumber&1)<<12; - patternNumber = patternNumber&~1; - patternNumber |= (line>>3); - patternAddress = (patternNumber<<4) | bank; + if (Sprite16) { + uint32 bank = (patternNumber & 1) << 12; + patternNumber = patternNumber & ~1; + patternNumber |= (line >> 3); + patternAddress = (patternNumber << 4) | bank; } else { - patternAddress = (patternNumber<<4) | (SpAdrHI<<9); + patternAddress = (patternNumber << 4) | (SpAdrHI << 9); } //offset into the pattern for the current line. //tricky: tall sprites have already had lines>8 taken care of by getting a new pattern number above. //so we just need the line offset for the second pattern - patternAddress += line&7; + patternAddress += line & 7; //garbage nametable fetches - //reset the scroll counter, happens at cycle 304 - if (realSprite) + int garbage_todo = 2; + if (PPUON) { - if ((sl == 0) && PPUON) + if (sl == 0 && ppur.status.cycle == 304) { - if (ppur.status.cycle == 304) - { - runppu(1); - ppur.install_latches(); - runppu(1); - } - else - runppu(kFetchTime); + runppu(1); + if (PPUON) ppur.install_latches(); + runppu(1); + garbage_todo = 0; + } + if ((sl != 0 && sl < 241) && ppur.status.cycle == 256) + { + runppu(1); + //at 257: 3d world runner is ugly if we do this at 256 + if (PPUON) ppur.install_h_latches(); + runppu(1); + garbage_todo = 0; } - else - runppu(kFetchTime); } + if (realSprite) runppu(garbage_todo); //Dragon's Lair (Europe version mapper 4) //does not set SpriteON in the beginning but it does //set the bg on so if using the conditional SpriteON the MMC3 counter //the counter will never count and no IRQs will be fired so use PPUON - if(((PPU[0]&0x38)!=0x18) && s == 2 && PPUON) { //SpriteON ) { + if (((PPU[0] & 0x38) != 0x18) && s == 2 && PPUON) { //(The MMC3 scanline counter is based entirely on PPU A12, triggered on rising edges (after the line remains low for a sufficiently long period of time)) //http://nesdevwiki.org/wiki/index.php/Nintendo_MMC3 //test cases for timing: SMB3, Crystalis //crystalis requires deferring this til somewhere in sprite [1,3] //kirby requires deferring this til somewhere in sprite [2,5.. - //if (PPUON && GameHBIRQHook) { - if(GameHBIRQHook) { + //if (PPUON && GameHBIRQHook) { + if (GameHBIRQHook) { GameHBIRQHook(); } } - if(realSprite) runppu(kFetchTime); + if (realSprite) runppu(kFetchTime); //pattern table fetches RefreshAddr = patternAddress; + if (SpriteON) + RENDER_LOG(RefreshAddr); oam[4] = CALL_PPUREAD(RefreshAddr); - if(realSprite) runppu(kFetchTime); + if (realSprite) runppu(kFetchTime); RefreshAddr += 8; + if (SpriteON) + RENDER_LOG(RefreshAddr); oam[5] = CALL_PPUREAD(RefreshAddr); - if(realSprite) runppu(kFetchTime); + if (realSprite) runppu(kFetchTime); //hflip - if(!(oam[2]&0x40)) { + if (!(oam[2] & 0x40)) { oam[4] = bitrevlut[oam[4]]; oam[5] = bitrevlut[oam[5]]; } @@ -2555,7 +2290,7 @@ int FCEUX_PPU_Loop(int skip) { ppuphase = PPUPHASE_BG; //fetch BG: two tiles for next line - for(int xt=0;xt<2;xt++) + for (int xt = 0; xt < 2; xt++) bgdata.main[xt].Read(); //I'm unclear of the reason why this particular access to memory is made. @@ -2565,33 +2300,29 @@ int FCEUX_PPU_Loop(int skip) { //the PPU is fetching background data on the next scanline). //(not implemented yet) runppu(kFetchTime); - if (sl == 0) - { - if (idleSynch && PPUON && !PAL) - ppur.status.end_cycle = 340; - else - ppur.status.end_cycle = 341; - idleSynch ^= 1; - } - else - ppur.status.end_cycle = 341; + if (sl == 0) { + if (idleSynch && PPUON && !PAL) + ppur.status.end_cycle = 340; + else + ppur.status.end_cycle = 341; + idleSynch ^= 1; + } else + ppur.status.end_cycle = 341; runppu(kFetchTime); - //After memory access 170, the PPU simply rests for 4 cycles (or the + //After memory access 170, the PPU simply rests for 4 cycles (or the //equivelant of half a memory access cycle) before repeating the whole //pixel/scanline rendering process. If the scanline being rendered is the very //first one on every second frame, then this delay simply doesn't exist. - if (ppur.status.end_cycle == 341) - runppu(1); + if (ppur.status.end_cycle == 341) + runppu(1); + } //scanline loop - } //scanline loop - - if(MMC5Hack && PPUON) MMC5_hb(240); + if (MMC5Hack) MMC5_hb(240); //idle for one line runppu(kLineTime); framectr++; - } finish: diff --git a/source/fceultra/ppu.h b/source/fceultra/ppu.h index 9d85529..5db7158 100644 --- a/source/fceultra/ppu.h +++ b/source/fceultra/ppu.h @@ -10,16 +10,18 @@ extern void (*PPU_hook)(uint32 A); extern void (*GameHBIRQHook)(void), (*GameHBIRQHook2)(void); /* For cart.c and banksw.h, mostly */ -extern uint8 NTARAM[0x800],*vnapage[4]; +extern uint8 NTARAM[0x800], *vnapage[4]; extern uint8 PPUNTARAM; extern uint8 PPUCHRRAM; void FCEUPPU_SaveState(void); void FCEUPPU_LoadState(int version); +uint32 FCEUPPU_PeekAddress(); uint8* FCEUPPU_GetCHR(uint32 vadr, uint32 refreshaddr); void ppu_getScroll(int &xpos, int &ypos); + #ifdef _MSC_VER #define FASTCALL __fastcall #else diff --git a/source/fceultra/pputile.inc b/source/fceultra/pputile.inc index 733b1d6..b935a7f 100644 --- a/source/fceultra/pputile.inc +++ b/source/fceultra/pputile.inc @@ -1,84 +1,82 @@ -uint8 *C; +uint8 *C; register uint8 cc; uint32 vadr; - + #ifndef PPUT_MMC5SP - uint8 zz; + register uint8 zz; #else - uint8 xs,ys; - xs=X1; - ys=((scanline>>3)+MMC5HackSPScroll)&0x1F; - if(ys>=0x1E) ys-=0x1E; + uint8 xs, ys; + xs = X1; + ys = ((scanline >> 3) + MMC5HackSPScroll) & 0x1F; + if (ys >= 0x1E) ys -= 0x1E; #endif - -if(X1>=2) { - uint8 *S=PALRAM; + +if (X1 >= 2) { + uint8 *S = PALRAM; uint32 pixdata; - pixdata=ppulut1[(pshift[0]>>(8-XOffset))&0xFF]|ppulut2[(pshift[1]>>(8-XOffset))&0xFF]; + pixdata = ppulut1[(pshift[0] >> (8 - XOffset)) & 0xFF] | ppulut2[(pshift[1] >> (8 - XOffset)) & 0xFF]; - pixdata|=ppulut3[XOffset|(atlatch<<3)]; - //printf("%02x ",ppulut3[XOffset|(atlatch<<3)]); + pixdata |= ppulut3[XOffset | (atlatch << 3)]; - P[0]=S[pixdata&0xF]; - pixdata>>=4; - P[1]=S[pixdata&0xF]; - pixdata>>=4; - P[2]=S[pixdata&0xF]; - pixdata>>=4; - P[3]=S[pixdata&0xF]; - pixdata>>=4; - P[4]=S[pixdata&0xF]; - pixdata>>=4; - P[5]=S[pixdata&0xF]; - pixdata>>=4; - P[6]=S[pixdata&0xF]; - pixdata>>=4; - P[7]=S[pixdata&0xF]; - P+=8; + P[0] = S[pixdata & 0xF]; + pixdata >>= 4; + P[1] = S[pixdata & 0xF]; + pixdata >>= 4; + P[2] = S[pixdata & 0xF]; + pixdata >>= 4; + P[3] = S[pixdata & 0xF]; + pixdata >>= 4; + P[4] = S[pixdata & 0xF]; + pixdata >>= 4; + P[5] = S[pixdata & 0xF]; + pixdata >>= 4; + P[6] = S[pixdata & 0xF]; + pixdata >>= 4; + P[7] = S[pixdata & 0xF]; + P += 8; } #ifdef PPUT_MMC5SP - vadr=(MMC5HackExNTARAMPtr[xs|(ys<<5)]<<4)+(vofs&7); + vadr = (MMC5HackExNTARAMPtr[xs | (ys << 5)] << 4) + (vofs & 7); #else - zz=RefreshAddr&0x1F; - C=vnapage[(RefreshAddr>>10)&3]; - vadr=(C[RefreshAddr&0x3ff]<<4)+vofs; /* Fetch name table byte. */ + zz = RefreshAddr & 0x1F; + C = vnapage[(RefreshAddr >> 10) & 3]; + vadr = (C[RefreshAddr & 0x3ff] << 4) + vofs; // Fetch name table byte. #endif #ifdef PPUT_HOOK - PPU_hook(0x2000|(RefreshAddr&0xfff)); + PPU_hook(0x2000 | (RefreshAddr & 0xfff)); #endif #ifdef PPUT_MMC5SP - cc=MMC5HackExNTARAMPtr[0x3c0+(xs>>2)+((ys&0x1C)<<1)]; - cc=((cc >> ((xs&2) + ((ys&0x2)<<1))) &3); + cc = MMC5HackExNTARAMPtr[0x3c0 + (xs >> 2) + ((ys & 0x1C) << 1)]; + cc = ((cc >> ((xs & 2) + ((ys & 0x2) << 1))) & 3); #else #ifdef PPUT_MMC5CHR1 - cc=(MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff] & 0xC0)>>6; + cc = (MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff] & 0xC0) >> 6; #else - cc=C[0x3c0+(zz>>2)+((RefreshAddr&0x380)>>4)]; /* Fetch attribute table byte. */ - cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3); + cc = C[0x3c0 + (zz >> 2) + ((RefreshAddr & 0x380) >> 4)]; // Fetch attribute table byte. + cc = ((cc >> ((zz & 2) + ((RefreshAddr & 0x40) >> 4))) & 3); #endif #endif -atlatch>>=2; -atlatch|=cc<<2; - -pshift[0]<<=8; -pshift[1]<<=8; +atlatch >>= 2; +atlatch |= cc << 2; + +pshift[0] <<= 8; +pshift[1] <<= 8; #ifdef PPUT_MMC5SP - C = MMC5HackVROMPTR+vadr; + C = MMC5HackVROMPTR + vadr; C += ((MMC5HackSPPage & 0x3f & MMC5HackVROMMask) << 12); #else #ifdef PPUT_MMC5CHR1 C = MMC5HackVROMPTR; - C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f & - MMC5HackVROMMask) << 12) + (vadr & 0xfff); - C += (MMC50x5130&0x3)<<18; //11-jun-2009 for kuja_killer + C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f & MMC5HackVROMMask) << 12) + (vadr & 0xfff); + C += (MMC50x5130 & 0x3) << 18; //11-jun-2009 for kuja_killer #elif defined(PPUT_MMC5) - C=MMC5BGVRAMADR(vadr); + C = MMC5BGVRAMADR(vadr); #else C = VRAMADR(vadr); #endif @@ -88,15 +86,33 @@ pshift[1]<<=8; PPU_hook(vadr); #endif -pshift[0]|=C[0]; -pshift[1]|=C[8]; +#ifdef PPU_BGFETCH + if (RefreshAddr & 1) { + if(ScreenON) + RENDER_LOG(vadr + 8); + pshift[0] |= C[8]; + pshift[1] |= C[8]; + } else { + if(ScreenON) + RENDER_LOG(vadr); + pshift[0] |= C[0]; + pshift[1] |= C[0]; + } +#else + if(ScreenON) + RENDER_LOG(vadr); + pshift[0] |= C[0]; + if(ScreenON) + RENDER_LOG(vadr + 8); + pshift[1] |= C[8]; +#endif -if((RefreshAddr&0x1f)==0x1f) - RefreshAddr^=0x41F; +if ((RefreshAddr & 0x1f) == 0x1f) + RefreshAddr ^= 0x41F; else RefreshAddr++; #ifdef PPUT_HOOK - PPU_hook(0x2000|(RefreshAddr&0xfff)); + PPU_hook(0x2000 | (RefreshAddr & 0xfff)); #endif diff --git a/source/fceultra/sound.cpp b/source/fceultra/sound.cpp index 3b33faf..e5ea920 100644 --- a/source/fceultra/sound.cpp +++ b/source/fceultra/sound.cpp @@ -18,11 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include - -#include - #include "types.h" #include "x6502.h" @@ -33,6 +28,10 @@ #include "wave.h" #include "debug.h" +#include +#include +#include + static uint32 wlookup1[32]; static uint32 wlookup2[203]; @@ -47,16 +46,19 @@ static uint8 TriMode=0; static int32 tristep=0; -static int32 wlcount[4]={0,0,0,0}; /* Wave length counters. */ +static int32 wlcount[4]={0,0,0,0}; // Wave length counters. -static uint8 IRQFrameMode=0; /* $4017 / xx000000 */ -/*static*/ uint8 PSG[0x10]; -static uint8 RawDALatch=0; /* $4011 0xxxxxxx */ -/*static*/ uint8 InitialRawDALatch=0; // used only for lua +// APU registers: +uint8 PSG[0x10]; // $4000-$400F / Channels 1-4 +uint8 DMCFormat=0; // $4010 / Play mode and frequency +uint8 RawDALatch=0; // $4011 / 7-bit DAC / 0xxxxxxx +uint8 DMCAddressLatch=0; // $4012 / Start of DMC waveform is at address $C000 + $40*$xx +uint8 DMCSizeLatch=0; // $4013 / Length of DMC waveform is $10*$xx + 1 bytes (128*$xx + 8 samples) +uint8 EnabledChannels=0; // $4015 / Sound channels enable and status +uint8 IRQFrameMode=0; // $4017 / Frame counter control / xx000000 -uint8 EnabledChannels=0; /* Byte written to $4015 */ - -/*static*/ ENVUNIT EnvUnits[3]; +uint8 InitialRawDALatch=0; // used only for lua +ENVUNIT EnvUnits[3]; static const int RectDuties[4]={1,2,4,6}; @@ -120,18 +122,10 @@ static const uint32 PALDMCTable[0x10]= 176, 148, 132, 118, 98, 78, 66, 50 }; -// $4010 - Frequency -// $4011 - Actual data outputted -// $4012 - Address register: $c000 + V*64 -// $4013 - Size register: Size in bytes = (V+1)*64 - /*static*/ int32 DMCacc=1; /*static*/ int32 DMCPeriod=0; /*static*/ uint8 DMCBitCount=0; -/*static*/ uint8 DMCAddressLatch=0,DMCSizeLatch=0; /* writes to 4012 and 4013 */ -/*static*/ uint8 DMCFormat=0; /* Write to $4010 */ - static uint32 DMCAddress=0; static int32 DMCSize=0; static uint8 DMCShift=0; @@ -232,74 +226,87 @@ static void SQReload(int x, uint8 V) static DECLFW(Write_PSG) { - A&=0x1F; - switch(A) - { - case 0x0:DoSQ1(); - EnvUnits[0].Mode=(V&0x30)>>4; - EnvUnits[0].Speed=(V&0xF); - break; - case 0x1: - sweepon[0]=V&0x80; - break; - case 0x2: - DoSQ1(); - curfreq[0]&=0xFF00; - curfreq[0]|=V; - break; - case 0x3: - SQReload(0,V); - break; - case 0x4: - DoSQ2(); - EnvUnits[1].Mode=(V&0x30)>>4; - EnvUnits[1].Speed=(V&0xF); - break; - case 0x5: - sweepon[1]=V&0x80; - break; - case 0x6:DoSQ2(); - curfreq[1]&=0xFF00; - curfreq[1]|=V; - break; - case 0x7: - SQReload(1,V); - break; - case 0xa:DoTriangle(); - break; - case 0xb: - DoTriangle(); - if(EnabledChannels&0x4) - lengthcount[2]=lengthtable[(V>>3)&0x1f]; - TriMode=1; // Load mode - break; - case 0xC:DoNoise(); - EnvUnits[2].Mode=(V&0x30)>>4; - EnvUnits[2].Speed=(V&0xF); - break; - case 0xE:DoNoise(); - break; - case 0xF: - DoNoise(); - if(EnabledChannels&0x8) - lengthcount[3]=lengthtable[(V>>3)&0x1f]; - EnvUnits[2].reloaddec=1; - break; - case 0x10:DoPCM(); - LoadDMCPeriod(V&0xF); - - if(SIRQStat&0x80) - { - if(!(V&0x80)) - { - X6502_IRQEnd(FCEU_IQDPCM); - SIRQStat&=~0x80; - } - else X6502_IRQBegin(FCEU_IQDPCM); - } - break; - } - PSG[A]=V; + A&=0x1F; + switch(A) + { + case 0x0: + DoSQ1(); + EnvUnits[0].Mode=(V&0x30)>>4; + EnvUnits[0].Speed=(V&0xF); +#ifdef WIN32 + if (swapDuty) + V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1); +#endif + break; + case 0x1: + sweepon[0]=V&0x80; + break; + case 0x2: + DoSQ1(); + curfreq[0]&=0xFF00; + curfreq[0]|=V; + break; + case 0x3: + SQReload(0,V); + break; + case 0x4: + DoSQ2(); + EnvUnits[1].Mode=(V&0x30)>>4; + EnvUnits[1].Speed=(V&0xF); +#ifdef WIN32 + if (swapDuty) + V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1); +#endif + break; + case 0x5: + sweepon[1]=V&0x80; + break; + case 0x6: + DoSQ2(); + curfreq[1]&=0xFF00; + curfreq[1]|=V; + break; + case 0x7: + SQReload(1,V); + break; + case 0xa: + DoTriangle(); + break; + case 0xb: + DoTriangle(); + if(EnabledChannels&0x4) + lengthcount[2]=lengthtable[(V>>3)&0x1f]; + TriMode=1; // Load mode + break; + case 0xC: + DoNoise(); + EnvUnits[2].Mode=(V&0x30)>>4; + EnvUnits[2].Speed=(V&0xF); + break; + case 0xE: + DoNoise(); + break; + case 0xF: + DoNoise(); + if(EnabledChannels&0x8) + lengthcount[3]=lengthtable[(V>>3)&0x1f]; + EnvUnits[2].reloaddec=1; + break; + case 0x10: + DoPCM(); + LoadDMCPeriod(V&0xF); + if(SIRQStat&0x80) + { + if(!(V&0x80)) + { + X6502_IRQEnd(FCEU_IQDPCM); + SIRQStat&=~0x80; + } + else X6502_IRQBegin(FCEU_IQDPCM); + } + break; + } + PSG[A]=V; } static DECLFW(Write_DMCRegs) diff --git a/source/fceultra/sound.h b/source/fceultra/sound.h index 3d094c2..4522766 100644 --- a/source/fceultra/sound.h +++ b/source/fceultra/sound.h @@ -58,6 +58,7 @@ extern unsigned char *cdloggerdata; #endif extern uint32 soundtsoffs; +extern bool swapDuty; #define SOUNDTS (timestamp + soundtsoffs) void SetNESSoundMap(void); diff --git a/source/fceultra/state.cpp b/source/fceultra/state.cpp index 3a73ec3..3059354 100644 --- a/source/fceultra/state.cpp +++ b/source/fceultra/state.cpp @@ -20,15 +20,6 @@ // TODO: Add (better) file io error checking -#include -#include -#include -#include -//#include //mbg merge 7/17/06 removed - -#include -#include - #include "version.h" #include "types.h" #include "x6502.h" @@ -58,6 +49,15 @@ #include "drivers/win/ramwatch.h" #endif +#include +#include +#include +#include +//#include //mbg merge 7/17/06 removed + +#include +#include + using namespace std; static void (*SPreSave)(void); @@ -82,6 +82,11 @@ bool internalSaveLoad = false; bool backupSavestates = true; bool compressSavestates = true; //By default FCEUX compresses savestates when a movie is inactive. +// a temp memory stream. We'll be dumping some data here and then compress +EMUFILE_MEMORY memory_savestate; +// temporary buffer for compressed data of a savestate +std::vector compressed_buf; + #define SFMDATA_SIZE (64) static SFORMAT SFMDATA[SFMDATA_SIZE]; static int SFEXINDEX; @@ -95,14 +100,16 @@ extern SFORMAT FCEUSND_STATEINFO[]; extern SFORMAT FCEUCTRL_STATEINFO[]; extern SFORMAT FCEUMOV_STATEINFO[]; +//why two separate CPU structs?? who knows SFORMAT SFCPU[]={ { &X.PC, 2|RLSB, "PC\0"}, { &X.A, 1, "A\0\0"}, - { &X.P, 1, "P\0\0"}, { &X.X, 1, "X\0\0"}, { &X.Y, 1, "Y\0\0"}, { &X.S, 1, "S\0\0"}, + { &X.P, 1, "P\0\0"}, + { &X.DB, 1, "DB"}, { &RAM, 0x800 | FCEUSTATE_INDIRECT, "RAM", }, { 0 } }; @@ -273,7 +280,10 @@ static bool ReadStateChunks(EMUFILE* is, int32 totalsize) ret=false; } break; - case 0x10:if(!ReadStateChunk(is,SFMDATA,size)) ret=false; break; + case 0x10: + if(!ReadStateChunk(is,SFMDATA,size)) + ret=false; + break; // now it gets hackier: case 5: @@ -355,11 +365,12 @@ extern int geniestage; bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel) { - //a temp memory stream. we'll dump some data here and then compress - //TODO - support dumping directly without compressing to save a buffer copy + // reinit memory_savestate + // memory_savestate is global variable which already has its vector of bytes, so no need to allocate memory every time we use save/loadstate + memory_savestate.set_len(0); // this also seeks to the beginning + memory_savestate.unfail(); - EMUFILE_MEMORY ms; - EMUFILE* os = &ms; + EMUFILE* os = &memory_savestate; uint32 totalsize = 0; @@ -404,7 +415,7 @@ bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel) if(SPreSave) SPostSave(); //save the length of the file - int len = ms.size(); + int len = memory_savestate.size(); //sanity check: len and totalsize should be the same if(len != totalsize) @@ -414,15 +425,16 @@ bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel) } int error = Z_OK; - uint8* cbuf = (uint8*)ms.buf(); + uint8* cbuf = (uint8*)memory_savestate.buf(); uLongf comprlen = -1; - if(compressionLevel != Z_NO_COMPRESSION && compressSavestates) + if(compressionLevel != Z_NO_COMPRESSION && (compressSavestates || FCEUMOV_Mode(MOVIEMODE_TASEDITOR))) { - //worst case compression. - //zlib says "0.1% larger than sourceLen plus 12 bytes" + // worst case compression: zlib says "0.1% larger than sourceLen plus 12 bytes" comprlen = (len>>9)+12 + len; - cbuf = new uint8[comprlen]; - error = compress2(cbuf,&comprlen,(uint8*)ms.buf(),len,compressionLevel); + if (compressed_buf.size() < comprlen) compressed_buf.resize(comprlen); + cbuf = &compressed_buf[0]; + // do compression + error = compress2(cbuf, &comprlen, (uint8*)memory_savestate.buf(), len, compressionLevel); } //dump the header @@ -435,19 +447,19 @@ bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel) outstream->fwrite((char*)header,16); outstream->fwrite((char*)cbuf,comprlen==-1?totalsize:comprlen); - if(cbuf != (uint8*)ms.buf()) delete[] cbuf; return error == Z_OK; } -void FCEUSS_Save(const char *fname) +void FCEUSS_Save(const char *fname, bool display_message) { EMUFILE* st = 0; char fn[2048]; - if(geniestage==1) + if (geniestage==1) { - FCEU_DispMessage("Cannot save FCS in GG screen.",0); + if (display_message) + FCEU_DispMessage("Cannot save FCS in GG screen.",0); return; } @@ -474,9 +486,10 @@ void FCEUSS_Save(const char *fname) st = FCEUD_UTF8_fstream(fn,"wb"); } - if(st == NULL || st->get_fp() == NULL) + if (st == NULL || st->get_fp() == NULL) { - FCEU_DispMessage("State %d save error.",0,CurrentState); + if (display_message) + FCEU_DispMessage("State %d save error.", 0, CurrentState); return; } @@ -515,8 +528,9 @@ void FCEUSS_Save(const char *fname) if(!fname) { - SaveStateStatus[CurrentState]=1; - FCEU_DispMessage("State %d saved.",0,CurrentState); + SaveStateStatus[CurrentState] = 1; + if (display_message) + FCEU_DispMessage("State %d saved.", 0, CurrentState); } redoSS = false; //we have a new savestate so redo is not possible } @@ -644,30 +658,33 @@ bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params) int stateversion = FCEU_de32lsb(header + 8); int comprlen = FCEU_de32lsb(header + 12); - std::vector buf(totalsize); + // reinit memory_savestate + // memory_savestate is global variable which already has its vector of bytes, so no need to allocate memory every time we use save/loadstate + if ((int)(memory_savestate.get_vec())->size() < totalsize) + (memory_savestate.get_vec())->resize(totalsize); + memory_savestate.set_len(totalsize); + memory_savestate.unfail(); + memory_savestate.fseek(0, SEEK_SET); - //not compressed: if(comprlen != -1) { - //load the compressed chunk and decompress - std::vector cbuf(comprlen); - is->fread((char*)&cbuf[0],comprlen); + // the savestate is compressed: read from is to compressed_buf, then decompress from compressed_buf to memory_savestate.vec + if ((int)compressed_buf.size() < comprlen) compressed_buf.resize(comprlen); + is->fread(&compressed_buf[0], comprlen); uLongf uncomprlen = totalsize; - int error = uncompress((uint8*)&buf[0],&uncomprlen,(uint8*)&cbuf[0],comprlen); + int error = uncompress(memory_savestate.buf(), &uncomprlen, &compressed_buf[0], comprlen); if(error != Z_OK || uncomprlen != totalsize) - return false; - //we dont need to restore the backup here because we havent messed with the emulator state yet - } - else + return false; // we dont need to restore the backup here because we havent messed with the emulator state yet + } else { - is->fread((char*)&buf[0],totalsize); + // the savestate is not compressed: just read from is to memory_savestate.vec + is->fread(memory_savestate.buf(), totalsize); } FCEUMOV_PreLoad(); - EMUFILE_MEMORY mstemp(&buf); - bool x = ReadStateChunks(&mstemp,totalsize)!=0; + bool x = (ReadStateChunks(&memory_savestate, totalsize) != 0); //mbg 5/24/08 - we don't support old states, so this shouldnt matter. //if(read_sfcpuc && stateversion<9500) @@ -677,14 +694,13 @@ bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params) { GameStateRestore(stateversion); } - if(x) + if (x) { FCEUPPU_LoadState(stateversion); FCEUSND_LoadState(stateversion); x=FCEUMOV_PostLoad(); - } - - if(!x && backup) { + } else if (backup) + { msBackupSavestate.fseek(0,SEEK_SET); FCEUSS_LoadFP(&msBackupSavestate,SSLOADPARAM_NOBACKUP); } @@ -693,7 +709,7 @@ bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params) } -bool FCEUSS_Load(const char *fname) +bool FCEUSS_Load(const char *fname, bool display_message) { EMUFILE* st; char fn[2048]; @@ -705,48 +721,56 @@ bool FCEUSS_Load(const char *fname) // MovieFlushHeader(); //} - if(geniestage==1) + if (geniestage == 1) { - FCEU_DispMessage("Cannot load FCS in GG screen.",0); + if (display_message) + FCEU_DispMessage("Cannot load FCS in GG screen.",0); return false; } - if(fname) + if (fname) { - st=FCEUD_UTF8_fstream(fname, "rb"); + st = FCEUD_UTF8_fstream(fname, "rb"); strcpy(fn, fname); - } - else + } else { strcpy(fn, FCEU_MakeFName(FCEUMKF_STATE,CurrentState,fname).c_str()); st=FCEUD_UTF8_fstream(fn,"rb"); strcpy(lastLoadstateMade,fn); } - if(st == NULL || (st->get_fp() == NULL)) + if (st == NULL || (st->get_fp() == NULL)) { - FCEU_DispMessage("State %d load error.",0,CurrentState); - //FCEU_DispMessage("State %d load error. Filename: %s",0,CurrentState, fn); - SaveStateStatus[CurrentState]=0; + if (display_message) + { + FCEU_DispMessage("State %d load error.", 0, CurrentState); + //FCEU_DispMessage("State %d load error. Filename: %s", 0, CurrentState, fn); + } + SaveStateStatus[CurrentState] = 0; return false; } //If in bot mode, don't do a backup when loading. //Otherwise you eat at the hard disk, since so many //states are being loaded. - if(FCEUSS_LoadFP(st, backupSavestates ? SSLOADPARAM_BACKUP : SSLOADPARAM_NOBACKUP)) + if (FCEUSS_LoadFP(st, backupSavestates ? SSLOADPARAM_BACKUP : SSLOADPARAM_NOBACKUP)) { - if(fname) + if (fname) { char szFilename[260]={0}; splitpath(fname, 0, 0, szFilename, 0); - FCEU_DispMessage("State %s loaded.",0,szFilename); - //FCEU_DispMessage("State %s loaded. Filename: %s",0,szFilename, fn); - } - else + if (display_message) + { + FCEU_DispMessage("State %s loaded.", 0, szFilename); + //FCEU_DispMessage("State %s loaded. Filename: %s", 0, szFilename, fn); + } + } else { - FCEU_DispMessage("State %d loaded.",0,CurrentState); - //FCEU_DispMessage("State %d loaded. Filename: %s",0,CurrentState, fn); - SaveStateStatus[CurrentState]=1; + if (display_message) + { + FCEU_DispMessage("State %d loaded.", 0, CurrentState); + //FCEU_DispMessage("State %d loaded. Filename: %s", 0, CurrentState, fn); + } + SaveStateStatus[CurrentState] = 1; } delete st; @@ -781,15 +805,16 @@ bool FCEUSS_Load(const char *fname) cur_input_display = FCEU_GetJoyJoy(); //Input display should show the last buttons pressed (stored in the savestate) return true; - } - else + } else { if(!fname) + SaveStateStatus[CurrentState] = 1; + + if (display_message) { - SaveStateStatus[CurrentState]=1; + FCEU_DispMessage("Error(s) reading state %d!", 0, CurrentState); + //FCEU_DispMessage("Error(s) reading state %d! Filename: %s", 0, CurrentState, fn); } - FCEU_DispMessage("Error(s) reading state %d!",0,CurrentState); - //FCEU_DispMessage("Error(s) reading state %d! Filename: %s",0,CurrentState, fn); delete st; return 0; } @@ -905,13 +930,13 @@ int FCEUI_SelectState(int w, int show) return oldstate; } -void FCEUI_SaveState(const char *fname) +void FCEUI_SaveState(const char *fname, bool display_message) { if(!FCEU_IsValidUI(FCEUI_SAVESTATE)) return; - StateShow=0; + StateShow = 0; - FCEUSS_Save(fname); + FCEUSS_Save(fname, display_message); } int loadStateFailed = 0; // hack, this function should return a value instead @@ -925,7 +950,7 @@ bool file_exists(const char * filename) } return false; } -void FCEUI_LoadState(const char *fname) +void FCEUI_LoadState(const char *fname, bool display_message) { if(!FCEU_IsValidUI(FCEUI_LOADSTATE)) return; @@ -937,7 +962,8 @@ void FCEUI_LoadState(const char *fname) information expected in newer save states, desynchronization won't occur(at least not from this ;)). */ - if (backupSavestates) BackupLoadState(); //If allowed, backup the current state before loading a new one + if (backupSavestates) + BackupLoadState(); // If allowed, backup the current state before loading a new one if (!movie_readonly && autoMovieBackup && freshMovie) //If auto-backup is on, movie has not been altered this session and the movie is in read+write mode { @@ -948,10 +974,11 @@ void FCEUI_LoadState(const char *fname) loadStateFailed = 1; return; // state doesn't exist; exit cleanly } - if(FCEUSS_Load(fname)) + if (FCEUSS_Load(fname, display_message)) { //mbg todo netplay - /*if(FCEUnetplay) +#if 0 + if(FCEUnetplay) { char *fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP, 0, 0).c_str()); FILE *fp; @@ -972,10 +999,10 @@ void FCEUI_LoadState(const char *fname) } free(fn); - }*/ + } +#endif freshMovie = false; //The movie has been altered so it is no longer fresh - } - else + } else { loadStateFailed = 1; } diff --git a/source/fceultra/state.h b/source/fceultra/state.h index 7db50b3..a0a2f93 100644 --- a/source/fceultra/state.h +++ b/source/fceultra/state.h @@ -24,8 +24,8 @@ enum ENUM_SSLOADPARAMS SSLOADPARAM_BACKUP, }; -void FCEUSS_Save(const char *); -bool FCEUSS_Load(const char *); +void FCEUSS_Save(const char *, bool display_message=true); +bool FCEUSS_Load(const char *, bool display_message=true); //zlib values: 0 (none) through 9 (max) or -1 (default) bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel); diff --git a/source/fceultra/types-des.h b/source/fceultra/types-des.h new file mode 100644 index 0000000..acb324a --- /dev/null +++ b/source/fceultra/types-des.h @@ -0,0 +1,458 @@ +/* Copyright (C) 2005 Guillaume Duhamel + Copyright (C) 2008-2009 DeSmuME team + + This file is part of DeSmuME + + DeSmuME 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 2 of the License, or + (at your option) any later version. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef TYPES_HPP +#define TYPES_HPP + +//analyze microsoft compilers +#ifdef _MSC_VER + #ifdef _XBOX + //#define _XBOX //already defined + #else + #define _WINDOWS + #ifdef _M_X64 + //#define _WIN64 //already defined in x64 compiler + #else + //#define _WIN32 //already defined + #endif + #endif +#endif + +//todo - everyone will want to support this eventually, i suppose +#ifdef _WINDOWS +#include "config.h" +#endif + +//xbox needs to include this to resemble windows +#ifdef _XBOX + #include + #include +#endif + +#ifdef DEVELOPER +#define IF_DEVELOPER(X) X +#else +#define IF_DEVELOPER(X) +#endif + +#ifdef _WINDOWS + //#define HAVE_WX //not useful yet.... + #define HAVE_LIBAGG + #define ENABLE_SSE + #define ENABLE_SSE2 + #ifdef DEVELOPER + #define HAVE_LUA + #endif +#endif + +#ifdef __GNUC__ +#ifdef __SSE__ +#define ENABLE_SSE +#endif +#ifdef __SSE2__ +#define ENABLE_SSE2 +#endif +#endif + +#ifdef NOSSE +#undef ENABLE_SSE +#endif + +#ifdef NOSSE2 +#undef ENABLE_SSE2 +#endif + +#ifdef _MSC_VER +#define strcasecmp(x,y) _stricmp(x,y) +#define snprintf _snprintf +#else +#define WINAPI +#endif + +#ifdef __GNUC__ +#include +#ifndef PATH_MAX +#define MAX_PATH 1024 +#else +#define MAX_PATH PATH_MAX +#endif +#endif + + +#ifdef _XBOX +#define MAX_PATH 1024 +#define PATH_MAX 1024 +#endif + + +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +#define ALIGN(X) __declspec(align(X)) +#elif __GNUC__ +#define ALIGN(X) __attribute__ ((aligned (X))) +#else +#define ALIGN(X) +#endif + +#define CACHE_ALIGN ALIGN(32) + +//use this for example when you want a byte value to be better-aligned +#define FAST_ALIGN ALIGN(4) + +#ifndef FASTCALL +#ifdef __MINGW32__ +#define FASTCALL __attribute__((fastcall)) +#elif defined (__i386__) && !defined(__clang__) +#define FASTCALL __attribute__((regparm(3))) +#elif defined(_MSC_VER) || defined(__INTEL_COMPILER) +#define FASTCALL +#else +#define FASTCALL +#endif +#endif + +#ifdef _MSC_VER +#define _CDECL_ __cdecl +#else +#define _CDECL_ +#endif + +#ifndef INLINE +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +#define INLINE _inline +#else +#define INLINE inline +#endif +#endif + +#ifndef FORCEINLINE +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +#define FORCEINLINE __forceinline +#define MSC_FORCEINLINE __forceinline +#else +#define FORCEINLINE inline __attribute__((always_inline)) +#define MSC_FORCEINLINE +#endif +#endif + +#if defined(__LP64__) +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; +#else +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +typedef unsigned __int64 u64; +#else +typedef unsigned long long u64; +#endif + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +typedef __int64 s64; +#else +typedef signed long long s64; +#endif +#endif + +typedef u8 uint8; +typedef u16 uint16; + +#ifndef OBJ_C +typedef u32 uint32; +#else +#define uint32 u32 //uint32 is defined in Leopard somewhere, avoid conflicts +#endif + +/*---------- GPU3D fixed-points types -----------*/ + +typedef s32 f32; +#define inttof32(n) ((n) << 12) +#define f32toint(n) ((n) >> 12) +#define floattof32(n) ((int32)((n) * (1 << 12))) +#define f32tofloat(n) (((float)(n)) / (float)(1<<12)) + +typedef s16 t16; +#define f32tot16(n) ((t16)(n >> 8)) +#define inttot16(n) ((n) << 4) +#define t16toint(n) ((n) >> 4) +#define floattot16(n) ((t16)((n) * (1 << 4))) +#define t16ofloat(n) (((float)(n)) / (float)(1<<4)) + +typedef s16 v16; +#define inttov16(n) ((n) << 12) +#define f32tov16(n) (n) +#define floattov16(n) ((v16)((n) * (1 << 12))) +#define v16toint(n) ((n) >> 12) +#define v16tofloat(n) (((float)(n)) / (float)(1<<12)) + +typedef s16 v10; +#define inttov10(n) ((n) << 9) +#define f32tov10(n) ((v10)(n >> 3)) +#define v10toint(n) ((n) >> 9) +#define floattov10(n) ((v10)((n) * (1 << 9))) +#define v10tofloat(n) (((float)(n)) / (float)(1<<9)) + +/*----------------------*/ + +#ifndef OBJ_C +typedef int BOOL; +#else +//apple also defines BOOL +typedef int desmume_BOOL; +#define BOOL desmume_BOOL +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifdef __BIG_ENDIAN__ +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#endif +#endif + +#ifdef WORDS_BIGENDIAN +# define LOCAL_BE +#else +# define LOCAL_LE +#endif + +/* little endian (ds' endianess) to local endianess convert macros */ +#ifdef LOCAL_BE /* local arch is big endian */ +# define LE_TO_LOCAL_16(x) ((((x)&0xff)<<8)|(((x)>>8)&0xff)) +# define LE_TO_LOCAL_32(x) ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)>>8)&0xff00)|(((x)>>24)&0xff)) +# define LE_TO_LOCAL_64(x) ((((x)&0xff)<<56)|(((x)&0xff00)<<40)|(((x)&0xff0000)<<24)|(((x)&0xff000000)<<8)|(((x)>>8)&0xff000000)|(((x)>>24)&0xff00)|(((x)>>40)&0xff00)|(((x)>>56)&0xff)) +# define LOCAL_TO_LE_16(x) ((((x)&0xff)<<8)|(((x)>>8)&0xff)) +# define LOCAL_TO_LE_32(x) ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)>>8)&0xff00)|(((x)>>24)&0xff)) +# define LOCAL_TO_LE_64(x) ((((x)&0xff)<<56)|(((x)&0xff00)<<40)|(((x)&0xff0000)<<24)|(((x)&0xff000000)<<8)|(((x)>>8)&0xff000000)|(((x)>>24)&0xff00)|(((x)>>40)&0xff00)|(((x)>>56)&0xff)) +#else /* local arch is little endian */ +# define LE_TO_LOCAL_16(x) (x) +# define LE_TO_LOCAL_32(x) (x) +# define LE_TO_LOCAL_64(x) (x) +# define LOCAL_TO_LE_16(x) (x) +# define LOCAL_TO_LE_32(x) (x) +# define LOCAL_TO_LE_64(x) (x) +#endif + +// kilobytes and megabytes macro +#define MB(x) ((x)*1024*1024) +#define KB(x) ((x)*1024) + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define CPU_STR(c) ((c==ARM9)?"ARM9":"ARM7") +typedef enum +{ + ARM9 = 0, + ARM7 = 1 +} cpu_id_t; + +///endian-flips count bytes. count should be even and nonzero. +inline void FlipByteOrder(u8 *src, u32 count) +{ + u8 *start=src; + u8 *end=src+count-1; + + if((count&1) || !count) return; /* This shouldn't happen. */ + + while(count--) + { + u8 tmp; + + tmp=*end; + *end=*start; + *start=tmp; + end--; + start++; + } +} + + + +inline u64 double_to_u64(double d) { + union { + u64 a; + double b; + } fuxor; + fuxor.b = d; + return fuxor.a; +} + +inline double u64_to_double(u64 u) { + union { + u64 a; + double b; + } fuxor; + fuxor.a = u; + return fuxor.b; +} + +inline u32 float_to_u32(float f) { + union { + u32 a; + float b; + } fuxor; + fuxor.b = f; + return fuxor.a; +} + +inline float u32_to_float(u32 u) { + union { + u32 a; + float b; + } fuxor; + fuxor.a = u; + return fuxor.b; +} + + +///stores a 32bit value into the provided byte array in guaranteed little endian form +inline void en32lsb(u8 *buf, u32 morp) +{ + buf[0]=(u8)(morp); + buf[1]=(u8)(morp>>8); + buf[2]=(u8)(morp>>16); + buf[3]=(u8)(morp>>24); +} + +inline void en16lsb(u8* buf, u16 morp) +{ + buf[0]=(u8)morp; + buf[1]=(u8)(morp>>8); +} + +///unpacks a 64bit little endian value from the provided byte array into host byte order +inline u64 de64lsb(u8 *morp) +{ + return morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24)|((u64)morp[4]<<32)|((u64)morp[5]<<40)|((u64)morp[6]<<48)|((u64)morp[7]<<56); +} + +///unpacks a 32bit little endian value from the provided byte array into host byte order +inline u32 de32lsb(u8 *morp) +{ + return morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24); +} + +///unpacks a 16bit little endian value from the provided byte array into host byte order +inline u16 de16lsb(u8 *morp) +{ + return morp[0]|(morp[1]<<8); +} + +#ifndef ARRAY_SIZE +//taken from winnt.h +extern "C++" // templates cannot be declared to have 'C' linkage +template +char (*BLAHBLAHBLAH( UNALIGNED T (&)[N] ))[N]; + +#define ARRAY_SIZE(A) (sizeof(*BLAHBLAHBLAH(A))) +#endif + + +//fairly standard for loop macros +#define MACRODO1(TRICK,TODO) { const int X = TRICK; TODO; } +#define MACRODO2(X,TODO) { MACRODO1((X),TODO) MACRODO1(((X)+1),TODO) } +#define MACRODO4(X,TODO) { MACRODO2((X),TODO) MACRODO2(((X)+2),TODO) } +#define MACRODO8(X,TODO) { MACRODO4((X),TODO) MACRODO4(((X)+4),TODO) } +#define MACRODO16(X,TODO) { MACRODO8((X),TODO) MACRODO8(((X)+8),TODO) } +#define MACRODO32(X,TODO) { MACRODO16((X),TODO) MACRODO16(((X)+16),TODO) } +#define MACRODO64(X,TODO) { MACRODO32((X),TODO) MACRODO32(((X)+32),TODO) } +#define MACRODO128(X,TODO) { MACRODO64((X),TODO) MACRODO64(((X)+64),TODO) } +#define MACRODO256(X,TODO) { MACRODO128((X),TODO) MACRODO128(((X)+128),TODO) } + +//this one lets you loop any number of times (as long as N<256) +#define MACRODO_N(N,TODO) {\ + if((N)&0x100) MACRODO256(0,TODO); \ + if((N)&0x080) MACRODO128((N)&(0x100),TODO); \ + if((N)&0x040) MACRODO64((N)&(0x100|0x080),TODO); \ + if((N)&0x020) MACRODO32((N)&(0x100|0x080|0x040),TODO); \ + if((N)&0x010) MACRODO16((N)&(0x100|0x080|0x040|0x020),TODO); \ + if((N)&0x008) MACRODO8((N)&(0x100|0x080|0x040|0x020|0x010),TODO); \ + if((N)&0x004) MACRODO4((N)&(0x100|0x080|0x040|0x020|0x010|0x008),TODO); \ + if((N)&0x002) MACRODO2((N)&(0x100|0x080|0x040|0x020|0x010|0x008|0x004),TODO); \ + if((N)&0x001) MACRODO1((N)&(0x100|0x080|0x040|0x020|0x010|0x008|0x004|0x002),TODO); \ +} + +//--------------------------- +//Binary constant generator macro By Tom Torfs - donated to the public domain + +//turn a numeric literal into a hex constant +//(avoids problems with leading zeroes) +//8-bit constants max value 0x11111111, always fits in unsigned long +#define HEX__(n) 0x##n##LU + +//8-bit conversion function +#define B8__(x) ((x&0x0000000FLU)?1:0) \ ++((x&0x000000F0LU)?2:0) \ ++((x&0x00000F00LU)?4:0) \ ++((x&0x0000F000LU)?8:0) \ ++((x&0x000F0000LU)?16:0) \ ++((x&0x00F00000LU)?32:0) \ ++((x&0x0F000000LU)?64:0) \ ++((x&0xF0000000LU)?128:0) + +//for upto 8-bit binary constants +#define B8(d) ((unsigned char)B8__(HEX__(d))) + +// for upto 16-bit binary constants, MSB first +#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) \ ++ B8(dlsb)) + +// for upto 32-bit binary constants, MSB first */ +#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \ ++ ((unsigned long)B8(db2)<<16) \ ++ ((unsigned long)B8(db3)<<8) \ ++ B8(dlsb)) + +//Sample usage: +//B8(01010101) = 85 +//B16(10101010,01010101) = 43605 +//B32(10000000,11111111,10101010,01010101) = 2164238933 +//--------------------------- + +#ifndef CTASSERT +#define CTASSERT(x) typedef char __assert ## y[(x) ? 1 : -1] +#endif + +static const char hexValid[23] = {"0123456789ABCDEFabcdef"}; + + +template inline void reconstruct(T* t) { + t->~T(); + new(t) T(); +} + + +#endif diff --git a/source/fceultra/types.h b/source/fceultra/types.h index fca8d8f..498b317 100644 --- a/source/fceultra/types.h +++ b/source/fceultra/types.h @@ -22,6 +22,12 @@ #ifndef __FCEU_TYPES #define __FCEU_TYPES +//enables a hack designed for debugging dragon warrior 3 which treats BRK as a 3-byte opcode +//#define BRK_3BYTE_HACK + +//enables a hack designed for debugging dragon warrior 3 which treats 0F and 1F NL files both as 1F +//#define DW3_NL_0F_1F_HACK + ///causes the code fragment argument to be compiled in if the build includes debugging #ifdef FCEUDEF_DEBUGGER #define DEBUG(X) X; diff --git a/source/fceultra/unif.cpp b/source/fceultra/unif.cpp index 85416f4..7db121a 100644 --- a/source/fceultra/unif.cpp +++ b/source/fceultra/unif.cpp @@ -22,11 +22,6 @@ /* **INCOMPLETE** */ /* Override stuff: CHR RAM instead of CHR ROM, mirroring. */ -#include -#include -#include - - #include "types.h" #include "fceu.h" #include "cart.h" @@ -40,6 +35,10 @@ #include "input.h" #include "driver.h" +#include +#include +#include + typedef struct { char ID[4]; uint32 info; @@ -78,7 +77,7 @@ static uint8 *malloced[32]; static uint32 mallocedsizes[32]; static int FixRomSize(uint32 size, uint32 minimum) { - uint32 x = 1; //mbg merge 7/17/06 made uint + uint32 x = 1; if (size < minimum) return minimum; @@ -126,8 +125,9 @@ static void MooMirroring(void) { } static int DoMirroring(FCEUFILE *fp) { - uint8 t, i; - if(uchead.info == 1) { + int t; + uint32 i; + if (uchead.info == 1) { if ((t = FCEU_fgetc(fp)) == EOF) return(0); mirrortodo = t; @@ -138,7 +138,7 @@ static int DoMirroring(FCEUFILE *fp) { } } else { FCEU_printf(" Incorrect Mirroring Chunk Size (%d). Data is:", uchead.info); - for(i = 0; i < uchead.info; i++) { + for (i = 0; i < uchead.info; i++) { if ((t = FCEU_fgetc(fp)) == EOF) return(0); FCEU_printf(" %02x", t); @@ -196,15 +196,16 @@ static int DINF(FCEUFILE *fp) { char *months[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" - }; + }; FCEU_printf(" Dumped on: %s %d, %d\n", months[(m - 1) % 12], d, y); } return(1); } static int CTRL(FCEUFILE *fp) { - int t, i; - if(uchead.info == 1) { + int t; + uint32 i; + if (uchead.info == 1) { if ((t = FCEU_fgetc(fp)) == EOF) return(0); /* The information stored in this byte isn't very helpful, but it's @@ -219,7 +220,7 @@ static int CTRL(FCEUFILE *fp) { GameInfo->input[1] = SI_ZAPPER; } else { FCEU_printf(" Incorrect Control Chunk Size (%d). Data is:", uchead.info); - for(i = 0; i < uchead.info; i++) { + for (i = 0; i < uchead.info; i++) { t = FCEU_fgetc(fp); FCEU_printf(" %02x", t); } @@ -314,10 +315,11 @@ static int LoadCHR(FCEUFILE *fp) { return(1); } -#define BMCFLAG_FORCE4 1 -#define BMCFLAG_16KCHRR 2 -#define BMCFLAG_32KCHRR 4 -#define BMCFLAG_EXPCHRR 8 +#define BMCFLAG_FORCE4 0x01 +#define BMCFLAG_16KCHRR 0x02 +#define BMCFLAG_32KCHRR 0x04 +#define BMCFLAG_128KCHRR 0x08 +#define BMCFLAG_256KCHRR 0x10 static BMAPPING bmap[] = { { "11160", BMC11160_Init, 0 }, @@ -349,7 +351,7 @@ static BMAPPING bmap[] = { { "CNROM", CNROM_Init, 0 }, { "CPROM", CPROM_Init, BMCFLAG_16KCHRR }, { "D1038", BMCD1038_Init, 0 }, - { "DANCE", UNLOneBus_Init, 0 }, // redundant + { "DANCE", UNLOneBus_Init, 0 }, // redundant { "DANCE2000", UNLD2000_Init, 0 }, { "DREAMTECH01", DreamTech01_Init, 0 }, { "EDU2000", UNLEDU2000_Init, 0 }, @@ -357,8 +359,8 @@ static BMAPPING bmap[] = { { "ELROM", ELROM_Init, 0 }, { "ETROM", ETROM_Init, 0 }, { "EWROM", EWROM_Init, 0 }, - { "FK23C", BMCFK23C_Init, BMCFLAG_EXPCHRR }, - { "FK23CA", BMCFK23CA_Init, BMCFLAG_EXPCHRR }, + { "FK23C", BMCFK23C_Init, BMCFLAG_256KCHRR }, + { "FK23CA", BMCFK23CA_Init, BMCFLAG_256KCHRR }, { "FS304", UNLFS304_Init, 0 }, { "G-146", BMCG146_Init, 0 }, { "GK-192", BMCGK192_Init, 0 }, @@ -369,6 +371,7 @@ static BMAPPING bmap[] = { { "HKROM", HKROM_Init, 0 }, { "KOF97", UNLKOF97_Init, 0 }, { "KONAMI-QTAI", Mapper190_Init, 0 }, + { "KS7010", UNLKS7010_Init, 0 }, { "KS7012", UNLKS7012_Init, 0 }, { "KS7013B", UNLKS7013B_Init, 0 }, { "KS7017", UNLKS7017_Init, 0 }, @@ -381,6 +384,7 @@ static BMAPPING bmap[] = { { "LH10", LH10_Init, 0 }, { "LH32", LH32_Init, 0 }, { "LH53", LH53_Init, 0 }, + { "MALISB", UNLMaliSB_Init, 0 }, { "MARIO1-MALEE2", MALEE_Init, 0 }, { "MHROM", MHROM_Init, 0 }, { "N625092", UNLN625092_Init, 0 }, @@ -392,6 +396,7 @@ static BMAPPING bmap[] = { { "NovelDiamond9999999in1", Novel_Init, 0 }, { "OneBus", UNLOneBus_Init, 0 }, { "PEC-586", UNLPEC586Init, 0 }, + { "RET-CUFROM", Mapper29_Init, BMCFLAG_32KCHRR }, { "RROM", NROM_Init, 0 }, { "RROM-128", NROM_Init, 0 }, { "SA-002", TCU02_Init, 0 }, @@ -419,9 +424,9 @@ static BMAPPING bmap[] = { { "SNROM", SNROM_Init, 0 }, { "SOROM", SOROM_Init, 0 }, { "SSS-NROM-256", SSSNROM_Init, 0 }, - { "SUNSOFT_UNROM", SUNSOFT_UNROM_Init, 0 }, // fix me, real pcb name, real pcb type + { "SUNSOFT_UNROM", SUNSOFT_UNROM_Init, 0 }, // fix me, real pcb name, real pcb type { "Sachen-74LS374N", S74LS374N_Init, 0 }, - { "Sachen-74LS374NA", S74LS374NA_Init, 0 }, //seems to be custom mapper + { "Sachen-74LS374NA", S74LS374NA_Init, 0 }, //seems to be custom mapper { "Sachen-8259A", S8259A_Init, 0 }, { "Sachen-8259B", S8259B_Init, 0 }, { "Sachen-8259C", S8259C_Init, 0 }, @@ -449,9 +454,14 @@ static BMAPPING bmap[] = { { "TVROM", TLROM_Init, BMCFLAG_FORCE4 }, { "Transformer", Transformer_Init, 0 }, { "UNROM", UNROM_Init, 0 }, + { "UNROM-512-8", UNROM512_Init, 0 }, + { "UNROM-512-16", UNROM512_Init, BMCFLAG_16KCHRR }, + { "UNROM-512-32", UNROM512_Init, BMCFLAG_32KCHRR }, { "UOROM", UNROM_Init, 0 }, { "VRC7", UNLVRC7_Init, 0 }, { "YOKO", UNLYOKO_Init, 0 }, + { "SB-2000", UNLSB2000_Init, 0 }, + { "COOLBOY", COOLBOY_Init, BMCFLAG_256KCHRR }, { 0, 0, 0 } }; @@ -507,13 +517,16 @@ static int InitializeBoard(void) { if (!strcmp((char*)sboardname, (char*)bmap[x].name)) { if (!malloced[16]) { if (bmap[x].flags & BMCFLAG_16KCHRR) - CHRRAMSize = 16384; + CHRRAMSize = 16; else if (bmap[x].flags & BMCFLAG_32KCHRR) - CHRRAMSize = 32768; - else if (bmap[x].flags & BMCFLAG_EXPCHRR) - CHRRAMSize = 128 * 1024; + CHRRAMSize = 32; + else if (bmap[x].flags & BMCFLAG_128KCHRR) + CHRRAMSize = 128; + else if (bmap[x].flags & BMCFLAG_256KCHRR) + CHRRAMSize = 256; else - CHRRAMSize = 8192; + CHRRAMSize = 8; + CHRRAMSize <<= 10; if ((UNIFchrrama = (uint8*)FCEU_malloc(CHRRAMSize))) { SetupCartCHRMapping(0, UNIFchrrama, CHRRAMSize, 1); AddExState(UNIFchrrama, CHRRAMSize, 0, "CHRR"); diff --git a/source/fceultra/unif.h b/source/fceultra/unif.h index b11c99b..0216c65 100644 --- a/source/fceultra/unif.h +++ b/source/fceultra/unif.h @@ -129,6 +129,7 @@ void UNLKS7032_Init(CartInfo *info); void UNLKS7037_Init(CartInfo *info); void UNLKS7057_Init(CartInfo *info); void UNLN625092_Init(CartInfo *info); +void UNLMaliSB_Init(CartInfo *info); void UNLOneBus_Init(CartInfo *info); void UNLPEC586Init(CartInfo *info); void UNLSC127_Init(CartInfo *info); @@ -141,6 +142,10 @@ void UNLTF1201_Init(CartInfo *info); void UNLVRC7_Init(CartInfo *info); void UNLYOKO_Init(CartInfo *info); void UNROM_Init(CartInfo *info); +void UNROM512_Init(CartInfo *info); +void UNLSB2000_Init(CartInfo *info); +void UNLKS7010_Init(CartInfo *info); +void COOLBOY_Init(CartInfo *info); extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM // bank switcherooing with certain boards... diff --git a/source/fceultra/utils/SConscript b/source/fceultra/utils/SConscript new file mode 100644 index 0000000..bc9d9da --- /dev/null +++ b/source/fceultra/utils/SConscript @@ -0,0 +1,25 @@ +import glob +#source_list = glob.glob('*.cpp') +source_list = Split( +""" +backward.cpp +ConvertUTF.c +xstring.cpp +crc32.cpp +endian.cpp +general.cpp +guid.cpp +md5.cpp +memory.cpp +""") + +Import('env') + + +if env['SYSTEM_MINIZIP'] == 0: + source_list.append('unzip.cpp') + source_list.append('ioapi.cpp') + +for x in range(len(source_list)): + source_list[x] = 'utils/' + source_list[x] +Return('source_list') diff --git a/source/fceultra/utils/backward.cpp b/source/fceultra/utils/backward.cpp new file mode 100644 index 0000000..7f8e776 --- /dev/null +++ b/source/fceultra/utils/backward.cpp @@ -0,0 +1,33 @@ +// Pick your poison. +// +// On GNU/Linux, you have few choices to get the most out of your stack trace. +// +// By default you get: +// - object filename +// - function name +// +// In order to add: +// - source filename +// - line and column numbers +// - source code snippet (assuming the file is accessible) + +// Install one of the following library then uncomment one of the macro (or +// better, add the detection of the lib and the macro definition in your build +// system) + +// - apt-get install libdw-dev ... +// - g++/clang++ -ldw ... +// #define BACKWARD_HAS_DW 1 + +// - apt-get install binutils-dev ... +// - g++/clang++ -lbfd ... +// #define BACKWARD_HAS_BFD 1 +#if BACKWARD_HAS_DW==1 +#include "backward.hpp" + +namespace backward { + +backward::SignalHandling sh; + +} // namespace backward +#endif diff --git a/source/fceultra/utils/backward.hpp b/source/fceultra/utils/backward.hpp new file mode 100644 index 0000000..80a2330 --- /dev/null +++ b/source/fceultra/utils/backward.hpp @@ -0,0 +1,2196 @@ +/* + * backward.hpp + * Copyright 2013 Google Inc. All Rights Reserved. + * + * 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. + */ + +#ifndef H_6B9572DA_A64B_49E6_B234_051480991C89 +#define H_6B9572DA_A64B_49E6_B234_051480991C89 + +#ifndef __cplusplus +# error "It's not going to compile without a C++ compiler..." +#endif + +#if defined(BACKWARD_CXX11) +#elif defined(BACKWARD_CXX98) +#else +# if __cplusplus >= 201103L +# define BACKWARD_CXX11 +# else +# define BACKWARD_CXX98 +# endif +#endif + +// You can define one of the following (or leave it to the auto-detection): +// +// #define BACKWARD_SYSTEM_LINUX +// - specialization for linux +// +// #define BACKWARD_SYSTEM_UNKNOWN +// - placebo implementation, does nothing. +// +#if defined(BACKWARD_SYSTEM_LINUX) +#elif defined(BACKWARD_SYSTEM_UNKNOWN) +#else +# if defined(__linux) +# define BACKWARD_SYSTEM_LINUX +# else +# define BACKWARD_SYSTEM_UNKNOWN +# endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BACKWARD_SYSTEM_LINUX) + +// On linux, backtrace can back-trace or "walk" the stack using the following +// library: +// +// #define BACKWARD_HAS_UNWIND 1 +// - unwind comes from libgcc, but I saw an equivalent inside clang itself. +// - with unwind, the stacktrace is as accurate as it can possibly be, since +// this is used by the C++ runtine in gcc/clang for stack unwinding on +// exception. +// - normally libgcc is already linked to your program by default. +// +// #define BACKWARD_HAS_BACKTRACE == 1 +// - backtrace seems to be a little bit more portable than libunwind, but on +// linux, it uses unwind anyway, but abstract away a tiny information that is +// sadly really important in order to get perfectly accurate stack traces. +// - backtrace is part of the (e)glib library. +// +// The default is: +// #define BACKWARD_HAS_UNWIND == 1 +// +# if BACKWARD_HAS_UNWIND == 1 +# elif BACKWARD_HAS_BACKTRACE == 1 +# else +# undef BACKWARD_HAS_UNWIND +# define BACKWARD_HAS_UNWIND 1 +# undef BACKWARD_HAS_BACKTRACE +# define BACKWARD_HAS_BACKTRACE 0 +# endif + +// On linux, backward can extract detailed information about a stack trace +// using one of the following library: +// +// #define BACKWARD_HAS_DW 1 +// - libdw gives you the most juicy details out of your stack traces: +// - object filename +// - function name +// - source filename +// - line and column numbers +// - source code snippet (assuming the file is accessible) +// - variables name and values (if not optimized out) +// - You need to link with the lib "dw": +// - apt-get install libdw-dev +// - g++/clang++ -ldw ... +// +// #define BACKWARD_HAS_BFD 1 +// - With libbfd, you get a fair about of details: +// - object filename +// - function name +// - source filename +// - line numbers +// - source code snippet (assuming the file is accessible) +// - You need to link with the lib "bfd": +// - apt-get install binutils-dev +// - g++/clang++ -lbfd ... +// +// #define BACKWARD_HAS_BACKTRACE_SYMBOL 1 +// - backtrace provides minimal details for a stack trace: +// - object filename +// - function name +// - backtrace is part of the (e)glib library. +// +// The default is: +// #define BACKWARD_HAS_BACKTRACE_SYMBOL == 1 +// +# if BACKWARD_HAS_DW == 1 +# elif BACKWARD_HAS_BFD == 1 +# elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1 +# else +# undef BACKWARD_HAS_DW +# define BACKWARD_HAS_DW 0 +# undef BACKWARD_HAS_BFD +# define BACKWARD_HAS_BFD 0 +# undef BACKWARD_HAS_BACKTRACE_SYMBOL +# define BACKWARD_HAS_BACKTRACE_SYMBOL 1 +# endif + + +# if BACKWARD_HAS_UNWIND == 1 + +# include +// while gcc's unwind.h defines something like that: +// extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *); +// extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *); +// +// clang's unwind.h defines something like this: +// uintptr_t _Unwind_GetIP(struct _Unwind_Context* __context); +// +// Even if the _Unwind_GetIPInfo can be linked to, it is not declared, worse we +// cannot just redeclare it because clang's unwind.h doesn't define _Unwind_Ptr +// anyway. +// +// Luckily we can play on the fact that the guard macros have a different name: +#ifdef __CLANG_UNWIND_H +// In fact, this function still comes from libgcc (on my different linux boxes, +// clang links against libgcc). +# include +extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*); +#endif + +# endif + +# include +# include +# include +# include +# include +# include +# include + +# if BACKWARD_HAS_BFD == 1 +# include +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# include +# undef _GNU_SOURCE +# else +# include +# endif +# endif + +# if BACKWARD_HAS_DW == 1 +# include +# include +# include +# endif + +# if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1) + // then we shall rely on backtrace +# include +# endif + +#endif // defined(BACKWARD_SYSTEM_LINUX) + +#if defined(BACKWARD_CXX11) +# include +# include // for std::swap + namespace backward { + namespace details { + template + struct hashtable { + typedef std::unordered_map type; + }; + using std::move; + } // namespace details + } // namespace backward +#elif defined(BACKWARD_CXX98) +# include + namespace backward { + namespace details { + template + struct hashtable { + typedef std::map type; + }; + template + const T& move(const T& v) { return v; } + template + T& move(T& v) { return v; } + } // namespace details + } // namespace backward +#else +# error "Mmm if its not C++11 nor C++98... go play in the toaster." +#endif + +namespace backward { + +namespace system_tag { + struct linux_tag; // seems that I cannot call that "linux" because the name + // is already defined... so I am adding _tag everywhere. + struct unknown_tag; + +#if defined(BACKWARD_SYSTEM_LINUX) + typedef linux_tag current_tag; +#elif defined(BACKWARD_SYSTEM_UNKNOWN) + typedef unknown_tag current_tag; +#else +# error "May I please get my system defines?" +#endif +} // namespace system_tag + + +namespace stacktrace_tag { +#ifdef BACKWARD_SYSTEM_LINUX + struct unwind; + struct backtrace; + +# if BACKWARD_HAS_UNWIND == 1 + typedef unwind currnet; +# elif BACKWARD_HAS_BACKTRACE == 1 + typedef backtrace current; +# else +# error "I know it's difficult but you need to make a choice!" +# endif +#endif // BACKWARD_SYSTEM_LINUX +} // namespace stacktrace_tag + + +namespace trace_resolver_tag { +#ifdef BACKWARD_SYSTEM_LINUX + struct libdw; + struct libbfd; + struct backtrace_symbol; + +# if BACKWARD_HAS_DW == 1 + typedef libdw current; +# elif BACKWARD_HAS_BFD == 1 + typedef libbfd current; +# elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1 + typedef backtrace_symbol current; +# else +# error "You shall not pass, until you know what you want." +# endif +#endif // BACKWARD_SYSTEM_LINUX +} // namespace trace_resolver_tag + +namespace details { + +template + struct rm_ptr { typedef T type; }; + +template + struct rm_ptr { typedef T type; }; + +template + struct rm_ptr { typedef const T type; }; + +template +struct deleter { + template + void operator()(U& ptr) const { + (*F)(ptr); + } +}; + +template +struct default_delete { + void operator()(T& ptr) const { + delete ptr; + } +}; + +template > +class handle { + struct dummy; + T _val; + bool _empty; + +#if defined(BACKWARD_CXX11) + handle(const handle&) = delete; + handle& operator=(const handle&) = delete; +#endif + +public: + ~handle() { + if (not _empty) { + Deleter()(_val); + } + } + + explicit handle(): _val(), _empty(true) {} + explicit handle(T val): _val(val), _empty(false) {} + +#if defined(BACKWARD_CXX11) + handle(handle&& from): _empty(true) { + swap(from); + } + handle& operator=(handle&& from) { + swap(from); return *this; + } +#else + explicit handle(const handle& from): _empty(true) { + // some sort of poor man's move semantic. + swap(const_cast(from)); + } + handle& operator=(const handle& from) { + // some sort of poor man's move semantic. + swap(const_cast(from)); return *this; + } +#endif + + void reset(T new_val) { + handle tmp(new_val); + swap(tmp); + } + operator const dummy*() const { + if (_empty) { + return 0; + } + return reinterpret_cast(_val); + } + T get() { + return _val; + } + T release() { + _empty = true; + return _val; + } + void swap(handle& b) { + using std::swap; + swap(b._val, _val); // can throw, we are safe here. + swap(b._empty, _empty); // should not throw: if you cannot swap two + // bools without throwing... It's a lost cause anyway! + } + + T operator->() { return _val; } + const T operator->() const { return _val; } + + typedef typename rm_ptr::type& ref_t; + ref_t operator*() { return *_val; } + const ref_t operator*() const { return *_val; } + ref_t operator[](size_t idx) { return _val[idx]; } + + // Watch out, we've got a badass over here + T* operator&() { + _empty = false; + return &_val; + } +}; + +} // namespace details + +/*************** A TRACE ***************/ + +struct Trace { + void* addr; + unsigned idx; + + Trace(): + addr(0), idx(0) {} + + explicit Trace(void* addr, size_t idx): + addr(addr), idx(idx) {} +}; + +// Really simple, generic, and dumb representation of a variable. +// A variable has a name and can represent either: +// - a value (as a string) +// - a list of values (a list of strings) +// - a map of values (a list of variable) +class Variable { +public: + enum Kind { VALUE, LIST, MAP }; + + typedef std::vector list_t; + typedef std::vector map_t; + + std::string name; + Kind kind; + + Variable(Kind k): kind(k) { + switch (k) { + case VALUE: + new (&storage) std::string(); + break; + + case LIST: + new (&storage) list_t(); + break; + + case MAP: + new (&storage) map_t(); + break; + } + } + + std::string& value() { + return reinterpret_cast(storage); + } + list_t& list() { + return reinterpret_cast(storage); + } + map_t& map() { + return reinterpret_cast(storage); + } + + + const std::string& value() const { + return reinterpret_cast(storage); + } + const list_t& list() const { + return reinterpret_cast(storage); + } + const map_t& map() const { + return reinterpret_cast(storage); + } + +private: + // the C++98 style union for non-trivial objects, yes yes I know, its not + // aligned as good as it can be, blabla... Screw this. + union { + char s1[sizeof (std::string)]; + char s2[sizeof (list_t)]; + char s3[sizeof (map_t)]; + } storage; +}; + +struct TraceWithLocals: public Trace { + // Locals variable and values. + std::vector locals; + + TraceWithLocals(): Trace() {} + TraceWithLocals(const Trace& mini_trace): + Trace(mini_trace) {} +}; + +struct ResolvedTrace: public TraceWithLocals { + + struct SourceLoc { + std::string function; + std::string filename; + unsigned line; + unsigned col; + + SourceLoc(): line(0), col(0) {} + + bool operator==(const SourceLoc& b) const { + return function == b.function + and filename == b.filename + and line == b.line + and col == b.col; + } + + bool operator!=(const SourceLoc& b) const { + return not (*this == b); + } + }; + + // In which binary object this trace is located. + std::string object_filename; + + // The function in the object that contain the trace. This is not the same + // as source.function which can be an function inlined in object_function. + std::string object_function; + + // The source location of this trace. It is possible for filename to be + // empty and for line/col to be invalid (value 0) if this information + // couldn't be deduced, for example if there is no debug information in the + // binary object. + SourceLoc source; + + // An optionals list of "inliners". All the successive sources location + // from where the source location of the trace (the attribute right above) + // is inlined. It is especially useful when you compiled with optimization. + typedef std::vector source_locs_t; + source_locs_t inliners; + + ResolvedTrace(const Trace& mini_trace): + TraceWithLocals(mini_trace) {} + ResolvedTrace(const TraceWithLocals& mini_trace_with_locals): + TraceWithLocals(mini_trace_with_locals) {} +}; + +/*************** STACK TRACE ***************/ + +// default implemention. +template +class StackTraceImpl { +public: + size_t size() const { return 0; } + Trace operator[](size_t) { return Trace(); } + size_t load_here(size_t=0) { return 0; } + size_t load_from(void*, size_t=0) { return 0; } + unsigned thread_id() const { return 0; } +}; + +#ifdef BACKWARD_SYSTEM_LINUX + +class StackTraceLinuxImplBase { +public: + StackTraceLinuxImplBase(): _thread_id(0), _skip(0) {} + + unsigned thread_id() const { + return _thread_id; + } + +protected: + void load_thread_info() { + _thread_id = syscall(SYS_gettid); + if (_thread_id == (size_t) getpid()) { + // If the thread is the main one, let's hide that. + // I like to keep little secret sometimes. + _thread_id = 0; + } + } + + void skip_n_firsts(size_t n) { _skip = n; } + size_t skip_n_firsts() const { return _skip; } + +private: + size_t _thread_id; + size_t _skip; +}; + +class StackTraceLinuxImplHolder: public StackTraceLinuxImplBase { +public: + size_t size() const { + return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0; + } + Trace operator[](size_t idx) { + if (idx >= size()) { + return Trace(); + } + return Trace(_stacktrace[idx + skip_n_firsts()], idx); + } + void** begin() { + if (size()) { + return &_stacktrace[skip_n_firsts()]; + } + return 0; + } + +protected: + std::vector _stacktrace; +}; + + +#if BACKWARD_HAS_UNWIND == 1 + +namespace details { + +template +class Unwinder { +public: + size_t operator()(F& f, size_t depth) { + _f = &f; + _index = -1; + _depth = depth; + _Unwind_Backtrace(&this->backtrace_trampoline, this); + return _index; + } + +private: + F* _f; + ssize_t _index; + size_t _depth; + + static _Unwind_Reason_Code backtrace_trampoline( + _Unwind_Context* ctx, void *self) { + return ((Unwinder*)self)->backtrace(ctx); + } + + _Unwind_Reason_Code backtrace(_Unwind_Context* ctx) { + if (_index >= 0 and static_cast(_index) >= _depth) + return _URC_END_OF_STACK; + + int ip_before_instruction = 0; + uintptr_t ip = _Unwind_GetIPInfo(ctx, &ip_before_instruction); + + if (not ip_before_instruction) { + ip -= 1; + } + + if (_index >= 0) { // ignore first frame. + (*_f)(_index, (void*)ip); + } + _index += 1; + return _URC_NO_REASON; + } +}; + +template +size_t unwind(F f, size_t depth) { + Unwinder unwinder; + return unwinder(f, depth); +} + +} // namespace details + + +template <> +class StackTraceImpl: public StackTraceLinuxImplHolder { +public: + __attribute__ ((noinline)) // TODO use some macro + size_t load_here(size_t depth=32) { + load_thread_info(); + if (depth == 0) { + return 0; + } + _stacktrace.resize(depth); + size_t trace_cnt = details::unwind(callback(*this), depth); + _stacktrace.resize(trace_cnt); + skip_n_firsts(0); + return size(); + } + size_t load_from(void* addr, size_t depth=32) { + load_here(depth + 8); + + for (size_t i = 0; i < _stacktrace.size(); ++i) { + if (_stacktrace[i] == addr) { + skip_n_firsts(i); + break; + } + } + + _stacktrace.resize(std::min(_stacktrace.size(), + skip_n_firsts() + depth)); + return size(); + } + +private: + struct callback { + StackTraceImpl& self; + callback(StackTraceImpl& self): self(self) {} + + void operator()(size_t idx, void* addr) { + self._stacktrace[idx] = addr; + } + }; +}; + + +#else // BACKWARD_HAS_UNWIND == 0 + +template <> +class StackTraceImpl: public StackTraceLinuxImplHolder { +public: + __attribute__ ((noinline)) // TODO use some macro + size_t load_here(size_t depth=32) { + load_thread_info(); + if (depth == 0) { + return 0; + } + _stacktrace.resize(depth + 1); + size_t trace_cnt = backtrace(&_stacktrace[0], _stacktrace.size()); + _stacktrace.resize(trace_cnt); + skip_n_firsts(1); + return size(); + } + + size_t load_from(void* addr, size_t depth=32) { + load_here(depth + 8); + + for (size_t i = 0; i < _stacktrace.size(); ++i) { + if (_stacktrace[i] == addr) { + skip_n_firsts(i); + _stacktrace[i] = (void*)( (uintptr_t)_stacktrace[i] + 1); + break; + } + } + + _stacktrace.resize(std::min(_stacktrace.size(), + skip_n_firsts() + depth)); + return size(); + } +}; + +#endif // BACKWARD_HAS_UNWIND +#endif // BACKWARD_SYSTEM_LINUX + +class StackTrace: + public StackTraceImpl {}; + +/*********** STACKTRACE WITH LOCALS ***********/ + +// default implemention. +template +class StackTraceWithLocalsImpl: + public StackTrace {}; + +#ifdef BACKWARD_SYSTEM_LINUX +#if BACKWARD_HAS_UNWIND +#if BACKWARD_HAS_DW + +template <> +class StackTraceWithLocalsImpl: + public StackTraceLinuxImplBase { +public: + __attribute__ ((noinline)) // TODO use some macro + size_t load_here(size_t depth=32) { + load_thread_info(); + if (depth == 0) { + return 0; + } + _stacktrace.resize(depth); + size_t trace_cnt = details::unwind(callback(*this), depth); + _stacktrace.resize(trace_cnt); + skip_n_firsts(0); + return size(); + } + size_t load_from(void* addr, size_t depth=32) { + load_here(depth + 8); + + for (size_t i = 0; i < _stacktrace.size(); ++i) { + if (_stacktrace[i].addr == addr) { + skip_n_firsts(i); + break; + } + } + _stacktrace.resize(std::min(_stacktrace.size(), + skip_n_firsts() + depth)); + return size(); + } + size_t size() const { + return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0; + } + const TraceWithLocals& operator[](size_t idx) { + if (idx >= size()) { + return _nil_trace; + } + return _stacktrace[idx + skip_n_firsts()]; + } + +private: + std::vector _stacktrace; + TraceWithLocals _nil_trace; + + void resolve_trace(TraceWithLocals& trace) { + Variable v(Variable::VALUE); + v.name = "var"; + v.value() = "42"; + trace.locals.push_back(v); + } + + struct callback { + StackTraceWithLocalsImpl& self; + callback(StackTraceWithLocalsImpl& self): self(self) {} + + void operator()(size_t idx, void* addr) { + self._stacktrace[idx].addr = addr; + self.resolve_trace(self._stacktrace[idx]); + } + }; +}; + +#endif // BACKWARD_HAS_DW +#endif // BACKWARD_HAS_UNWIND +#endif // BACKWARD_SYSTEM_LINUX + +class StackTraceWithLocals: + public StackTraceWithLocalsImpl {}; + +/*************** TRACE RESOLVER ***************/ + +template +class TraceResolverImpl; + +#ifdef BACKWARD_SYSTEM_UNKNOWN + +template <> +class TraceResolverImpl { +public: + template + void load_stacktrace(ST&) {} + ResolvedTrace resolve(ResolvedTrace t) { + return t; + } +}; + +#endif + +#ifdef BACKWARD_SYSTEM_LINUX + +class TraceResolverLinuxImplBase { +protected: + std::string demangle(const char* funcname) { + using namespace details; + _demangle_buffer.reset( + abi::__cxa_demangle(funcname, _demangle_buffer.release(), + &_demangle_buffer_length, 0) + ); + if (_demangle_buffer) { + return _demangle_buffer.get(); + } + return funcname; + } + +private: + details::handle _demangle_buffer; + size_t _demangle_buffer_length; +}; + +template +class TraceResolverLinuxImpl; + +#if BACKWARD_HAS_BACKTRACE_SYMBOL == 1 + +template <> +class TraceResolverLinuxImpl: + public TraceResolverLinuxImplBase { +public: + template + void load_stacktrace(ST& st) { + using namespace details; + if (st.size() == 0) { + return; + } + _symbols.reset( + backtrace_symbols(st.begin(), st.size()) + ); + } + + ResolvedTrace resolve(ResolvedTrace trace) { + char* filename = _symbols[trace.idx]; + char* funcname = filename; + while (*funcname && *funcname != '(') { + funcname += 1; + } + trace.object_filename.assign(filename, funcname++); + char* funcname_end = funcname; + while (*funcname_end && *funcname_end != ')' && *funcname_end != '+') { + funcname_end += 1; + } + *funcname_end = '\0'; + trace.object_function = this->demangle(funcname); + trace.source.function = trace.object_function; // we cannot do better. + return trace; + } + +private: + details::handle _symbols; +}; + +#endif // BACKWARD_HAS_BACKTRACE_SYMBOL == 1 + +#if BACKWARD_HAS_BFD == 1 + +template <> +class TraceResolverLinuxImpl: + public TraceResolverLinuxImplBase { +public: + TraceResolverLinuxImpl(): _bfd_loaded(false) {} + + template + void load_stacktrace(ST&) {} + + ResolvedTrace resolve(ResolvedTrace trace) { + Dl_info symbol_info; + + // trace.addr is a virtual address in memory pointing to some code. + // Let's try to find from which loaded object it comes from. + // The loaded object can be yourself btw. + if (not dladdr(trace.addr, &symbol_info)) { + return trace; // dat broken trace... + } + + // Now we get in symbol_info: + // .dli_fname: + // pathname of the shared object that contains the address. + // .dli_fbase: + // where the object is loaded in memory. + // .dli_sname: + // the name of the nearest symbol to trace.addr, we expect a + // function name. + // .dli_saddr: + // the exact address corresponding to .dli_sname. + + if (symbol_info.dli_sname) { + trace.object_function = demangle(symbol_info.dli_sname); + } + + if (not symbol_info.dli_fname) { + return trace; + } + + trace.object_filename = symbol_info.dli_fname; + bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname); + if (not fobj.handle) { + return trace; // sad, we couldn't load the object :( + } + + + find_sym_result* details_selected; // to be filled. + + // trace.addr is the next instruction to be executed after returning + // from the nested stack frame. In C++ this usually relate to the next + // statement right after the function call that leaded to a new stack + // frame. This is not usually what you want to see when printing out a + // stacktrace... + find_sym_result details_call_site = find_symbol_details(fobj, + trace.addr, symbol_info.dli_fbase); + details_selected = &details_call_site; + +#if BACKWARD_HAS_UNWIND == 0 + // ...this is why we also try to resolve the symbol that is right + // before the return address. If we are lucky enough, we will get the + // line of the function that was called. But if the code is optimized, + // we might get something absolutely not related since the compiler + // can reschedule the return address with inline functions and + // tail-call optimisation (among other things that I don't even know + // or cannot even dream about with my tiny limited brain). + find_sym_result details_adjusted_call_site = find_symbol_details(fobj, + (void*) (uintptr_t(trace.addr) - 1), + symbol_info.dli_fbase); + + // In debug mode, we should always get the right thing(TM). + if (details_call_site.found and details_adjusted_call_site.found) { + // Ok, we assume that details_adjusted_call_site is a better estimation. + details_selected = &details_adjusted_call_site; + trace.addr = (void*) (uintptr_t(trace.addr) - 1); + } + + if (details_selected == &details_call_site and details_call_site.found) { + // we have to re-resolve the symbol in order to reset some + // internal state in BFD... so we can call backtrace_inliners + // thereafter... + details_call_site = find_symbol_details(fobj, trace.addr, + symbol_info.dli_fbase); + } +#endif // BACKWARD_HAS_UNWIND + + if (details_selected->found) { + if (details_selected->filename) { + trace.source.filename = details_selected->filename; + } + trace.source.line = details_selected->line; + + if (details_selected->funcname) { + // this time we get the name of the function where the code is + // located, instead of the function were the address is + // located. In short, if the code was inlined, we get the + // function correspoding to the code. Else we already got in + // trace.function. + trace.source.function = demangle(details_selected->funcname); + + if (not symbol_info.dli_sname) { + // for the case dladdr failed to find the symbol name of + // the function, we might as well try to put something + // here. + trace.object_function = trace.source.function; + } + } + + // Maybe the source of the trace got inlined inside the function + // (trace.source.function). Let's see if we can get all the inlined + // calls along the way up to the initial call site. + trace.inliners = backtrace_inliners(fobj, *details_selected); + +#if 0 + if (trace.inliners.size() == 0) { + // Maybe the trace was not inlined... or maybe it was and we + // are lacking the debug information. Let's try to make the + // world better and see if we can get the line number of the + // function (trace.source.function) now. + // + // We will get the location of where the function start (to be + // exact: the first instruction that really start the + // function), not where the name of the function is defined. + // This can be quite far away from the name of the function + // btw. + // + // If the source of the function is the same as the source of + // the trace, we cannot say if the trace was really inlined or + // not. However, if the filename of the source is different + // between the function and the trace... we can declare it as + // an inliner. This is not 100% accurate, but better than + // nothing. + + if (symbol_info.dli_saddr) { + find_sym_result details = find_symbol_details(fobj, + symbol_info.dli_saddr, + symbol_info.dli_fbase); + + if (details.found) { + ResolvedTrace::SourceLoc diy_inliner; + diy_inliner.line = details.line; + if (details.filename) { + diy_inliner.filename = details.filename; + } + if (details.funcname) { + diy_inliner.function = demangle(details.funcname); + } else { + diy_inliner.function = trace.source.function; + } + if (diy_inliner != trace.source) { + trace.inliners.push_back(diy_inliner); + } + } + } + } +#endif + } + + return trace; + } + +private: + bool _bfd_loaded; + + typedef details::handle + > bfd_handle_t; + + typedef details::handle bfd_symtab_t; + + + struct bfd_fileobject { + bfd_handle_t handle; + bfd_vma base_addr; + bfd_symtab_t symtab; + bfd_symtab_t dynamic_symtab; + }; + + typedef details::hashtable::type + fobj_bfd_map_t; + fobj_bfd_map_t _fobj_bfd_map; + + bfd_fileobject& load_object_with_bfd(const std::string& filename_object) { + using namespace details; + + if (not _bfd_loaded) { + using namespace details; + bfd_init(); + _bfd_loaded = true; + } + + fobj_bfd_map_t::iterator it = + _fobj_bfd_map.find(filename_object); + if (it != _fobj_bfd_map.end()) { + return it->second; + } + + // this new object is empty for now. + bfd_fileobject& r = _fobj_bfd_map[filename_object]; + + // we do the work temporary in this one; + bfd_handle_t bfd_handle; + + int fd = open(filename_object.c_str(), O_RDONLY); + bfd_handle.reset( + bfd_fdopenr(filename_object.c_str(), "default", fd) + ); + if (not bfd_handle) { + close(fd); + return r; + } + + if (not bfd_check_format(bfd_handle.get(), bfd_object)) { + return r; // not an object? You lose. + } + + if ((bfd_get_file_flags(bfd_handle.get()) & HAS_SYMS) == 0) { + return r; // that's what happen when you forget to compile in debug. + } + + ssize_t symtab_storage_size = + bfd_get_symtab_upper_bound(bfd_handle.get()); + + ssize_t dyn_symtab_storage_size = + bfd_get_dynamic_symtab_upper_bound(bfd_handle.get()); + + if (symtab_storage_size <= 0 and dyn_symtab_storage_size <= 0) { + return r; // weird, is the file is corrupted? + } + + bfd_symtab_t symtab, dynamic_symtab; + ssize_t symcount = 0, dyn_symcount = 0; + + if (symtab_storage_size > 0) { + symtab.reset( + (bfd_symbol**) malloc(symtab_storage_size) + ); + symcount = bfd_canonicalize_symtab( + bfd_handle.get(), symtab.get() + ); + } + + if (dyn_symtab_storage_size > 0) { + dynamic_symtab.reset( + (bfd_symbol**) malloc(dyn_symtab_storage_size) + ); + dyn_symcount = bfd_canonicalize_dynamic_symtab( + bfd_handle.get(), dynamic_symtab.get() + ); + } + + + if (symcount <= 0 and dyn_symcount <= 0) { + return r; // damned, that's a stripped file that you got there! + } + + r.handle = move(bfd_handle); + r.symtab = move(symtab); + r.dynamic_symtab = move(dynamic_symtab); + return r; + } + + struct find_sym_result { + bool found; + const char* filename; + const char* funcname; + unsigned int line; + }; + + struct find_sym_context { + TraceResolverLinuxImpl* self; + bfd_fileobject* fobj; + void* addr; + void* base_addr; + find_sym_result result; + }; + + find_sym_result find_symbol_details(bfd_fileobject& fobj, void* addr, + void* base_addr) { + find_sym_context context; + context.self = this; + context.fobj = &fobj; + context.addr = addr; + context.base_addr = base_addr; + context.result.found = false; + bfd_map_over_sections(fobj.handle.get(), &find_in_section_trampoline, + (void*)&context); + return context.result; + } + + static void find_in_section_trampoline(bfd*, asection* section, + void* data) { + find_sym_context* context = static_cast(data); + context->self->find_in_section( + reinterpret_cast(context->addr), + reinterpret_cast(context->base_addr), + *context->fobj, + section, context->result + ); + } + + void find_in_section(bfd_vma addr, bfd_vma base_addr, + bfd_fileobject& fobj, asection* section, find_sym_result& result) + { + if (result.found) return; + + if ((bfd_get_section_flags(fobj.handle.get(), section) + & SEC_ALLOC) == 0) + return; // a debug section is never loaded automatically. + + bfd_vma sec_addr = bfd_get_section_vma(fobj.handle.get(), section); + bfd_size_type size = bfd_get_section_size(section); + + // are we in the boundaries of the section? + if (addr < sec_addr or addr >= sec_addr + size) { + addr -= base_addr; // oups, a relocated object, lets try again... + if (addr < sec_addr or addr >= sec_addr + size) { + return; + } + } + + if (not result.found and fobj.symtab) { + result.found = bfd_find_nearest_line(fobj.handle.get(), section, + fobj.symtab.get(), addr - sec_addr, &result.filename, + &result.funcname, &result.line); + } + + if (not result.found and fobj.dynamic_symtab) { + result.found = bfd_find_nearest_line(fobj.handle.get(), section, + fobj.dynamic_symtab.get(), addr - sec_addr, + &result.filename, &result.funcname, &result.line); + } + + } + + ResolvedTrace::source_locs_t backtrace_inliners(bfd_fileobject& fobj, + find_sym_result previous_result) { + // This function can be called ONLY after a SUCCESSFUL call to + // find_symbol_details. The state is global to the bfd_handle. + ResolvedTrace::source_locs_t results; + while (previous_result.found) { + find_sym_result result; + result.found = bfd_find_inliner_info(fobj.handle.get(), + &result.filename, &result.funcname, &result.line); + + if (result.found) /* and not ( + cstrings_eq(previous_result.filename, result.filename) + and cstrings_eq(previous_result.funcname, result.funcname) + and result.line == previous_result.line + )) */ { + ResolvedTrace::SourceLoc src_loc; + src_loc.line = result.line; + if (result.filename) { + src_loc.filename = result.filename; + } + if (result.funcname) { + src_loc.function = demangle(result.funcname); + } + results.push_back(src_loc); + } + previous_result = result; + } + return results; + } + + bool cstrings_eq(const char* a, const char* b) { + if (not a or not b) { + return false; + } + return strcmp(a, b) == 0; + } + +}; +#endif // BACKWARD_HAS_BFD == 1 + +#if BACKWARD_HAS_DW == 1 + +template <> +class TraceResolverLinuxImpl: + public TraceResolverLinuxImplBase { +public: + TraceResolverLinuxImpl(): _dwfl_handle_initialized(false) {} + + template + void load_stacktrace(ST&) {} + + ResolvedTrace resolve(ResolvedTrace trace) { + using namespace details; + + Dwarf_Addr trace_addr = (Dwarf_Addr) trace.addr; + + if (not _dwfl_handle_initialized) { + // initialize dwfl... + _dwfl_cb.reset(new Dwfl_Callbacks); + _dwfl_cb->find_elf = &dwfl_linux_proc_find_elf; + _dwfl_cb->find_debuginfo = &dwfl_standard_find_debuginfo; + _dwfl_cb->debuginfo_path = 0; + + _dwfl_handle.reset(dwfl_begin(_dwfl_cb.get())); + _dwfl_handle_initialized = true; + + if (not _dwfl_handle) { + return trace; + } + + // ...from the current process. + dwfl_report_begin(_dwfl_handle.get()); + int r = dwfl_linux_proc_report (_dwfl_handle.get(), getpid()); + dwfl_report_end(_dwfl_handle.get(), NULL, NULL); + if (r < 0) { + return trace; + } + } + + if (not _dwfl_handle) { + return trace; + } + + // find the module (binary object) that contains the trace's address. + // This is not using any debug information, but the addresses ranges of + // all the currently loaded binary object. + Dwfl_Module* mod = dwfl_addrmodule(_dwfl_handle.get(), trace_addr); + if (mod) { + // now that we found it, lets get the name of it, this will be the + // full path to the running binary or one of the loaded library. + const char* module_name = dwfl_module_info (mod, + 0, 0, 0, 0, 0, 0, 0); + if (module_name) { + trace.object_filename = module_name; + } + // We also look after the name of the symbol, equal or before this + // address. This is found by walking the symtab. We should get the + // symbol corresponding to the function (mangled) containing the + // address. If the code corresponding to the address was inlined, + // this is the name of the out-most inliner function. + const char* sym_name = dwfl_module_addrname(mod, trace_addr); + if (sym_name) { + trace.object_function = demangle(sym_name); + } + } + + // now let's get serious, and find out the source location (file and + // line number) of the address. + + // This function will look in .debug_aranges for the address and map it + // to the location of the compilation unit DIE in .debug_info and + // return it. + Dwarf_Addr mod_bias = 0; + Dwarf_Die* cudie = dwfl_module_addrdie(mod, trace_addr, &mod_bias); + +#if 1 + if (not cudie) { + // Sadly clang does not generate the section .debug_aranges, thus + // dwfl_module_addrdie will fail early. Clang doesn't either set + // the lowpc/highpc/range info for every compilation unit. + // + // So in order to save the world: + // for every compilation unit, we will iterate over every single + // DIEs. Normally functions should have a lowpc/highpc/range, which + // we will use to infer the compilation unit. + + // note that this is probably badly inefficient. + while ((cudie = dwfl_module_nextcu(mod, cudie, &mod_bias))) { + Dwarf_Die die_mem; + Dwarf_Die* fundie = find_fundie_by_pc(cudie, + trace_addr - mod_bias, &die_mem); + if (fundie) { + break; + } + } + } +#endif + +//#define BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE +#ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE + if (not cudie) { + // If it's still not enough, lets dive deeper in the shit, and try + // to save the world again: for every compilation unit, we will + // load the corresponding .debug_line section, and see if we can + // find our address in it. + + Dwarf_Addr cfi_bias; + Dwarf_CFI* cfi_cache = dwfl_module_eh_cfi(mod, &cfi_bias); + + Dwarf_Addr bias; + while ((cudie = dwfl_module_nextcu(mod, cudie, &bias))) { + if (dwarf_getsrc_die(cudie, trace_addr - bias)) { + + // ...but if we get a match, it might be a false positive + // because our (address - bias) might as well be valid in a + // different compilation unit. So we throw our last card on + // the table and lookup for the address into the .eh_frame + // section. + + handle frame; + dwarf_cfi_addrframe(cfi_cache, trace_addr - cfi_bias, &frame); + if (frame) { + break; + } + } + } + } +#endif + + if (not cudie) { + return trace; // this time we lost the game :/ + } + + // Now that we have a compilation unit DIE, this function will be able + // to load the corresponding section in .debug_line (if not already + // loaded) and hopefully find the source location mapped to our + // address. + Dwarf_Line* srcloc = dwarf_getsrc_die(cudie, trace_addr - mod_bias); + + if (srcloc) { + const char* srcfile = dwarf_linesrc(srcloc, 0, 0); + if (srcfile) { + trace.source.filename = srcfile; + } + int line = 0, col = 0; + dwarf_lineno(srcloc, &line); + dwarf_linecol(srcloc, &col); + trace.source.line = line; + trace.source.col = col; + } + + deep_first_search_by_pc(cudie, trace_addr - mod_bias, + inliners_search_cb(trace)); + if (trace.source.function.size() == 0) { + // fallback. + trace.source.function = trace.object_function; + } + + return trace; + } + +private: + typedef details::handle > + dwfl_handle_t; + details::handle > + _dwfl_cb; + dwfl_handle_t _dwfl_handle; + bool _dwfl_handle_initialized; + + // defined here because in C++98, template function cannot take locally + // defined types... grrr. + struct inliners_search_cb { + void operator()(Dwarf_Die* die) { + switch (dwarf_tag(die)) { + const char* name; + case DW_TAG_subprogram: + if ((name = dwarf_diename(die))) { + trace.source.function = name; + } + break; + + case DW_TAG_inlined_subroutine: + ResolvedTrace::SourceLoc sloc; + Dwarf_Attribute attr_mem; + + if ((name = dwarf_diename(die))) { + trace.source.function = name; + } + if ((name = die_call_file(die))) { + sloc.filename = name; + } + + Dwarf_Word line = 0, col = 0; + dwarf_formudata(dwarf_attr(die, DW_AT_call_line, + &attr_mem), &line); + dwarf_formudata(dwarf_attr(die, DW_AT_call_column, + &attr_mem), &col); + sloc.line = line; + sloc.col = col; + + trace.inliners.push_back(sloc); + break; + }; + } + ResolvedTrace& trace; + inliners_search_cb(ResolvedTrace& t): trace(t) {} + }; + + + static bool die_has_pc(Dwarf_Die* die, Dwarf_Addr pc) { + Dwarf_Addr low, high; + + // continuous range + if (dwarf_hasattr(die, DW_AT_low_pc) and + dwarf_hasattr(die, DW_AT_high_pc)) { + if (dwarf_lowpc(die, &low) != 0) { + return false; + } + if (dwarf_highpc(die, &high) != 0) { + Dwarf_Attribute attr_mem; + Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_high_pc, &attr_mem); + Dwarf_Word value; + if (dwarf_formudata(attr, &value) != 0) { + return false; + } + high = low + value; + } + return pc >= low and pc < high; + } + + // non-continuous range. + Dwarf_Addr base; + ptrdiff_t offset = 0; + while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) { + if (pc >= low and pc < high) { + return true; + } + } + return false; + } + + static Dwarf_Die* find_fundie_by_pc(Dwarf_Die* parent_die, Dwarf_Addr pc, + Dwarf_Die* result) { + if (dwarf_child(parent_die, result) != 0) { + return 0; + } + + Dwarf_Die* die = result; + do { + switch (dwarf_tag(die)) { + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + if (die_has_pc(die, pc)) { + return result; + } + default: + bool declaration = false; + Dwarf_Attribute attr_mem; + dwarf_formflag(dwarf_attr(die, DW_AT_declaration, + &attr_mem), &declaration); + if (not declaration) { + // let's be curious and look deeper in the tree, + // function are not necessarily at the first level, but + // might be nested inside a namespace, structure etc. + Dwarf_Die die_mem; + Dwarf_Die* indie = find_fundie_by_pc(die, pc, &die_mem); + if (indie) { + *result = die_mem; + return result; + } + } + }; + } while (dwarf_siblingof(die, result) == 0); + return 0; + } + + template + static bool deep_first_search_by_pc(Dwarf_Die* parent_die, + Dwarf_Addr pc, CB cb) { + Dwarf_Die die_mem; + if (dwarf_child(parent_die, &die_mem) != 0) { + return false; + } + + bool branch_has_pc = false; + Dwarf_Die* die = &die_mem; + do { + bool declaration = false; + Dwarf_Attribute attr_mem; + dwarf_formflag(dwarf_attr(die, DW_AT_declaration, &attr_mem), &declaration); + if (not declaration) { + // let's be curious and look deeper in the tree, function are + // not necessarily at the first level, but might be nested + // inside a namespace, structure, a function, an inlined + // function etc. + branch_has_pc = deep_first_search_by_pc(die, pc, cb); + } + if (not branch_has_pc) { + branch_has_pc = die_has_pc(die, pc); + } + if (branch_has_pc) { + cb(die); + } + } while (dwarf_siblingof(die, &die_mem) == 0); + return branch_has_pc; + } + + static const char* die_call_file(Dwarf_Die *die) { + Dwarf_Attribute attr_mem; + Dwarf_Sword file_idx = 0; + + dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem), + &file_idx); + + if (file_idx == 0) { + return 0; + } + + Dwarf_Die die_mem; + Dwarf_Die* cudie = dwarf_diecu(die, &die_mem, 0, 0); + if (not cudie) { + return 0; + } + + Dwarf_Files* files = 0; + size_t nfiles; + dwarf_getsrcfiles(cudie, &files, &nfiles); + if (not files) { + return 0; + } + + return dwarf_filesrc(files, file_idx, 0, 0); + } + +}; +#endif // BACKWARD_HAS_DW == 1 + +template<> +class TraceResolverImpl: + public TraceResolverLinuxImpl {}; + +#endif // BACKWARD_SYSTEM_LINUX + +class TraceResolver: + public TraceResolverImpl {}; + +/*************** CODE SNIPPET ***************/ + +class SourceFile { +public: + typedef std::vector > lines_t; + + SourceFile() {} + SourceFile(const std::string& path): _file(new std::ifstream(path.c_str())) {} + bool is_open() const { return _file->is_open(); } + + lines_t& get_lines(size_t line_start, size_t line_count, lines_t& lines) { + using namespace std; + // This function make uses of the dumbest algo ever: + // 1) seek(0) + // 2) read lines one by one and discard until line_start + // 3) read line one by one until line_start + line_count + // + // If you are getting snippets many time from the same file, it is + // somewhat a waste of CPU, feel free to benchmark and propose a + // better solution ;) + + _file->clear(); + _file->seekg(0); + string line; + size_t line_idx; + + for (line_idx = 1; line_idx < line_start; ++line_idx) { + getline(*_file, line); + if (not *_file) { + return lines; + } + } + + // think of it like a lambda in C++98 ;) + // but look, I will reuse it two times! + // What a good boy am I. + struct isspace { + bool operator()(char c) { + return std::isspace(c); + } + }; + + bool started = false; + for (; line_idx < line_start + line_count; ++line_idx) { + getline(*_file, line); + if (not *_file) { + return lines; + } + if (not started) { + if (std::find_if(line.begin(), line.end(), + not_isspace()) == line.end()) + continue; + started = true; + } + lines.push_back(make_pair(line_idx, line)); + } + + lines.erase( + std::find_if(lines.rbegin(), lines.rend(), + not_isempty()).base(), lines.end() + ); + return lines; + } + + lines_t get_lines(size_t line_start, size_t line_count) { + lines_t lines; + return get_lines(line_start, line_count, lines); + } + + // there is no find_if_not in C++98, lets do something crappy to + // workaround. + struct not_isspace { + bool operator()(char c) { + return not std::isspace(c); + } + }; + // and define this one here because C++98 is not happy with local defined + // struct passed to template functions, fuuuu. + struct not_isempty { + bool operator()(const lines_t::value_type& p) { + return not (std::find_if(p.second.begin(), p.second.end(), + not_isspace()) == p.second.end()); + } + }; + + void swap(SourceFile& b) { + _file.swap(b._file); + } + +#if defined(BACKWARD_CXX11) + SourceFile(SourceFile&& from): _file(0) { + swap(from); + } + SourceFile& operator=(SourceFile&& from) { + swap(from); return *this; + } +#else + explicit SourceFile(const SourceFile& from) { + // some sort of poor man's move semantic. + swap(const_cast(from)); + } + SourceFile& operator=(const SourceFile& from) { + // some sort of poor man's move semantic. + swap(const_cast(from)); return *this; + } +#endif + +private: + details::handle + > _file; + +#if defined(BACKWARD_CXX11) + SourceFile(const SourceFile&) = delete; + SourceFile& operator=(const SourceFile&) = delete; +#endif +}; + +class SnippetFactory { +public: + typedef SourceFile::lines_t lines_t; + + lines_t get_snippet(const std::string& filename, + size_t line_start, size_t context_size) { + + SourceFile& src_file = get_src_file(filename); + size_t start = line_start - context_size / 2; + return src_file.get_lines(start, context_size); + } + + lines_t get_combined_snippet( + const std::string& filename_a, size_t line_a, + const std::string& filename_b, size_t line_b, + size_t context_size) { + SourceFile& src_file_a = get_src_file(filename_a); + SourceFile& src_file_b = get_src_file(filename_b); + + lines_t lines = src_file_a.get_lines(line_a - context_size / 4, + context_size / 2); + src_file_b.get_lines(line_b - context_size / 4, context_size / 2, + lines); + return lines; + } + + lines_t get_coalesced_snippet(const std::string& filename, + size_t line_a, size_t line_b, size_t context_size) { + SourceFile& src_file = get_src_file(filename); + + using std::min; using std::max; + size_t a = min(line_a, line_b); + size_t b = max(line_a, line_b); + + if ((b - a) < (context_size / 3)) { + return src_file.get_lines((a + b - context_size + 1) / 2, + context_size); + } + + lines_t lines = src_file.get_lines(a - context_size / 4, + context_size / 2); + src_file.get_lines(b - context_size / 4, context_size / 2, lines); + return lines; + } + + +private: + typedef details::hashtable::type src_files_t; + src_files_t _src_files; + + SourceFile& get_src_file(const std::string& filename) { + src_files_t::iterator it = _src_files.find(filename); + if (it != _src_files.end()) { + return it->second; + } + SourceFile& new_src_file = _src_files[filename]; + new_src_file = SourceFile(filename); + return new_src_file; + } +}; + +/*************** PRINTER ***************/ + +#ifdef BACKWARD_SYSTEM_LINUX + +namespace Color { + enum type { + yellow = 33, + purple = 35, + reset = 39 + }; +} // namespace Color + +class Colorize { +public: + Colorize(std::FILE* os): + _os(os), _reset(false), _istty(false) {} + + void init() { + _istty = isatty(fileno(_os)); + } + + void set_color(Color::type ccode) { + if (not _istty) return; + + // I assume that the terminal can handle basic colors. Seriously I + // don't want to deal with all the termcap shit. + fprintf(_os, "\033[%im", static_cast(ccode)); + _reset = (ccode != Color::reset); + } + + ~Colorize() { + if (_reset) { + set_color(Color::reset); + } + } + +private: + std::FILE* _os; + bool _reset; + bool _istty; +}; + +#else // ndef BACKWARD_SYSTEM_LINUX + + +namespace Color { + enum type { + yellow = 0, + purple = 0, + reset = 0 + }; +} // namespace Color + +class Colorize { +public: + Colorize(std::FILE*) {} + void init(); + void set_color(Color::type) {} +}; + +#endif // BACKWARD_SYSTEM_LINUX + +class Printer { +public: + bool snippet; + bool color; + bool address; + bool object; + + Printer(): + snippet(true), + color(true), + address(false), + object(false) + {} + + template + FILE* print(StackTrace& st, FILE* os = stderr) { + using namespace std; + + Colorize colorize(os); + if (color) { + colorize.init(); + } + + fprintf(os, "Stack trace (most recent call last)"); + if (st.thread_id()) { + fprintf(os, " in thread %u:\n", st.thread_id()); + } else { + fprintf(os, ":\n"); + } + + _resolver.load_stacktrace(st); + for (unsigned trace_idx = st.size(); trace_idx > 0; --trace_idx) { + fprintf(os, "#%-2u", trace_idx); + bool already_indented = true; + const ResolvedTrace trace = _resolver.resolve(st[trace_idx-1]); + + if (not trace.source.filename.size() or object) { + fprintf(os, " Object \"%s\", at %p, in %s\n", + trace.object_filename.c_str(), trace.addr, + trace.object_function.c_str()); + already_indented = false; + } + + if (trace.source.filename.size()) { + for (size_t inliner_idx = trace.inliners.size(); + inliner_idx > 0; --inliner_idx) { + if (not already_indented) { + fprintf(os, " "); + } + const ResolvedTrace::SourceLoc& inliner_loc + = trace.inliners[inliner_idx-1]; + print_source_loc(os, " | ", inliner_loc); + if (snippet) { + print_snippet(os, " | ", inliner_loc, + colorize, Color::purple, 5); + } + already_indented = false; + } + + if (not already_indented) { + fprintf(os, " "); + } + print_source_loc(os, " ", trace.source, trace.addr); + if (snippet) { + print_snippet(os, " ", trace.source, + colorize, Color::yellow, 7); + } + + if (trace.locals.size()) { + print_locals(os, " ", trace.locals); + } + } + } + return os; + } +private: + TraceResolver _resolver; + SnippetFactory _snippets; + + void print_snippet(FILE* os, const char* indent, + const ResolvedTrace::SourceLoc& source_loc, + Colorize& colorize, Color::type color_code, + int context_size) + { + using namespace std; + typedef SnippetFactory::lines_t lines_t; + + lines_t lines = _snippets.get_snippet(source_loc.filename, + source_loc.line, context_size); + + for (lines_t::const_iterator it = lines.begin(); + it != lines.end(); ++it) { + if (it-> first == source_loc.line) { + colorize.set_color(color_code); + fprintf(os, "%s>", indent); + } else { + fprintf(os, "%s ", indent); + } + fprintf(os, "%4li: %s\n", it->first, it->second.c_str()); + if (it-> first == source_loc.line) { + colorize.set_color(Color::reset); + } + } + } + + void print_source_loc(FILE* os, const char* indent, + const ResolvedTrace::SourceLoc& source_loc, + void* addr=0) { + fprintf(os, "%sSource \"%s\", line %i, in %s", + indent, source_loc.filename.c_str(), (int)source_loc.line, + source_loc.function.c_str()); + + if (address and addr != 0) { + fprintf(os, " [%p]\n", addr); + } else { + fprintf(os, "\n"); + } + } + + void print_var(FILE* os, const char* base_indent, int indent, + const Variable& var) { + fprintf(os, "%s%s: ", base_indent, var.name.c_str()); + switch (var.kind) { + case Variable::VALUE: + fprintf(os, "%s\n", var.value().c_str()); + break; + case Variable::LIST: + fprintf(os, "["); + for (size_t i = 0; i < var.list().size(); ++i) { + if (i > 0) { + fprintf(os, ", %s", var.list()[i].c_str()); + } + fprintf(os, "%s", var.list()[i].c_str()); + } + fprintf(os, "]\n"); + break; + case Variable::MAP: + fprintf(os, "{\n"); + for (size_t i = 0; i < var.map().size(); ++i) { + if (i > 0) { + fprintf(os, ",\n%s", base_indent); + } + print_var(os, base_indent, indent + 2, var.map()[i]); + } + fprintf(os, "]\n"); + break; + }; + } + + void print_locals(FILE* os, const char* indent, + const std::vector& locals) { + fprintf(os, "%sLocal variables:\n", indent); + for (size_t i = 0; i < locals.size(); ++i) { + if (i > 0) { + fprintf(os, ",\n%s", indent); + } + print_var(os, indent, 0, locals[i]); + } + } +}; + +/*************** SIGNALS HANDLING ***************/ + +#ifdef BACKWARD_SYSTEM_LINUX + +class SignalHandling { +public: + SignalHandling(): _loaded(false) { + // TODO: add a signal dedicated stack, so we can handle stack-overflow. + bool success = true; + const int signals[] = { + // default action: Core + SIGILL, + SIGABRT, + SIGFPE, + SIGSEGV, + SIGBUS, + + // I am not sure the following signals should be enabled by + // default: + + // default action: Term + SIGHUP, + SIGINT, + SIGPIPE, + SIGALRM, + SIGTERM, + SIGUSR1, + SIGUSR2, + SIGPOLL, + SIGPROF, + SIGVTALRM, + SIGIO, + SIGPWR, + + // default action: Core + SIGQUIT, + SIGSYS, + SIGTRAP, + SIGXCPU, + SIGXFSZ + }; + for (const int* sig = signals; + sig != signals + sizeof signals / sizeof *signals; ++sig) { + + struct sigaction action; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + action.sa_sigaction = &sig_handler; + + int r = sigaction(*sig, &action, 0); + if (r < 0) success = false; + } + _loaded = success; + } + + bool loaded() const { return _loaded; } + +private: + bool _loaded; + + static void sig_handler(int, siginfo_t* info, void* _ctx) { + ucontext_t *uctx = (ucontext_t*) _ctx; + + StackTrace st; + void* error_addr = 0; +#ifdef REG_RIP // x86_64 + error_addr = reinterpret_cast(uctx->uc_mcontext.gregs[REG_RIP]); +#elif defined(REG_EIP) // x86_32 + error_addr = reinterpret_cast(uctx->uc_mcontext.gregs[REG_EIP]); +#else +# warning ":/ sorry, ain't know no nothing none not of your architecture!" +#endif + if (error_addr) { + st.load_from(error_addr, 32); + } else { + st.load_here(32); + } + + Printer printer; + printer.address = true; + printer.print(st, stderr); + + psiginfo(info, 0); + exit(EXIT_FAILURE); + } +}; + +#endif // BACKWARD_SYSTEM_LINUX + +#ifdef BACKWARD_SYSTEM_UNKNOWN + +class SignalHandling { +public: + SignalHandling() {} + bool init() { return false; } +}; + +#endif // BACKWARD_SYSTEM_UNKNOWN + +#if 0 +void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext) +{ + void * array[50]; + void * caller_address; + char ** messages; + int size, i; + sig_ucontext_t * uc; + + uc = (sig_ucontext_t *)ucontext; + + /* Get the address at the time the signal was raised from the EIP (x86) */ + caller_address = (void *) uc->uc_mcontext.eip; + + fprintf(stderr, "signal %d (%s), address is %p from %p\n", + sig_num, strsignal(sig_num), info->si_addr, + (void *)caller_address); + + size = backtrace(array, 50); + + /* overwrite sigaction with caller's address */ + array[1] = caller_address; + + messages = backtrace_symbols(array, size); + + +void sig_handler(int sig, siginfo_t* info, void* _ctx) { +ucontext_t *context = (ucontext_t*) _ctx; + +psiginfo(info, "Shit hit the fan"); +exit(EXIT_FAILURE); +} + +using namespace std; + +void badass() { +cout << "baddass!" << endl; +((char*)&badass)[0] = 42; +} + +int main() { +struct sigaction action; +action.sa_flags = SA_SIGINFO; +sigemptyset(&action.sa_mask); +action.sa_sigaction = &sig_handler; +int r = sigaction(SIGSEGV, &action, 0); +if (r < 0) { err(errno, 0); } +r = sigaction(SIGILL, &action, 0); +if (r < 0) { err(errno, 0); } + +badass(); +return 0; +} + + +#endif + +// i want to get a stacktrace on: +// - abort +// - signals (segfault.. abort...) +// - exception +// - dont messup with gdb! +// - thread ID +// - helper for capturing stack trace inside exception +// propose a little magic wrapper to throw an exception adding a stacktrace, +// and propose a specific tool to get a stacktrace from an exception (if its +// available). +// - optional override __cxa_throw, then the specific magic tool could get +// the stacktrace. Might be possible to use a thread-local variable to do +// some shit. RTLD_DEEPBIND might do the tricks to override it on the fly. + +// maybe I can even get the last variables and theirs values? +// that might be possible. + +// print with code snippet +// print traceback demangled +// detect color stuff +// register all signals +// +// Seperate stacktrace (load and co function) +// than object extracting informations about a stack trace. + +// also public a simple function to print a stacktrace. + +// backtrace::StackTrace st; +// st.snapshot(); +// print(st); +// cout << st; + +} // namespace backward + +#endif /* H_GUARD */ diff --git a/source/fceultra/utils/endian.h b/source/fceultra/utils/endian.h index 5bdbcde..eb7ca31 100644 --- a/source/fceultra/utils/endian.h +++ b/source/fceultra/utils/endian.h @@ -82,7 +82,7 @@ inline int read_double_le(double *Bufo, EMUFILE*is) { uint64 temp; int ret = rea template int readle(T *Bufo, EMUFILE*is) { - CTASSERT(sizeof(T)==1||sizeof(T)==2||sizeof(T)==4||sizeof(T)==8); + //CTASSERT(sizeof(T)==1||sizeof(T)==2||sizeof(T)==4||sizeof(T)==8); switch(sizeof(T)) { case 1: return read8le((uint8*)Bufo,is); case 2: return read16le((uint16*)Bufo,is); @@ -96,7 +96,7 @@ int readle(T *Bufo, EMUFILE*is) template int writele(T *Bufo, EMUFILE*os) { - CTASSERT(sizeof(T)==1||sizeof(T)==2||sizeof(T)==4||sizeof(T)==8); + //CTASSERT(sizeof(T)==1||sizeof(T)==2||sizeof(T)==4||sizeof(T)==8); switch(sizeof(T)) { case 1: return write8le(*(uint8*)Bufo,os); case 2: return write16le(*(uint16*)Bufo,os); diff --git a/source/fceultra/utils/memory.cpp b/source/fceultra/utils/memory.cpp index 8acc343..088c9a8 100644 --- a/source/fceultra/utils/memory.cpp +++ b/source/fceultra/utils/memory.cpp @@ -1,26 +1,26 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/// \file -/// \brief memory management services provided by FCEU core - +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/// \file +/// \brief memory management services provided by FCEU core + #include #include #include @@ -28,7 +28,7 @@ #include "../fceu.h" #include "memory.h" -///allocates the specified number of bytes. exits process if this fails +///allocates the specified number of bytes. exits process if this fails void *FCEU_gmalloc(uint32 size) { @@ -47,7 +47,7 @@ void *FCEU_gmalloc(uint32 size) return ret; } -///allocates the specified number of bytes. returns null if this fails +///allocates the specified number of bytes. returns null if this fails void *FCEU_malloc(uint32 size) { void *ret; diff --git a/source/fceultra/utils/memory.h b/source/fceultra/utils/memory.h index 58eee62..34676d3 100644 --- a/source/fceultra/utils/memory.h +++ b/source/fceultra/utils/memory.h @@ -1,36 +1,36 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* Various macros for faster memory stuff - (at least that's the idea) -*/ - -#define FCEU_dwmemset(d,c,n) {int _x; for(_x=n-4;_x>=0;_x-=4) *(uint32 *)&(d)[_x]=c;} - -void *FCEU_malloc(uint32 size); -void *FCEU_gmalloc(uint32 size); -void FCEU_gfree(void *ptr); -void FCEU_free(void *ptr); -void FCEU_memmove(void *d, void *s, uint32 l); - -// wrapper for debugging when its needed, otherwise act like -// normal malloc/free -void *FCEU_dmalloc(uint32 size); -void FCEU_dfree(void *ptr); +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Various macros for faster memory stuff + (at least that's the idea) +*/ + +#define FCEU_dwmemset(d,c,n) {int _x; for(_x=n-4;_x>=0;_x-=4) *(uint32 *)&(d)[_x]=c;} + +void *FCEU_malloc(uint32 size); +void *FCEU_gmalloc(uint32 size); +void FCEU_gfree(void *ptr); +void FCEU_free(void *ptr); +void FCEU_memmove(void *d, void *s, uint32 l); + +// wrapper for debugging when its needed, otherwise act like +// normal malloc/free +void *FCEU_dmalloc(uint32 size); +void FCEU_dfree(void *ptr); diff --git a/source/fceultra/utils/xstring.h b/source/fceultra/utils/xstring.h index 5d66874..b42aec1 100644 --- a/source/fceultra/utils/xstring.h +++ b/source/fceultra/utils/xstring.h @@ -100,22 +100,22 @@ inline uint64 uint64DecFromIstream(EMUFILE* is) { return templateIntegerDecFromI template void putdec(EMUFILE* os, T dec) { char temp[DIGITS]; - int ctr = 0; - for(int i=0;ifwrite(temp+DIGITS-ctr-1,ctr+1); + if (!PAD) + os->fwrite(temp + (DIGITS - 1) - ctr, ctr + 1); else - os->fwrite(temp,DIGITS); + os->fwrite(temp, DIGITS); } std::string mass_replace(const std::string &source, const std::string &victim, const std::string &replacement); diff --git a/source/fceultra/version.h b/source/fceultra/version.h index a780c2e..3b9e833 100644 --- a/source/fceultra/version.h +++ b/source/fceultra/version.h @@ -60,8 +60,8 @@ #define FCEU_COMPILER_DETAIL "" #endif -#define FCEU_VERSION_NUMERIC 22000 -#define FCEU_VERSION_STRING "2.2.1" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER +#define FCEU_VERSION_NUMERIC 22020 +#define FCEU_VERSION_STRING "2.2.3" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER #define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING #endif diff --git a/source/fceultra/video.cpp b/source/fceultra/video.cpp index 81d1a2d..4956a38 100644 --- a/source/fceultra/video.cpp +++ b/source/fceultra/video.cpp @@ -18,16 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef WIN32 -#include -#endif - -#include -#include -#include -#include -#include - #include "types.h" #include "video.h" #include "fceu.h" @@ -55,6 +45,17 @@ #include "drivers/videolog/nesvideos-piece.h" #endif +//no stdint in win32 (but we could add it if we needed to) +#ifndef WIN32 +#include +#endif + +#include +#include +#include +#include +#include + uint8 *XBuf=NULL; uint8 *XBackBuf=NULL; int ClipSidesOffset=0; //Used to move displayed messages when Clips left and right sides is checked @@ -169,7 +170,7 @@ void FCEU_PutImage(void) { char nameo[512]; strcpy(nameo,FCEUI_GetSnapshotAsName().c_str()); - if (nameo) + if (nameo[0]) { SaveSnapshot(nameo); FCEU_DispMessage("Snapshot Saved.",0); @@ -180,6 +181,10 @@ void FCEU_PutImage(void) { DrawNSF(XBuf); +#ifdef _S9XLUA_H + FCEU_LuaGui(XBuf); +#endif + //Save snapshot after NSF screen is drawn. Why would we want to do it before? if(dosnapsave==1) { @@ -443,7 +448,6 @@ void FCEU_DispMessageOnMovie(char *format, ...) void FCEU_DispMessage(char *format, int disppos=0, ...) { -#ifndef GEKKO va_list ap; va_start(ap,disppos); @@ -473,7 +477,6 @@ void FCEU_DispMessage(char *format, int disppos=0, ...) guiMessage.howlong = 0; } #endif -#endif } void FCEU_ResetMessages() diff --git a/source/fceultra/vsuni.cpp b/source/fceultra/vsuni.cpp index 297639e..e7e718a 100644 --- a/source/fceultra/vsuni.cpp +++ b/source/fceultra/vsuni.cpp @@ -18,9 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include - #include "types.h" #include "x6502.h" #include "fceu.h" @@ -30,6 +27,9 @@ #include "state.h" #include "driver.h" +#include +#include + #define IOPTION_GUN 0x1 #define IOPTION_SWAPDIRAB 0x2 diff --git a/source/fceultra/wave.cpp b/source/fceultra/wave.cpp index bc305b0..de6f1dc 100644 --- a/source/fceultra/wave.cpp +++ b/source/fceultra/wave.cpp @@ -1,6 +1,3 @@ -#include -#include - #include "types.h" #include "fceu.h" @@ -8,6 +5,9 @@ #include "sound.h" #include "wave.h" +#include +#include + static FILE *soundlog=0; static long wsize; diff --git a/source/fceultra/x6502.cpp b/source/fceultra/x6502.cpp index 9384d15..472232d 100644 --- a/source/fceultra/x6502.cpp +++ b/source/fceultra/x6502.cpp @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include "types.h" #include "x6502.h" #include "fceu.h" @@ -29,6 +28,8 @@ #endif #include "x6502abbrev.h" + +#include X6502 X; uint32 timestamp; void (*MapIRQHook)(int a); @@ -482,6 +483,8 @@ extern int test; test++; //will probably cause a major speed decrease on low-end systems DEBUG( DebugCycle() ); + IncrementInstructionsCounters(); + _PI=_P; b1=RdMem(_PC); @@ -529,7 +532,12 @@ void FCEUI_GetIVectors(uint16 *reset, uint16 *irq, uint16 *nmi) //the opsize table is used to quickly grab the instruction sizes (in bytes) const uint8 opsize[256] = { -/*0x00*/ 1,2,0,0,0,2,2,0,1,2,1,0,0,3,3,0, +#ifdef BRK_3BYTE_HACK +/*0x00*/ 3, //BRK +#else +/*0x00*/ 1, //BRK +#endif +/*0x01*/ 2,0,0,0,2,2,0,1,2,1,0,0,3,3,0, /*0x10*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0, /*0x20*/ 3,2,0,0,2,2,2,0,1,2,1,0,3,3,3,0, /*0x30*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0, diff --git a/source/fceultra/x6502.h b/source/fceultra/x6502.h index b30e0fb..34d4385 100644 --- a/source/fceultra/x6502.h +++ b/source/fceultra/x6502.h @@ -61,7 +61,7 @@ extern uint32 timestamp; extern void (*MapIRQHook)(int a); -#define NTSC_CPU 1789772.7272727272727272 +#define NTSC_CPU (dendy ? 1773447.467 : 1789772.7272727272727272) #define PAL_CPU 1662607.125 #define FCEU_IQEXT 0x001 diff --git a/source/fceustate.cpp b/source/fceustate.cpp index f36c079..3dc1c03 100644 --- a/source/fceustate.cpp +++ b/source/fceustate.cpp @@ -112,3 +112,22 @@ LoadStateAuto (bool silent) return LoadState(filepath, silent); } + +bool SavePreviewImg (char * filepath, bool silent) +{ + int device; + + if(!FindDevice(filepath, &device)) + return 0; + + if(gameScreenPngSize > 0) + { + char screenpath[1024]; + strncpy(screenpath, filepath, 1024); + screenpath[strlen(screenpath)] = 0; + sprintf(screenpath, "%s.png", screenpath); + SaveFile((char *)gameScreenPng, screenpath, gameScreenPngSize, silent); + } + + return 1; +} diff --git a/source/fceustate.h b/source/fceustate.h index f6acdc7..5093ffd 100644 --- a/source/fceustate.h +++ b/source/fceustate.h @@ -13,3 +13,4 @@ bool SaveState (char * filepath, bool silent); bool SaveStateAuto (bool silent); bool LoadState (char * filepath, bool silent); bool LoadStateAuto (bool silent); +bool SavePreviewImg (char * filepath, bool silent); \ No newline at end of file diff --git a/source/filelist.h b/source/filelist.h index 351126e..4942e15 100644 --- a/source/filelist.h +++ b/source/filelist.h @@ -94,6 +94,8 @@ extern const u8 icon_game_load_png[]; extern const u32 icon_game_load_png_size; extern const u8 icon_game_save_png[]; extern const u32 icon_game_save_png_size; +extern const u8 icon_game_delete_png[]; +extern const u32 icon_game_delete_png_size; extern const u8 icon_game_reset_png[]; extern const u32 icon_game_reset_png_size; @@ -105,6 +107,8 @@ extern const u8 icon_settings_gamecube_png[]; extern const u32 icon_settings_gamecube_png_size; extern const u8 icon_settings_nunchuk_png[]; extern const u32 icon_settings_nunchuk_png_size; +extern const u8 icon_settings_wiiupro_png[]; +extern const u32 icon_settings_wiiupro_png_size; extern const u8 icon_settings_nescontroller_png[]; extern const u32 icon_settings_nescontroller_png_size; @@ -121,6 +125,9 @@ extern const u8 icon_settings_network_png[]; extern const u32 icon_settings_network_png_size; extern const u8 icon_settings_video_png[]; extern const u32 icon_settings_video_png_size; +extern const u8 icon_settings_screenshot_png[]; +extern const u32 icon_settings_screenshot_png_size; + extern const u8 button_png[]; extern const u32 button_png_size; @@ -248,6 +255,9 @@ extern const u32 bg_game_selection_png_size; extern const u8 bg_game_selection_entry_png[]; extern const u32 bg_game_selection_entry_png_size; +extern const u8 bg_preview_png[]; +extern const u32 bg_preview_png_size; + extern const u8 scrollbar_png[]; extern const u32 scrollbar_png_size; @@ -314,4 +324,4 @@ extern const u32 player3_grab_png_size; extern const u8 player4_grab_png[]; extern const u32 player4_grab_png_size; -#endif +#endif \ No newline at end of file diff --git a/source/gcvideo.cpp b/source/gcvideo.cpp index de3b784..8c870c0 100644 --- a/source/gcvideo.cpp +++ b/source/gcvideo.cpp @@ -1315,222 +1315,312 @@ struct st_palettes palettes[] = { 0xffe890, 0xf0f4a4, 0xc0ffc0, 0xacf4f0, 0xa0e8ff, 0xc2c2c2, 0x202020, 0x101010 } }, - { "loopy", "Loopy's palette", - { 0x757575, 0x271b8f, 0x0000ab, 0x47009f, - 0x8f0077, 0xab0013, 0xa70000, 0x7f0b00, - 0x432f00, 0x004700, 0x005100, 0x003f17, - 0x1b3f5f, 0x000000, 0x000000, 0x000000, - 0xbcbcbc, 0x0073ef, 0x233bef, 0x8300f3, - 0xbf00bf, 0xe7005b, 0xdb2b00, 0xcb4f0f, - 0x8b7300, 0x009700, 0x00ab00, 0x00933b, - 0x00838b, 0x000000, 0x000000, 0x000000, - 0xffffff, 0x3fbfff, 0x5f97ff, 0xa78bfd, - 0xf77bff, 0xff77b7, 0xff7763, 0xff9b3b, - 0xf3bf3f, 0x83d313, 0x4fdf4b, 0x58f898, - 0x00ebdb, 0x000000, 0x000000, 0x000000, - 0xffffff, 0xabe7ff, 0xc7d7ff, 0xd7cbff, - 0xffc7ff, 0xffc7db, 0xffbfb3, 0xffdbab, - 0xffe7a3, 0xe3ffa3, 0xabf3bf, 0xb3ffcf, - 0x9ffff3, 0x000000, 0x000000, 0x000000 } - }, - { "quor", "Quor's palette", - { 0x3f3f3f, 0x001f3f, 0x00003f, 0x1f003f, - 0x3f003f, 0x3f0020, 0x3f0000, 0x3f2000, - 0x3f3f00, 0x203f00, 0x003f00, 0x003f20, - 0x003f3f, 0x000000, 0x000000, 0x000000, - 0x7f7f7f, 0x405f7f, 0x40407f, 0x5f407f, - 0x7f407f, 0x7f4060, 0x7f4040, 0x7f6040, - 0x7f7f40, 0x607f40, 0x407f40, 0x407f60, - 0x407f7f, 0x000000, 0x000000, 0x000000, - 0xbfbfbf, 0x809fbf, 0x8080bf, 0x9f80bf, - 0xbf80bf, 0xbf80a0, 0xbf8080, 0xbfa080, - 0xbfbf80, 0xa0bf80, 0x80bf80, 0x80bfa0, - 0x80bfbf, 0x000000, 0x000000, 0x000000, - 0xffffff, 0xc0dfff, 0xc0c0ff, 0xdfc0ff, - 0xffc0ff, 0xffc0e0, 0xffc0c0, 0xffe0c0, - 0xffffc0, 0xe0ffc0, 0xc0ffc0, 0xc0ffe0, - 0xc0ffff, 0x000000, 0x000000, 0x000000 } - }, - { "chris", "Chris Covell's palette", - { 0x808080, 0x003DA6, 0x0012B0, 0x440096, - 0xA1005E, 0xC70028, 0xBA0600, 0x8C1700, - 0x5C2F00, 0x104500, 0x054A00, 0x00472E, - 0x004166, 0x000000, 0x050505, 0x050505, - 0xC7C7C7, 0x0077FF, 0x2155FF, 0x8237FA, - 0xEB2FB5, 0xFF2950, 0xFF2200, 0xD63200, - 0xC46200, 0x358000, 0x058F00, 0x008A55, - 0x0099CC, 0x212121, 0x090909, 0x090909, - 0xFFFFFF, 0x0FD7FF, 0x69A2FF, 0xD480FF, - 0xFF45F3, 0xFF618B, 0xFF8833, 0xFF9C12, - 0xFABC20, 0x9FE30E, 0x2BF035, 0x0CF0A4, - 0x05FBFF, 0x5E5E5E, 0x0D0D0D, 0x0D0D0D, - 0xFFFFFF, 0xA6FCFF, 0xB3ECFF, 0xDAABEB, - 0xFFA8F9, 0xFFABB3, 0xFFD2B0, 0xFFEFA6, - 0xFFF79C, 0xD7E895, 0xA6EDAF, 0xA2F2DA, - 0x99FFFC, 0xDDDDDD, 0x111111, 0x111111 } - }, - { "matt", "Matthew Conte's palette", - { 0x808080, 0x0000bb, 0x3700bf, 0x8400a6, - 0xbb006a, 0xb7001e, 0xb30000, 0x912600, - 0x7b2b00, 0x003e00, 0x00480d, 0x003c22, - 0x002f66, 0x000000, 0x050505, 0x050505, - 0xc8c8c8, 0x0059ff, 0x443cff, 0xb733cc, - 0xff33aa, 0xff375e, 0xff371a, 0xd54b00, - 0xc46200, 0x3c7b00, 0x1e8415, 0x009566, - 0x0084c4, 0x111111, 0x090909, 0x090909, - 0xffffff, 0x0095ff, 0x6f84ff, 0xd56fff, - 0xff77cc, 0xff6f99, 0xff7b59, 0xff915f, - 0xffa233, 0xa6bf00, 0x51d96a, 0x4dd5ae, - 0x00d9ff, 0x666666, 0x0d0d0d, 0x0d0d0d, - 0xffffff, 0x84bfff, 0xbbbbff, 0xd0bbff, - 0xffbfea, 0xffbfcc, 0xffc4b7, 0xffccae, - 0xffd9a2, 0xcce199, 0xaeeeb7, 0xaaf7ee, - 0xb3eeff, 0xdddddd, 0x111111, 0x111111 } - }, - { "pasofami", "PasoFami/99 palette", - { 0x7f7f7f, 0x0000ff, 0x0000bf, 0x472bbf, - 0x970087, 0xab0023, 0xab1300, 0x8b1700, - 0x533000, 0x007800, 0x006b00, 0x005b00, - 0x004358, 0x000000, 0x000000, 0x000000, - 0xbfbfbf, 0x0078f8, 0x0058f8, 0x6b47ff, - 0xdb00cd, 0xe7005b, 0xf83800, 0xe75f13, - 0xaf7f00, 0x00b800, 0x00ab00, 0x00ab47, - 0x008b8b, 0x000000, 0x000000, 0x000000, - 0xf8f8f8, 0x3fbfff, 0x6b88ff, 0x9878f8, - 0xf878f8, 0xf85898, 0xf87858, 0xffa347, - 0xf8b800, 0xb8f818, 0x5bdb57, 0x58f898, - 0x00ebdb, 0x787878, 0x000000, 0x000000, - 0xffffff, 0xa7e7ff, 0xb8b8f8, 0xd8b8f8, - 0xf8b8f8, 0xfba7c3, 0xf0d0b0, 0xffe3ab, - 0xfbdb7b, 0xd8f878, 0xb8f8b8, 0xb8f8d8, - 0x00ffff, 0xf8d8f8, 0x000000, 0x000000 } - }, - { "crashman", "CrashMan's palette", - { 0x585858, 0x001173, 0x000062, 0x472bbf, - 0x970087, 0x910009, 0x6f1100, 0x4c1008, - 0x371e00, 0x002f00, 0x005500, 0x004d15, - 0x002840, 0x000000, 0x000000, 0x000000, - 0xa0a0a0, 0x004499, 0x2c2cc8, 0x590daa, - 0xae006a, 0xb00040, 0xb83418, 0x983010, - 0x704000, 0x308000, 0x207808, 0x007b33, - 0x1c6888, 0x000000, 0x000000, 0x000000, - 0xf8f8f8, 0x267be1, 0x5870f0, 0x9878f8, - 0xff73c8, 0xf060a8, 0xd07b37, 0xe09040, - 0xf8b300, 0x8cbc00, 0x40a858, 0x58f898, - 0x00b7bf, 0x787878, 0x000000, 0x000000, - 0xffffff, 0xa7e7ff, 0xb8b8f8, 0xd8b8f8, - 0xe6a6ff, 0xf29dc4, 0xf0c0b0, 0xfce4b0, - 0xe0e01e, 0xd8f878, 0xc0e890, 0x95f7c8, - 0x98e0e8, 0xf8d8f8, 0x000000, 0x000000 } - }, - { "mess", "MESS palette", - { 0x747474, 0x24188c, 0x0000a8, 0x44009c, - 0x8c0074, 0xa80010, 0xa40000, 0x7c0800, - 0x402c00, 0x004400, 0x005000, 0x003c14, - 0x183c5c, 0x000000, 0x000000, 0x000000, - 0xbcbcbc, 0x0070ec, 0x2038ec, 0x8000f0, - 0xbc00bc, 0xe40058, 0xd82800, 0xc84c0c, - 0x887000, 0x009400, 0x00a800, 0x009038, - 0x008088, 0x000000, 0x000000, 0x000000, - 0xfcfcfc, 0x3cbcfc, 0x5c94fc, 0x4088fc, - 0xf478fc, 0xfc74b4, 0xfc7460, 0xfc9838, - 0xf0bc3c, 0x80d010, 0x4cdc48, 0x58f898, - 0x00e8d8, 0x000000, 0x000000, 0x000000, - 0xfcfcfc, 0xa8e4fc, 0xc4d4fc, 0xd4c8fc, - 0xfcc4fc, 0xfcc4d8, 0xfcbcb0, 0xfcd8a8, - 0xfce4a0, 0xe0fca0, 0xa8f0bc, 0xb0fccc, - 0x9cfcf0, 0x000000, 0x000000, 0x000000 } - }, - { "zaphod-cv", "Zaphod's VS Castlevania palette", - { 0x7f7f7f, 0xffa347, 0x0000bf, 0x472bbf, - 0x970087, 0xf85898, 0xab1300, 0xf8b8f8, - 0xbf0000, 0x007800, 0x006b00, 0x005b00, - 0xffffff, 0x9878f8, 0x000000, 0x000000, - 0xbfbfbf, 0x0078f8, 0xab1300, 0x6b47ff, - 0x00ae00, 0xe7005b, 0xf83800, 0x7777ff, - 0xaf7f00, 0x00b800, 0x00ab00, 0x00ab47, - 0x008b8b, 0x000000, 0x000000, 0x472bbf, - 0xf8f8f8, 0xffe3ab, 0xf87858, 0x9878f8, - 0x0078f8, 0xf85898, 0xbfbfbf, 0xffa347, - 0xc800c8, 0xb8f818, 0x7f7f7f, 0x007800, - 0x00ebdb, 0x000000, 0x000000, 0xffffff, - 0xffffff, 0xa7e7ff, 0x5bdb57, 0xe75f13, - 0x004358, 0x0000ff, 0xe7005b, 0x00b800, - 0xfbdb7b, 0xd8f878, 0x8b1700, 0xffe3ab, - 0x00ffff, 0xab0023, 0x000000, 0x000000 } - }, - { "zaphod-smb", "Zaphod's VS SMB palette", - { 0x626a00, 0x0000ff, 0x006a77, 0x472bbf, - 0x970087, 0xab0023, 0xab1300, 0xb74800, - 0xa2a2a2, 0x007800, 0x006b00, 0x005b00, - 0xffd599, 0xffff00, 0x009900, 0x000000, - 0xff66ff, 0x0078f8, 0x0058f8, 0x6b47ff, - 0x000000, 0xe7005b, 0xf83800, 0xe75f13, - 0xaf7f00, 0x00b800, 0x5173ff, 0x00ab47, - 0x008b8b, 0x000000, 0x91ff88, 0x000088, - 0xf8f8f8, 0x3fbfff, 0x6b0000, 0x4855f8, - 0xf878f8, 0xf85898, 0x595958, 0xff009d, - 0x002f2f, 0xb8f818, 0x5bdb57, 0x58f898, - 0x00ebdb, 0x787878, 0x000000, 0x000000, - 0xffffff, 0xa7e7ff, 0x590400, 0xbb0000, - 0xf8b8f8, 0xfba7c3, 0xffffff, 0x00e3e1, - 0xfbdb7b, 0xffae00, 0xb8f8b8, 0xb8f8d8, - 0x00ff00, 0xf8d8f8, 0xffaaaa, 0x004000 } - }, - { "vs-drmar", "VS Dr. Mario palette", - { 0x5f97ff, 0x000000, 0x000000, 0x47009f, - 0x00ab00, 0xffffff, 0xabe7ff, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0xe7005b, 0x000000, 0x000000, 0x000000, - 0x5f97ff, 0x000000, 0x000000, 0x000000, - 0x000000, 0x8b7300, 0xcb4f0f, 0x000000, - 0xbcbcbc, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0x000000, 0x000000, - 0x00ebdb, 0x000000, 0x000000, 0x000000, - 0x000000, 0xff9b3b, 0x000000, 0x000000, - 0x83d313, 0x000000, 0x3fbfff, 0x000000, - 0x0073ef, 0x000000, 0x000000, 0x000000, - 0x00ebdb, 0x000000, 0x000000, 0x000000, - 0x000000, 0x000000, 0xf3bf3f, 0x000000, - 0x005100, 0x000000, 0xc7d7ff, 0xffdbab, - 0x000000, 0x000000, 0x000000, 0x000000 } - }, - { "vs-cv", "VS Castlevania palette", - { 0xaf7f00, 0xffa347, 0x008b8b, 0x472bbf, - 0x970087, 0xf85898, 0xab1300, 0xf8b8f8, - 0xf83800, 0x007800, 0x006b00, 0x005b00, - 0xffffff, 0x9878f8, 0x00ab00, 0x000000, - 0xbfbfbf, 0x0078f8, 0xab1300, 0x6b47ff, - 0x000000, 0xe7005b, 0xf83800, 0x6b88ff, - 0xaf7f00, 0x00b800, 0x6b88ff, 0x00ab47, - 0x008b8b, 0x000000, 0x000000, 0x472bbf, - 0xf8f8f8, 0xffe3ab, 0xf87858, 0x9878f8, - 0x0078f8, 0xf85898, 0xbfbfbf, 0xffa347, - 0x004358, 0xb8f818, 0x7f7f7f, 0x007800, - 0x00ebdb, 0x000000, 0x000000, 0xffffff, - 0xffffff, 0xa7e7ff, 0x5bdb57, 0x6b88ff, - 0x004358, 0x0000ff, 0xe7005b, 0x00b800, - 0xfbdb7b, 0xffa347, 0x8b1700, 0xffe3ab, - 0xb8f818, 0xab0023, 0x000000, 0x007800 } - }, - { "vs-smb", "VS SMB/VS Ice Climber palette", - { 0xaf7f00, 0x0000ff, 0x008b8b, 0x472bbf, - 0x970087, 0xab0023, 0x0000ff, 0xe75f13, - 0xbfbfbf, 0x007800, 0x5bdb57, 0x005b00, - 0xf0d0b0, 0xffe3ab, 0x00ab00, 0x000000, - 0xbfbfbf, 0x0078f8, 0x0058f8, 0x6b47ff, - 0x000000, 0xe7005b, 0xf83800, 0xf87858, - 0xaf7f00, 0x00b800, 0x6b88ff, 0x00ab47, - 0x008b8b, 0x000000, 0x000000, 0x3fbfff, - 0xf8f8f8, 0x006b00, 0x8b1700, 0x9878f8, - 0x6b47ff, 0xf85898, 0x7f7f7f, 0xe7005b, - 0x004358, 0xb8f818, 0x0078f8, 0x58f898, - 0x00ebdb, 0xfbdb7b, 0x000000, 0x000000, - 0xffffff, 0xa7e7ff, 0xb8b8f8, 0xf83800, - 0xf8b8f8, 0xfba7c3, 0xffffff, 0x00ffff, - 0xfbdb7b, 0xffa347, 0xb8f8b8, 0xb8f8d8, - 0xb8f818, 0xf8d8f8, 0x000000, 0x007800 } - } + { "loopy", "Loopy's palette", + { 0x757575, 0x271b8f, 0x0000ab, 0x47009f, + 0x8f0077, 0xab0013, 0xa70000, 0x7f0b00, + 0x432f00, 0x004700, 0x005100, 0x003f17, + 0x1b3f5f, 0x000000, 0x000000, 0x000000, + 0xbcbcbc, 0x0073ef, 0x233bef, 0x8300f3, + 0xbf00bf, 0xe7005b, 0xdb2b00, 0xcb4f0f, + 0x8b7300, 0x009700, 0x00ab00, 0x00933b, + 0x00838b, 0x000000, 0x000000, 0x000000, + 0xffffff, 0x3fbfff, 0x5f97ff, 0xa78bfd, + 0xf77bff, 0xff77b7, 0xff7763, 0xff9b3b, + 0xf3bf3f, 0x83d313, 0x4fdf4b, 0x58f898, + 0x00ebdb, 0x000000, 0x000000, 0x000000, + 0xffffff, 0xabe7ff, 0xc7d7ff, 0xd7cbff, + 0xffc7ff, 0xffc7db, 0xffbfb3, 0xffdbab, + 0xffe7a3, 0xe3ffa3, 0xabf3bf, 0xb3ffcf, + 0x9ffff3, 0x000000, 0x000000, 0x000000 } + }, + { "quor", "Quor's palette", + { 0x3f3f3f, 0x001f3f, 0x00003f, 0x1f003f, + 0x3f003f, 0x3f0020, 0x3f0000, 0x3f2000, + 0x3f3f00, 0x203f00, 0x003f00, 0x003f20, + 0x003f3f, 0x000000, 0x000000, 0x000000, + 0x7f7f7f, 0x405f7f, 0x40407f, 0x5f407f, + 0x7f407f, 0x7f4060, 0x7f4040, 0x7f6040, + 0x7f7f40, 0x607f40, 0x407f40, 0x407f60, + 0x407f7f, 0x000000, 0x000000, 0x000000, + 0xbfbfbf, 0x809fbf, 0x8080bf, 0x9f80bf, + 0xbf80bf, 0xbf80a0, 0xbf8080, 0xbfa080, + 0xbfbf80, 0xa0bf80, 0x80bf80, 0x80bfa0, + 0x80bfbf, 0x000000, 0x000000, 0x000000, + 0xffffff, 0xc0dfff, 0xc0c0ff, 0xdfc0ff, + 0xffc0ff, 0xffc0e0, 0xffc0c0, 0xffe0c0, + 0xffffc0, 0xe0ffc0, 0xc0ffc0, 0xc0ffe0, + 0xc0ffff, 0x000000, 0x000000, 0x000000 } + }, + { "wiivc", "SuperrSonic's WIIvc palette", + { 0x494949, 0x00006a, 0x090063, 0x290059, + 0x42004a, 0x490000, 0x420000, 0x291100, + 0x182700, 0x003010, 0x003000, 0x002910, + 0x012043, 0x000000, 0x000000, 0x000000, + 0x747174, 0x003084, 0x3101ac, 0x4b0194, + 0x64007b, 0x6b0039, 0x6b2101, 0x5a2f00, + 0x424900, 0x185901, 0x105901, 0x015932, + 0x01495a, 0x101010, 0x000000, 0x000000, + 0xadadad, 0x4a71b6, 0x6458d5, 0x8450e6, + 0xa451ad, 0xad4984, 0xb5624a, 0x947132, + 0x7b722a, 0x5a8601, 0x388e31, 0x318e5a, + 0x398e8d, 0x383838, 0x000000, 0x000000, + 0xb6b6b6, 0x8c9db5, 0x8d8eae, 0x9c8ebc, + 0xa687bc, 0xad8d9d, 0xae968c, 0x9c8f7c, + 0x9c9e72, 0x94a67c, 0x84a77b, 0x7c9d84, + 0x73968d, 0xdedede, 0x000000, 0x000000 } + }, + { "3dsvc", "SuperrSonic's 3DSvc palette", + { 0x494949, 0x00006a, 0x090063, 0x290059, + 0x42004a, 0x490000, 0x420000, 0x291100, + 0x182700, 0x003010, 0x003000, 0x002910, + 0x012043, 0x000000, 0x000000, 0x000000, + 0x747174, 0x003084, 0x3101ac, 0x4b0194, + 0x64007b, 0x6b0039, 0x6b2101, 0x5a2f00, + 0x424900, 0x185901, 0x105901, 0x015932, + 0x01495a, 0x101010, 0x000000, 0x000000, + 0xadadad, 0x4a71b6, 0x6458d5, 0x8450e6, + 0xa451ad, 0xad4984, 0xb5624a, 0x947132, + 0x7b722a, 0x5a8601, 0x388e31, 0x318e5a, + 0x398e8d, 0x383838, 0x000000, 0x000000, + 0xb6b6b6, 0x8c9db5, 0x8d8eae, 0x9c8ebc, + 0xa687bc, 0xad8d9d, 0xae968c, 0x9c8f7c, + 0x9c9e72, 0x94a67c, 0x84a77b, 0x7c9d84, + 0x73968d, 0xdedede, 0x000000, 0x000000 } + }, + { "chris", "Chris Covell's palette", + { 0x808080, 0x003DA6, 0x0012B0, 0x440096, + 0xA1005E, 0xC70028, 0xBA0600, 0x8C1700, + 0x5C2F00, 0x104500, 0x054A00, 0x00472E, + 0x004166, 0x000000, 0x050505, 0x050505, + 0xC7C7C7, 0x0077FF, 0x2155FF, 0x8237FA, + 0xEB2FB5, 0xFF2950, 0xFF2200, 0xD63200, + 0xC46200, 0x358000, 0x058F00, 0x008A55, + 0x0099CC, 0x212121, 0x090909, 0x090909, + 0xFFFFFF, 0x0FD7FF, 0x69A2FF, 0xD480FF, + 0xFF45F3, 0xFF618B, 0xFF8833, 0xFF9C12, + 0xFABC20, 0x9FE30E, 0x2BF035, 0x0CF0A4, + 0x05FBFF, 0x5E5E5E, 0x0D0D0D, 0x0D0D0D, + 0xFFFFFF, 0xA6FCFF, 0xB3ECFF, 0xDAABEB, + 0xFFA8F9, 0xFFABB3, 0xFFD2B0, 0xFFEFA6, + 0xFFF79C, 0xD7E895, 0xA6EDAF, 0xA2F2DA, + 0x99FFFC, 0xDDDDDD, 0x111111, 0x111111 } + }, + { "matt", "Matthew Conte's palette", + { 0x808080, 0x0000bb, 0x3700bf, 0x8400a6, + 0xbb006a, 0xb7001e, 0xb30000, 0x912600, + 0x7b2b00, 0x003e00, 0x00480d, 0x003c22, + 0x002f66, 0x000000, 0x050505, 0x050505, + 0xc8c8c8, 0x0059ff, 0x443cff, 0xb733cc, + 0xff33aa, 0xff375e, 0xff371a, 0xd54b00, + 0xc46200, 0x3c7b00, 0x1e8415, 0x009566, + 0x0084c4, 0x111111, 0x090909, 0x090909, + 0xffffff, 0x0095ff, 0x6f84ff, 0xd56fff, + 0xff77cc, 0xff6f99, 0xff7b59, 0xff915f, + 0xffa233, 0xa6bf00, 0x51d96a, 0x4dd5ae, + 0x00d9ff, 0x666666, 0x0d0d0d, 0x0d0d0d, + 0xffffff, 0x84bfff, 0xbbbbff, 0xd0bbff, + 0xffbfea, 0xffbfcc, 0xffc4b7, 0xffccae, + 0xffd9a2, 0xcce199, 0xaeeeb7, 0xaaf7ee, + 0xb3eeff, 0xdddddd, 0x111111, 0x111111 } + }, + { "pasofami", "PasoFami/99 palette", + { 0x7f7f7f, 0x0000ff, 0x0000bf, 0x472bbf, + 0x970087, 0xab0023, 0xab1300, 0x8b1700, + 0x533000, 0x007800, 0x006b00, 0x005b00, + 0x004358, 0x000000, 0x000000, 0x000000, + 0xbfbfbf, 0x0078f8, 0x0058f8, 0x6b47ff, + 0xdb00cd, 0xe7005b, 0xf83800, 0xe75f13, + 0xaf7f00, 0x00b800, 0x00ab00, 0x00ab47, + 0x008b8b, 0x000000, 0x000000, 0x000000, + 0xf8f8f8, 0x3fbfff, 0x6b88ff, 0x9878f8, + 0xf878f8, 0xf85898, 0xf87858, 0xffa347, + 0xf8b800, 0xb8f818, 0x5bdb57, 0x58f898, + 0x00ebdb, 0x787878, 0x000000, 0x000000, + 0xffffff, 0xa7e7ff, 0xb8b8f8, 0xd8b8f8, + 0xf8b8f8, 0xfba7c3, 0xf0d0b0, 0xffe3ab, + 0xfbdb7b, 0xd8f878, 0xb8f8b8, 0xb8f8d8, + 0x00ffff, 0xf8d8f8, 0x000000, 0x000000 } + }, + { "crashman", "CrashMan's palette", + { 0x585858, 0x001173, 0x000062, 0x472bbf, + 0x970087, 0x910009, 0x6f1100, 0x4c1008, + 0x371e00, 0x002f00, 0x005500, 0x004d15, + 0x002840, 0x000000, 0x000000, 0x000000, + 0xa0a0a0, 0x004499, 0x2c2cc8, 0x590daa, + 0xae006a, 0xb00040, 0xb83418, 0x983010, + 0x704000, 0x308000, 0x207808, 0x007b33, + 0x1c6888, 0x000000, 0x000000, 0x000000, + 0xf8f8f8, 0x267be1, 0x5870f0, 0x9878f8, + 0xff73c8, 0xf060a8, 0xd07b37, 0xe09040, + 0xf8b300, 0x8cbc00, 0x40a858, 0x58f898, + 0x00b7bf, 0x787878, 0x000000, 0x000000, + 0xffffff, 0xa7e7ff, 0xb8b8f8, 0xd8b8f8, + 0xe6a6ff, 0xf29dc4, 0xf0c0b0, 0xfce4b0, + 0xe0e01e, 0xd8f878, 0xc0e890, 0x95f7c8, + 0x98e0e8, 0xf8d8f8, 0x000000, 0x000000 } + }, + { "mess", "MESS palette", + { 0x747474, 0x24188c, 0x0000a8, 0x44009c, + 0x8c0074, 0xa80010, 0xa40000, 0x7c0800, + 0x402c00, 0x004400, 0x005000, 0x003c14, + 0x183c5c, 0x000000, 0x000000, 0x000000, + 0xbcbcbc, 0x0070ec, 0x2038ec, 0x8000f0, + 0xbc00bc, 0xe40058, 0xd82800, 0xc84c0c, + 0x887000, 0x009400, 0x00a800, 0x009038, + 0x008088, 0x000000, 0x000000, 0x000000, + 0xfcfcfc, 0x3cbcfc, 0x5c94fc, 0x4088fc, + 0xf478fc, 0xfc74b4, 0xfc7460, 0xfc9838, + 0xf0bc3c, 0x80d010, 0x4cdc48, 0x58f898, + 0x00e8d8, 0x000000, 0x000000, 0x000000, + 0xfcfcfc, 0xa8e4fc, 0xc4d4fc, 0xd4c8fc, + 0xfcc4fc, 0xfcc4d8, 0xfcbcb0, 0xfcd8a8, + 0xfce4a0, 0xe0fca0, 0xa8f0bc, 0xb0fccc, + 0x9cfcf0, 0x000000, 0x000000, 0x000000 } + }, + { "zaphod-cv", "Zaphod's VS Castlevania palette", + { 0x7f7f7f, 0xffa347, 0x0000bf, 0x472bbf, + 0x970087, 0xf85898, 0xab1300, 0xf8b8f8, + 0xbf0000, 0x007800, 0x006b00, 0x005b00, + 0xffffff, 0x9878f8, 0x000000, 0x000000, + 0xbfbfbf, 0x0078f8, 0xab1300, 0x6b47ff, + 0x00ae00, 0xe7005b, 0xf83800, 0x7777ff, + 0xaf7f00, 0x00b800, 0x00ab00, 0x00ab47, + 0x008b8b, 0x000000, 0x000000, 0x472bbf, + 0xf8f8f8, 0xffe3ab, 0xf87858, 0x9878f8, + 0x0078f8, 0xf85898, 0xbfbfbf, 0xffa347, + 0xc800c8, 0xb8f818, 0x7f7f7f, 0x007800, + 0x00ebdb, 0x000000, 0x000000, 0xffffff, + 0xffffff, 0xa7e7ff, 0x5bdb57, 0xe75f13, + 0x004358, 0x0000ff, 0xe7005b, 0x00b800, + 0xfbdb7b, 0xd8f878, 0x8b1700, 0xffe3ab, + 0x00ffff, 0xab0023, 0x000000, 0x000000 } + }, + { "zaphod-smb", "Zaphod's VS SMB palette", + { 0x626a00, 0x0000ff, 0x006a77, 0x472bbf, + 0x970087, 0xab0023, 0xab1300, 0xb74800, + 0xa2a2a2, 0x007800, 0x006b00, 0x005b00, + 0xffd599, 0xffff00, 0x009900, 0x000000, + 0xff66ff, 0x0078f8, 0x0058f8, 0x6b47ff, + 0x000000, 0xe7005b, 0xf83800, 0xe75f13, + 0xaf7f00, 0x00b800, 0x5173ff, 0x00ab47, + 0x008b8b, 0x000000, 0x91ff88, 0x000088, + 0xf8f8f8, 0x3fbfff, 0x6b0000, 0x4855f8, + 0xf878f8, 0xf85898, 0x595958, 0xff009d, + 0x002f2f, 0xb8f818, 0x5bdb57, 0x58f898, + 0x00ebdb, 0x787878, 0x000000, 0x000000, + 0xffffff, 0xa7e7ff, 0x590400, 0xbb0000, + 0xf8b8f8, 0xfba7c3, 0xffffff, 0x00e3e1, + 0xfbdb7b, 0xffae00, 0xb8f8b8, 0xb8f8d8, + 0x00ff00, 0xf8d8f8, 0xffaaaa, 0x004000 } + }, + { "vs-drmar", "VS Dr. Mario palette", + { 0x5f97ff, 0x000000, 0x000000, 0x47009f, + 0x00ab00, 0xffffff, 0xabe7ff, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0xe7005b, 0x000000, 0x000000, 0x000000, + 0x5f97ff, 0x000000, 0x000000, 0x000000, + 0x000000, 0x8b7300, 0xcb4f0f, 0x000000, + 0xbcbcbc, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x00ebdb, 0x000000, 0x000000, 0x000000, + 0x000000, 0xff9b3b, 0x000000, 0x000000, + 0x83d313, 0x000000, 0x3fbfff, 0x000000, + 0x0073ef, 0x000000, 0x000000, 0x000000, + 0x00ebdb, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0xf3bf3f, 0x000000, + 0x005100, 0x000000, 0xc7d7ff, 0xffdbab, + 0x000000, 0x000000, 0x000000, 0x000000 } + }, + { "vs-cv", "VS Castlevania palette", + { 0xaf7f00, 0xffa347, 0x008b8b, 0x472bbf, + 0x970087, 0xf85898, 0xab1300, 0xf8b8f8, + 0xf83800, 0x007800, 0x006b00, 0x005b00, + 0xffffff, 0x9878f8, 0x00ab00, 0x000000, + 0xbfbfbf, 0x0078f8, 0xab1300, 0x6b47ff, + 0x000000, 0xe7005b, 0xf83800, 0x6b88ff, + 0xaf7f00, 0x00b800, 0x6b88ff, 0x00ab47, + 0x008b8b, 0x000000, 0x000000, 0x472bbf, + 0xf8f8f8, 0xffe3ab, 0xf87858, 0x9878f8, + 0x0078f8, 0xf85898, 0xbfbfbf, 0xffa347, + 0x004358, 0xb8f818, 0x7f7f7f, 0x007800, + 0x00ebdb, 0x000000, 0x000000, 0xffffff, + 0xffffff, 0xa7e7ff, 0x5bdb57, 0x6b88ff, + 0x004358, 0x0000ff, 0xe7005b, 0x00b800, + 0xfbdb7b, 0xffa347, 0x8b1700, 0xffe3ab, + 0xb8f818, 0xab0023, 0x000000, 0x007800 } + }, + { "vs-smb", "VS SMB/VS Ice Climber palette", + { 0xaf7f00, 0x0000ff, 0x008b8b, 0x472bbf, + 0x970087, 0xab0023, 0x0000ff, 0xe75f13, + 0xbfbfbf, 0x007800, 0x5bdb57, 0x005b00, + 0xf0d0b0, 0xffe3ab, 0x00ab00, 0x000000, + 0xbfbfbf, 0x0078f8, 0x0058f8, 0x6b47ff, + 0x000000, 0xe7005b, 0xf83800, 0xf87858, + 0xaf7f00, 0x00b800, 0x6b88ff, 0x00ab47, + 0x008b8b, 0x000000, 0x000000, 0x3fbfff, + 0xf8f8f8, 0x006b00, 0x8b1700, 0x9878f8, + 0x6b47ff, 0xf85898, 0x7f7f7f, 0xe7005b, + 0x004358, 0xb8f818, 0x0078f8, 0x58f898, + 0x00ebdb, 0xfbdb7b, 0x000000, 0x000000, + 0xffffff, 0xa7e7ff, 0xb8b8f8, 0xf83800, + 0xf8b8f8, 0xfba7c3, 0xffffff, 0x00ffff, + 0xfbdb7b, 0xffa347, 0xb8f8b8, 0xb8f8d8, + 0xb8f818, 0xf8d8f8, 0x000000, 0x007800 } + }, + { "RGB", "Nestopia's RGB palette", + { 0x6d6d6d, 0x002492, 0x0000db, 0x6d49db, + 0x92006d, 0xb6006d, 0xb62400, 0x924900, + 0x6d4900, 0x244900, 0x006d24, 0x009200, + 0x004949, 0x000000, 0x000000, 0x000000, + 0xb6b6b6, 0x006ddb, 0x0049ff, 0x9200ff, + 0xb600ff, 0xff0092, 0xff0000, 0xdb6d00, + 0x926d00, 0x249200, 0x009200, 0x00b66d, + 0x009292, 0x242424, 0x000000, 0x000000, + 0xffffff, 0x6db6ff, 0x9292ff, 0xdb6dff, + 0xff00ff, 0xff6dff, 0xff9200, 0xffb600, + 0xdbdb00, 0x6ddb00, 0x00ff00, 0x49ffdb, + 0x00ffff, 0x494949, 0x000000, 0x000000, + 0xffffff, 0xb6dbff, 0xdbb6ff, 0xffb6ff, + 0xff92ff, 0xffb6b6, 0xffdb92, 0xffff49, + 0xffff6d, 0xb6ff49, 0x92ff6d, 0x49ffdb, + 0x92dbff, 0x929292, 0x000000, 0x000000 } + }, + { "Uns-v6", "Unsaturated-V6 palette", + { 0x6B6B6B, 0x001E87, 0x1F0B96, 0x3B0C87, + 0x590D61, 0x5E0528, 0x551100, 0x461B00, + 0x303200, 0x0A4800, 0x004E00, 0x004619, + 0x003A58, 0x000000, 0x000000, 0x000000, + 0xB2B2B2, 0x1A53D1, 0x4835EE, 0x7123EC, + 0x9A1EB7, 0xA51E62, 0xA52D19, 0x874B00, + 0x676900, 0x298400, 0x038B00, 0x008240, + 0x007891, 0x000000, 0x000000, 0x000000, + 0xFFFFFF, 0x63ADFD, 0x908AFE, 0xB977FC, + 0xE771FE, 0xF76FC9, 0xF5836A, 0xDD9C29, + 0xBDB807, 0x84D107, 0x5BDC3B, 0x48D77D, + 0x48CCCE, 0x555555, 0x000000, 0x000000, + 0xFFFFFF, 0xC4E3FE, 0xD7D5FE, 0xE6CDFE, + 0xF9CAFE, 0xFEC9F0, 0xFED1C7, 0xF7DCAC, + 0xE8E89C, 0xD1F29D, 0xBFF4B1, 0xB7F5CD, + 0xB7F0EE, 0xBEBEBE, 0x000000, 0x000000 } + }, + { "YUV-V3", "YUV-V3 palette", + { 0x666666, 0x002a88, 0x1412a7, 0x3b00a4, + 0x5c007e, 0x6e0040, 0x6c0700, 0x561d00, + 0x333500, 0x0c4800, 0x005200, 0x004c18, + 0x003e5b, 0x000000, 0x000000, 0x000000, + 0xadadad, 0x155fd9, 0x4240ff, 0x7527fe, + 0xa01acc, 0xb71e7b, 0xb53120, 0x994e00, + 0x6b6d00, 0x388700, 0x0d9300, 0x008c47, + 0x007aa0, 0x000000, 0x000000, 0x000000, + 0xffffff, 0x64b0ff, 0x9290ff, 0xc676ff, + 0xf26aff, 0xff6ecc, 0xff8170, 0xea9e22, + 0xbcbe00, 0x88d800, 0x5ce430, 0x45e082, + 0x48cdde, 0x4f4f4f, 0x000000, 0x000000, + 0xffffff, 0xc0dfff, 0xd3d2ff, 0xe8c8ff, + 0xfac2ff, 0xffc4ea, 0xffccc5, 0xf7d8a5, + 0xe4e594, 0xcfef96, 0xbdf4ab, 0xb3f3cc, + 0xb5ebf2, 0xb8b8b8, 0x000000, 0x000000 } + } }; //CAK: We need to know the OUT1 pin of the expansion port for Famicom 3D System glasses diff --git a/source/gcvideo.h b/source/gcvideo.h index 9b6becd..43bb999 100644 --- a/source/gcvideo.h +++ b/source/gcvideo.h @@ -13,7 +13,7 @@ #define _GCVIDEO_H_ // color palettes -#define MAXPAL 13 +#define MAXPAL 18 struct st_palettes { char name[32], desc[32]; @@ -49,4 +49,4 @@ extern bool shutter_3d_mode; extern bool anaglyph_3d_mode; extern bool eye_3d; -#endif +#endif \ No newline at end of file diff --git a/source/gui/gui.h b/source/gui/gui.h index c1ab877..32e5461 100644 --- a/source/gui/gui.h +++ b/source/gui/gui.h @@ -123,6 +123,16 @@ typedef struct _paddata { u8 triggerR; } PADData; +typedef struct _wupcfulldata { + u32 btns_d; + u32 btns_u; + u32 btns_h; + s16 stickX; + s16 stickY; + s16 substickX; + s16 substickY; +} WUPCFullData; + #define EFFECT_SLIDE_TOP 1 #define EFFECT_SLIDE_BOTTOM 2 #define EFFECT_SLIDE_RIGHT 4 @@ -226,6 +236,7 @@ class GuiTrigger WPADData wpaddata; //!< Wii controller trigger data PADData pad; //!< GameCube controller trigger data + WUPCFullData wupcdata; //!< WiiU Pro controller trigger data WPADData * wpad; //!< Wii controller trigger s32 chan; //!< Trigger controller channel (0-3, -1 for all) u8 type; //!< trigger type (TRIGGER_SIMPLE, TRIGGER_HELD, TRIGGER_BUTTON_ONLY, TRIGGER_BUTTON_ONLY_IN_FOCUS) diff --git a/source/gui/gui_button.cpp b/source/gui/gui_button.cpp index a6941e5..89693af 100644 --- a/source/gui/gui_button.cpp +++ b/source/gui/gui_button.cpp @@ -254,7 +254,7 @@ void GuiButton::Update(GuiTrigger * t) // button triggers if(this->IsClickable()) { - s32 wm_btns, wm_btns_trig, cc_btns, cc_btns_trig; + s32 wm_btns, wm_btns_trig, cc_btns, cc_btns_trig, wupc_btns, wupc_btns_trig; for(int i=0; i<3; i++) { if(trigger[i] && (trigger[i]->chan == -1 || trigger[i]->chan == t->chan)) @@ -267,11 +267,16 @@ void GuiButton::Update(GuiTrigger * t) cc_btns = t->wpad->btns_d >> 16; cc_btns_trig = trigger[i]->wpad->btns_d >> 16; + // lower 16 bits only (WiiU Pro controller) + wupc_btns = t->wupcdata.btns_d >> 16; + wupc_btns_trig = trigger[i]->wupcdata.btns_d >> 16; + if( (t->wpad->btns_d > 0 && (wm_btns == wm_btns_trig || (cc_btns == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) || - (t->pad.btns_d == trigger[i]->pad.btns_d && t->pad.btns_d > 0)) + (t->pad.btns_d == trigger[i]->pad.btns_d && t->pad.btns_d > 0) || + (wupc_btns == wupc_btns_trig && wupc_btns_trig > 0)) { if(t->chan == stateChan || stateChan == -1) { @@ -303,7 +308,7 @@ void GuiButton::Update(GuiTrigger * t) if(this->IsHoldable()) { bool held = false; - s32 wm_btns, wm_btns_h, wm_btns_trig, cc_btns, cc_btns_h, cc_btns_trig; + s32 wm_btns, wm_btns_h, wm_btns_trig, cc_btns, cc_btns_h, cc_btns_trig, wupc_btns, wupc_btns_h, wupc_btns_trig; for(int i=0; i<3; i++) { @@ -319,11 +324,17 @@ void GuiButton::Update(GuiTrigger * t) cc_btns_h = t->wpad->btns_h >> 16; cc_btns_trig = trigger[i]->wpad->btns_h >> 16; + // lower 16 bits only (WiiU Pro controller) + wupc_btns = t->wpad->btns_d >> 16; + wupc_btns_h = t->wpad->btns_h >> 16; + wupc_btns_trig = trigger[i]->wpad->btns_h >> 16; + if( (t->wpad->btns_d > 0 && (wm_btns == wm_btns_trig || (cc_btns == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) || - (t->pad.btns_d == trigger[i]->pad.btns_h && t->pad.btns_d > 0)) + (t->pad.btns_d == trigger[i]->pad.btns_h && t->pad.btns_d > 0) || + (wupc_btns == wupc_btns_trig && wupc_btns > 0)) { if(trigger[i]->type == TRIGGER_HELD && state == STATE_SELECTED && (t->chan == stateChan || stateChan == -1)) @@ -334,7 +345,8 @@ void GuiButton::Update(GuiTrigger * t) (t->wpad->btns_h > 0 && (wm_btns_h == wm_btns_trig || (cc_btns_h == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) || - (t->pad.btns_h == trigger[i]->pad.btns_h && t->pad.btns_h > 0)) + (t->pad.btns_h == trigger[i]->pad.btns_h && t->pad.btns_h > 0) || + (wupc_btns_h == wupc_btns_trig && wupc_btns_h > 0)) { if(trigger[i]->type == TRIGGER_HELD) held = true; diff --git a/source/gui/gui_filebrowser.cpp b/source/gui/gui_filebrowser.cpp index c989fd2..42edebd 100644 --- a/source/gui/gui_filebrowser.cpp +++ b/source/gui/gui_filebrowser.cpp @@ -108,12 +108,12 @@ GuiFileBrowser::GuiFileBrowser(int w, int h) fileListText[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff}); fileListText[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); fileListText[i]->SetPosition(5,0); - fileListText[i]->SetMaxWidth(380); + fileListText[i]->SetMaxWidth(295); fileListBg[i] = new GuiImage(bgFileSelectionEntry); fileListIcon[i] = NULL; - fileList[i] = new GuiButton(380, 26); + fileList[i] = new GuiButton(295, 26); fileList[i]->SetParent(this); fileList[i]->SetLabel(fileListText[i]); fileList[i]->SetImageOver(fileListBg[i]); diff --git a/source/gui/gui_optionbrowser.cpp b/source/gui/gui_optionbrowser.cpp index 3e23d33..9665706 100644 --- a/source/gui/gui_optionbrowser.cpp +++ b/source/gui/gui_optionbrowser.cpp @@ -79,12 +79,12 @@ GuiOptionBrowser::GuiOptionBrowser(int w, int h, OptionList * l) optionTxt[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff}); optionTxt[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); optionTxt[i]->SetPosition(8,0); - optionTxt[i]->SetMaxWidth(230); + optionTxt[i]->SetMaxWidth(375); optionVal[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff}); optionVal[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); - optionVal[i]->SetPosition(250,0); - optionVal[i]->SetMaxWidth(230); + optionVal[i]->SetPosition(400,0); + optionVal[i]->SetMaxWidth(300); optionBg[i] = new GuiImage(bgOptionsEntry); @@ -313,7 +313,14 @@ void GuiOptionBrowser::Update(GuiTrigger * t) t->chan = currChan; if(optionBtn[i]->GetState() == STATE_SELECTED) + { selectedItem = i; + } + + if(selectedItem == i) + optionTxt[i]->SetScroll(SCROLL_HORIZONTAL); + else + optionTxt[i]->SetScroll(SCROLL_NONE); } // pad/joystick navigation diff --git a/source/gui/gui_trigger.cpp b/source/gui/gui_trigger.cpp index 06a4165..b074aee 100644 --- a/source/gui/gui_trigger.cpp +++ b/source/gui/gui_trigger.cpp @@ -22,6 +22,7 @@ static u32 delay[4]; GuiTrigger::GuiTrigger() { chan = -1; + memset(&wupcdata, 0, sizeof(WUPCFullData)); memset(&wpaddata, 0, sizeof(WPADData)); memset(&pad, 0, sizeof(PADData)); wpad = &wpaddata; @@ -43,6 +44,7 @@ void GuiTrigger::SetSimpleTrigger(s32 ch, u32 wiibtns, u16 gcbtns) { type = TRIGGER_SIMPLE; chan = ch; + wupcdata.btns_d = wiibtns; wpaddata.btns_d = wiibtns; pad.btns_d = gcbtns; } @@ -56,6 +58,7 @@ void GuiTrigger::SetHeldTrigger(s32 ch, u32 wiibtns, u16 gcbtns) { type = TRIGGER_HELD; chan = ch; + wupcdata.btns_h = wiibtns; wpaddata.btns_h = wiibtns; pad.btns_h = gcbtns; } @@ -68,6 +71,7 @@ void GuiTrigger::SetButtonOnlyTrigger(s32 ch, u32 wiibtns, u16 gcbtns) { type = TRIGGER_BUTTON_ONLY; chan = ch; + wupcdata.btns_d = wiibtns; wpaddata.btns_d = wiibtns; pad.btns_d = gcbtns; } @@ -81,6 +85,7 @@ void GuiTrigger::SetButtonOnlyInFocusTrigger(s32 ch, u32 wiibtns, u16 gcbtns) { type = TRIGGER_BUTTON_ONLY_IN_FOCUS; chan = ch; + wupcdata.btns_d = wiibtns; wpaddata.btns_d = wiibtns; pad.btns_d = gcbtns; } @@ -157,12 +162,15 @@ bool GuiTrigger::Left() { u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_UP : WPAD_BUTTON_LEFT; - if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT) + if(((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)) + || ((wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)) || (pad.btns_d | pad.btns_h) & PAD_BUTTON_LEFT || pad.stickX < -PADCAL - || WPAD_StickX(0) < -PADCAL) + || WPAD_StickX(0) < -PADCAL + || wupcdata.stickX < -WUPCCAL) { - if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT) + if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)) + || (wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)) || pad.btns_d & PAD_BUTTON_LEFT) { prev[chan] = gettime(); @@ -190,12 +198,15 @@ bool GuiTrigger::Right() { u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_DOWN : WPAD_BUTTON_RIGHT; - if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT) + if(((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT)) + || ((wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT)) || (pad.btns_d | pad.btns_h) & PAD_BUTTON_RIGHT || pad.stickX > PADCAL - || WPAD_StickX(0) > PADCAL) + || WPAD_StickX(0) > PADCAL + || wupcdata.stickX > WUPCCAL) { - if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT) + if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT)) + || (wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT)) || pad.btns_d & PAD_BUTTON_RIGHT) { prev[chan] = gettime(); @@ -223,12 +234,15 @@ bool GuiTrigger::Up() { u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_RIGHT : WPAD_BUTTON_UP; - if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_UP) + if(((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_UP)) + || ((wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_UP)) || (pad.btns_d | pad.btns_h) & PAD_BUTTON_UP || pad.stickY > PADCAL - || WPAD_StickY(0) > PADCAL) + || WPAD_StickY(0) > PADCAL + || wupcdata.stickY > WUPCCAL) { - if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_UP) + if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_UP)) + || (wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_UP)) || pad.btns_d & PAD_BUTTON_UP) { prev[chan] = gettime(); @@ -256,12 +270,15 @@ bool GuiTrigger::Down() { u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_LEFT : WPAD_BUTTON_DOWN; - if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN) + if(((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN)) + || ((wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN)) || (pad.btns_d | pad.btns_h) & PAD_BUTTON_DOWN || pad.stickY < -PADCAL - || WPAD_StickY(0) < -PADCAL) + || WPAD_StickY(0) < -PADCAL + || wupcdata.stickY < -WUPCCAL) { - if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN) + if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN)) + || wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN) || pad.btns_d & PAD_BUTTON_DOWN) { prev[chan] = gettime(); diff --git a/source/gui/gui_window.cpp b/source/gui/gui_window.cpp index fd5e785..636d8ba 100644 --- a/source/gui/gui_window.cpp +++ b/source/gui/gui_window.cpp @@ -228,8 +228,8 @@ void GuiWindow::ToggleFocus(GuiTrigger * t) } } // change focus - else if(t->wpad->btns_d & (WPAD_BUTTON_1 | WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B) - || t->pad.btns_d & PAD_BUTTON_B) + else if((t->wpad->btns_d & (WPAD_BUTTON_1 | WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)) + || (t->pad.btns_d & PAD_BUTTON_B) || (t->wupcdata.btns_d & WPAD_CLASSIC_BUTTON_B)) { for (i = found; i < elemSize; ++i) { diff --git a/source/images/bg_game_selection.png b/source/images/bg_game_selection.png index c92c6fa8f2dc141e140f8914ab143c2086d41e1c..751d94f68d16a13b033f79f79b0bf3a22e38ee6d 100644 GIT binary patch literal 1432 zcmeAS@N?(olHy`uVBq!ia0y~yV6+BeP7XGp$m_g@L?FeM|H(?D8gCb z5n0T@z%2~Ij105pNB{-dOFVsD+3$16vGN;mG&JsKU|?1Cba4!+xb^myea0MCiQ^yd z$4<_kyu~v*YL#HH)75WTT(WtSoCEOu&yxCTs+G7VU+C$^-ynXjpv)zZB% zSi{^SxY*k()9deasYNQelV)8xx_ysZ_Vt)QHQSz7-hU~%Z;yM>$=WT^Ul)72O@70B z;F$5`lwB9!`24@_J++!8uX<9ainbu4u(PkC>spYrX+&1SPZ~Stl%vy27!!>t)DSC5H-(2+i`2Mw%=j51J%l}gb zsqIx+-o0~MZoHhF_0+k)=au*-9Nt~{_H)eMA7PbSXFa*;w)ykZyEnE*e?9D}r*?Ca zO11mE(;pUwU%G7lq{-p>j-R(f()9LDKKk=ylIip(7u_}+hyTqk+{JPCz`DhfmPUFd z4%c7GTh00Fe$RJp{*H*ZexIr)h1_2I%h_|D=DePsxkZKxvcK}mo%yHy`03S7m6d9i zasO7mmbZBlsmCv7dHpxJ6MXxr z(}86dc9;5B)+~tn)8aeHE47=OakkUaThVgaq3VqP_>b@jSTk&7Mk9{!IlN)OAkY*+ zx!6KWIe4eled&dDnb zzLRH`e&4jGV(Xr|wHM#aiIm?RHEI1M8SVW$vwyt&l50QV-rDLI;Tr|h^5f25I#lwk z{$JJK#hZK6o!bj9(lTIi7r`SlDS7^N?vBI zXHKx^?cA(Q=U$xqq`YKJ+UBYcl@Gkjo=uN=_9=1G%_)Ae_eG;_NT-{e3t(utwyJQM zbg}o-=r{R&#VY6O9x^WI6_D*NHaU0cRD0~|KL;Kco;ydJt*HZtqZ`9E3fUHHy7{&Tg%`sY7#q;5#Nee3DwXUM(1qg3b4 z-sf8bUP_;fe))F}^GjE*3v&zSo$+@olP^kQSTlRyzu(C%$GW3`7dOc1-m5eF_P!*F zVa@7)3u`}$mAHRiC!DUs`eNQQa~``lQy5;H@y$40d-Q1rSHS1Zc27?=2s15Et}^2h zn|?dEVb|wXA+O4u7)o4Lu3o-lO^Kxt!#{2&mIek!1qTKo;t&8KCKez9ia~_2i6JS4 zt3whS2HJtX!Qml@FlrcKC>^5Ohf-u7xF4`yUwpc^ro;8mS(PiFwJ^NsxG%0RI(@UI zLvUqi^o&AKI?sKWQyA&X_)Bel-QEwLJ1UdUX)a_V` z{q*~#LBL$~IlWJ0x_tYwYKN2BmEV`oEI;&SC;uEVhFtIZ=zzHr|39-`*&y+}_lpwy zi*AeePnTakdH7-b`uTnK1~0!bL`=T_%&%>wuz%~#SM5jNmOPy4r|-4A@BOLSQ!VBn zzZw4LT;oG^r~A)j7p5OxaG7PnQt9h@Ew>Jp%=rKF^wj>oqm_30r&`%xMt$*^GyUlYy7s^FQ&R-I;{<{zT)Vcrw diff --git a/source/images/bg_game_selection_entry.png b/source/images/bg_game_selection_entry.png index b1842c21041f3ceacdf8d528fea493138d061afe..378a82e88a29d4ee88145726b7061c29396691f5 100644 GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0y~yV6+CZr8wAt#WAGf*4rx^Ia?S+SP!mW z(Rq{AEHR_}dY3L|nS%IijzfuA^8GV~%x*lpu|Jxz<@KtpiHsfd@21ZRW%!hSoqsWx z!=5mv18*44@Sza~)(o4OF$kcdO{M4mhcKR)f4BB;2+)l1(A7K+yTtFE;9`_vi`oTr O6oaR$pUXO@geCwH*H&Qw literal 268 zcmeAS@N?(olHy`uVBq!ia0y~yV4MJC%W$v(N&j6hZv!dG64!{5;QX|b^2DN42FH~A zq*MjZ+{EeIAkr3?aKuS@2dC2MV$GbB5BLsU||6vVtD_KepLVUt1g1Mp~fNZ{81@}C(N5>pJ8-ZX{EG=!C{uN f6@&dv772zoz5bP0l+XkK3(`{8 diff --git a/source/images/bg_preview.png b/source/images/bg_preview.png new file mode 100644 index 0000000000000000000000000000000000000000..3cae25869361046bc54ff95a4dee583f42ce3c5a GIT binary patch literal 20416 zcmce8Wl&px6eaHNh2R?83GQB;LUAa?TOhawcemnFv_NSnQrxX*kOHN+7c1@oHviq( zZ~J9uc6KsM!poZ{_gy*n-1AGEuC^*Z4mA!E5)!_;nvy=^{RIgL85;`&@yV>|JOJ^A z@lI1!39%XRD(R}qKy1NwS2OWMLc%5e?++O%uYd}%5z|XuOBr(m4IhnKY<3$YhJ?g` zq^=}y==bNiYc$1fG;8lxsAC|%7}glrs;Z=7ukxNhL!B*#)5!bt%-??`@%l~`$|p@T z8n{l3a=4#oNYJjdX|Rc|bR35;s1?N8+uJ+hvtA2|vj_?9x!;~K2Kj_s(oQtBW~|;y zC46nmamB<7xWlEl>V_Q`oCfVnhFcLA!#AE6!1U^r(D zbwhcPJX58(68!*Ip+|Y4JPQfBdQv@yqP?)ow!S>}zM!r&zzXqctm5vd?%ZS_p37i8 zWbpqE`GO6<-Lst^{#aAj(fa%~80X{fJN#JddRYBqfwjAC0M#A63}W|}K$QQrJ086D zIJl>MaCji3?`l@|2domGrY8*C@c7d3bonwA#DVdAR(2};uqb{fd*Anj*$YF)wBB3@ z893~CVg4p&S1eB>3W+ESxfho#eu7@{LeiwYFjgM_KBi2)f9UNQ3ti8-muTs};o~_& zTnUa+@F8-()#Lh^OYM?kWA6(Z!+%E=*&u8PX}dnN`t2|godnhW_2;zyzB$B6=1LWb z0otpx)Wi0|g{O0Iw0|N9unxCMTC z^@z7re@>1M6?E(F;BL&Mm%|#7Q55|Uq^zh03tG&+0e-jHwvR^d!Ka~sBOXEhMvKkB z|NK{!`|jiKdYeACfoObO2#x56w`a@sHUr`7(f{vv{r_^3|Kp`oz;A&67k71+k6YIq zO!5Jq6ys7H9`c)5SwIiKh;#sIO^zVymk~f1t>>_pu#BiexP&n|E>cM&Y`a~J@gky^ z4(q?~n21$~ZK%>6;M7DVO$tLqTh8kkFG1_p(Vy>zvv7JfC0?gSWUgx zD=b{~yJ7ga&+CzfR@w4}bV$nPA!v@m2QRwde$q(!P&Oc8c_t`X3Cn356>-WJ_plc` zv8U|Sr}AE%pU8!>4AYKVAhvk&NNS)`01>G5n@b}y!UaN#dsF&}yijhoruag6HI#cr z#Cv|OVQn+V_vF7oy?m%xSfiO)zwIym3q$Wo>M_`eVYDGDZRS`#K{90#6SE~MYJHr; zRC;zr39xZT9-^e(#}-c0@Iz5+LetJ8R|B3fTKBnayYbAYH2AE&FDydXWC=?iIF=3uy+DHBG8!hKzm~e(2K9YZj*c>z=I$_W` zMY-4JXSN$tNEQ+TXpR;D?sj-rrqQ4VsWP!b=zajUDuW#a^q;?GV%Hd&cwBk-b0paVA5F4yveBl@>(QrlLzD`1Kj(iFQhv7QHV?`VeuFWQBSs zPeeuatA`Dqv}{6kie*!NrCgmF@+R2AJ5|OqNbQ{R^GMt9)_RtrEH!hGU!Ps*@Gp%Rp-(raEQVhlQCftTKIH^eE|m1gf;2c3N4(tuaYwEGxBvMSe#bfPhEA%> zyRXR(oh5v-gG#i}Bu(>7x0@pwLPgCI`3hM@k475RuIDW9Or+^tF35i_A z8d-lV5+nL-njsvgdw+>C3jJjg36k3Qu=J9k@GWEJrqs|Po1SD>SQ;}3B1DNqzU_cz z>)i!J(U7;2@gJ5z+Jk)rfczEGE-^Uy6eHy+z8s%AIT4`~2V)nV8mNn-*u*9va!`nf z{u6^5OGkyUMdp(KC8yY+xcVV)e3=5JNSBOTNXHO zb`P{N2X>EoEw5*Gr638NgOT@r74fA=c9z!;qp`dpT_p03EZh=|XtVnA`@5=Xj5)cH zQ$ko3WExIe9PdClL@4GXeV5WT^VFi0h%-#G+=fpd_iLpF-3N0u3U{}vE5|{Emi<9U z3RsOu36ZF}P_t`H*R6KQ0ls_B?dCuXS&1rJ~Oy#7feXf9pUZ6&rL zqeSZZzXy6OPzBkuhO%{G0$I-ECyw#+Vlw8WdG%)1J$y6V*}94AbMztArv(MQRvvq`G&(}a`b5zJUC*i6l9&^d!b>Y}9h_{^G%DU*qfx*^ zMtTWRqUBSo&f?EsTkV&S`iIm>wYjBlZ~amF9OS7DAXrdq5W~PuQv-bqla)pw7+Fnl{~5i|KkoP1c5;xp;4RUFf~XAG#Vn56&L1 zMV5U!7MOe>xDH6ltrl$*5_;X7FHEiVxYe}rvaEHj3Ovj3$@%H_hkJM4G`p9Jjm?t- zjPmd&e|=(pgubeLjLTLxv)5=0?%g+$aGqzqLc!v2H@?!v2vU=GwWrHCK@k8mB))tI z*KQfl&kzb{*f~55Jy zZ{2Uo8uXX-pc+|f^u>Bp?95F2ue|gb*IK>bT0NSHNI9i5zLGj=xLK}aZyJ@u^sx*_ zX&uciI4*8J`}3iK&;pW{QPGgEFdb0$M!I+7Ml-G5ik-{jSWp7@Zi0Jnj+oa%d=oGU=}I%lG*OmC z5TV62!l4$*Hw?O)O?c9@w7SR7t(Y$@nI7}%Ov6aDJ3v3vv;sM;%5SZ*v+-IQ;&i6Z zs%Gote7(`>Uin?Gn_JD5MfGR;o^svTO0re=J?(A?6#?Q2=^(3rCGq{7d+$G;C*PA2 zZyP>?bpYb1NS9dmjw}1kpf*RZu2EVK8@pg~TLUl`4rcV;2AeMqT}qdyBEZyhgV^&I zuNfC1i^XWsZ{^)0ebwU#_rujgD%<(ZIOYmb4rjz^Djg399j$F)!JLvAKBgsWZsVnW zCn2qibKus7A16qqG?~5fEFtRwAdDtem* zH_>pyou7d!$x%m(akX4n*O4V$KBU(yzZUH~OR{1qRXBg8EEQ8^FBnimUTj|*$4rZ; z=snbT1ATx0XbQ3S;capSB!-EF=C|~Dea8Mt>oI{MgWfc~`|QWtNK1N!%O>8Hp0xPe zUqBm}xzkIED$@pW+uC!0BlU4VdKaZ(eb%$R*-75MxG&>#f5Ita7!(HlEF!ck04Rhq z0}dzIuI&@X8-;}9olU6+<>s@$*13^j*g)>$xgW#c2!!;ZQQqd?TjW*%5`S4d@*m+dFvGk6@R?6&? zjiaZd6&1tmuJFnZfyYmpv6A#J?5F1TC6ufwX<%sY#gpuF>&C@lynR>y@d|+5A=|56 zdI|>1_+>t}B{!cr`=~@(;s~2S%A2tcHHzoQTQWBr1b3G1I=eIEh10}ksU#_AM+lW4 z>7Gk*&f_EnY;y%8AuhFD43b*@fZkGd327F6`-pvFQQ0u=b{@XVM+hr-e`Pz9_{}8O zS_n%;pmK~WII^0Wg!-xC2r|ebP(6t!uk-rVUin6=0srm*lL6n}ALWm9Bqdp;>qnPY z=b8X|SGU!zsXgg{r%>Z%NdO(KL9H=vI)5-hmOy&>Y?d9QBE7TTA|~qoe(P*<3IR@P z%eicKge7PU?BeHsy;4kEK6RJtjLid|y24orn}d z{9)@X&(MQO$_=h|d{*G(Z$h`JD;L|>ek<3;IhZ+1e}t$)1XMio3RKhHXXf1>WUF=e zT7!DMH|bw8LI%$d#9>9!`|~%vTwDpAk2h>?Jz*$6MwbBI#-#cuBDwn>7><%d)pf6K&8FATWz2EobIpbFsnR;co0ycvd z$IC*{k?_Al29BN#juRp-a1WR?GMkpv)o)v68tsH%HOq26RF8#MA~n)Bo~jPB0^v#Q2c6z_kGPY);#AT*<;1{ z{o5oTk}vW@E=$Es3mLZ4Ev@IVDM0HT+Qh5nT7K+u_&q;UA6NqQeiE2-$@np+k*$gU z%?d>jGQF!n|2avtq?-Jv>(z$qk8 zmu07)Iy7+fWSNE=`jtdA{3#;XvMWdgK(eogSH7V2bkUnoBEo#b-(@{7pKt9T`7>{ zbDjO`bT8KilE@KUd%U4*k8QoMuUiD;3nmm`n-y@g|F(0H z`hh(M0Mf_d<>Ni)A_%#&dNB@qzPFWmy7J7^DsG+^>As)5eU-!{6LOWaTBws_R$y!A zpBs4luc4y@Hn%T{b)J5mW!HUk#!I-};`b1g-+sz3)RU+of?}%k{7(IqZfb}E8P5dA z-^SL~=s?utpFDTaxIXtBBzl8qQ@WW+m*uakJn=@KL|t)X9`l5=^ zL`i4E^zkhYiE@L_IKOm80-Gc zu)aRVZ`)^QUB1}ishb=-392bzi|nX2V2z6=2YyvmHh_+fG0Hml0brj`~AXCIpBy*s)z@7qAvC~F+{z|-6MjsMAtiqvO# zd%IDv-;Xij2y3({_={G*PRbh7)n-RuuLs80fCCx!AiHb_3Jn2`M-$3&f7EOV%dQHl#mPD%4P3Q#>RJhs`UKSDpCPg=p9g5JBVxE zP=y`j(HD~6n4yV?im9m^UNbWqze~?V6`S;riCJ&@IV^_l#!PE>Je9U6t@}a-Lf20T zHKv;Prn@xyvcxB2XN$Nj#zrr{(b)lyLDCFOKgZF%@g0oY9h#}QCeZDub<8`?=5|`f znR|CpR>__yvcl*{flg)N(;1yex~}I*qk$qy;KBPP@rX^VMf|&sh#0)+(SpHkzM>6( zy2RN@VlV~pUS~hgT){m|evt0vJj}$cW-VfBEc`%MCa!T562mI?+(U^=`ze{~~SK6-`A3b2! z%^SLRa;<}s3=8b^=Qxk_V)>|@&}3rI#_Dh%MK$#xp2@BCM13Okp(46)&%`!Gv> zD*U#P7nu{E{I|detwju?5%xi^rILY_P;vWot0vNfT2cScRzgt13X$%LNr`}l1sFj} ze!vnSC6rG$RCr=*?S$HG;Ox`!JgG+*$=TW51 z#OOJ8G2}tW^h6@RMKq_-%33%cBrdbpX!V@fRxNr&*w20LKj(K@O?rxihr}?A8Y#V;;G%VH zssl3Lw$E2jgR`fGSc{)7h>K3YH*~(PvmEiZhy+m19*tg`wo$*ODlZUctr{T<9-^S1 zJ7(8JwJ@=R*c634KfYud^ZEMU1ks#tvAS@LPfYThS-~$uhQ}!- zr2>B>5kcQtSlHWu!?Nbr`)*nF$~krhGvr{AQg#((D%Cr6%;u4i0d)ao0EjE#?lA({ z*x0y&Oa!&2t<||8Zm!z2!V@A7P??y7&9xndZlBe;1!rW;8H8`fip9jJi%&Z@)bppj zwy=-q{Y}N+Yyxt4`)gOTKs}^DN^<7U+4QfB1*=6W!q=u)pN7x^5~n+-dts{@B>k9Al_Y zYDY(j2;o{_4F7A4Kuf8>Q8=8e_9%Z)59Gu9iefWoxNPXOL>+{+2qscsiW=-dPG6(J zeb(dGK+5l-62=M3sQ6Z@W~*g8eynnAZq5L9oNUg>*JgdVdbXA;n<-iPAV{tgu~1N4 zd|8$vYZGi+m{nm1kd;QeFbc@Uo1m~{k^RK6TEMoOogbPf6Q)qs#BsfwkY}FQb>@BE z3}orv#?)6Q;`o+7Ls@ZA`Qc}7d{C3hP&_5f%EKExyxQUGw|~+?l&rab5f6jh$1+gW zH-GOdZ2957inBV-MHl>>*;hZlH%#5)=C*P7roE7tugJ}FscmE7fzzc{^R*UiM}-!< zYI4TikBX0+;+1bRW&v`*pU_Qr zHNaq#y_rfKm!1Y|ZUjaJX@pvZFm6J^*E;C=J)g|JgBxVHzaK@YvGJ}uWg9dkUxuqA zQ?2}s?icBChZBi@DmwasF;VO*s`8nCW5Ra|x@xJ-@^a3FATZEE0 ziINQwa{*S5e#JU{y;sD;qZkhS2~s>aXW+q@c(kFGn=f`a%PVQK5X=A@LM4YKxPFC%TB~Qh%yZt>1`L^P($DwYRMz4n<48j) zT|bQ=nwXjrlom-+A;w^|3Oc81+E`n5o5^!#uT!YNnZ?Oitx}RX6lji*la$uJcZy&p zTJ$0nOq=>0&r{bhD_6lQm57g#^bvciJ84#3Lz+t9udj)v<$Hhc+}Z>#$o;tLRXgnu zQ8B;$H4C^#($t$6g!_X7e8z?msIX<>i@E*w=*I-a@js z2gIZx@Jx;7{);i3>wtGMz;f=%hm`z~PoJKgENZ~b0z?cN*R8D!PwX#s4LfpH+keF= zOvz)?MHf8mthkKw-VPmiLk2RcU?wJ}?;+r{|K^G27MACKXKa0LZ*ubs?VOzApuuM% z;d;H4DRh?yRk98U)Zk!$)-pe3>Dyb?mWmQ#cQG!*qeznmV97jTX_AL+{ zD^8!dN|n8-s!AV;h8x6G2pC`G(Gco=D9J}86($49U%ZeDIwSRzo2I0UxPUTJxB9R4s zQVinUGv>!Y=>0~-E!9z z|HY31&~|VBy`v)M`edBl>gkY?v2Bp&jR}KRJp~ zxrl2t-XHm+-!FDfg&}KD>5}uDV{=a7o6xP}t3>)>xBv|e4L1+Z<~^O>A0WqT5c})? z@q>2JmQCvP!p?3nPTIPp-P}_5ozdl_s9aUo<+><6Q8LUjFTfN`+eu^@-Vt(3pOfe6 z5$Kr_L%6QU+y;`}hlSi>n*x9Q5cNAcku>BK`7dc(b-sVu2$gIRTl)RBY{psO82`7d z)J{f9NdJl1_}98_9Ws?gUZ5DJH(PPU4rby2)<_yCS&=C6SIrw&XVA+kJr5lDj3=~u zXuV9}>8#eb-=D6qR@0Dd-!Oiw5f znGLzlD8I09@%Z?k;9u`A3pFckfiW%rI)~Ptk(ZYx%?pYV4*J&IbZ2uQM)>f0&{A{% z4Ne|-WTzo3Kn5>s$J;Bwcw%CTC|cq6eC&T~0R#*TJ_f-$1gv|c9tf}aWXIQ@7R9#q zDCO!bVc8#9`0R7n-_D+YSuigJ?ZB_l7+Lxpm74Vx+nt{3MyM@H|1Rbyu#;DorBs&# zmpu+=Ws* zT@G_aG#Jza1L+qJ6XLqsqw>>CbZ#GmDfajL;8(Apw}i3GLl+k)>(4i;cn_!&U37fK zZkJaFp43Uyr#&yBeb!1u(SYNg&9e=BJu)z&>76>^!RU)^oD-VTft_*D<(su6Osf3> zAc(@^j~*uc3ToeYC7bfSn?8X^sIMi dz(hXmMvYMk@jjw<7)UT5g_md?y9A$zin zacxoTS}31!-f8(fapaUmEtkjFpGcNk5hqoVkT2Ae%Swt09IDIjM09Uy`uswYBfqYM zO7OPW?3rPW;uXRj*|`;g+<=vpaNsnOGXC_|#AI*t@sv1PU}QuUeo*`@eyx(! z+)Ta(dE`~gcC8witK$3X1%12z)*;yY6`+4pegW9c$w-@;)Ggys8H+Ww zP3FhS%`e`r97$4pL^faCJ%*!g!8tkR+x8M964Qm3vqlSiTk=D7HF86Lf55j7$v{Uf zUWI4Qp8TShc}!;07~vTBVIic`Jl63K=s-^~34$bX$9=X6*{Sqe|S~pGwyO-dYC+CTr!g?+rz}cVuB~IclJKX8D$w0vI}Ql7Ax?~$9DFN zLXV86O=nIl88J!Lug`1V)MRnarVX9g^1CUE^8af#MpDhE0c%~xO*GJWimta-S8VL; zB${^hwe&plXlv`dB8WCGC?rKgfIy)MzKLxRFBo9JUCXa5^X~YDyXB=hS0TSf`tpZ} zU*abJ#@R-w4bj<*7y|MDJmwGT8z1uqo>0m1I($zzx`I=*TSof&klm8Cr%e(4%Y@t0 zLd##TM=xF|qCFCy;)>B2+V6|-{p%e#F{M36lbASA1u7&P#*qKaevO}+Y{o^D{ubz* z9B8{7h`3u!M-j7vq5>8%6JGiGJ(RqaBW-qQmK5u)Ii=FXL7qY_ys=6Zr1PKk1tRob*UneYe;|fUGNA#w#J6HXZuVE! z+K2jQNs9JKhxEEJxIJgccis4h>EiX**S?-#7NS&Z*3Y_o`%mqi@cgjq+**g{zobMB z`HQ-JJln)PCFN>u1#Pp--oKLP-^@EFfVK2zcVLSsrpQ`xm>8wNwyKAZRbLs zW`5GA(ho!`eBW}?bbfhm7nd;>hm{#EmJ)pUQ=cYX7Cr{HAOLOUfnRe!p``EshmO-M*6AII}*&_3;Tqm`jZ>6x}# zu@Ddt5FwMi%}`h_oR^#1oo3xLdLO+p7KL4G+c>vZ|`8RNzG--!I!e`~CmeyxF7cR|KlZ zCntzQMg^6qKE_XYDbrxSp+XzfldJnv zzJBES^4zf~LA%`aQoD9Rin4flE}f!BR9;)pq1DC8SM7yGWeL>lt-m3|21;>XjnPSKVX`TVkzm+8o33QFBZp+-y>YrK2Y^6g!9`BQ4 zNfh!*LM^{{woiz4pKFzJY+Y=H!yq@WYyjVzy%Xl=$!o4Vt~#V|Zg1~fUT)SK+uH{( zwggYRZjma4DfbF3e zmN5Zc8bnGHlapE!55JpU?8~1Nu-aF7d+v@sYar+c_S;?P;@PVn^YJ6|Zz!#tqa`1O z>AMyEW|V1*i7d=nKgzCa&IRcKsF}n;;Wot(XiBDfJFtNuLY-TG;v~OKP8($pbtIsa zv_yG{Q&Q4!ELlXIMu#n)O=^AnX#GwCOmucN>dDK;cW#aew3`K5AMY*hMy?+xa#VMvkBjKxB9o_COp}I& z(93K+FI}H$3U5%kd3gmzgochHf~8;%HA{ogyVuRj9JKr4bam*-%+pyCYZoZzyR05R zl9(%Fd7-+6bmvRr|KNZIBgF^u_W)$|s$TD4;ds}5l&aGW|2J?Abm-Q0xzJ01hgAKS zp{N|HJ@W0VAej-@M3#KdXVQt5jmdmwdrFG`VAa)C0iEM+Okw6Fk_{s`k7CdL+ z+ujreQndLh+yVV@a3j%q`LAQ;Pp5L#+~(iEu^DBy;h?>RI{fa(RX0!n`OU+Nbi`y& z&Bt9jCD3hMnW6R2OI%87=kAUSd4g~1^5irq;WC4CkAjkl05fV`K|+~j*gU3TzeZ{) zJJUmtEZlusW5!XKXCR~uyQe8hOh{yMGhYk|%|^*>di(Drw$R+%U3YfV&!%25E9XLM zcg&YxMBlPO7l{Fpt1{Q~c2^wMtsN-@sPKxmUzP2SP*y%rm_G42hc!P{sJ5$38g6hR z`YZbyS(O1hm&&ZZ54hh|61xE16EYu&T@ zjSHyA<<~+Ksdmr0t$jeeC3GYu1P+X_%(kx`sxxbOYi?e;^yL!aNp!Ly@%x|&7!2&< znNfWJGz1`cpOA@zdtg#PAtD?Q^RDR+qM#Mo9Yj@l#Wjxmi>7WCf@)yT(sZ}1!?mv6hFQFWG zU<=BTG=DY{6#+zybD)iLajk^xf7C{h*h@=@ZVYQ$*o^0&tY6H5eg4U+G=hBDJKRF) zF}3k=O(yI)m+9lM4h+nWcna=!SL#~WSU53T>GEV>%3^;%s*i7L6Gv34^ogPxqL-H# z9ty%EvB}&w z;y{K*F1gxR-#SIzh^XZE?>t`KUn>L|P^~TwdZP z6A+wpk@xez1KXuJQf+|JPqO*alFRjLFK;B>z%S2|1%<_pJuR@&QEXEuqXnb;f4<$y zJ+g>deR^SG;V-43-G8e*-5u>3Rm}9j}WP+kjFJ?ZP*mn09I~u_xpFxpWh838n#F1t)sA+RM07H z^Z=u2wc&>{hF=?o?hcehoYA27e&FbM1?nUxuOYES*@?;D2eV^dm_cOtaixr2=<}u- zrj4$D4+U~tSkB3ZYrg7No8jH(1wcGQRDTr9B}+b3K0xA17AIF?_Hv4fR4T47%V3Z= z4}fc(+u00aI8imXd-oSV1U~YTR#BmB^yw16(8~~4Qi&9o88%#3R|6S^2J0*vemImK8cU+5d zHxElC_`*_#J;yza@`AAlw?`0)r;nZLM=$+tRy)@LT}#%Wzn4ph!5efQ%!NI0T25m9 z(Y&nx{L5=tNk#Y!(mWw?H?E+1eukG>K8Qu>MQrCaSl90F6jjqc(FX}Rl-G2de{~g7pMqg zr2H?+g_E+|`c?FlDvTV08~gfZXb^b4+K}_LP75MVnUk5fKvQ!Ueq>uB4$~Yv^{Oie z3W$&kNTdC|0#o5bfG#A0yPNM@1tW!B^a`xrM|u&f!K!@Xo8y)ETyQeHqCvc=cnm z{q8hVnj#vxKTSzu_%gU={xAunQ|mEAd1dX-*49?|z<}6jQcm(Zj^6J#L*KP;E`VBO zs(^0)fy;fq*1%gH3JM3T=rS~JlBW0!3X_U31E&(h#8`z$=2vuu`niSj>R}VN$K>xV zeaajtwm7K;uwt$x(w*zH>r8amQ6}5F3SN?z<8pV3+kVtiQKUzQgnYLal1$AslJdU^ zpK&x4yn-4Asr1E`WsoAG4J;jl7`*-0xdD{TEiEn%hct_%g8L62I5jhz;zKgXY0_Ni_#jfJ!kl)!c1E)v{=!!i z42Wr2?;bfgK=ciq4<|s>;`}$SBGZoUC-~<5AC7^6fm)&nhVu<)TeM{j+Q&2`AZ^oW z>ANti`9vSfEgs&_T;!Rl2V|dBoTnQ=Na^xEr2DRS zj~`wLuHP-FnimwEBb0>*jFaQsjBwBQ_O3-CH;-mg{_xDpOVWRx-je6Dup$Q&5OV(I z!|t2q_O~>Z=wJXzEk|+W*Li30v&o2=X!H=^pE}XgkQ2s`=kpQ&Nj{}_r>pdM8I)<6 zU*2xE6Hv#-#4oj(sFV@&S$;66GjtTDnV6iKb)A2egaR-KhLV?xC#>f%Nu6#eDaO7l z)gXt;MERf%)}+oIdPL}ecpWF}eU*jX(~7cxW^u{%t78NTzTN?L@+b50co^u-NpO#& zHP9GW&INuu@<0HUgb|%DhP6XRHi{^Y1T(1~j7chm4tzhBRwb-`ZBb_?ruaZKn4}T}DleR}%;>Fl?>J?7HT;3-SK? z_3PPY4E@D6{R@Z|PW%PbMi1qMo=L@MS4B*xS1&o4!<2`xb9dT!H56MAB*hNeV%^zB zSIbPbKJVuTG)@hDXEz@VLo{&Y6(Ar5qTzkb`wuS6nK=7s{E5Pr)yD#*JVK$YKa>L? zaI6V;PIB(DKYQY2q`bUfh1%%rVy7Dp)E|ry7XAth0c~CK6|vCge`KKZWD%9d_e3$o z4O&-pnOs^z->1x$3cN?i$EKFuRyUsr7yjM`9QQ!9K%Ild9a`n@_(2$#?&=Gbl!;ON zKf6Cj`3vL38KyRI59D;T7-0?Y3%E5qy}X?UD>|2 zye@~TV#X8{BL=j12(VlFcK2hmMp@W4_VY1JX7lW>fFp6PPDUM@2%Q-rw!sRgVwEcW z`T2hB5o@*VcF2~B0NB;pJSKfX`pD0mPlQc{@x;ZeZ%asCYyO)oSo z_pE98^^XO_fEn!XFV9cSD)zRH zs^@Ejokb`p_N&Fr?&ecx+;gs)qFAs>L^~8dO0fL9PEA8v&#mue!X0L=2_*ecjf-OuiURGNih$9D+kvJ6+0M(^nnzSCn z6v0$w_$w;v#qG{zW?1bCeTfw@(ssF9^OB}f7~g@4oms5IloM8jL6RFY|wVoIL_OrJ=$ifSy zL0joNgsb92>3M*8I&uc<6#@2xbf-q4bD7c2;n)rFd-cFId^N}(f>8%X*lY!E_{q2~ zFzUu5NUxr`&*IXBslnf;$X`c+(^RkpzJCy=Df{*&h$5SUL{ONV3LBg>FwFmvg9}K`PLQqpUbqxpw8)f|^dk5D5p$|p*B1ZgF0K8;_*z%?wrdPU z0IY1LsB+C2><#X72bC^&^@CX@SbI8unF|FnE>xKvAAj(yZ-Je3m8!`wT=H=KKbO!?{lmOb{9o06N|laWZqp8(UWi8wcKhk)6`U+B@UJ z4Eg~Zj)=nUv9r-im%P8-N>G&V@6QrSlY~+v6=)gM(^(|udXO zCq;OtU$#r`Xq~l~;fTfyQp4dZwO`fUsEs%*U9OkTZhrQ|8D)onM^TshJv+ zoTGh3RsV*mtS|)M9FmsbEDJhGspzQz&>gc{NsW)LJIU`Z=0zhm`HSy_V#D>HzBNaK zhQa0lcJR-6$5Q^CLwKY{UD*C(lr_iGl{|EOaji?SOIin@5*=*XwgQvDZnNQFGs*oV zPmG5lEoID9oHWI9Czl=PFGq)q=tzgsSblR;DOB)q^_8odiGZisj`%_9gZD+S}+8rMomc za`qA1Q3nv$PdBc+nfsUeLPUP(*xbhfel)pOq9{d)ebi3pEHx*B)e3R^1~$Z(*onMVMsOW{NBnl~x@ z@tU%Pp}NZJGGgC^yO0}q8QZ0hGRllKBBuv8W3!hZkGq4^%T|Y>hMp?2jrf}H2e%;+ zJ7t5F7tpmFh1wiedfPZtg?kQ*O!wme!S6E@vyL#*)7KKEXCex^hP0OOejp-wA8`$MA2 zh>#23VG((X&(C zXr+QWSz7Cop7w0bfY18pZJq5%v_gm8e|@0{8OKR(u9t>x6$AbFDC!)G%_f z7$XN~sCks%@x~)o18DQXe!pZW{#)%(>@pcpcR(qhcB*|{&%P=*&zZEg)p~JqdCqHHWI|TsIkf#PlvY)*?-(~MHC>}_%<(ru0l4i)m*tEP zgKpf@fxmLNF>}v8zw`Xg7BBL~VQ>J-z8s)DrB2mA$H-RfVxvJCpR7U^Jz8F_X7p*% zrMaN&dr8a23r)w9z^wh{`LPa0&RE@b5y9L@i!9jV zQgK@ETR*;;uZR$Dd@+QVzn9zi8F@9gryrQs4_xl7&A5({QYOB8M>^*`3 z+0Ku62zh8J$560{A1*YtLLv|BFQgs0ro(DSucz6oG>Xp_zy`%C4SRS?w z)of876IOWon`~($gsF!K!;XjP9pH@-3?0`((+(mb7|-0OKc9Jy2y%9Nt@#liP85|k zQ)E!0zaGG1I&xrop4ml-!p?J1k@5P$t{eVm27Zw+f=~lCw(_eEdH1Rx1_SM64imH? zDIZABTB*MLoHqy*0AlqI_M24>m$gxeX#uB_2@ytGe=2liio}eJ0*KR~a305LO5!Su zIuuY4nqV^Hpw5mu!Zlcr>pE$XkO)Qo`(1!l;Ko}YL|Jl^Mg5trmN((5o2!6VRTvYonvFE#LfG(3oF&2@#}NG%knypA{%tdB_6?c;lqpW zocS<)Vh;8P%XiF|A{G)}2mdj^@8{sXK~Ij$VOuast|Nu%2Ud7Hw`2iOa!)>;KDH`+ zZ)lp@y?^!XXwwf7L+N@%mD2tSz@O*2-H~TXM8g7{$r&le>Tc_oo!BWdwTFmBf@U30 zVJ>kM$2S5dFUQd^zfg{k6?SfoUm3^o8d4|~Sa#*8_^JQX#$pqHAsw=`zb-T{C1Gp^ z^H*SozCLoIWu%Ss0z3>L4_Kp_8c5cG_iuRKk(b#bq%Q~WG@}+aTD6_WY!021lzKr} zjh_nj&7XX+(kmEq`;6IE-&8k=<$uWd z$)en=ev9^L!LlNR9`7*-UZ#VPwK&+fM^%YL$QK_}1N-?|u)@*aGMTMDQOW?(i4Q@M zdTLZE+}u;d7<%1@WWrt7X$yQSET=2GX|z zY1*tbVe!Ja?BluidFZQsUYtqmEr%paXdlwt9Qe;0+js2%4&H)O*=-QnGVa+b{gJi?>-?uopXHBzBwO$f!uSzKxPW?!HP@mNnNXGoEOx+|pEw!u<#JrKv9ST9YQdCdQzRk`HfK_UUh;m45E?Y_ zCR*Ph8e8(@{cHaNM_vq3#gj(MMp-Z1)CI6B2MoI|+%WIvFO->NREZ7McGp9FIE9xu zrQ#ON7NSkoRrokUlUbd~Pu81zfGeqy!A`sPX?1Htfy{Wulks+3pNn<&u9==he8iG4rBi%?yM%ulP7}q3mV0R|1 ztmR(Stoqp$p12sjPc@GkU0TK>0w&*wkP;QlM#2OM5@(Zwdm5Cyx$)TsS)R}8o@Ct+ zvAGsKxFVmWrg(Bhj{&zH$}!9&*ysafTPgl4toE@@1+cdU?E%qS)D87j+6{m<8y+4; zh7n#*E${!%-1qf0i@Hcds(;c6(aHauUjK^M+95Z$O3#T|tnYj9yHXvgA<-L4nyT@) z@heeK!xgxB{1R4h@Yg+`hrFg48igOeV>5dMGCPi2&pG7e-JDwv&R-($Ix*{k4w*Y# z&S0od%4`!(TO_mrRAZR{5L=%-o-7v^zrFOzUVTlW#XuOAj-`!+F<&vb|G4^WuHY>b z-_v}tjc}?zN`B$!qp=&Z?B!U2lMM_`a3fs2(hj`5BL=i_ zN=02$xLFV^`}%KzOlw%GyRkzPr`D|MBIPGfh7oIuafMvQsGk%^9fDaBi|j43^J2Q) zZl{s(acZl4Wfn%0I(TqV`J1S-Y(Np(&j&8i^ysDWli>wF z{K!=u{CtZ7?u}H#;xBN5IA>vTadC~jCAfBX>fGvOWwua{2MpZwx8)}|uzD21UDrkO z!PFl@szsUz7m zv7y@sm|4|JfnH)z%$f1$7VOzu4u)zNla&cKuR?h^X6EPneAKRzsgw{3f$sLA_=~@5 zwEELJ&jAF}Rb`0hU^_X2=Vz46pKvh`Y8E-AwQumz2tmGW0^4p0mK6N*4OEz8(nE*{Q5EOoIaQ$8USl zc%+Qj^FI8Dc{dW;XI#r;7{HMOa=_Id;LM>9s1(t@!M5H|ty_wp(`_4dh95^=?Lx5l z<`zw_7xaS*ji9rVx9#j?Fb6!PQUGIY3f|a{VI*VD}uKe$?Um2rl8~9`W9zY$la5|B`2?5 z&-}-mg2@UL>Fxq8krmE*e0)9TWNsP)eyG^`G)%0Q(V4jPK#?&jb&ZZp)qd zCP|26itR)2EMZ=mci)eTuG5gEb~6F6rg6knmFjTuFb6AKqd4g{B1z zFxGbS3MwMUSUfxT-)Oe?I&;Ag1=OWkKM-TRRqEIrTXZHQ?Ummxb*r->9=DBHV8!DEg zVq?*EwOFrO6dhcxCVpm03)#n#XHmLqvU}xNE;9AhsDeXj0F3ENV(g%1>>(F;lP<6; zNdmg+I!DFb<5*;=4HOD>)r7*#Yir(>%5lTxN*q|^Qk+eDq>QS#OB^^Hgd5)X?;Z^z zasbB>sUz(KU}#KmOO>1l>6Nc=D?dk%+!8i6h>|0;kcQcqB^&yzU}O}t%XT>y)V-`P z8y7E@A|dx?(5n5uh7Mb|jdnbvNSnR?!Sxc~)Lu8f^SwUP=Dct_v(KtU)|tamcNJQB zMjAy}9p&hIC;T7U!$cbc4qg~?87PbfG`?6n8X%mc*&%^X#*`Bauv+u&&kH3j@ss!O zJ)^%t;{+2swWg+iYwGH%Qxg{Z8zys8+MX&DWCK{{niFWnztf!4#X~l*sgx|PlzSy3 zfSA$UeJfqYeIiS^QR9(&IrYlpvt>EQ!aBY2?yQ~ii}q*uPBeDb$2gD#vva>!J`Uq| zrz)NP*%%{hK+z%@TWfOM8EONW$|A-!6CunE*|DbZu9UfmS!PK!k3xY`t`Y^6`cJ0Q zHR4*kqh)DJvhOx8ZYQG6=tm?L(qVTCdNg@d&t#iCy$7kIKJ@qZU!c@_Yies_&_)-_ zZ)s73T2~@A^^5#9?%OdL?IY(W_ommw0Obwtm|o_oS9tg-wGD3Trc%d8vu7)O1-D&u zom}5s+ngsqzZtQK6ZyKlGs8G}OAGX!A+m?Ef&9Qq*+Fa;H9X?4U(d|VAxg*Dtu}Io zJS2K8mHNRIT9-if+>8QjHDXk>d2lnC*C-%rGa7`m?x#Ud80WB9?4Tr*f@~z0J3#Dl zULVu!TwRrEXlMk49aiOvdC_)f!y&2pF$t6KN%cZ`6-+rZP<}>%i;8fZ!WGU|F-sZE zn4_^sFpd?tXJMU{0!&HBy?5!>b5=mqFqP()Oz?A7pHEItDQdDU6E=ZL$wTv)ZTwpDpnBrGo@wp@t%|$F1qA>v}J5+ zKAoRcf95{VLiRwX?H=nQcPCMvXMWtVn7RQN8}h|tay=c6H14GY&9rr+pu&1ltO*^D zpuctue-apl-;J9l4jMUaw~pr$QDy;$bB5V5!n(bdbK5zt*&}EPwl28UUJw7^^Vo}g z2NMxX#ON`bpTc_0YzYNJf0Ml+AZk{3f&>cw?(g;EQ*l;iU`{1)2!XAwioY;l!MVPE zJO4N1Wj>~46k=R)#-zDFf+(rC*&|c^J<(Slb=UTaAQ z4~uA&U|@>n&P%@rsU|th86}@2-he72J#0m9smFU literal 0 HcmV?d00001 diff --git a/source/images/button_gamesave.png b/source/images/button_gamesave.png index 0f44608a3e4a93b50c6398d7dd348fb71f1f6133..1e44a737e6f7d09772e0aa73b0de81309ae7e884 100644 GIT binary patch delta 412 zcmV;N0b~B91fm3xNq@viL_t(|+U(b{N*qxXfZ;n)BwJampx`3}R1mBJN>Zk^O28&> zVC9mKLJ+O?Z7dBg=>iMc1oH+9Q&>b06I_?cImGw?Ry*>2aNy3A2Y&8Mb<V+}3oz@(F~gXC=dvE;i|Rh;gP3Fcf!69p)F&Bq-ppq)bAR(Yugd(V52adrVLdS8 zn(r6o?(nGGoqx{9Y0ORr{Ur`B=hipN!r7@ULCf5}ep9BS{PHe?4Ek3b7N3v4m1=dx zcA#xH^|&s7);IEal|eUoitlfmftLEc^zSl$W)<*s2pR+p2pSMHAZQRYAZS3)fS>_E zgP;LH1A+zw4U<3t3IY%`lP>`q0uVHlF990@5Hyo70U3Po_@J-y(2Q%_fEH@%hjy+c7srr_TW@YSdWR&6G(7Y_zQ8w2(qrc*b{1wOz1hAGPRT#kx{?~S zx~@mMmBTGVSc&y*cB>yxjfx8CR(yK(o^hm*y(u}nQ7o^N*h&(Bb{ z<<)a@EcX}LpKkA;r*~T*&P^@<(%7Cl@eEGdWzq zr0N|mC}cQXXjsr#&-Y7-|M0Wzxel#uhgVqcHj)=gJ)%x<5(ol~i#w>$UB`t$w2RoPdZJ62Qv`S1(>jpl}XXRMu} pyt`3LX6xB+O3!k3{1HuH=u{6eyBqIL%$DsfKAOJ~3 zK~#9!?R`C~ci(l~8tEoQAV|c84NjvE5D0_l}1 zAQuJ&M=4CS$HhH+@0nTaT&axUxhi!3_xZh?v(Mh^W!9`&_{Govte&4ARn>p2s()Qo ze_Y>wzWsdr`Tzare^u4rRMmg^!4H4(S5;NtdH&%~tLkS}^&h?+=5IgWetvI${`fhw zKl`8m{XhL_RTX~m^FRAhRsFQ8zWe<@{BeE%kN)J_GJX5`_Vau4^Q&L}w0`xsKdY+x zO;!E)qpJR*s=oWr|KQ&|hnYoI0aaC~sw(c^SVi#p>+^H|v8ssY5A}Qi&wm!`^K(o7 z`~G^~Pq1)4^L`Wg`A2}oLg8Lykt_h``tDcYxjg+Q=4HwC`|rf(XY4=7SNaVRB^P~P zf4=eadih-c`6^Bqpx2RW_?;du``h?pt9G46!BdRr-JGvy9Je&mR6c@v`%0 z?A0j$PWw##9(+FAv)s@75ns>yobNMZ`A(?50d>vuekk{&>w$R2`y+wp8PN6vf7|`) zwb=FT%jws-pEX(ay+8Vs`py6Qb^ZO{{q=XN>MuU3>R(k={lOpq`zo$;4D?NVd*a!I z%**5bQtX9%ZjN%c_b;Sx3OfqqUAyAh1fTc4-@D(j&c~huzYq0e9E$tFq6$l{`#D^U zbtFEY2cDJ7hajI@C1;0KRm-;a-8;`=u64dkHz|sDVQpQX@7NFGc_`#IN^;<~eUS~t z^WM6KviADyb^BaL{hadv#c-kG`edK&Z40bx2&p#jdByWASZ*vpStG1xt)9Ev&s_G? z-kWF1P@kWT=O}ZXJ$LPm9B`HymV4;7@m-H$*jFjfM>j8YiD=J&&$^(Q&AYDGxQi2{ zI3T(1Jl1E=vg%*_%YRpY|95{~RrSMAh+X_&zN@2b-#&tKT@?zbw!C zJVcaDbKkt~n()PO$QocDa{Z>|MqYo}hyOmR`y~{Egt7yGKL^YFY1Totd_0!%gvrnME|31q&>&WOiKi*b83Ud>zV_l?w>&Dq!*pKb z1qsoKu+$n+#iJMBc|yp2U`qD*dDboR|BPxZn!=D8uvq{P&vo7EMs2Hjy|Z~X`FPNL z3(HfDlX986kFUmaSg59I4cUi!!${8nNkFF@Qq!IuZMHDJ83?wtl|%M&!xEl7rmy+% zMWH!mHE0%okUc9{cRkO8W0}SA9e^96a!R-;A)Upqa-BSjOyY!_+l$^%?_N_45!1HD zcupoW2NjP5J#ewk+cTgf{MrYSes8qomdA)_3c|%}YqmuuB51uSg=dZOyw2S(O|N_U zI7J@n{o^cOFLI5F?run`rU56YnJt@#tFWP<+C7hCEIhYot+s`>{m}DCTQzb=i()_+ zn8@SFk%5)0$-bTwrQkE|YEecwxC!l0Kj3MZzwo1KvL}` znfoU93?1x3q4=2_eMXUpb5RQHtrjVnam15{S4OV1eFHl$5|v^G%ow=AWSBoJ;BFRL zA2LVFVq2b`BTRs&9YVf<<>9f()j+fwK6eJ%Za#;40al+-t}NH@5m~e7oc{@ugXda6 z!nFhNq_5>m-c~Pp9Xfuee%ZrPj`xqZ!bQCu(E0jm*h4)uz6LRIk{0_huVcU{VpCl2 z$QG;gYnHWtqB|&9nHk25)ibBn0JxrEaR}?d{(TDAj4XqTRpAEMBG2h?*4gI2lIT+Ag%1qtko-&2f{F>9j$8ZQVuTL}>Wl_!q!e~lX znzJ!Vfs6t~tc`(O(=)36I?KD`_sQd16f^uc=-&) zzf#g8gg33}S?j(MG^rO{q&-?i0qC$ zuaEAil~gkv%m-^;8biKQVf3<)z!&`Ei`*$A6FuK;U0b|2 z+Q-BheNV)ik7ta%bUlWqHH3{)c7z8_eNAdgg?VbzZX`6^?$>0v)fYKxmZxXW+pXb^ z0PbPl&w{b`wm0@oKXq3ZekoL?4uut@g&k#U(z)5rLCC-e+^qV454 zh))^Pz+T+f%opqxou#ErBSqb{x4fO*lD*)Fj&er@rJ0;&^-;|Pql1RcTWQ%rziS_M zNO|P07bQ1^07UO0h=yWsA$1>ts$8v)b}eT)86>=$OdJfoCIPtDA&q}LXxX@`PVnO z=7MdAcaZ8vEWKPs0oaQ0$d~yD{LUmkBfy$Js4nN4b>}DTl%FnRRKRY3mN6NHJf_lh>ffUD{(* zPqi6A$s=GxIS8jF-a@^Q1dhcE^g|L%n(JV|(#t?VDnUd}0;-3ARI@Be+g7HeveocoeS?m8I)dk8c)_hec(3pMR@+%+gR z@abR&xU8&CL$LybV9U>MIdi8=)f%gAn7l5~7ty6Q(6I6E(JSB&;iS}1Qw$%vv)NA0 za&%c6;DuOHjdAO?(5=cE3(TE3vLu|l=8W}1QDTIb4Ai}r^Ie5r*U(h1n=9?YJ!;JR zoPwA&G|g@4HF+(=aca+)*e?MT&gFg_==isDzDn_RiC!f zZoSci)>Wl@#qg6@yW317u;ai4Q&@Z@Vdo^9PrSh6S1sCd&nCDC9p0vbMh4cF?P1%` zaey(_8T(mEhC6ERU%22Sj;)qcWsNc)W;v8wd~$-J^Z*z#esfHX^%Y=SH}rspq7P&r zY_o%E%H}xKybPV_IT7Hs%bdBC*;hZpc{Dwh5tKo+b-{mlf^2 zgoe-8;)x;v??*q)E{GoWx}F4Zwv+-}3JhJ8{_z$JV=jps4rNynZ6Ov&+bTE|(i`DL zt_jf;q@E3$nkCiK50qKf9f5#tjdrizzUSQv>*2DbN+;)Cr9rW=g{6mfduo(KT!JYX z@BFOOx{XT`ZCt7`p1_R))!saxm_V_r!#{=j8RZqilYdJXBb;S;d4uTF!=hT(=ZHf0 zFv<_r^$0hgx`4+)Hw6Uj=y8Oikk-E7CR^V3cv2@2FgWE;I2-GtK9CI<87PsI9_i=} zpBN{Xe&wa)!WI2`2>MEAu_O4gH8DtPz#-;lhUU+_v<$;r+@ zXhm}fV~a`M+#V7Tdc6{JI}9;`hZ*_a6qk*PeAAr^_GXXvhlX}+C7d#7 z(|M)Ro(OmY>JAV?(Sj2#a@9kMm%s!Nh;0Qwk6vRI$XP)=4ygbhYq<04+gOloVFJ!6 zRmnCtB(K}NWI7C(cme1uEe{*kBk4TF?fIyE=ZoSUIJOm5lxhl_tbrTBK>OAcCsBG} z&->4sL@IO9U$my5)9-A87c|z!+6Mt^>`J$CCNeFnhIW7E$V;KJ8)m;Y7HA_2Te&ma zNY8gPTI%xf9JpXvXMta=MJp3_&q@b4sLI_?j#R;bc0Ngc3^Nj3mcT)C& z5>9rVl~M^v)RwW{Q5nAZY^OQEnu%|ie8Sy8tl8*J`yeduVLu$GLZJwLG1M zwr6lFMp{3A(04?`N>D%3@;sj7k zbfPD%Bs}5Z+6HNgJ|3wgHzA{xl|hJFPf$prEZoWpyDvzewwU5Et{?* z3UO0HYg;;z2^(@B(OmhOc{%a9=ciX4hX(;kQ}kLP6`u=bdPLQUIC>q_XJV0H2hfCA zvWE5*MRvt<=E1YFPVfK~an|ybu!2@yvWZa#*}HBosI$znE+M^V_YNThSqb?pT*0y` z+Df!itUf0M9>I7zK`S2=Sx6l4PJqlXv-O6V?LLNr;vFkwbCBHzXQQmSU5;HcK{*22 z8kK$Lt#bx$0GUic)Jx}!Xu(C%UcYl4uxd&AP>wsOAwGT4*6|?kDm#L;SRUoxm|(e-0hWJ$&@P!=ZgT9<_!ya7+8l76`MO>%$lVBSqvSxBAecf_IsnK8 z(UzP$CArXB+rS>>9z@hTIrc+8p>Rm`u+YFd28jaUNgt}5iw;uJ`x39L44=Cxg6?ma zgFXYTL3-oHeV|A5uLY(Y%YU`#WHY;-RhevbzQGJE*Se8V4YEs)jd?|ds&LX$unnQ$ zmIjp?ysqG0l}B7kc`CAV`kx&Db}YivtRQ^QQ%5)r@D}NQqJ+IomBbIT>K`3a z=*jz+rKcXX1d_h*Ne!Kp);!qR`%(!ksR)ay!>FU&lk^4EOR%@CDahm>#b^v>>tK25 z5SaQ`UR5$EVV!AHkAxWZP}lDFhDkS)P_lv^2K3%a#RJp~(zVlQ9Zl=BR3t#NwD$bc zP@IQ~10u|5xLy*Hv%Vn12$gbQ^C`;2nl7#9GYJ&YpV-oYxHI0U<(;L|w^~QT8Ch#8 ze&#mh7yahRD1Ygbo%HdV@mx=njyRTxt0)oQ?Ce^J0>EsiDa8HHmwnb?_T-XCH!Kk(uz~^>Ao8tVdc+#I@;h z4-Fm-a-r9?5qyA2g~fviCjp7vaHS@irA;qY2UXEE*x(>BYbQrmXPNVQ%B zGL+|&$aoNPh&f!U6hY|i!tt7VnLKiHXsh3oQOew;hOu?JRTnlzz|5nr(rs6aUnAa%4j?=Cqs$*!E$C_I2O7%VXw&&XOsOm>R+g(#^ zQOkRiVZ%$#UcGO>rl@i_8yv!BPU?%3TmZc0ov-<*D2!LkUh2HlB(Y?_t#9z=so2WR zqX*?EmlzRXMT9qa4_ZSNeMC)c7!!!AF8J1ZI|cx`Uot}hg{`a&aD4xu1K$lM_@%B_ zMo@Ukm8+rk<9MPjq+dg8-g04wO(n5myezpF2Dmu5BDx)AHD&?Osc@RImo5C_29 zp&6XjeCG|Zsh6(_^gPil}YM0- z*HGzD2tl98QW1av(IOuOtEs3QzCdMY?$+YyE}(m|4vZ}ma7=^q7Q*YEnv_kiz=M|3 zdT!Y->7=}zGsF~_nXD*|4WzA_-H^HBpbW=FwNNrFX6DvRpbw@hjkB^s;2afXpA7} z;n1d&>Y7^(R9nX0qZ*y2Q+=6Ij0AT|k2o41S6v2&N`T~5P)wD0^$sb8pj}Pbh}bl; zG349K(iMeQ4@vQ8ebW_@Brt2KpA>SMj8R=JmNAC6$ph!eu7XB;s8aKi#Bfnty z?&hH{QJ|sFm@Q}BwLnNY;mR1{G4`m!r z!%)nr)JLzz*Ed?T_DQQqp>Jr@*!v=fUIGe*$K#NzoO@e?We-&l?E;F?tkbYElM_zc z-^d}-vntn#VJ7jE+`BS{tALO#Ag`ut!WUFf3*FSFg=!-olV@Ccy_R06!l<`UmUNFP zt@U&}(^X;|q+y0Xp2wdCnY%8|97lLh3Q5QnP#f<-$`UHG48GxG%X#k8G|t_Y$*%l* zqrp!2X;FbjuYzW&q1SMmO^-~}S)6_>`~gF)Z$R1uETCO8TkVWC+DKJu*!HvWD5jxkK=aIp)vgU5Z^Or}P(74KjBMrS zOqEdD{7_Wuwf^Xd=|r@-P5jg`Bvw;f*9TL@2@s_K<M$V^A1$9070HWe zEXxBSlC3I0cZBDL@jvG6sXpIx%r@gf6i0yD6K?H@!>FK&4k5(on5_~beO4E3XT7XV zj7e3&2*Sq37d^6pVFVDb#Fj;SDMLee7ya);+9SOZgfBbxbSOa9ySyDXF^tueQ7N!B z0vPu8QTMut@{Y0$O*YG_Gq{5Rg2b5-BEq@ax>U(Hp0|*j!S>-*t4!v^7QDBBRHT1w zdf>Vi^Uwp>Dbn^n&nGT=U;MpApmX=);z>YCLx)9z;pk{rVnT4)_(S}C4&W7?`L}|lVrVEm zP(FdoYPiNVn4%~f`U09yUkrpJ!RljTV7v``x0W+YW>cy~^WBcpj3=Ujy@vp}{TnmK>SG)iDla zni>0}t<5w%A@l))iNeq~Z&6OU{H}nZxWPmW<`ui0RrjU*AN29jljg7NrKRRq!R@(p3&YqZx7Pg$p(U zg9pskD{a+=Hg+hCsaBMA(7fI|<(1TF5f{|@d>l)3sw13Tlzjd9oU`PR*RRw=_AnW+ zHo?!gtXUK>bjztSOLg_FRgm#&&t0Jj7$IlCjY8bt=ZI7c`nw{4C4z%j8@-p`D)hQ?wn)r*Bb83dH0ND)IpuN7!1 zM5%D}aJL(-fikwL`qcK-M$Fi^w8=Q)fmhIZQr*H-7O%Bl1Ax#23%Hix=OE^^o#(eW zP&F%3t!#Q|px7;7pOG`>!61~tW%5Ew;;^}Z%mtO8UF1k@wow2u_hIc3nmpdk=mZQP zMsirBGD>MB;(lM7a)@mAqYYLAV3Poi@*qRp@DkQudXL{}U|E@N7G6jeZ|$EZqAzO)DvR$b%9!+Rh!(>_^rkow#Qo>vA^O_b0)ake z7@|YA=dc~(6W84z(;zd^IkR*CkW>#g?@T@Sq%VM?(PPyR!i@NH22HPE^3bI-l*&ZV z6AiW^`lM7*HBcwzQ@MPW)Cr$fdp=#mnr+~kdJxDpOvL=VP%yo%R4V~>)?$C1mEq2J z#Z}wL9bI}@*m(sA!vi*oXiRx*5aF`1y-1y`hI2SNZsZjqO)&B~Et#;1+}&{8VAg?d zNe(J3rfrjhW`Jg5*-QNrFsAW4%SITK~(!uF}t}8d~-{T zMy}u>JjMz|$?ZuIj0LQLc?2|&Y=$D7 zdvaB4U=Ot=I295Jf^v$kdCeMz$#)}WeDJ7>Bvlfvu|oI

CSF<@I(;r%+3UM<#l{ z3F2EsvuY~V9zYRn!`}S$>HU51A+mhi2F-V3X_9)3q{cL)u}Y&Zo1@{@ZKe68sqmJ2 zBO_jvPFV@hLPxe06$CXzTS^`2Wxz8G%nzL9;pHN2h_I=&U%ET8u{jE>%eMf-G|Yo` z-^D$8=JfVAhOw9=kc_fPdQKHpE`JtX4)z|l)tYLAzvNRvHmL(a2UJ6hX~wf?cH3rI zR$JfY%GPsy%F{67ht5Z{v=2>MTuQi3r?kGdCue7jHB!vO%bwi;p=bJ+m54QjBM6Z~ zT9XY;<35@|GB^tAFW>6WUl_bWQDJy}6IOBw5EaO`@g+4~MGfko`bbyL%h2t9@4`aU zXXT41H5+LKRywOz`)7>bsT^V5i6)I}as>)w)_J`Sm(()Zs21vmiIb>e^_EJ$PH~MX zi5YU!b5!ER<4k=m8Gf};b{JNOdTr9sQ_wO|4&RyRw9Qo$e8k4+z)3}4?x$E2`hHg_ z?QF5g)GyCvr+$XC4KhWM5gtuT>Lo9lzW1~}rVjEDg3r_aqLh>Ma&)=v8;HbeOPh8R zXLEgp(x&Ow!=T*SRpVkiZJw>dhv1G|H7gWk<_~=lNt_f+Cic%sQ@a*ZACDtpx1sSh zkR)zMc|6{54Z)u5a=~5TTr9)#J_-tXh(7adI&gduRbA8=5ZHV&Qt?5*XB6I81=aVSQmg z{kg=tqKj?5Qa{_YN8Jdkni}JaagsM~T42qJ8egh<@Exb9cY*lUX;-s1NLigXlIj~E zJ5_@C3gpI6`WnK0jR+Ro{Q2fdr+fcW2DL453DK*|=9Ke)rjKUmsV51hiRmBmNp)=^ zeBm4hMHV)Md&Iv+L-ysG;U%qU-Ee&vt%a@pVu}yn*MoW1rakKKD?hBmC^vd04C#;h~d8ED`~m9_uJukagwIgwlImbRtp>B}W^u2T|P^^rkRJ zP&F0|@U^!^N}0Tjn|U>7leivU_I>m694cf^8*)+#n*4D_A=SVyQ7ah?cs^;GLQb^- zB#;}=_h-JW@@JFN7<@+uo74UJ%N&P7_C-Xm@U`%G6xK%a7_Ra*u^Oef&ylj7^%;LXB*rZKQj} zTjE0Ouj#1`Y-rMx(pIait2JzSQ{?rd9#<$z9^{%XE33+(ZO8bcu!a#3=ueobU?+m>%n_-wr7~3DFb3vD=AADS zF{Y7ElM79?+9_|fDvPdx;kME9A4I8%6y)P*?*#x?R5LBbhX?YC)=mlYK=pf3>1oN2 zqT5q4Gq2L*zpGQ6868(qeo^GO@2o28%0hj~b&=?08a#GulFv0xVusl>Jd90tCD54= z)}Bw)x=dt{p^?TOSETYw*_wKj2RK>Y^-|+RPsf;hg2v4^TBaq@t08E;@)7CTh&`~U zj@v*A(8Up`nBu=wiyg-3P)ELdn`RgI&k;3QIa)Q%HT&q-x^A5}GH<9}7rF;Q2ta=x zyyYPRI@_<+_ThCq8tEYB3FX{ba!~x_p{qi=%Cuiqhpe6OHIn~C{I&jj+8b2ClQC0? zF$UJo0Zq^B4V3rrZ!4q5JF-U1o~$*hi-K~ha)L$nj<~XdQU^@#>Djogz%I#r2UXD&~()>G#;IlqV0nFdUKZ1 z2@|EOtR{u}L1Jh?0XYqGB^(uv;ZL;ArTraU;9(k8pc5MT1$4?N(Rr>KM=e_zIT2vk z;n{%WU1F!Hlex6=i3SG(iV4(nWJVeO6YFdu`IcL(NQ3AAQ+vc~Mzy0Y=te$E`W-yy zomEjCzqo7UJ?nkHq3t^t+F#QCg)*@<41K~>@Zv;XOAb1Yhu$ENEB-UQ1^cwZJw9`q zafOgZYM%M&wI*dSJv?mWZAdf5NJJqxxx91A%f@@6j|@7$tn=_Zjo3no7{?8=)*X9t zD3mZ#i*p1ZXJrZS6VP>uV4#9iyLEH13vy;rcEVV&hAPN1FTW!ASr7NTr6yLMk-_yT zR;l}s>xd($y+IppeHm^0b4@Hklvq{WW+pGO<{@Uz3UWSs^q6Z1PaLrcTly3INjMQc z`lEuyf|}5I8s+mGSb4zO#BpR;PUxlZB~OCS-FI3_Mv%G8;=NUPEP!;o=d$OX?s*YD$shGjETX#K zqmoe^)5nU=E>Sprn-ARwA7%cuBuu+kclESzwUnz2L?OC{@)Zz=wQYXN;q37_SM1+f zV$HBjbc|uhwMg(FdZ$Oy4R~aWlE$i~HkkTGM_jcANeF-Y5!`dsD_iGQHK~~cOkSeO zO<($KCp=!Tw;ZCYjo|h}AA!gSm#>W(lu@Qs-sq^;WA@4LkngXXF4^cD)pQSDGj3RL z)1+tsf{HRoi{?(H5!&QR(&6oZyF&XJlH7ZvL{!M;k=GV+wlNwf8HBDu^zx4(cd2;$ zJpKh{y|etXMCe^}1)5UCfzw2@%2iTR@-$G~vkwNjS{27LwZ)`#aU^-(pqGcQ&SvaF zRBpEdmdH3IJVqZ2Q;nRXMhhWn6y96zd%q4t$2M3k!r+2UGrxyI4TMh9-1+-DVs;mq zr?=Kh!~*2=LdY=5_?QD*tP=$S(Y|QXJ9Q_VloM<&`6)E7O?{=taY3%}RaJ>SNa*Z! z6|^!JEE2_)bCUDHzzX1}!!+I4IK$#F%8)C+d0J69`l(Kx2) zey|fxm<)v>R<&xpf+o=)y_H0-5FkxpFNd}9WvV)dZUs_D_6!AV40Ypk$;&51G+JaQ zzBA~Pny^A}ildn|66h(B2OSBvdaIL&tzTQ)N_QVPZl15d6X~&NMGD$@B?*^}6tk>U zr2ElQxNN%&^2Ki>8F8#PGE{A7)dp1&^(9}n_cKIpX%N(Xtx(7neYDah9?zlwcU67w zTB?dRtqi?`6mfv08k8+XWt(Lh-V9&l?U8|aa$>4u&Zo%Nu8pMvhi5gHDMcvl)s#M7 zi6(3h2E$0*>q{gTx50D6sF>6R*GP(Jh_IE`n5rGEsP;rjRZg%?-D&3DH}#kD5pV*w z-7&#Pw3lTvya-Bfj>Pe2vCQZ|@_5z2GunrisTwg{jRy?$O+B`zFIPfP(eVY$>1>dw z#EDW(afYk!UcDa~gS1IDvLgTIqpJQ#RsGxV;McYI&z{gsE=Y^}sYBelcX&`nOllmp zEV-jd^qjU#(S^Q*01;}FA>fr=TYL8+od!WD{WIza%Mqp40>2pV3(!3E!7rKBa4 zOO|ueXpB(iEUAb(rj8H|->q+1W()%>YP%xC6W^g_x|GueRRL8ELxq8$A@ANhf7ehH z#*fNNW1zsf61bJnvtLdH*$V&UJ>xwXDSK6d8 z0F}`OJ4amf>UAx@i(l_o{tbTd^FRAhRsFQ8zWe<@{BixmKdgEcoqPQQ8VTb4C*C_T z`ro^6<#6)1T+7RQd#$Gi-PD)wovttWn|LKpgF(OuwEo&J zp4V?%#xEY1%HzIWzF*(C2`mO=ef7LMR~Lyhi>wmscX*D!ZQs5>g;q5tVW`ELE{Z+})*^_!~t@kdqtRaO0YRsHAZAHMy3`}y|sd-C&t@2`LUgCG9n zzkTQVkH4&{A6M0Xt*T#sTc&S6-+q2Cet!9!*&qMlhd=qts;YkkP^5_L%Z_#Q00000 LNkvXXu0mjf%)699 literal 546 zcmeAS@N?(olHy`uVBq!ia0vp^Ux3(ygAGU?RKM{7NJ*BsMwA5SrAr>EaktaqG?Xjb1W=A`K6%1686U*DQFT%n~B7hRG{v z*;cOuYWWFICrxk?So~-&a zN-xLieczV+E!iwNjN9P#F~h?%>Yi_sd(!>N?nU#Azp8xt&##%EK6G=XuH)%D`|5(1E&lUK zubJmpxQy8R{(V!kN{^N;$Tk1EL$Cgt`KOAhj^>qJ@AGFjPW!d@%X_1`G|>+w98xU2 z98v-%3K<~maG_xVqhm7=GdHn;Bxox6;m3mYpDy%d-)<1gdevUG-uQ)l<*YY*w@YR$ zJh{8QtX=ZU@fj~mOmrsS-M)0^k4)zaZL=+-&Zcd?n`05ZE^pWAp9KQNIj$F?_MS_v z{bc`Qi|l6k&7zx=>p(y^|LE`T--I!PC{xWt~$(69D>N B-%$Vn diff --git a/source/images/button_palette.png b/source/images/button_palette.png new file mode 100644 index 0000000000000000000000000000000000000000..2dcbabd46af25ee24062672a92906d4468607b28 GIT binary patch literal 1838 zcmV+}2hsS6P)NoG8+rEaYXDDEt_7f4~?sA#Y`WX9Qu$p zl`~BiW--^CX$H|@e2J+{D<(&a@deukw0H>+TeZ|R4Z|RCJAK$)y4+m^bIIM?`OPo` z|8wr0o#%PxdCooe?1P{munRE?NCnbRgc29fs7cuv>Kls?IX)Ix1Y`p-*Ujiog(8830+p3%~-vs{C`!*bl4+HfmCO{v1;87?4CRBcq8V7NNx8mX1Hmpt z9PkeC*yZL8899=;)KuapOi-=~A?I8!+)Yimo0@u?>I9zAq^t^gAlQYN3vBAC{*Rq8 zgQ*WbNczHsj2JUUd96Pe2rVsqw|zTJ6%`yTDd8_q&}z^Dtk9%f6S6?C3-OY#6a+BK z;b78&1x%bbPkHDXaJs&pgC!;GUb~h*TU&!oDFYtYq-?vYK(Gt(4v=ruC*|ZY%i$nR z1wdHvYjZPS6&A8*-MV1I6~F_Ul;?W7-r7qLybC;U)bD-e6&@=pA}%#mc_2)_^|%zAT}w9Wo2a~Oqrsr9AT`>$uVXI4=`VovYTiLa_w8jN5uP9u2ew~p*&Ms zYTVDU0`J>}i0-j8*oBx0ysg*nfAv+e^752LBb2BC0~k1XFx4M_+-3xCqPie3VF$crDgPBX0Dl3|V`2_`x z>RuuSq1zwQuMwWr&&tZnV^U6zvY<(@SgqW#WQkE;?q4eiUp9yZegV1`5RRQYx%HlV zlm$(Mr=x?{Gcq{y3FtPEhQ`M;JULle z%*5QBo^F&TN8vqf+{K8L6qOB3&W+>78Kqk+K)2&WDjS%exRey5lxp#9EOaqo&>&?g zlXJtcVMZx7$`}aIF)^w%n4IXC7^5`EqRjID<5EY5QR;{STJ%a=ON+_~Ca1G4;2dk4 z#TW?f7cMAEnViWPE-Ya6VB;>*HDgbhq1Q2oWzU_Wib7G z-}L{|6$qM?^}sg$tlewY1lxsDL?CKIAY(iLo*?#Tk!-ug(M>F=$JC#KvkYfi9P#n0{tI(u; zK`#V+8`>tse&9Y}lwWJyyO+TuN0JzL#7PmxoT{l|i^D;y+pU*dfNUrHcG*C1g2yJr zSHM%iK)+u5#TUd3A5P-5Y0AP8z{%=rw&mw@vbx$h^t2{rg;5OJAHi25s(?rIbLz^= z`OD)W_3pcsrNfx-N=w<|aNureFb=KOq$~_}O^>Z}oX}_!;wZ3CuQ%`8hr6MH#Ec9E z4jH1X9%k%XwTc}D1$11zXdEgst_%7U2) zSzud!KGh$66l}Oqlk&OCUEkOCdRf3$g7jFtY4T)l%grTy@nVL?$19Kghjg~LQ?+#~ z-|yH#-Iremo8kdp>`Sl3D`~iy0F>fwx*e3!nVF>JPMYZa`7C7;q zDcF29|F=Pe>eKjwVlJ>4xCNN3eAF+v@SZdM3@Fp2JQ<3civIk>b|KOLwMYmZM>Hur c`s2ob1E;zb9;93l4*&oF07*qoM6N<$f+*{14gdfE literal 0 HcmV?d00001 diff --git a/source/images/button_palette_over.png b/source/images/button_palette_over.png new file mode 100644 index 0000000000000000000000000000000000000000..448af496675aaede19002c28c1420c4499d7e45a GIT binary patch literal 1784 zcmVX;&4p- zLmY}S@r5GDRW=+7Ls1ZP5n-}9Rx_Q}J>BS5wytT@G|lp8((50&sW&&N>$cP-m-7t= z+V45{63+SdcYf!0&iU2CG$0%bwga6&7Xp<;FK|+lm6Mfzv86%-?+4ZaYk<3efEcrB zMH2W)D_>SZ7?x`kz)IkGU@cH5#^<_WKkyOonItQ@|4j&*0A2%b7h_OWI1Oxp~<~~H*oVB9&s}Rxt{aiS+hiqoV zSalG%XEMuRxsvI??)1~qxdFF-sp#=4Ms{qJv&TMRH2RmZ>RZh+lq@mpCK16J;A6mA z;2PZXn6)rSlebg!bd|$ubMX9ked+`%E8{3Vu z!297)&`}ioF<67UjKQL|IcsSStbp=sRe>6qCR#i0rSHT}J>3ax1GY|P5nk8-;_`LT zI_o}E@u}&LH*hn7+4mbYvRT_KEVc;YP*BFOci_L_4q*vQf^|7hoE7&w^;3vP8JOQ__3lP@8Oz_XRli`71^qW=z zZQS=1riOLEgcn)wnoXl;!DO2m0yPT@9{+M8eS7ufI=v89>T5i{rNTEbDO}Bqj6#t0 z&f@Cg)xr`~RTaHvLO2^ca5!7Yqz4OBdpH#AvV}vz4t)U0W_M$EdWC;rW-&C)&mbQM=&|Ya~UI*ED^$ZHYF^A z$&t$@jMRXQ{OyYR<_GpQA!!95Re>k8^@O`_MU3?qYK;zLKuRed1I$}^KaHw!;=mceSZRoqjP=(|}wyK`PP5 zSZaV&;vA|vY3k)(^7$3_P365;oQpXe3T`5wZOwbRwl;?ci$&z>uGmT-6PwC0!W{4} zuvLT#Mo5~NAw#- amBc@(3)XVA|I=Ln0000O=|v literal 0 HcmV?d00001 diff --git a/source/images/button_prompt.png b/source/images/button_prompt.png index 2f244c2526fc2407a1f57b055b686cf474a739cf..850aa963849462d13489b79ace62cf6368fdbea2 100644 GIT binary patch delta 1708 zcmV;d22=Uj4B!orNPh-`Nkl&0tF38hQL z3k?-Y6bePPgI=Uf$SKq!R4-I2)!G{u@2MeTg%%6VmqtMFgVznmSd#KRSDJ)Paa^cK z$mQ$BLwx)_htSVLjY3<6GGPYrmQ9i=W3f@jrsGW*Vz|&Qp+AJOaUX!6k}YF&kBr&Z zk}@q7+9~@A)_-nENujZG=hCoAlPG-15E|-mP)Jx9ZV%`+UcPuiEmy9P``$fjzI>S) zPMn~o%1Upie=78$&?=$A?p(i5H=Z(u3;iIp#_HghIddpBHI?EPETDm-M&XWuH_nsW zx9Qf=qvR?pqsCLGyq&g9=u08DTBtu|`aeTN2py6gW`7Sx&zeQ!v$JX3(xtc~z;CE4 zETkLz_Z#N0fIHqF2|e<~5Nw7Lp%3%}$s0FP!s^wiec-oLZ{JQ;>(^Tysu0RBP0?LL zaGG>NXtqZmAvu|*ZP`M@5))D5!0%~xI_cN7YpJQKNRDsb(`n+GHTcs4Y(+v|o)Oy`Uz;Dyc@;ced$D@PIFWA|&H}(@yqlFpjise((PGg` z#EZT}z1c!=s?;%CmB$+lLjYhy;ukG4VqAR~MeXyRI$8*i$4?WMEko-7Yz@b_Heknd zkbm;|vFljz;g(q%9vMj=JDt>b&>++ruq|!Rp3wn^gWL}usKs%dGR^epOsA#648Zn; z_U~`Ry2eaSnNrk};YmqImq1X!v0iuRkXn?&EyQ@WBr-l8H3fnKi&!5YrW;~#TpU^m z5EK}(t{H+`2#NVIzjlpcrcFa_0o%i|u2I7+M1@-NSLYQ90I($%v0lk7#D5vJ z#C7^KwLN`m%=G}kuJGi(KhK@hi_6VEL`_Gh`u=^o;W@tp0NcSa{;auKEvjA7+S*`_ zLmUwL);w~(pn%?6z8tj%YzxP@#y3;`_%j)bkTpS@m&@A%>448zMjGc44@H7 zNvJ_!8>)Biq^o=O=*6ETu3L9UZ6TN|W*%ko+vd&GQd5Ik1h#-#Nd$AJ`2xxfcp~}vSl<~BsFVun%ixcwHf;$&3P=8r&E@~76 zG#tYm%Nlv=x~_U3q9e@`8coX9rw?!5q$a16-pS0QkWg$k3IeNT_+`~9a-BJ&AKD@G zo#;DIS1p8^I+d#he8JL{E9qWsEovDA1RSd+IXPBlD3>wb32%nrHz#-yqC!ufis#Lv zn%%om+rY2k80A>CNRujLY=670e$VGk7h`A4pb1%7Mj8cxzi{*9Nn;e+b@r^);c{sP zpEg}I;r-@#-w4Z|H5+2&)TtDgkwF7Tj>H`SZ=5H0@6xT361po|12%*gcE~iTN89qM z@Pf!cQCAzcPo7L;Q&VYJLIQ;qNFKUyl5s*|G>;Z z@H*f>$ULi}UK*j4v?b+~-j*Ts&P$;b00GIr0t^77Njh%TTdQgS0000)G;JhWji{x? zN=n2MDMW&;K1hY4C<^+Z_#pVARFsxJ1i_*;SS$t~iqb%eqDCvF`M}VU)L=|X+K^4s z?6zr=-FVLKop$E#Y|O`|*`59W;DqGv?qoUp|IfW=W_C`>xqr4734mm!YWq>k-|iT0 zJC9?higFH*{6CIVq#eYN07nOhm!qGfRmDUsHoja#lycN_)F~rC{9vUKja8fe-mgp| zrZ~yb!ZEbejk}ikx=N0(IR-fnan!;LV3kc$tF$<%v{`vO3{lAO1xFW0BR&TZr!*>! zeyKFOB1@({9DkpyTEUjAyb8))`ygfJtf$npEXv3(qm&d(93Xbg%?0SXZ-4?be!4dK z4_zHSNB)VvXiwkE@hr#794BIBh;)vF9Ix6vn7eih<$5Y9udtfZ))e3q11pN`U^8>d zL%-*E9-!j&bu@Ehj3!3T(p7Ia8>CZziR{3?G4&PD?A!azmQKLUlTJby;-d&4N z0>mA%gO(Wi_eUD)`$m6wr_%J((M;i$ z(`$?xrGM>RcFU(|N15dC)edW|u$eYgy#q6Vgh8|_nicJ8>`)q~g&3lN!Y4Z{X1I6r zo8)q(A`Cwz4;jh#Wlzta3r3R$Mm6ko+Zl7hLEMw%|b!WH{c93 za4PvlkAyUCLbSivY={P{gC0lLfWv2r2#xPC3{gg=YsXXF8JHb_<0;@}lW5&UB`=%G z#D5Um^kUkTdIvHF9F5DBZdY7y6GLn@k7VXnAX^|Qu+jQfF@$AwO-2zi1(E_Atye@E zBC{Bo0?A>BNUetqVY!yWotBGCfutZUJ>uKYC1ME6s8)Fc;M~GG^59Xn3uyt#%3N?( zADR|JSnhZhn7xinfutZ1n9_%QVhFG0Nq;jwWC|n&!N{HegcxGLGH2WvMW#SfV59W` zF+`7fWXeB;Oo61pM(aIdh<5Xcf1($e0!e|5*3XC`elm~94W5F*X=DpHyMADePkR5- zhue%AqUTmo?WeKf-;gojXhh?)Gn3|_3su{X4jAVlj+-Cx4*!CT0Y_t_@n-p97=Pj` z3OAilYpcG{Ju(4sBI8&7(C_9KP#(Bx2x(2!VwqAdwtRE*=jxrvShSh?Z^c2;R)ILx-Iqgx5&B zlw+v3In=cUfJ8<#ELzrAPaJQU2Y*~PPdH#6@Qt6R{_f9^QIODxhDFO72Y7ZEna>b{ z9D;4K))QUych@Hr49+04AmL^P(XMD%qlvWB4bco?ES=gSOwoCeru>7*GDrwSs~0;y zwlhPU(l{;D5OVFtZqlxEk}2o>nfGX9@D#EQ;u_JYXw_z!)ULE`dwtS;J%8rpixJX` zE28P56ep9T-Q-#KB;^-AjO>HBVSMCI@?QGcuIZvNGwh}%HeEDK@eGCgMp(KEg<7C; zh#|7`H=!*rST&5cyuR@ZAwxu=NiCC>)t1*-KD|QWt74_QP@e8ciNW4u5sll8e!>96 zl53Ow3vJvk$XBH0$Z7LJwtwwj#QSJgQ_e@E?v$(}Z|r~G900cyxjyM_j^TyAV6k`I zkPYwSc!;!Xp8$v>T9iijEyfIsogvJerEo|1QVKU(sZ)hFn$dyPKrW?d We6}P-j8}310000_@3WG`lqacW+D1ss(k|Im|ODT*ZNs0o?LIpDwSE4anrjxU!+wFG0cDvvE z_IbWP^mE_c&D(ZcyYD?Ocy8nQ{@D0@@BMwA&u^U|2!NbDvVR2%h>KY>vlbwT!sB7~ zw``N9y=!02V}=6#gAQh!n5}2FhMAL|88Hh)nH`huz*Ggoqo3yWoy@*rHppxbvyCJM zVivK;FX4BYU1WBG8KydAvn_~D`HvrE_V9H60fHzXtC;PT#qr!!ZZO%D3E%!7FnfH$ zn;LCkvebjQVt)ZWBBJ0V;y#E+2O$yl<~pTG&R9?s&tMgKCIqpL+5TK9QH5;@RM)M9 zYG(%+&2{wDh#4oHib8Ox8zRAr5EwWKf-t5&rGwciX4{$VETkY_mGiW5)VjOC=C}i@ z9Ic#Jpr=L5IAsPiI9#hmt6#Jp{7e)>{XfH4I?kVFWPkQPNR2&D$QAKv2?A537u8Oi zqYY{oblnt!Kq4UiKTMW+;A-3;iesq%CuT>~r(lE6kIXhO8_snf-7WedK4P{_?VQ)} z5Y#Vzke&iDXYmjG3fHe3gj6D=K6IMdz3pB5qLUTGxHPHUAzP>BX!K zuJ-PQ5r6*$^`Y-EQZP}Z^G%tsZTD^7VX10_1xq%A#kvRtN{@)5sAE(@W9v5XT-XC4 z-#PverZ;afdp(~Bfx|BFYUjxz@ol^W zQ8eiFMyPY&2mKfK^KKk~`UammsUrjq$5^EtwAx!>@$Ju2X%d>jd-V{rA9&XYvj!F= zhSd>bEiVSdG4F1Q41}g|y6=b3&{>E_2X4IgLF#9FQyn3`2C4Hx#O_)RuEvd2f`sPq z{eOED20h^QfFq648l9P?L0z_eV70XZ%O&NkP){r2GlE7fHt6j|~2rKW=>&vM^O_T&>WoEU@F-{OVy%7YO0!ows zI(+$OV$CuiLZApilmvp1QoF>S>LBk)r(;xyAWDL#Zp}lKg@a&N-IF+th%B$iK zk6Z&&g^Nmz(6%6M&WTXyR$7@31J`3c8twz5rJhQR&@7{&OOQ&2d6$O;2M;fZ=anOo z;9pSVq(ub??GlUht6ksXha!kWAb&0I=TPbq;Xn^qYnD^V5t<{F2twF@UhV!2Klmx6 zpYTz_WO0G3=@BYDLURPXry=M)!@GJ}y0n~+5Xgrht*0+;eiDyfXDXs7L1+uiepF&W z-cx?z1g>ZtHD@4PWArkD(Hh+>8!M?VaCb~YK z4h9S@xXZ*>z^&gjHkK6oDWW5NV6irUrK*WVj0$=p#H=F-Y4If;i(Jh%MhWDX`YVvf zUe)>bxE*7L6^AcC+EgW@29Jgv9=Kt>;pGwB#4;;XS?B-KN<6~pZ|!W$N_e| z;r`Ue^SSS2x}Z^d_kVyi-U)XntyZ6qhz*IR45~F4ZJ^VY(bFReN-`15XPPrAWEV)C z%_I5Vdn#ixcFSqhYaoq%vgSH5%O1f5F&kjr7dx1HCVQcNihmG?ioeWkA+r}iYLQCQ zb0Gdlx4&V)tNPh-`Nkl&0tF38hQL z3k?-Y6bePPgI=Uf$SKq!R4-I2)!G{u@2MeTg%%6VmqtMFgVznmSd#KRSDJ)Paa^cK z$mQ$BLwx)_htSVLjY3<6GGPYrmQ9i=W3f@jrsGW*Vz|&Qp+AJOaUX!6k}YF&kBr&Z zk}@q7+9~@A)_-nENujZG=hCoAlPG-15E|-mP)Jx9ZV%`+UcPuiEmy9P``$fjzI>S) zPMn~o%1Upie=78$&?=$A?p(i5H=Z(u3;iIp#_HghIddpBHI?EPETDm-M&XWuH_nsW zx9Qf=qvR?pqsCLGyq&g9=u08DTBtu|`aeTN2py6gW`7Sx&zeQ!v$JX3(xtc~z;CE4 zETkLz_Z#N0fIHqF2|e<~5Nw7Lp%3%}$s0FP!s^wiec-oLZ{JQ;>(^Tysu0RBP0?LL zaGG>NXtqZmAvu|*ZP`M@5))D5!0%~xI_cN7YpJQKNRDsb(`n+GHTcs4Y(+v|o)Oy`Uz;Dyc@;ced$D@PIFWA|&H}(@yqlFpjise((PGg` z#EZT}z1c!=s?;%CmB$+lLjYhy;ukG4VqAR~MeXyRI$8*i$4?WMEko-7Yz@b_Heknd zkbm;|vFljz;g(q%9vMj=JDt>b&>++ruq|!Rp3wn^gWL}usKs%dGR^epOsA#648Zn; z_U~`Ry2eaSnNrk};YmqImq1X!v0iuRkXn?&EyQ@WBr-l8H3fnKi&!5YrW;~#TpU^m z5EK}(t{H+`2#NVIzjlpcrcFa_0o%i|u2I7+M1@-NSLYQ90I($%v0lk7#D5vJ z#C7^KwLN`m%=G}kuJGi(KhK@hi_6VEL`_Gh`u=^o;W@tp0NcSa{;auKEvjA7+S*`_ zLmUwL);w~(pn%?6z8tj%YzxP@#y3;`_%j)bkTpS@m&@A%>448zMjGc44@H7 zNvJ_!8>)Biq^o=O=*6ETu3L9UZ6TN|W*%ko+vd&GQd5Ik1h#-#Nd$AJ`2xxfcp~}vSl<~BsFVun%ixcwHf;$&3P=8r&E@~76 zG#tYm%Nlv=x~_U3q9e@`8coX9rw?!5q$a16-pS0QkWg$k3IeNT_+`~9a-BJ&AKD@G zo#;DIS1p8^I+d#he8JL{E9qWsEovDA1RSd+IXPBlD3>wb32%nrHz#-yqC!ufis#Lv zn%%om+rY2k80A>CNRujLY=670e$VGk7h`A4pb1%7Mj8cxzi{*9Nn;e+b@r^);c{sP zpEg}I;r-@#-w4Z|H5+2&)TtDgkwF7Tj>H`SZ=5H0@6xT361po|12%*gcE~iTN89qM z@Pf!cQCAzcPo7L;Q&VYJLIQ;qNFKUyl5s*|G>;Z z@H*f>$ULi}UK*j4v?b+~-j*Ts&P$;b00GIr0t^77Njh%TTdQgS0000 CBSOjm diff --git a/source/images/icon_game_delete.png b/source/images/icon_game_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..b267180505173e4b16b2f4a1df40dbe977f05247 GIT binary patch literal 5892 zcmb7I0fDd`Xpq!ES^q(tcf zftTN(@a}cbJ!_p0cYnKQ?;WS7qeenVPY3`2NHo+D`j5T*v8+INk9Wq`2R)XGOD|K8g*D*5X#WU5pCbs6e~b}*J@Y6=zC zHJ3eh(>=@)oGn7M@-RYuz4L?tp`(p`x*MvwwqdIToa8dJC@WG5p$;$kr+S12E) z(@#lW$|IH{cexZVLLB$5q;2=zyLXLdLRG*;r>|;YjoU@SsH0$z=KlHX=hd_ZZ2fs& z9YNKGA5C;eA8>Zg0-ovWvJ(#oHT#k}(yUk{&v(&|3Hb$;Y<7O{ub?(adW2t3ifH9L zDdQWO?Gf}~d<8BTR8FE!hZ5-{{Yo09upuHN6&AyPf%cx3bG`h%7Pt{f2Df^A-G1)S z_wg9J3Tuo;_n?20ZW}3&YOUpTH?+0;3bh<9AVtJcAa8H)>j7E3#tX_jsC}^yGnWyz z`hcppM?2Ob8)^_$JG`FZuUJfUwH|n~Qd3idhGTXzM3XvIu)oJYdwMInbjg- zHK5U5K{{rEHIuZ&CpBFxI0=+XrwHER&l<1mex|8ADj5-T--tBg{?MB+MOt|8d$AGQ zVENp#!;G{;iNFp|p_4@qH+5-2(IJSaDGY_&LeHkS*ifM3;V{%)Ie&5Ib(7E^^=t={YvMkhEL_c<6-$ur_cpt ztwlF|#VH=68y}c6{JD2!+}M}~NFs9jqBv?(VT5v5L^do0qDjx%CWx88L6 zTkBFvX5J}nhBork`dgwZ9mc^mf8$0WrFTk7s_o$9J~vjz0Z|I)jxOwz+X_7rT-)a%q5;^9a zs2#%SSmn(F@w%B&W0{|Z-?~j_(l%(Y=-+U)cl09+paE=QDEeXAStR>tbRMM7N~QP< z|NhnJaq739rqs=$ANV5T!xVwQ@ZtYa z)}3X?G6y(y84Ki=_v3)A--s~>ZrH3bH*}lZ@5N|fY4Y!!hA%e$sYz>SS|^UeYg$p#t${=ZVfL-=#?-g`iUUHPKvZ(uMR+mhyrcQnB+H*GOlg< zL8@q_iqmUWnpNQj33FVLf}kscgOfjjex zB=WzDXzx+!I~{}ESPD@fs}X22``ACFMI?%jSjRh>v}on6k^7bKI*;tgPQf8JMdyF= znS_$J}npzYnW3_0ZKr!mG#iXINan>W{A7u6a=<>i5h2M~4le zU3yTtWI!sZg57M7V1ZVtdzk35al9%7S~P9#=Vus5)G=C&@Ax5%2mB?9-tzu1AwzUv zAoTvvp!~xh%kd*)V>1f|ruWW_wHD~!OH4+~i6H?`g0VJoGhD5G9;h)C#mR16`qi4+ z0~VAZ?RGs^*A^`N;FnsMipmtaq+=8}6tbiU+WanQh_TK!qvJA)AiOE|0Xg71<~O!u zF)S)VHvbHon`9;lnzl<=yxGJ(Q5NF*uO@sCOCo9J%~nHEwfUGU%k62|lZrTiHMJp3 zZ=h;#{UbI{OCuKvFx=1tlU%We5EFxmtolq?c^ZFm{t0o8pv>vr$tmY~HLM`MmAos$ zA|qiN>mcAX9Kqx6d1U2I;Y^dD!ZIhI`saK@_hsd6X9S`GwUIW$QbVq&nEQ_DWpNCy zP6l?X=s`~`TzrPD*oSPU;DDA=3?|)V)xOlb7a2l6%u>JBbLK)(t-;RWn|Jxpr0{&s zRdMnOmA%?zZqfbcD*l{{tONz)R6g22f3_`a;}p`uqUpHwG#M(|L+{rKHWS~>vX!Z; zBJ$k|UEQyGL(1I*8T@icB{?qCsBCze^>${5nY4>hiaQD(OyN2wn=9kWQ-*%3!5Ok4 ze?IAEJ#4vJ)|h7|?uU+Es(iEL%j;MU_{jQ9^W!m@dtvGnD~!krsr<>+M4dc_a`cfam!XOeC`sbJwf%eTA`cmTf1N)3IjU zE{k5C$RHg?{yWUR6-r1%M16N0wiZdkKlulSaFMqY+?GTD%Fp6lt!#}~quRWo@uHF) z%x&+$!NIt-$TpXQMVcu8+9Wswft*VhMu4LqnBWSKtm;Dwe$i8p7i87`L;fC@qb_F`_D z3E)&qFIIh8D0u+7(KF#)uK%lkI5RlT2De(Xz$t?YcgY{^VQMK)@U z<$!gOGu~nnp9PwCcYfS2CL89`F}&(@+?x+Fqz?Bc4vgDHPPWl|zt&dm+NIhK2)xrt zrjx&kbsRVEu^kDKRoHBoA3auwv6tB5`%w!}Cug*WPR|gUrpac9-h3F%og7$*FE(iB zbkaV)YprQbbD37Yaw)O^&J=jhUTvQ|cw?sTw`THufa2*~?Xunp$E>TqJ9HiF=v=eF zs|#D@qo_qebdZ4^guJ!~!FeU5q+sF1DsCf2dL$#sp<@jA;WxnYuu~RPy}wUqCRH$Cn?GFQMU`vT z#57kO#8#^wN$d;CoLzo}r}v)VNb~^*nz=*A~@w zw-ueawarI;3GgnCJ+|^y@bCA3B?(@jpS$s2EeU4-;@}!Ep#gPB^HVy&f2BY9GPr-W z#Yz)tQlMG&#bRNno>*L5T-swp0oiM)7ng^v`P_9?^8t)Cx{J-};N{}-0Zr-EbelMY z%z|iIJ7p5Iu3Tay={PxG>NosOuFQyf<2aR;VVx)KN92{3zAo=0uKSF6L0JgTl!mNV z?s67~;nn?luSK?e1tghSHhDQt)a_x3S5Gg30KYgAUR?~(x3-xyC*ET-UInlYH|@9O z=4qE6J&M%*3~t>U*1(z4UPI1`n}KgUOipcgXIIJG)D5=PzoBLypDjJFaW-&b#K%sa z)=u_bjVCN?9oK%Aglpdf+&fZ$kz6)YLqUmONTkeCd_N(+b(AD5G}jg4fJ;O?#kndo zke8L(`A3i5WiK*sNMpE$kKEu{brLCL?O~{H`v-63&*WAe*m0jPfm_CgJ-VJs)pDoP-Y}5%_SfDT`HK&0T9on;F&UF6iSJDdXeF5jT<*TtNz%1v*D{n7?0h)oUO`%rr_t88`h?X*2{IaMyDzPyB@3gx*WV^G1b~^lJJ(WGTqBc_$$hJ-PGh{oKl<8FYvQ+B= z^q&km3bal0(Bo=%c2~rBQfpEqZvR9sWN+SV|FyR zto%hifGWj*YDk8K4$JC(unzbylKoPIByQ8)(J z--#pg@>`}fCoGSkKe5FmlgSbr+4&7QoK#<^vNA^WnDN;o8=$uu@r7qEK z6LeIU9e0!z{wfNRj^8Q;k2Uxmv#kB8nRhgU`M-U5G}^4D&tV>w}<;^HR|BICD;6>0I7KD{owe12(j_2OVa-awOe_&PZTwRSaL!ifM{ zD@w4K=J0eovihj#P8h^<0cqdEUJ4w7D?el^FgpFCr$ly zXqAY=dGSBK?@s^yivBLLs5f*sNm!acSZ}aJErES2GnySMT;A_2+p)e}o~{4yHaB>( zaBv}oC6aLb+ol4=TrT$L4%8+C>DP%(&)T210-KvfUN+lLRHiV?9mF14D12iK*5Qo? zRr$>^nWC`Mv*bmqjo^V#g6n%;ZBJ+FUmuSxvT$?701zC9Mz2D4KfrClRvu#_uR1*? z&3TFwq2|dc5!g`m?{MEiPo_MZjU$p@TCU3sQm=d-Q-heGE+0qAsvh+yZ0JjU{*d$M zw;WbFh}}iO-rKz#$}Y2SC>#$R@T#3C?{iVa&^HsPGT{`=c%sn|%F(!>wk($tVR~bB z30XwrE(qN2Ov4Gur?nhe9~zPrjsxExO(UMbFOs{KO-&TVeO zxJ$6_Y4F9!<^rkTAgR zdQJQ>FRYsCvc=Km7x0~md(Q{?ryFu-wk_0nSV|dcU}{zfHVnUxM4i)xc{Xfe?2N39 z08Fbyy9BkvC_@t&i+w4y*UuMT!qTchf!o#l0w%@R-ww?{w z)&)=mK(hw%ko!s&-Mj3jQSNukBL+B$6}wD|UnZ2Hh4N zT<|)-jVJya8l9qAwz(eqaMwcTEGrmzLw~`YA}6_3;7V@HfKv#+%X;^BnBjHn?u$LI z4j*^T=$-9K{$G_TY*WMM)>+kaNL*g`!b%9lm>za+EwX1+lvH!kF8Ms1!__vuVSnF0ATB@gRtC+Hbe^_>gnC`1}St6_9z%AzgC(N%|%GcgF V2D^C{KIYW`4HX?ky^>YL{{c*x0hj;) literal 0 HcmV?d00001 diff --git a/source/images/icon_settings_screenshot.png b/source/images/icon_settings_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..6cc3a45a0b100a3ebb6bccee06084807142b97f0 GIT binary patch literal 11719 zcmZ`W(aumdQTc#+IsEY7%R$3 zA-w!|<#rS&y^g$fl!G`UAYkDC*ANlXGf7?t(Ol$}rO{w0c-Z7fbZ=#P5fG>mp3c{PmsJdW+ zw@o5{#tIX`~svj$VclnxsjoaBfXZ+vCV^S_oe~jnRqnt-< ze_5ZKKg8d{N0o|K6BUL<9K!qUC)uj2F#Y$N{X2eiDLP9$Yd2H*9tvx^y9&;F+BgYO zR?8J&187n*5eh-T&|$6^P8=j!6sa>H3hhT`i+T*tVqZjuV%X!BIFtDERZhr#n-JRe zi-R{z4>k=EYxg2aqBsK|H6ud2RLv;r^ZNwDT~pTSIt$}}jO9W>@{xRDS}D`^a7zgm zUc2`lbj)p@&-cU}&$Fse2DA5VBCqc%?|4eVKe&5x@1)UNZq|CkQCuIjRFT_2-(S&p z50E+)1x4)IL6Hif0Hy>0R0~)-tvhYsJj^9oy;78HmPa4zK0Dlx!I9~8kmLLB^W~Hn z+II7bs>naf?Aun^I+fG!AnSnw&fn(|#(V{Jgwhb)AjZ1@Y(xNnCLT-^ia>({qQ?7} z47Myv0Miyp*eGYi8}#givapV|qC@`%RAv)SbX)|&o{yIvKmS0+3+TF7qw4(RO60)g zyLTN<7gm5Q`8#8rk zvv-G(l)Ofna+2P9)`C_0`j#mZPtUZk=23t5IG$p$eGCQAwt0=a&Qf2BkqHk1k2gN9 zEHD2Q-;<>#M3q)Is_YlUK+>(uJj9~ftr9-n{+VIF+Z~9^%EmT*;Gzbm38BWp>3ihF zDH%!ZF_d`yR&VEMc(!*+s)3+#iiK^319cJYD5kDe!}K;prFquKC~t6P6HgIiH9rGx z@N(!6Pvv_xdgR#uDXptX4dpz`VnSanxF;aXFK6Fn#D%Ybl{qtxlG9;_T&QJ$?$nEz z@uWRTWR#OZk~tKL#Pk7xGo&#Fz@fwm!NHMo^g2Dq;^XJISS%JBcjPfL*}|J$dS}8j zKoT=C#4TCAYM!@XVr7-E)8AjSc<8fH{c_yptL&-Z%H~_|zXkVmTSC8|uP0_79zQ1e zIk@#UY4}Gz(2?(_{er$fMO^zO#p7ArBY>Y=RL1;U!>}4SU*lgQv*r{Y4IOon8i3~W z9K{PusEpO{<|ZDt_~XZD42qF_T9hA3#fu|&pl;;OeLE1~lU${P&y_bN4(S!B2!Jh0-S`WY0jZue! ztYWor0~7{8GIF63AJl%%W0zhhiCChPN(==M;GG)T9pf~wd0}L!L~~nAs6ovxsZo$n zjB~i99Lk|$SH5v#tLRui2dAsdpY6m$N!*p^Xf?Q!5X#2z+{hPe&{q=Su6H??p%P@(qpS-ulH3MD2P*V z!N6a%`R})wOE||z(%8~6JQ~xaIImOOfJBAHi=*z__QN)V=PL_wZnW(=L)iW9>s%|7 zt;Js$#QWI)-i6UIY`vA%T+gz2^=zugK=;e}Qy*c7xf*zIEe|@(jb8X?Sdu}tR4GYO zA+6V$`P;#63ly(Z>Y|XR>&^LKbo7IOi)HNfwX4h)rx}FD$`_&Cy|mh@PNlfxYJbvi z_b+*Twev%4*KK(@@jU;Dxc4*C%8K4Q@R|+*>KbY*hW^^+@6(OEa9D`O^p;gofj0CS zpr-#uhUv3_%I6T8t!BA~3A$Iww$Zudut z->`ljtJ0P5TYoxDO&Y#R=`rkf;WHA-P=}%>*W(zvx+YV3++t7dyG+XzKw~`f?C>SQf%k-`|v6CNU-G=|aoJ*VUW)3WnyS4BAh#pRf&bR0AtjmqoCR`V*TeC{VJ zMn$8>JUGP+#mv9E0_gBiY4C7;^ZJ|HzDSWT?ceIHJc-Tngffjrt&8efJ^w9$jXpo2 zfg@4?wP>cs#F^D6yy!G;ziT6;Q7-Tt9*H!w@n%=0 z=cMCUSPy*%Ch3g4Y}E@4FOk}tDQ@_s>P2n9?H52#>PlNAlC=` zutj7?`R;zo4^xM1=Rfx(mjqmrr^p#%}spZl`{a=awKz##1LlJjiuldaa@;Y_3GaMpQ2TcjOZ zt&e-yOO)6S*~k~J#w#nqCcmEphFw7FP^ejCLcjN}(e)-@~_9xp7x6Z1H4khT08c5Iaa2tYCaiq5~zhW;fAKI9L zBO)dxA%i6M39>xr|0vv5@ERq0kKO$an}vQ)m&{VV!!NGw`xT%XAmsNb@Njc1%ZxWF z?8#h<(Ly4IFQ0E7T%RF1;Ab+1)^VwGSUNJ46(jvUpB1CMTC_|GIQ=MG=eaB2sk!vSe<^WY z6l`_U_43RkKmFE}%d=MkKuL2z8_w|M^odJ`F2s;0TW!o-hb$0?LSnMlAk50jHf7%& z587mnL?y`ar$?O#6=jm}!9+3szK<*>@SUnFOUs@lPS%5}Cb<}lwZ&?tX~a_A;f~R5 zh&9BrSXTBWQ>D0$m1U%?Pe}F*7e`SMgIw6nR>#p;1Dxwu(;n8}?7x4(np)JYB znz%Jb)*TnuQF^al9MJ4ZY4rCHU7Qa=q2>bQoTRaPw-1?K`}BPC3#B7~e_AZX$;~>t zUw5ZABsI*2Jw(ip*O?XMGq0z~WFGsw#3LANle~7;kZFnd2OYYys{M}1IKMpLus9ro zXWRSGZpI~V2yLYykt55Yw8|#!myxVwfsT7;8$a!4O`Uk18SgpbV+YGI@Cq=0Z^TbK z4()SW+|O*iM2=@E6C}1L(-oNtKwX6OC$fYGm$-`sod&a*{6m7#7G_GOcqNEwaD61l z%z~>s8W=qSu>MGQ_lmWW(n+D89foqlC(eIO`lejRDsD3{I`r>UN^}bk&fgG$Bp@jw z*H`irS>ls7H$*EdE7#%)V49F2#4SK<-2gn zI*~!)aB!Gk*QBF>6w`Q5qb3NTF>hSCa}Uq9a54(iYLjkWk+unS_G^y)fJpUT0!da5 zTeUJQ0sh`IWeX3vB<-;9po3YltV|b$!5P~VRkwO&G^-Ki^z*YEHzwlLKp$cHxk3w zmjA9l-eW+`hE2I*=LD3ImbSmgqP^ou_V)p9w%VQLc?z^+-yuv4gb7Zihaa*0ff9^( z#$oSo-S`nhBXsQ0@{v&UhR@Rn8lWDhi%UzpGesBxM9uUIk?TM5K6n^ER0hAaxgBXs{|O&c?W5QcTh*aFq3()UWwvuX~NBWBeZslO~>zklm(xF#gDi z-Cp7+V6EMp>dWO84(K&QBeXWt)C4n7ZTtSq^+l2})FK#PQ{WD@lJN-IHytyaa+n#x zL7IR>)fEEGw>>fF>BT(WSjFjC{a5zn0~MCD*vT?72+RU2nF|SQPi?mQqne`Y#~v3B4&RTQUFq>?Z% zEO1CyCq}(Fw9V`+tORA*_mVH4=wSW1xw_HfRtXo!0^=+vnn~*iG$A zKx2xejZMXgIF4v-;+XkorJw4$$3*J>BYclv9T-E_|K2+*8_l<$NS&xL+l%7$lE-Va zQWpV0A2oGNX1>Oh-Rc*v|6Ov9wbX#lCTYxbv0xAp5nJuB6%r)8H#IRUhvv^&*Vg%m zI>RUNkzxi+bdRyHMenG?u_&d=7lYd$s@i@%WIt>U%?M6p3kE}-yi6MGdtHy24)rru zb6^-_-HOF3M&;-s5jM57A8^a%Mn3A&gpiM~h-n}27r3e^C@*`iY4VOTBv3%1?LPkq z2e#fqQq(7_I-H^MU5t~?ty!osOh1N6tYbMfH2ZI#mt^m!!o?!AqUPq11uU!@g+#8V z{KMHW>O_j?tW8)H)iuV<@v}wlQN*u5i-%6Xhh)lW~k?w)TIezFkrPuhPaZu(& zqw=VI+bF5&WA^n5JD{mM%$MVK&6~eEQ*b=39u5QtYNVhFjZP1&XPS6hgge70F7CGC zoS&{2oCYI>hc9EsOlyU13WFGK=-l6b@|JX4KT6}awYMvZoIbhL<{nL+2hdar5w4Y^ z$NOKV`f&o7-VE$D7*x)re}Z;PdSrWSMhd`H*z$yY9@a}MLUBsIggRrvMb`!eU9&A7 zXqVV#5nv&zdpnkBf0nC@d^2F0B;M zC~T?4t+&2s-Xi%hUpBF`KeMWwl(EBHNy}iTcBW7X#lY{_u!*@hL*;SnOnp)|J9T5g zBKHMIqm}@Rp#OJEqM z`3$zRU)&><$ z&vu$cw!GC)bM*#u<@5l8?F6D{s9tts7$iG&VB4;v*lS)vooU#RXMKA(>96B90JJM- zmAG)>!EvU7gjGqfHrSDp5437_rgl7AH}X4P@Q)UMJTmb)xy-S!Xrm%zlrpq(ifryU zwrjt(^ABSkwb~JU&`M!4mzKP;T!w92jI>UWb=z zhphi|miW4H)8)H|+&}r$nDgFc#napJUFiH!UCc@-c+<9jq4S29((CLK7Nrn@GuMYt zA#xAsl(^jw0HuIeCjtklG~+J-%<1DqE;`z`C{B$nEHajC!-lzth>4Qs;|ftNCDT<7>$rSrZRj}&L?#z< zv2>UI^mCQewCvUxf4LZGD17Q;A9vEUwJd@;M5cJ<^|UdHG2+YM%;?wSbH(>_h?{!D;cHKcS4$8VhO3P|UHYU>KgWtJ$OI&|DS4f_H?cDkLah|%7uWCmK4jfI4^Sde# zIp3Ba*y5bm+P^JS9#UBEFl(KX9Q?ZN->EC!T(0$Wl)a)FGVEeK-^{1|CKz#Id9^mH z#F>B6QpDWEB#X?UJ;AMQ6_|XC3ch@y;i2nX7iH&cc7F(O>mQ}`(%DMRSSyG#S`iv` z6xbGj9E`gtdbtt^{v>YC`A=x@%Bd=wWVb^lwQ=sL+GqRaj?n@h;FGn4uPQ!X$-gSn z(bDN>%0tPbM~q7ww&UeutKa`xWSclAH8%3LuG;I*Gf>ZGs}`DZ=7?A@`zH-v?!&uc zPg~HSPR&Bc+IoYQJex^5j~@)~N3>t_;oLgHDyx*!nO%fJFf04j$RQSm(0wdpHgGq< zhho{8qg{>7%{#y0CZO`x)>@68^=&TDJVu6YB3pDca1QyZwWH)?LVynPN3G>-U6%$T zY!6-pgDj4DX~o$ER>h{Krn?T?--Upx@SUrGd~Ot+m}gyXI{Fy+E{yDvB?S$8N1=T&;=GD@8(YZ^j04dh(TbkAhK~2qM_7SkAX3Pm(CfFlecQ1Bw&){H$5;Nc1BK~$HtR^SrK7Hh0d6FZM0Dx& zq{*nnB*vU=GJ}^l#O#^yqhHQS0|hN*@hB&&4p`3tcs(pn-%-5JG_j8oh{bY|@*I zJ93y{g&i> zD|+h)d%B%Ib{kfn&wPs;`@QAwxauM8fcFUVD?)Vp*V*Uk@D(1&`gT4e&HlB0ihzHj zxFEZfutB>J-T0;U*}7S{g7tLk`-;QPdXJ=w@Nu7cR8VQ7hxPb3B%?;H6@}qroW9bW z=W_p|bmWV!pr=jPqn`UxS?jPMY-o0lSl6Z$`g*X{8opwNulSv#k#CltKaQ$@d(;m- zV#c=FAEI_?y7x+e6ynrL;+IEQ-r> zC?5zA`#_5XO*Z4p;L27q@gUl$i`Vtemf=F39y*(|DOK*Fr8m=5!(^?8$aIOXhZ1K? z+DK-@Nhlio4hfM}Gq)G(dKm^h<-F%7yqAx$ASr_k-o_7oWnPnEcV@y{NK`u*B?~i| z?n==?m01*WNpz=@1&T}7jhkimNKU3HWV**%+UR+uXjiY)OX`xMYR(@ry^N)sTo}1< zRBE%am_SCdhGtJJKjl{U2)Y^JHMKr^WaEXMC`IY$A+^*dYoGc3Nh5OFcdC7$X|>xa zE;HK=zEdq{U@7 z9-;o+szw!3jV&-YGYwV(CN&QCA+)nudl&TT(A#S6^$6gM*Q|@IT!u z**`{LR>OnDcdfpS%z1DKYirN`LCp&0eGo^7~%n7%wugJ?fF&dVD$a zICLyU`^5q!6{oCpp}Q`QRj~@{wN$QN*y;_vJh}?6sH&Q_YTnYfN1!ng!WUV6jTeo` zC^p5q5#wklZKp+D*FCqVV~F>~ixh*WID9BfK6@y=oY?#T+$S~aiPQ`Ql6d(89VTfJ z&h}7^L?!s13x4K8IsZvQ;Ky2b3gbO z9IoPj7z&T}zjkc4 zf_m-k;pC9)=|i`DHr9_BD(5s)R9DknQCUs+uk^wpYqBdrJ;d}Sr0|KZTQ{75wk~{e zRSM-}>Bnf#5_%LJeSMSb?m!u0ZtJA*4-GqbxfBB=4V|jm8EUoDLANFqro~Xpn zYiAdHuppWzI&CXLMD23I(;MGFl3uo%?swD~Un(g}=kmBwhU&>_P#G0Q5ph4J$yh3L zvTSW&Qk~69S6jRrA-QmiP8l}wQwZZv#~~M^Pos>pZLZ0Z4tw&;=JXe>wdT^2e|3+jIV+e1XTyatO+S!3~NF$cHKNth!(L=M> zlsx$aB_fm^F_7;)xSS!xCJEQkk{;0c$^df|4^^Pb1e62Vb6v4|w!GMsY~G(1w3PBe zuD)nW1F+~3wW$k3h6xOG3jruh05QIuMr@6K5@@e?Ae(|3QsdNj?3Cy=it??_3ik-= zZf{%71gmi>fx8wB`94|(KF+=s;Cp>V6wjITYFnA43BedX%-<3{5DkKQz5CE})6@B+ViW1gdTgRBOwf^XlNTvH#b+ZEAqPE^<& zlBz-zw-(`wWv2M|pU}l#Ws8N%Ky7YxD)ARbXtK0iD3vMz{B5asGLw7zRb3$WpB5nX zTD>TrxqA?)be{8CU6hJ!-M;AlH4U=nibd6x<8ReG0-?aq6*k(V_rsf&nQ<^W3)A-X zXYrCiQ4sYK8`Ahs)HcKS@u2!!8uXb3f5;Oycw z?OXMKBaj#_jZP(Pa@HO}Qye+mng9TeS5tbeMh-t>X6#(+d>IXb_bFLF2K>uG&dk`- z=L4FNI_Lrq^{i`f`V*-|v;2|#JOU=AezXkD6z$Em6o48PG?4Z!>n>F+(OlElL1;WO zm|%!{M%^V;O{nx*unaj|&Eo5T$QjPu1lH%|Pwr_G2?aVlZbnoTB5v2zui1M@Tvi^J zV3wZ4CsVA~ivN*^~l)rX+IJH^6Bv4PI#QB}qX|vb4g~ zh#H~USaO!EM|gao1OX`y?T4&UM~E~j-e427H0j^jqv+vPL zO1}*(-zPRY-Gg-QL4Vvftykx0=%{o5`m3VvBUh6%%9^0m2ul&P_PE%T^jBai@BZgL zpRw)Qv=8~Ji3&8?UP#_BGN)DF8XuhV#liJ#e#2<=+Z-yiBBqm8jII_X*Ik}(Ts`C+ z@8>yaiEk5BA4WP79TGatF2SCUtMXd&^Mj-p2DQE+k8(4y6B|MVFqlDWhz zRwAb25&}ih8@O~v3c((t29|$QO~)sVBs|?j88ZE;{?<*42Q?SFmL)fNAmJ_#5QK1; z)zXB>H68 z_xoxTaLy1fA^`h`ghId#mqa@rQV`t=91X;gnVDoqBQRGPYxrd*Aw1zzP)*C9*2J~o z85Hg6uYEo4=3EM!-V!6+hi)n0sIoFO1zyw~Ws9@~&ToLkk&I|MO?m<_vumvP(A{(Y zZiD@mT_G57`Z*Av^kW$cD-%6vIILYa2^Ts=P5%`|ggLa7;2#v_)QJfCy>H>i8Cpe% z1@kCNIQF-vbKxH`jC&4ZJ-vUvd0C|unegKV6$`jiHqEQ^lhZ9mS@W40xe~JQ_6UvD zl9e{`wfJq(!i5wy!m;vn?FNcf)Q4kkB3DY$qYvCX_J6^3R-4B#8BZ8S-}zr1aaV}l zYf{$H%K&lYcj;SzQK5s>XQ2E;0(wFzg#m>r`rXeWPR$r2tBSasJZMyjTn=)XYMX5R z7o^xrU;s@B^g0t#NF*aS_WqOafHt2ET9BMhJPmKh?G=l!qYhPYEZ*g}1a*H1}?aTS~LNn3zE&b4;6_@El&fOl> znWX=Q>=5_3C6AFA46ookBELjusVnXhK5=<9%;<6U%wN~|OS-vP;voz6n_E@9pTd1r zRWq3+>3s7XzSz|?FznzHjPEYqZRfr=N_FdAlI@R<3CIKB1vR2L6x`m{db~YCSDj0c zv06R4{e${lL)}lPWpyRCu~ThzQd0q(Ob80ReAdNYqQU)QveJ8x0HTqWxNG54XA-t#c+*pj|#}8Q_TjKWFIUl^gJoTm06Bd4)hKmn+`(Mcl zy6k;i?I(;XGk%ys)%8@#KHlnlpps(lDN-c93--VEb|Lou`w)iq>-hW1tD;DgXvjE* z4_$p}F5XyAXgD0Q?-ce(O+Vd8?^#_o@RcCD2`9DCz@WMXQsSDIG~S7+R@ z%1ZlufRFO%V*tSf+HpIK!gcN)xf>%k4Tac6EV`5uNiepuE^2P<8$yR34=L-&p-~r? z5U|b%T7aozjIZJKo-&}6e!VepmRn6{$ zjJgQPoY)p1qgc?$BfrtCkNA*pf57;Zn{KDFxZ|m17Fpk9gmN$QnDg@#nDP6f^%or9 zCl{ztWhL>G*NP@I0?Gu59xEZfeQf9#zxMy zm7nR9&CEzU?)Jk!btlmApH+38iTUkyi1(~?Jv?xFW}G_)ROhqrd2kt7Sy4?0v1f}< z_RffzoAnnd9=>vz+-wT$*7i+U4xq#tp98i!1cMWX{4@W{OMWdUfegAF_%zE^SONSF5lHk(}IN=$D{N|IBY7(m@_|QZ=0ImWC}i^H&crD%-`@C_&#FDC0!2iccitQdIzMcbo5cZOjBJ@ zIQWMgSK4j=^JIUDg#Ri+jtTS4_CK+jpENMN?1g;yCff>2P%FCXCn;NkrmN5f6~AjU znU{ee2i7M@ZM+5KwEu+GqT-4)eN#3f5iPLER~I5En#lCDyDtAaTfA|1E-a)_dWv`5 zqe!@KaBl8`cYY<-St`bJRg=yFOfKxIm+a~a#tD){!*f5T7(oxV z5D-apDaxCR;&#qkL{cd}eAC>tlKX*?kvn9*;q6$ataY%m=-BsZB@5J|%PS$lqRUq# z)UKJcb5m)DiDeR#O;A1e=$mY@H1MYgKifyz8gUzL%9ENO@3nlp*Wb>*1w>YF zqA-TUOWje7{4Q3Gj&o}pd*ds!g{xqtrM;lDcfA?BD_KCHaciT0))uO?i2|URl3_IR zl{f!0>hScvIrDKH_F&k;AX-?TY zx4c+OnEn->UgZtKY`IIGSYp|}&J)Ergi9=KZCs5=cKxd%vN4V$JQCFq5+U2<+@zL$)lDM>{tz_TSh>96s?U@=d3Xg8ws}T zxaKQrA~L@HW|L<$++$6k7Byym{KgDZ4*q3K)VF(2iG{vOUt&a5>hs3u?~9JNmQjfw zopf61G?D)3^td#;2@2A0?rr&gGa}wI)!5Yy`TlXzhOj6Dvd4ZDy0DNi#{v)uMbd`B zMa0H&lS@M?IfUbfniv#5kUriwML&e1aX8sZ>HwXw=Mf^4>AVpm+6k4ENXfUBCa*cL znov{T&w3;{*er9N%+@&O0q2L(&pjTg_jb2Q0{*RNDpxnW?-!Qu(i`V%7i$UG1&nnG zipuOpCQ+TBB&+oZYE@-@_OMM-bzzto@(A(Tw-M8@o=246m=+V;;J17Y6es2k<}e>`ql>o5y7 z(K6iZ+y?U-8S%Yux}VAcc-d2b#cZ3tkwH?@)m6Cj&c&KWLU2pVqJ;&r>_vPnD(Rfl z5j6NXhgmW%oYUL>UV9fcyi!P28}V!*M768kt_%9%(8Os+IWx9`>4^MSkc;_d#V0}m zUn)xmu8;gCOXO>k>dzFl%m)t;Y4GT77$4Iw?bP92d76xa>x*=UQq)Ma~6${!ntAhpd zB3r*wDxjD1Y)s&fzSyiuB<%PXJYCUzR$(ZlBnEsyMneG-uBP+MeH6GCa{gp6Rb#NJ zb}?{4jYXkGumAju?eW>qg^=~fp^JWDZ?TS|BHTR&dUullkDrZ7+RZakuAaf~!oaSj zl}Z{eEuYFfgOPF8C}DiZ;b=HN@bFH`K$-pTtL;8UWfOD@=5+XOg+5#Ul6zZv z4TVy8e1seI_zuDz%AGeaq`t4C0$^M92h_oU;u5Lx@d-V%nRIvFPGbNTsVeVN_Dkra3~ zthtBR?luIvmya#C@%z*98XU14x4Bz=yOUXf)uoEFCI zS~|$8tzJ&}`N$SgCn31>=g%3vQ&2Ma95Hm10tISQ_wwZ&Gwk zN00uI>rM~|@u&E~sg(mkNWH&6!Zy9BLDLiyz7hj|sEWdok}ERbroZm}BMH4My1zybxqIAzXnJ+1R z3#W=Jx^kxCz_-Xas3sAvPWIU7N{$MEux1aDITF~G9SH}w68}-6`uXGHj$CYG!&apU ztm>iYop^!uW9Q;1TWK;RJswW8_8g!MDWSxU{0KJ0XE-w#wGNuFqSDfm3?nBi83FyW zdh4n~acV=48=g53j3G0J!Pigg`8+$j9B;&3XX<7_`HX_HBL=ObZpSWH|iCSIeH6Lbxrv+7Y8j z_AldY^abw+ITz{1NvQHWBqE-nDssNYQliVNw0l{Bh>(-wg@j&JzSW2`|y zJe%rJpOIh`L1r>lY`w9s{ubnBFEO~CYmTe}Pk0;V*)N#-hDLbdvr*K-{A{Ltv>EDH z9`87bFhY68;CjiIpm=v&GJ5E!=w2p9mZNzum+wOoEf6KCgoL~g^4mq|fTHA$M|Qem zRzL_;!CgW$oTmt9kW7JtTi#~xFbo>15O-)Tu`*=SateHvA@ZeNAdqE|8M%E@17Z%162Cp@UU6pyc z_a98lAOkbXm>wZZg}9e>$B<%Dp(aUGwuE4h%bD24fE&)pL$3ovLMeWDR|K8-*qvQ< zp4Rhj9rOIkeBD}L-ycD!8TO+7=NZ^MBPjaoXl#k>yjoVl*Q?Ct@+yS54P z&42HwWe`hb%t|?D?+FEh!?Ra0jxYT^0T0o$6U)lrqm{MaKM`~{Zw8o$)7>r(o{3?D zZ|YzFVro9f710cdSWUcIUBN%LyZV|{GKH$b%0)T=23_-=HZbVdVxWvK=?1%%d?dP6z1m)m-IxI{j3@#?4MZFI@@YK49J1oanaS$(y(o-WEUuHlj`@1bYwV~0N2gH*6H%Q(HMExgr3%Ga~N|pFkB`KM~mhYNnmyLj1_X>!UC4g z`Cg|mVtm%`e01lw_y{rjn=K|9sJRwoNw#>T#T_Bb0o%kN|4QdLXnq^2AYbYS8bLef z=jpAc6v5rH;o0&r0J>7z-!n z!lQvRtve;cOn3HR(EI3E`IlO4yJW4c+K~4!|G$;pzz5G(;-_?=|NYC7x^$$fP91BN z`oys93_L^<8))k{eM9Fi?Mm;CS~_ElX#tOtRv9EZWr#c%`Hw?wWy0SPpH$W-8)dxd`l%B4Z>oP0;U|#;8 zJrDJm$s5Y_k8L=D3sCL|>IfDa7Mwxn=C9;+z$@d!oskGoHJQ|@c%^Bk5#?1J|X z4k{~qiE@L9M#c#d$DgzpiE{5A0F%k)Rw(_Kw{WzkXs035@^P>4&SNAQtJm{ENHSkPgSxK+nMz5al z288nCM=rnBI0&$Yw=i+SjIrc_q&XFI;s)}9Ei6#VMe}RlL7w{Yrs+{nPtQY{uHU!1 zw)RySkw(8lNzZXN&F9q==oqD`n|f}lpMD0AI4=5+;uz>w%ep#>!`rvOFl z`K0h^0Qgdpy%fXO(RoEAx=R)_7^7%{M0az4TM)>BP_5AKSW!E0@o`l$MWB_=@^NiP zO>O#Dea|N$Ob0BSf-rs=bO~>!8)f;21isL3G{)3bsO6mGbL8`g^F69 z_HuN}lL%gKrKt0kGZ}$^edhTWE5{#G(*eR13tpVfd!G>uEg^PM;F6NETpLF8@9kH7 zsc9s^7PbD$dU5)H6B8hYt~rRlX+_x`(FX0(5r3UG6Ys@kZ=B9Y{DRC=s_&)>1}?i@ zoZi}NC58}r_rE;+iG{$1H(!`D>I8Myws07xFIo8gjE^t%l;|HIDLSZ=RmKhOu{YYN zmv!(`DWHD<#gFo>nRncPcMjHME+vq)wb`|cPCDx+cHN0ho7CW2vdbpaux|n0We#O3 z0bFS5wy}aN@^$(N8093Q15Hn?f6;0rkjH<1tu7}Qbx*@b8ZKP%wI&K5^+=+B=<~v^ zGvJ1O`mbdY9y*a{EoM!tPfJ#q!7y;n2_LnvUNPXqbD<~JC2nF2@6GP^4(HGPspY#2UDSV=VFrCijoY* z*x+A+kAj9Cu0d0DxRB^EhN;h146?Gyj71DNN*FLpfk{Sd5y~VyP{6D4*LWtt{h!?V z)}~nTfA`|QrS+r6jXQTt6eAxmKkd^}482%<*1C$cb9?ROno>tgLN!TN_`{5DCqv z?EDzop2vLpRD=;v!nxZ?PM1Te-_7}QYCiho;^|4JxcEY?#xFHVThpalWk!FV9g)3y z3JM2sP?<|p0nxh&lQPaJkf)fNL(;}%t|Uc3)^XH0jDR00QLi`fzzrz10fwNi?mr1T z$)Zc?B8KUcKBcs~T5hGnd2PSiUmx_#6^v}Y_|BzYitsgQxodB)i@ONQe&HqYeSTZM zda`iJT?hcWS!i{en^k|??n`xpeh=Z743}Y-X0L^kiijly|LnMjbwigq**XkuCDVU5fpKAA3Xyl0WUHA&3tPOoOg@9HXYRcf9I)FR zZ#0udK^H8z(cw=s&k^QMJUZ-=6h&;`G8pql4I(w!bQ9`OPiDI&u*Bbdo?1!IzGI4q zWn4XlB3~eSzbVYU76>65N>?WrUK3#WNG*0JF7>>JIq(fj%`;=)fx2QJZx1hRlpmAt z-Q3=3O_n0?Fsvb}kUqd1clm_#*b9)2{T5UveCukTT<~@x;8c|*`aKkNaHnNeJokq(jX5piM_^VkkqT&{20739II>TO;aDQjvxK_4@zWbQ$p=oVic1C90h$ zjap_~Nv?cy8DcX$zcjAdJbEu@?8Xo-(;C5~Mm6N4{ybR}3|G?j5*Lb$1hd>m@!De@ zP$;^MBh&M(dF&mTL4bStvCbV?vel!Qy>oTp>MjUyT@~rX>_6|u`LJ0I1iPtv{MToA z_C0t-NiQ|u0FJR`!}uiZWPG^2@Lt<&SNZVEou&Q=*&jULPxKmKyw+stYN0@jcSxDp zr)abQr&I}tm~w&zs0e*oRD3Z1iEi4h8r*I8Hml!;$?}Vnkulc6rx>be~lLvkHkGy-QP#L%BO|ht$XIc zK=A`ECw2TB{gOQ1nQp<0V)tNSwPxfaPgd(#!O+rR!)_D{SwC{)_#5?aA-|sQ)5rQW z*^=KM3IwsClXEzA_m#S>OQSb?XehL3inr1>Ua0v08|jv@DsMls>4k#AfrmX(beXNL z|M3D3ldo2So$%uf&3o-cs-D{F@)prsRsbrJSGRsL2gqeB=6&qHyZwqJiNOHBgH zPj2lC3t7Bma&U6ue>`{Zf73`;_hW1l{odQjK962^F{8O%IPPA-u_QoEbnUX-yFK94 zT`~Fd5W{pe<3!!tC)Udto=rQ<%Uuwa&%H1GfG>yT+iOvZHaN}7%FB{6&!tc6gCuvH zgh09!U@|hq>bhkW)Tt7mKkFi4Hm0ZNApF=O@7;-E6F`%I=$xIUQc$SbUmY9Du_{GA z_bADZ7%(!u5qm@R;>Qa3MrUblGf#IS|I7}i2l5PsLb>{?`0v&q`FBdzhM76q=!M-0 zlVvQut5EAJ6iH|0?2_NAtY15)Q^1KaryV+4N>Nok+UCwX9S&1!o1NvUR`~ewqjtSj z)R5Y}#OY!{u`eo}J8z}PC zDpBIQuSI1X)sEG z#w~RmAVF;`%c5ORvQAYw82O)vxGG0hQf2-%qv?}*$FXC=Y0lTq5?g;tX{HT?f&KX$ zthJkLBi4QXWh!dk8N8cE7>xfMS@AYn^@m^fxXUBzpY}fEUYiL%36%kqku1Xsy5*c0 zxd<4ZKCD&x)BrwJTY`&TM`IHc9UMY9SdmDu_S2WamLi?K2w%_aY&SF6TQT|A$r zVan`C*8=aNOQGc#kdENZ7M$+yh)WIS5vAJ}(IT3=TN)uFrWWWYO}k;w-|#2~Ep}TE zxN$BLnY(5EKd>AGGilRsd4A_6QJhv2LKpm@Rk=IYR5j||L;lWx*8Ey#;W(axp>*Bi ziSI89Othg7pUTbJI~Rxbs?udRCTE5TRyXR$jOfxG)l{fpG1U<^u@_cF8@xm z{orQ*1b3jCNK#JrUcOWgTub#noFpk@#;8L|7(Bc@KQHXq-|%7Wf<*0|&zMC@bl$Xl z+kB`xq5(FE1Mb#5NT|9f-F zP>LhR!EWZc#mN3*>0qS)28uacRRAsdFgaMa{lZhexRd&ElFC&5SfbYT1z$NbB3!h6s8}(hEa>EHgw)Ef*IBKEsdPv{nIDg*k*QHD@zQ9_ z92dj{yEm|5>%J7g|8H9}d)(V89gikPnmun?KWL$lA#-ezfvLd^X@tlX_u(0VQW}P> zt~B|pE>K>VX5T<_s@%ThJsr>+Tj{QPy4%(^A4xBu@|O>6h5l=5hFdlw9Pin!Q{uET zpY58uCX>{7@boKhMJU&raqac`mRsQviQDjn1_i)mtxPx-!qf+x+USOQD6+P8pZbR5 zYRtlyI6~{}nMw&|&`^8FDg_tbz(Swa9Dxjc$v$AkOI)}HBnYU5>r`1R3FsG$NgA-< zTqI{AH-LVvq2z4jrfcQdD5>}G*CG~-fY2Ru+5l~+An>cHdhoj1eU!z4s`QqN-rK$g z+~)2r5&G+_J#@Nqpumn7g&sGk=SP#Ko*Q{rm;0kPOa{qpq=R_0dS2h6TprVf?OUlRz&FDV?t+8@LfPJEFv8&N^dd?ef8O-n1BLfPZ8$2OljIk8ub zje*(#879;uv>*{)F^PL@5gnwp?^x}i__mPAtE3B>&5)|`<$MT zGE1LMY29ht4z+jzeKJd-W&g$G-o?S$(9aWvdt{=3L^*MMqc}YbM5e(jN4yXVtaEE_ zA$A@qHJ^;T85x^Aeg3rn^g$#k&3-MMM}}uR@~K)%|8-m*co#rEbbHN%>!PzjBckU( zmK5|sW4Ib_D*4%xW=CQo<@Cni6nU1`PZj~|Ue1Z&uNzJIxEsb6e9Db6QKvd)v)K!~ zOU>s3|Fa3N4wZV>Xi4_^9qWpQO- zQl6d4r<^oN7(vlXDNUFr68O2s%Fn^ zX^sZV%9&44BV%Jt7^SB?R>75k7)C_+BnW|I)b3*7J<{`0Uee(P7TeqMvT|~d=)?aA z-ha=kT&5O6Ptc>L)fDNWrk^IOlaIqrDNY`I-74409nqGKP0DAnkhAb#ecNpgrB-_3 z$~c+)^q=eQI$>5az3vZ)L}eshR6^hqEMGael}UkQdzhu#{F+aj>cQX6CO+pcf&G2g zzTs#SeX$0Rf)a3B^iCFi@H>I%w9kiWDnUN+Jq?$>#X^x_NNHt#eZ1Vdl%`vJ&w+|_ ze!;I-0&OyyToeXTt(#Trl>|bBJ0ZO10DZqnN~KBaP|e|R_j~$gZna*Kjh>`&CHhRl z-&%V#PSZqS2;npGP(us^Qzuz=-&AAO<8e1WwXgJvfg2|Q)6?^9^YimkRc?U$JPTe- zJHFIRsux_po%3a7tzIXyZ1JWkg>3)O4BT(c1_DG^9R38S_SmTOg~OL`qL-gYy*-Iz zG!S+IQ{4o^Y+}21y`7`G@qbZNct3)pR|{5FSL(3iAh(Qa2W{31j#Lj%77=)sxUzpp z#yBw0N>p|6BJ}DN=aDx*6fjI_2WR+l+6A1*mxay{Hacak1Oh0I=I(vWO5-*7%8Qh_ zcaKh(pHhnH=j;w+4y5PL#-rg0KVvuy*AA2AL%9d>k%S>xxRT-0Dc_`Zm;iViI9#ux zexE`tGHi8EgaVcZ(Db7)c%9)s_?ugdY@5343Wx3KmzObkG0_#~!<2O~&L0z?W>8cG znpx)8ILO^s6U4%+?>(76@04Dt>~4v6$H&6W!bhmkIhtR^N<%!S_T~opQ?-H{qbDZr zTB8o4_X5bnle6A4oj-ret?cJgKr^V!!O5s49#xPTLN#DT$I8l@9m#R|`&EeCx@D%C zAM=DeyWAM7K~zTslk&+3p`eVL>qy4+!%n7p-Y;FF=kb5qjt+k~?)?@be~3Aty7>Me zKd@w=Yoh*os93O`6q-#1ZAmJjFJz?3${J|E*pF;LMhOX>~ z6eiBo=1x2%-xFK$i~5i$VQQCDS`QBoVfuwZCKQVIV_F9EV&sYDH-meI7A4*uPlJPb zIUib)stM(FYtDSB89*dGiE*Qn$qa8iTPQ+NeFd4SpYtgwC{$E7N7=Id>f*JH-rVfT zX=z-vB(C$m;rAHkqGvJud|BEQgy6BY)clE_QtNQP%TV{-*kp@Y=BwZHY0aS?_1r(v zcOiH-Ik|TvFzoy()ua^OtrVH;S~E*}w>X4IBD2d_F8hJE^mEzFXfW*Ru*FR=tYUBByx^04$@FXN1M&vHIt^8MBN8GtQ9R zg_BsSJl~ho%75JqMv243hEHO=HS!liXP9DwUO6Wz^uPMUglGFucS4DOF&U%_9DaJ| zQ7H0S3u*d%_+hWG0ltyCqCFQ#{n~mb`L^niPSs3DWo}+Tu8^3>L!Y_`^w5!%z*yY03kVU9Rv?H^bIq<<*HaR13p z%Bfz8t4Mr~DEW<8oUsO^f#33C18222b8NBkrTirK*&Zn@5w@d8M{+%0iS3^cMycbG zXeX^ZGV|{L_H;!}Y-YyD{sZ3`P0BDy8+S*lZ*84#2r9!x^9HVX#J#%`bLwJX)ahr! zRlYkDxAy1TZIs1ow$pojpV}4b+lkC2P^9TIh(E4Ry zeSLjTSNE;6R{x|=^K&YH#Cl?LxZVBp7AlzBzk14%#BtZ?vg)YlKuM}3PA8OQ-kI4w z^G4;Q_FTw2gVz##J^V}C#SH@Pzz6fzs;wN^qMhN%OY;$MmUk;JJv{Cntd$3`9~~VP zTJ{QcwT*J-3!h64g?ycwXC3Y@HMB4X4maljAC;R@g$;aRFj@Qh;!4ZkNqk5WO>*LBBX4id`pW9^})qH$Os*Ag_k7|qx1V4QN=9t^#mJg|-~;pqY? zt#He7G&ELd${Kppn`a;QB*ok+eMa`fW)j*60U z+e-o3&qCFagJBT7W-81zw_*m0;lWhKMiRUttH3O*?^weKuG{h?`&SPq)ff%ag$!AY zhD_R#^z+F5I;O!#3JJ4!vu2FmB_vK%okX|K#C-5T7OE51visY^YC6iCLxr2Y>`?7a zZ{vc@frd0RB@Ysa_yB`niN^)caqx{}76a%>)93Twv(YhJm*tJAZ)p`pAPEa>pdwM6 z6?xIEF3{i}&dh;l3`sQ$STNz-vEqHrH~<7pPFk54jhjg|437FXVBWufi8aLv8^iT= zB6wYv(Nhf8hry&oL5r((3w3w;Sh*)G^v@lNRTc?Intp5w#Y$P$&R5 zZ#-63Wo|Q;aY0`3a*_d;Jha8TQ^5W@f_*F9zgmTVicJh|P!uP2W+Sp^6)urr?5mY+ zBTcyZF*8%I)GES&5+rPmKxh}Sv6Xd?ugXJwUZ^NWg*!^U4o{{PRGOl>-J{$biICg`_;4olsCo2i9H-*3NE>~YSG8GE|- zF`|DU1W{?n`#VfDQpkj&#@F}jfJA56BoJdYYk=hGnq_D$V+|iaYGl-uv0%4yMd5t0 zCy3H$7(U(jKjg>MRLr_;HNq3XH{s4d&r~>)?CNP>eL$Fe3Ge|p1B~FXB18U+(y6!+ zk6Lq@K2io7wwLl%vo~yA-S;QH!rM%T>aZ{cMt6*|Os)*kluF#ia85bO!45a%P3N|M zYHs~L7Tpw(VKl|_53`&DW$Dzd6ctFBUb1LKv?edZ&DB?3)12Hy6`0%YC^k3oWjao) z6^-lh*MFy)&;BV&Ji2HOJ(E8DtaId0v`UQ|Wx?YRDDBdLfyr4EK>_^cek~`dR!}LU zL9GqN5jvY=DDtEi7gGFt!@rlWJNgWyIr08^s47%?cja_CNt79+1HV72z3L+{a72dY z!d{A{n#U62C12zSL?$K7-jv5q2#Q3OaDArCi-*@N3V?{K5F`si>{7lS=Igo6<9GE5O|c0KYeOm6;6Rz|bcMga9! zH?f53q4>$)k?oeLzqSJ(BdSOzU)aG|3mJFTd^jQB3+Ya~=TFlc7;<(?BFv}dI8g9{ z2{)?<#ea}4DMOl|u!$4I`F9ch2O(*JzsukU=Y5ej2g}Jz5PnD;!;7IEWIo+*(|l$> zzmS(lwY&ogDhnVAO+}MTubRNneFI*X2fCX z)NUOPRZV`>vX1A{aLeMg&D#P=IF{sF;%8~oaawrXE_%?%_#-jHdMm7cY&&}_-o8|e zP1ml@|6pF<*Kc@EVJ35p9rL4t>3T*fqK-2dWZXG3;s}`_+3*s zv9a&zUMlB=qfeK6nOAUy_n7zd=!g{6WUrcljh6vth%`v7#yM%SKNkLp;p|S=vQhw7 zhklFK-=)Z}2jd5*2!KC?Kg}N54|a;IDH5eCeh2Hi8g!kOY|aH|3u4>vq$8^*(ZXq^ zQivUn9MQ=gll25|E18o%)9dla&4qbqc?vLZPsNeVzxHR&bPO)H7{?QydDLGbu;oUA zqr1t#?VB}w1DHBgzT~K-L-9!4pb7bom#O0Hf@#aqjz)lV8MuBY!@J(j;24U>&3nlY zZ~C4q1PeB%T#956f6hH=-Xx)H>5F?)A?L~~?e_h(3&zQ8kMG5kVM~39*GJfKkvu{N-)b8C+aUu&M0)n=x^LLmubw$cd|O=I_K=lV`SDKk`fT2kOX^Cx?5r(Tj+ z9ikfBIl1&w`zQNr=ziNKIhieL%Q>)R1)zD~TN z9zn1|7t+0Q374nD3mpIVt#YZB!{X~GE|j6k_FcrB-PQUY|H9b+(a8A!cRHpNUxa2I X?64N+9saMG6JV%oa=%R5KK%ayBr9>- literal 0 HcmV?d00001 diff --git a/source/menu.cpp b/source/menu.cpp index 301740f..31a7c2e 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef HW_RVL #include @@ -47,9 +48,14 @@ static GuiImageData * pointer[4]; #endif - -#define MEM_ALLOC(A) (u8*)memalign(32, A) -#define MEM_DEALLOC(A) free(A) +#ifdef USE_VM + #include "vmalloc.h" + #define MEM_ALLOC(A) (u8*)vm_malloc(A) + #define MEM_DEALLOC(A) vm_free(A) +#else + #define MEM_ALLOC(A) (u8*)memalign(32,A) + #define MEM_DEALLOC(A) free(A) +#endif static GuiTrigger * trigA = NULL; @@ -67,6 +73,7 @@ static GuiWindow * mainWindow = NULL; static GuiText * settingText = NULL; static GuiText * settingText2 = NULL; static int lastMenu = MENU_NONE; +static int wiiuproCtrl = 0; static int mapMenuCtrl = 0; static int mapMenuCtrlNES = 0; @@ -789,7 +796,7 @@ static void WindowCredits(void * ptr) txt[i] = new GuiText("Credits", 30, (GXColor){0, 0, 0, 255}); txt[i]->SetAlignment(ALIGN_CENTRE, ALIGN_TOP); txt[i]->SetPosition(0,y); i++; y+=32; - txt[i] = new GuiText("Official Site: http://code.google.com/p/fceugc/", 20, (GXColor){0, 0, 0, 255}); + txt[i] = new GuiText("Official Site: https://github.com/dborth/fceugc", 20, (GXColor){0, 0, 0, 255}); txt[i]->SetAlignment(ALIGN_CENTRE, ALIGN_TOP); txt[i]->SetPosition(0,y); i++; y+=40; txt[i]->SetPresets(20, (GXColor){0, 0, 0, 255}, 0, @@ -883,10 +890,10 @@ static void WindowCredits(void * ptr) Menu_Render(); - if((userInput[0].wpad->btns_d || userInput[0].pad.btns_d) || - (userInput[1].wpad->btns_d || userInput[1].pad.btns_d) || - (userInput[2].wpad->btns_d || userInput[2].pad.btns_d) || - (userInput[3].wpad->btns_d || userInput[3].pad.btns_d)) + if((userInput[0].wpad->btns_d || userInput[0].pad.btns_d || userInput[0].wupcdata.btns_d) || + (userInput[1].wpad->btns_d || userInput[1].pad.btns_d || userInput[1].wupcdata.btns_d) || + (userInput[2].wpad->btns_d || userInput[2].pad.btns_d || userInput[2].wupcdata.btns_d) || + (userInput[3].wpad->btns_d || userInput[3].pad.btns_d || userInput[3].wupcdata.btns_d)) { exit = true; } @@ -896,6 +903,7 @@ static void WindowCredits(void * ptr) // clear buttons pressed for(i=0; i < 4; i++) { + userInput[i].wupcdata.btns_d = 0; userInput[i].wpad->btns_d = 0; userInput[i].pad.btns_d = 0; } @@ -926,6 +934,7 @@ static int MenuGameSelection() GuiImageData iconSettings(icon_settings_png); GuiImageData btnOutline(button_long_png); GuiImageData btnOutlineOver(button_long_over_png); + GuiImageData bgPreviewImg(bg_preview_png); GuiTrigger trigHome; trigHome.SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, 0); @@ -973,13 +982,16 @@ static int MenuGameSelection() buttonWindow.Append(&settingsBtn); buttonWindow.Append(&exitBtn); - GuiFileBrowser gameBrowser(424, 268); - gameBrowser.SetPosition(10, 98); + GuiFileBrowser gameBrowser(330, 268); + gameBrowser.SetPosition(20, 98); ResetBrowser(); + GuiImage bgPreview(&bgPreviewImg); + bgPreview.SetPosition(365, 98); + GuiImage preview; - preview.SetAlignment(ALIGN_RIGHT, ALIGN_MIDDLE); - preview.SetPosition(-10, 0); + preview.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); + preview.SetPosition(175, -8); //preview.SetPosition(380, 125); u8* imgBuffer = MEM_ALLOC(512 * 512 * 4); int previousBrowserIndex = -1; char screenshotPath[MAXJOLIET + 1]; @@ -990,6 +1002,7 @@ static int MenuGameSelection() mainWindow->Append(&titleTxt); mainWindow->Append(&gameBrowser); mainWindow->Append(&buttonWindow); + mainWindow->Append(&bgPreview); mainWindow->Append(&preview); ResumeGui(); @@ -1076,7 +1089,7 @@ static int MenuGameSelection() if(DecodePNG(savebuffer, &width, &height, imgBuffer, 512, 512)) { preview.SetImage(imgBuffer, width, height); - preview.SetScale(180.0f / width); + preview.SetScale( MIN(225.0f / width, 235.0f / height) ); } else { @@ -1102,6 +1115,7 @@ static int MenuGameSelection() mainWindow->Remove(&titleTxt); mainWindow->Remove(&buttonWindow); mainWindow->Remove(&gameBrowser); + mainWindow->Remove(&bgPreview); mainWindow->Remove(&preview); MEM_DEALLOC(imgBuffer); return menu; @@ -1207,7 +1221,27 @@ static int MenuGame() GuiText titleTxt((char *)romFilename, 22, (GXColor){255, 255, 255, 255}); titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); - titleTxt.SetPosition(50,50); + titleTxt.SetPosition(50,40); + + char memInfo[128]; + memset(&memInfo[0], 0, 128); + #ifdef USE_VM + sprintf(&memInfo[0], "Memory Free: RAM %.2fMB VM %.2fMB" + ,((float)((u32)SYS_GetArena1Hi()-(u32)SYS_GetArena1Lo())/1024/1024) + ,((float)(vm_size_free())/1024/1024)); + #else + #ifdef HW_RVL + sprintf(&memInfo[0], "Memory Free: MEM1 %.2fMB MEM2 %.2fMB" + ,((float)((u32)SYS_GetArena1Hi()-(u32)SYS_GetArena1Lo())/1024/1024) + ,((float)((u32)SYS_GetArena2Hi()-(u32)SYS_GetArena2Lo())/1024/1024)); + #else + sprintf(&memInfo[0], "Memory Free: RAM %.2fMB" + ,((float)((u32)SYS_GetArena1Hi()-(u32)SYS_GetArena1Lo())/1024/1024)); + #endif + #endif + GuiText memTxt(memInfo, 18, (GXColor){255, 255, 255, 255}); + memTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + memTxt.SetPosition(50,70); GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM); GuiSound btnSoundClick(button_click_pcm, button_click_pcm_size, SOUND_PCM); @@ -1220,6 +1254,7 @@ static int MenuGame() GuiImageData iconGameSettings(icon_game_settings_png); GuiImageData iconLoad(icon_game_load_png); GuiImageData iconSave(icon_game_save_png); + GuiImageData iconDelete(icon_game_delete_png); GuiImageData iconReset(icon_game_reset_png); GuiImageData battery(battery_png); @@ -1235,7 +1270,7 @@ static int MenuGame() GuiImage saveBtnIcon(&iconSave); GuiButton saveBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight()); saveBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - saveBtn.SetPosition(-125, 120); + saveBtn.SetPosition(-200, 120); saveBtn.SetLabel(&saveBtnTxt); saveBtn.SetImage(&saveBtnImg); saveBtn.SetImageOver(&saveBtnImgOver); @@ -1252,7 +1287,7 @@ static int MenuGame() GuiImage loadBtnIcon(&iconLoad); GuiButton loadBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight()); loadBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - loadBtn.SetPosition(125, 120); + loadBtn.SetPosition(0, 120); loadBtn.SetLabel(&loadBtnTxt); loadBtn.SetImage(&loadBtnImg); loadBtn.SetImageOver(&loadBtnImgOver); @@ -1263,6 +1298,23 @@ static int MenuGame() loadBtn.SetTrigger(trig2); loadBtn.SetEffectGrow(); + GuiText deleteBtnTxt("Delete", 22, (GXColor){0, 0, 0, 255}); + GuiImage deleteBtnImg(&btnLargeOutline); + GuiImage deleteBtnImgOver(&btnLargeOutlineOver); + GuiImage deleteBtnIcon(&iconDelete); + GuiButton deleteBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight()); + deleteBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); + deleteBtn.SetPosition(200, 120); + deleteBtn.SetLabel(&deleteBtnTxt); + deleteBtn.SetImage(&deleteBtnImg); + deleteBtn.SetImageOver(&deleteBtnImgOver); + deleteBtn.SetIcon(&deleteBtnIcon); + deleteBtn.SetSoundOver(&btnSoundOver); + deleteBtn.SetSoundClick(&btnSoundClick); + deleteBtn.SetTrigger(trigA); + deleteBtn.SetTrigger(trig2); + deleteBtn.SetEffectGrow(); + GuiText resetBtnTxt("Reset", 22, (GXColor){0, 0, 0, 255}); GuiImage resetBtnImg(&btnLargeOutline); GuiImage resetBtnImgOver(&btnLargeOutlineOver); @@ -1376,9 +1428,15 @@ static int MenuGame() w.Append(&titleTxt); w.Append(&saveBtn); w.Append(&loadBtn); + w.Append(&deleteBtn); w.Append(&resetBtn); w.Append(&gameSettingsBtn); + if(GCSettings.DisplayVM == 1) + { + w.Append(&memTxt); //show memory usage + } + #ifdef HW_RVL w.Append(batteryBtn[0]); w.Append(batteryBtn[1]); @@ -1399,6 +1457,7 @@ static int MenuGame() bgTopImg->SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 35); closeBtn.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 35); titleTxt.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 35); + memTxt.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 35); mainmenuBtn.SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_IN, 35); bgBottomImg->SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_IN, 35); btnLogo->SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_IN, 35); @@ -1432,8 +1491,17 @@ static int MenuGame() } else { - newStatus = false; - newLevel = 0; + struct WUPCData *data = WUPC_Data(i); + if(data != NULL) + { + newStatus = true; + newLevel = data->battery; + } + else + { + newStatus = false; + newLevel = 0; + } } if(status[i] != newStatus || level[i] != newLevel) @@ -1468,6 +1536,10 @@ static int MenuGame() { menu = MENU_GAME_LOAD; } + else if(deleteBtn.GetState() == STATE_CLICKED) + { + menu = MENU_GAME_DELETE; + } else if(resetBtn.GetState() == STATE_CLICKED) { if (WindowPrompt("Reset Game", "Are you sure that you want to reset this game? Any unsaved progress will be lost.", "OK", "Cancel")) @@ -1509,6 +1581,7 @@ static int MenuGame() bgTopImg->SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 15); closeBtn.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 15); titleTxt.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 15); + memTxt.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 15); mainmenuBtn.SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_OUT, 15); bgBottomImg->SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_OUT, 15); btnLogo->SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_OUT, 15); @@ -1585,6 +1658,7 @@ static int MenuGameSaves(int action) int j = 0; SaveList saves; char filepath[1024]; + char deletepath[1024]; char scrfile[1024]; char tmp[MAXJOLIET+1]; struct stat filestat; @@ -1603,6 +1677,8 @@ static int MenuGameSaves(int action) if(action == 0) titleTxt.SetText("Load Game"); + else if (action == 2) + titleTxt.SetText("Delete Saves"); else titleTxt.SetText("Save Game"); @@ -1712,12 +1788,16 @@ static int MenuGameSaves(int action) FreeSaveBuffer(); saves.length = j; - if(saves.length == 0 && action == 0) + if(saves.length == 0 && action == 0) // No Saves to load error + { + InfoPrompt("No game saves found."); + menu = MENU_GAME; + } + if(saves.length == 0 && action == 2) // No Saves to delete error { InfoPrompt("No game saves found."); menu = MENU_GAME; } - GuiSaveBrowser saveBrowser(552, 248, &saves, action); saveBrowser.SetPosition(0, 108); saveBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); @@ -1733,11 +1813,11 @@ static int MenuGameSaves(int action) ret = saveBrowser.GetClickedSave(); - // load or save game + // load, save and delete save games if(ret > -3) { result = 0; - + if(action == 0) // load { MakeFilePath(filepath, saves.type[ret], saves.filename[ret]); @@ -1751,7 +1831,34 @@ static int MenuGameSaves(int action) break; } if(result) - menu = MENU_EXIT; + menu = MENU_EXIT; + } + else if(action == 2) // delete RAM/State + { + if (WindowPrompt("Delete File", "Delete this save file? Deleted files can not be restored.", "OK", "Cancel")) + { + MakeFilePath(filepath, saves.type[ret], saves.filename[ret]); + switch(saves.type[ret]) + { + case FILE_RAM: + strncpy(deletepath, filepath, 1024); + deletepath[strlen(deletepath)-4] = 0; + sprintf(deletepath, "%s.sav", deletepath); + remove(deletepath); // Delete the *.sav file (Battery save file) + break; + case FILE_STATE: + strncpy(deletepath, filepath, 1024); + deletepath[strlen(deletepath)-4] = 0; + sprintf(deletepath, "%s.png", deletepath); + remove(deletepath); // Delete the *.png file (Screenshot file) + strncpy(deletepath, filepath, 1024); + deletepath[strlen(deletepath)-4] = 0; + sprintf(deletepath, "%s.fcs", deletepath); + remove(deletepath); // Delete the *.fcs file (Save State file) + break; + } + } + menu = MENU_GAME_DELETE; } else // save { @@ -1797,7 +1904,6 @@ static int MenuGameSaves(int action) } } } - if(backBtn.GetState() == STATE_CLICKED) { menu = MENU_GAME; @@ -1839,6 +1945,7 @@ static int MenuGameSaves(int action) static int MenuGameSettings() { int menu = MENU_NONE; + char filepath[1024]; GuiText titleTxt("Game Settings", 26, (GXColor){255, 255, 255, 255}); titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); @@ -1854,6 +1961,7 @@ static int MenuGameSettings() GuiImageData iconVideo(icon_settings_video_png); GuiImageData iconController(icon_game_controllers_png); GuiImageData iconCheats(icon_game_cheats_png); + GuiImageData iconScreenshot(icon_settings_screenshot_png); GuiImageData btnCloseOutline(button_small_png); GuiImageData btnCloseOutlineOver(button_small_over_png); @@ -1902,7 +2010,7 @@ static int MenuGameSettings() GuiImage controllerBtnIcon(&iconController); GuiButton controllerBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight()); controllerBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - controllerBtn.SetPosition(-125, 250); + controllerBtn.SetPosition(-200, 250); controllerBtn.SetLabel(&controllerBtnTxt); controllerBtn.SetImage(&controllerBtnImg); controllerBtn.SetImageOver(&controllerBtnImgOver); @@ -1913,13 +2021,30 @@ static int MenuGameSettings() controllerBtn.SetTrigger(trig2); controllerBtn.SetEffectGrow(); + GuiText screenshotBtnTxt("ScreenShot", 22, (GXColor){0, 0, 0, 255}); + GuiImage screenshotBtnImg(&btnLargeOutline); + GuiImage screenshotBtnImgOver(&btnLargeOutlineOver); + GuiImage screenshotBtnIcon(&iconScreenshot); + GuiButton screenshotBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight()); + screenshotBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); + screenshotBtn.SetPosition(0, 250); + screenshotBtn.SetLabel(&screenshotBtnTxt); + screenshotBtn.SetImage(&screenshotBtnImg); + screenshotBtn.SetImageOver(&screenshotBtnImgOver); + screenshotBtn.SetIcon(&screenshotBtnIcon); + screenshotBtn.SetSoundOver(&btnSoundOver); + screenshotBtn.SetSoundClick(&btnSoundClick); + screenshotBtn.SetTrigger(trigA); + screenshotBtn.SetTrigger(trig2); + screenshotBtn.SetEffectGrow(); + GuiText cheatsBtnTxt("Cheats", 22, (GXColor){0, 0, 0, 255}); GuiImage cheatsBtnImg(&btnLargeOutline); GuiImage cheatsBtnImgOver(&btnLargeOutlineOver); GuiImage cheatsBtnIcon(&iconCheats); GuiButton cheatsBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight()); cheatsBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - cheatsBtn.SetPosition(125, 250); + cheatsBtn.SetPosition(200, 250); cheatsBtn.SetLabel(&cheatsBtnTxt); cheatsBtn.SetImage(&cheatsBtnImg); cheatsBtn.SetImageOver(&cheatsBtnImgOver); @@ -1967,6 +2092,7 @@ static int MenuGameSettings() w.Append(&mappingBtn); w.Append(&videoBtn); w.Append(&controllerBtn); + w.Append(&screenshotBtn); w.Append(&cheatsBtn); w.Append(&closeBtn); w.Append(&backBtn); @@ -1999,6 +2125,14 @@ static int MenuGameSettings() else InfoPrompt("Cheats file not found!"); } + else if(screenshotBtn.GetState() == STATE_CLICKED) + { + if (WindowPrompt("Preview Screenshot", "Save a new Preview Screenshot? Current Screenshot image will be overwritten.", "OK", "Cancel")) + { + snprintf(filepath, 1024, "%s%s/%s", pathPrefix[GCSettings.SaveMethod], GCSettings.ScreenshotsFolder, romFilename); + SavePreviewImg(filepath, NOTSILENT); + } + } else if(closeBtn.GetState() == STATE_CLICKED) { menu = MENU_EXIT; @@ -2048,7 +2182,7 @@ static int MenuGameCheats() if(!FCEUI_GetCheat(i,&name,NULL,NULL,NULL,&status,NULL)) break; - snprintf (options.name[i], 100, "%s", name); + snprintf (options.name[i], 300, "%s", name); sprintf (options.value[i], status ? "On" : "Off"); } @@ -2086,7 +2220,7 @@ static int MenuGameCheats() GuiOptionBrowser optionBrowser(552, 248, &options); optionBrowser.SetPosition(0, 108); optionBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - optionBrowser.SetCol2Position(350); + optionBrowser.SetCol2Position(400); HaltGui(); GuiWindow w(screenwidth, screenheight); @@ -2254,6 +2388,7 @@ static int MenuSettingsMappingsController() GuiImageData iconClassic(icon_settings_classic_png); GuiImageData iconGamecube(icon_settings_gamecube_png); GuiImageData iconNunchuk(icon_settings_nunchuk_png); + GuiImageData iconWiiupro(icon_settings_wiiupro_png); GuiText gamecubeBtnTxt("GameCube Controller", 22, (GXColor){0, 0, 0, 255}); gamecubeBtnTxt.SetWrap(true, btnLargeOutline.GetWidth()-30); @@ -2297,7 +2432,7 @@ static int MenuSettingsMappingsController() GuiImage classicBtnIcon(&iconClassic); GuiButton classicBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight()); classicBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - classicBtn.SetPosition(-125, 250); + classicBtn.SetPosition(-200, 250); classicBtn.SetLabel(&classicBtnTxt); classicBtn.SetImage(&classicBtnImg); classicBtn.SetImageOver(&classicBtnImgOver); @@ -2308,6 +2443,24 @@ static int MenuSettingsMappingsController() classicBtn.SetTrigger(trig2); classicBtn.SetEffectGrow(); + GuiText wiiuproBtnTxt("Wii U Pro Controller", 22, (GXColor){0, 0, 0, 255}); + wiiuproBtnTxt.SetWrap(true, btnLargeOutline.GetWidth()-20); + GuiImage wiiuproBtnImg(&btnLargeOutline); + GuiImage wiiuproBtnImgOver(&btnLargeOutlineOver); + GuiImage wiiuproBtnIcon(&iconWiiupro); + GuiButton wiiuproBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight()); + wiiuproBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); + wiiuproBtn.SetPosition(0, 250); + wiiuproBtn.SetLabel(&wiiuproBtnTxt); + wiiuproBtn.SetImage(&wiiuproBtnImg); + wiiuproBtn.SetImageOver(&wiiuproBtnImgOver); + wiiuproBtn.SetIcon(&wiiuproBtnIcon); + wiiuproBtn.SetSoundOver(&btnSoundOver); + wiiuproBtn.SetSoundClick(&btnSoundClick); + wiiuproBtn.SetTrigger(trigA); + wiiuproBtn.SetTrigger(trig2); + wiiuproBtn.SetEffectGrow(); + GuiText nunchukBtnTxt1("Wiimote", 22, (GXColor){0, 0, 0, 255}); GuiText nunchukBtnTxt2("&", 18, (GXColor){0, 0, 0, 255}); GuiText nunchukBtnTxt3("Nunchuk", 22, (GXColor){0, 0, 0, 255}); @@ -2318,7 +2471,7 @@ static int MenuSettingsMappingsController() GuiImage nunchukBtnIcon(&iconNunchuk); GuiButton nunchukBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight()); nunchukBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - nunchukBtn.SetPosition(125, 250); + nunchukBtn.SetPosition(200, 250); nunchukBtn.SetLabel(&nunchukBtnTxt1, 0); nunchukBtn.SetLabel(&nunchukBtnTxt2, 1); nunchukBtn.SetLabel(&nunchukBtnTxt3, 2); @@ -2359,6 +2512,7 @@ static int MenuSettingsMappingsController() { w.Append(&nunchukBtn); w.Append(&classicBtn); + w.Append(&wiiuproBtn); } #endif w.Append(&backBtn); @@ -2383,6 +2537,13 @@ static int MenuSettingsMappingsController() } else if(classicBtn.GetState() == STATE_CLICKED) { + wiiuproCtrl = 0; + menu = MENU_GAMESETTINGS_MAPPINGS_MAP; + mapMenuCtrl = CTRLR_CLASSIC; + } + else if(wiiuproBtn.GetState() == STATE_CLICKED) + { + wiiuproCtrl = 1; menu = MENU_GAMESETTINGS_MAPPINGS_MAP; mapMenuCtrl = CTRLR_CLASSIC; } @@ -2437,7 +2598,14 @@ ButtonMappingWindow() sprintf(msg, "Press any button on the Wiimote now. Press Home to clear the existing mapping."); break; case CTRLR_CLASSIC: - sprintf(msg, "Press any button on the Classic Controller now. Press Home to clear the existing mapping."); + if(wiiuproCtrl == 1) + { + sprintf(msg, "Press any button on the Wii U Pro Controller now. Press Home to clear the existing mapping."); + } + else + { + sprintf(msg, "Press any button on the Classic Controller now. Press Home to clear the existing mapping."); + } break; case CTRLR_NUNCHUK: sprintf(msg, "Press any button on the Wiimote or Nunchuk now. Press Home to clear the existing mapping."); @@ -2469,7 +2637,6 @@ ButtonMappingWindow() { pressed = userInput[0].pad.btns_d; - if(userInput[0].pad.substickX < -70 || userInput[0].pad.substickX > 70 || userInput[0].pad.substickY < -70 || @@ -2506,6 +2673,8 @@ ButtonMappingWindow() break; } } + if(pressed == 0) + pressed = userInput[0].wupcdata.btns_d; } } @@ -2536,7 +2705,14 @@ static int MenuSettingsMappingsMap() titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); titleTxt.SetPosition(50,30); - sprintf(menuSubtitle, "%s - %s", gettext(ctrlName[mapMenuCtrlNES]), gettext(ctrlrName[mapMenuCtrl])); + if(wiiuproCtrl == 1) + { + sprintf(menuSubtitle, "%s - %s", gettext(ctrlName[mapMenuCtrlNES]),"Wii U Pro Controller"); + } + else + { + sprintf(menuSubtitle, "%s - %s", gettext(ctrlName[mapMenuCtrlNES]), gettext(ctrlrName[mapMenuCtrl])); + } GuiText subtitleTxt(menuSubtitle, 20, (GXColor){255, 255, 255, 255}); subtitleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); subtitleTxt.SetPosition(50,60); @@ -2678,6 +2854,7 @@ static int MenuSettingsMappingsMap() optionBrowser.TriggerUpdate(); } } + wiiuproCtrl = 0; HaltGui(); mainWindow->Remove(&optionBrowser); mainWindow->Remove(&w); @@ -3035,7 +3212,8 @@ static int MenuSettingsVideo() break; case 3: // palette - if ( ++GCSettings.currpal > MAXPAL ) + GCSettings.currpal++; + if ( GCSettings.currpal > MAXPAL ) GCSettings.currpal = 0; break; @@ -3096,9 +3274,8 @@ static int MenuSettingsVideo() case 3: sprintf (options.value[2], "Both"); break; } - sprintf (options.value[3], "%s", - GCSettings.currpal ? palettes[GCSettings.currpal-1].desc : "Default"); - + sprintf (options.value[3], "%s", (GCSettings.currpal > -1) ? palettes[GCSettings.currpal].desc : "Default"); + switch(GCSettings.timing) { case 0: sprintf (options.value[4], "NTSC"); break; @@ -3113,16 +3290,11 @@ static int MenuSettingsVideo() switch(GCSettings.videomode) { - case 0: - sprintf (options.value[9], "Automatic (Recommended)"); break; - case 1: - sprintf (options.value[9], "NTSC (480i)"); break; - case 2: - sprintf (options.value[9], "Progressive (480p)"); break; - case 3: - sprintf (options.value[9], "PAL (50Hz)"); break; - case 4: - sprintf (options.value[9], "PAL (60Hz)"); break; + case 0: sprintf (options.value[9], "Automatic (Recommended)"); break; + case 1: sprintf (options.value[9], "NTSC (480i)"); break; + case 2: sprintf (options.value[9], "Progressive (480p)"); break; + case 3: sprintf (options.value[9], "PAL (50Hz)"); break; + case 4: sprintf (options.value[9], "PAL (60Hz)"); break; } optionBrowser.TriggerUpdate(); } @@ -3558,6 +3730,7 @@ static int MenuSettingsMenu() sprintf(options.name[i++], "Sound Effects Volume"); sprintf(options.name[i++], "Rumble"); sprintf(options.name[i++], "Language"); + sprintf(options.name[i++], "Display Virtual Memory"); options.length = i; for(i=0; i < options.length; i++) @@ -3641,6 +3814,9 @@ static int MenuSettingsMenu() else if(GCSettings.language == LANG_JAPANESE) GCSettings.language = LANG_ENGLISH; break; + case 6: + GCSettings.DisplayVM ^= 1; + break; } if(ret >= 0 || firstRun) @@ -3692,22 +3868,28 @@ static int MenuSettingsMenu() switch(GCSettings.language) { - case LANG_JAPANESE: sprintf(options.value[5], "Japanese"); break; - case LANG_ENGLISH: sprintf(options.value[5], "English"); break; - case LANG_GERMAN: sprintf(options.value[5], "German"); break; - case LANG_FRENCH: sprintf(options.value[5], "French"); break; - case LANG_SPANISH: sprintf(options.value[5], "Spanish"); break; - case LANG_ITALIAN: sprintf(options.value[5], "Italian"); break; - case LANG_DUTCH: sprintf(options.value[5], "Dutch"); break; - case LANG_SIMP_CHINESE: sprintf(options.value[5], "Chinese (Simplified)"); break; - case LANG_TRAD_CHINESE: sprintf(options.value[5], "Chinese (Traditional)"); break; - case LANG_KOREAN: sprintf(options.value[5], "Korean"); break; - case LANG_PORTUGUESE: sprintf(options.value[5], "Portuguese"); break; + case LANG_JAPANESE: sprintf(options.value[5], "Japanese"); break; + case LANG_ENGLISH: sprintf(options.value[5], "English"); break; + case LANG_GERMAN: sprintf(options.value[5], "German"); break; + case LANG_FRENCH: sprintf(options.value[5], "French"); break; + case LANG_SPANISH: sprintf(options.value[5], "Spanish"); break; + case LANG_ITALIAN: sprintf(options.value[5], "Italian"); break; + case LANG_DUTCH: sprintf(options.value[5], "Dutch"); break; + case LANG_SIMP_CHINESE: sprintf(options.value[5], "Chinese (Simplified)"); break; + case LANG_TRAD_CHINESE: sprintf(options.value[5], "Chinese (Traditional)"); break; + case LANG_KOREAN: sprintf(options.value[5], "Korean"); break; + case LANG_PORTUGUESE: sprintf(options.value[5], "Portuguese"); break; case LANG_BRAZILIAN_PORTUGUESE: sprintf(options.value[5], "Brazilian Portuguese"); break; - case LANG_CATALAN: sprintf(options.value[5], "Catalan"); break; - case LANG_TURKISH: sprintf(options.value[5], "Turkish"); break; + case LANG_CATALAN: sprintf(options.value[5], "Catalan"); break; + case LANG_TURKISH: sprintf(options.value[5], "Turkish"); break; } + if (GCSettings.DisplayVM == 1) + sprintf (options.value[6], "Enabled"); + else + sprintf (options.value[6], "Disabled"); + + optionBrowser.TriggerUpdate(); } @@ -3953,7 +4135,10 @@ MainMenu (int menu) break; case MENU_GAME_SAVE: currentMenu = MenuGameSaves(1); - break; + break; + case MENU_GAME_DELETE: + currentMenu = MenuGameSaves(2); + break; case MENU_GAMESETTINGS: currentMenu = MenuGameSettings(); break; @@ -4023,7 +4208,11 @@ MainMenu (int menu) if(gameScreenPng) { + #ifdef USE_VM + vm_free(gameScreenPng); + #else free(gameScreenPng); + #endif gameScreenPng = NULL; } diff --git a/source/menu.h b/source/menu.h index 0d967d1..ca3edde 100644 --- a/source/menu.h +++ b/source/menu.h @@ -35,6 +35,7 @@ enum MENU_GAME, MENU_GAME_SAVE, MENU_GAME_LOAD, + MENU_GAME_DELETE, MENU_GAMESETTINGS, MENU_GAMESETTINGS_MAPPINGS, MENU_GAMESETTINGS_MAPPINGS_CTRL, diff --git a/source/pad.cpp b/source/pad.cpp index da50a2a..121c5a1 100644 --- a/source/pad.cpp +++ b/source/pad.cpp @@ -191,6 +191,7 @@ void UpdatePads() { #ifdef HW_RVL + WUPC_UpdateButtonStats(); WPAD_ScanPads(); #endif @@ -207,6 +208,15 @@ UpdatePads() userInput[i].pad.substickY = PAD_SubStickY(i); userInput[i].pad.triggerL = PAD_TriggerL(i); userInput[i].pad.triggerR = PAD_TriggerR(i); + #ifdef HW_RVL + userInput[i].wupcdata.btns_d = WUPC_ButtonsDown(i); + userInput[i].wupcdata.btns_u = WUPC_ButtonsUp(i); + userInput[i].wupcdata.btns_h = WUPC_ButtonsHeld(i); + userInput[i].wupcdata.stickX = WUPC_lStickX(i); + userInput[i].wupcdata.stickY = WUPC_lStickY(i); + userInput[i].wupcdata.substickX = WUPC_rStickX(i); + userInput[i].wupcdata.substickY = WUPC_rStickY(i); + #endif } } @@ -288,7 +298,7 @@ static int pos_y = 0; static void UpdateCursorPosition (int chan) { #define ZAPPERPADCAL 20 - + #define WUPCZAPPERPADCAL 160 // gc left joystick if (userInput[chan].pad.stickX > ZAPPERPADCAL) @@ -334,7 +344,6 @@ static void UpdateCursorPosition (int chan) pos_x -= (wm_ax*-1.0)/ZAPPERPADCAL; if (pos_x < 0) pos_x = 0; } - if (wm_ay < -ZAPPERPADCAL) { pos_y += (wm_ay*-1.0)/ZAPPERPADCAL; @@ -345,6 +354,32 @@ static void UpdateCursorPosition (int chan) pos_y -= (wm_ay*1.0)/ZAPPERPADCAL; if (pos_y < 0) pos_y = 0; } + + /* WiiU Pro Controller */ + s8 wupc_ax = userInput[chan].wupcdata.stickX; + s8 wupc_ay = userInput[chan].wupcdata.stickX; + + if (wupc_ax > WUPCZAPPERPADCAL) + { + pos_x += (wupc_ax*1.0)/WUPCZAPPERPADCAL; + if (pos_x > 256) pos_x = 256; + } + if (wupc_ax < -WUPCZAPPERPADCAL) + { + pos_x -= (wupc_ax*-1.0)/WUPCZAPPERPADCAL; + if (pos_x < 0) pos_x = 0; + } + + if (wupc_ay < -WUPCZAPPERPADCAL) + { + pos_y += (wupc_ay*-1.0)/WUPCZAPPERPADCAL; + if (pos_y > 224) pos_y = 224; + } + if (wupc_ay > WUPCZAPPERPADCAL) + { + pos_y -= (wupc_ay*1.0)/WUPCZAPPERPADCAL; + if (pos_y < 0) pos_y = 0; + } } #endif } @@ -370,7 +405,12 @@ static unsigned char DecodeJoy(unsigned short chan) u32 wp = userInput[chan].wpad->btns_h; u32 exp_type; - if ( WPAD_Probe(chan, &exp_type) != 0 ) exp_type = WPAD_EXP_NONE; + if ( WPAD_Probe(chan, &exp_type) != 0 ) + exp_type = WPAD_EXP_NONE; + + s16 wupc_ax = userInput[chan].wupcdata.stickX; + s16 wupc_ay = userInput[chan].wupcdata.stickY; + u32 wupcp = userInput[chan].wupcdata.btns_h; #endif /*** @@ -408,17 +448,32 @@ static unsigned char DecodeJoy(unsigned short chan) else if(sin(angle) < -THRES) J |= JOY_DOWN; } + + /* WiiU Pro Controller */ + if (wupc_ax * wupc_ax + wupc_ay * wupc_ay > WUPCCAL * WUPCCAL) + { + angle = atan2(wupc_ay, wupc_ax); + if(cos(angle) > THRES) + J |= JOY_RIGHT; + else if(cos(angle) < -THRES) + J |= JOY_LEFT; + if(sin(angle) > THRES) + J |= JOY_UP; + else if(sin(angle) < -THRES) + J |= JOY_DOWN; + } #endif // Report pressed buttons (gamepads) int i; for (i = 0; i < MAXJP; i++) { - if ( (jp & btnmap[CTRL_PAD][CTRLR_GCPAD][i]) // gamecube controller + if ( (jp & btnmap[CTRL_PAD][CTRLR_GCPAD][i]) // gamecube controller #ifdef HW_RVL - || ( (exp_type == WPAD_EXP_NONE) && (wp & btnmap[CTRL_PAD][CTRLR_WIIMOTE][i]) ) // wiimote + || ( (exp_type == WPAD_EXP_NONE) && (wp & btnmap[CTRL_PAD][CTRLR_WIIMOTE][i]) ) // wiimote || ( (exp_type == WPAD_EXP_CLASSIC) && (wp & btnmap[CTRL_PAD][CTRLR_CLASSIC][i]) ) // classic controller || ( (exp_type == WPAD_EXP_NUNCHUK) && (wp & btnmap[CTRL_PAD][CTRLR_NUNCHUK][i]) ) // nunchuk + wiimote + || ( (wupcp & btnmap[CTRL_PAD][CTRLR_CLASSIC][i]) ) // WiiU Pro Controller #endif ) { @@ -512,9 +567,12 @@ bool MenuRequested() userInput[i].pad.btns_h & PAD_BUTTON_A && userInput[i].pad.btns_h & PAD_BUTTON_B && userInput[i].pad.btns_h & PAD_TRIGGER_Z - ) || - (userInput[i].wpad->btns_h & WPAD_BUTTON_HOME) || - (userInput[i].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME) + ) + #ifdef HW_RVL + || (userInput[i].wpad->btns_h & WPAD_BUTTON_HOME) || + (userInput[i].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME) || + (userInput[i].wupcdata.btns_h & WPAD_CLASSIC_BUTTON_HOME) + #endif ) { return true; @@ -531,12 +589,13 @@ void GetJoy() UpdatePads(); - // Turbo mode - // RIGHT on c-stick and on classic ctrlr right joystick - if(userInput[0].pad.substickX > 70 || userInput[0].WPAD_StickX(1) > 70) - turbomode = 1; - else - turbomode = 0; +// Turbo mode +// RIGHT on c-stick and on classic ctrlr right joystick +// if(userInput[0].pad.substickX > 70 || userInput[0].WPAD_StickX(1) > 70 || userInput[0].wupcdata.substickX > 560) +// turbomode = 1; +// else +// turbomode = 0; + turbomode = 0; // request to go back to menu if(MenuRequested()) diff --git a/source/pad.h b/source/pad.h index b4f89c2..e75d801 100644 --- a/source/pad.h +++ b/source/pad.h @@ -14,9 +14,11 @@ #include #include +#include #define PI 3.14159265f #define PADCAL 50 +#define WUPCCAL 400 #define MAXJP 11 #define RAPID_A 256 #define RAPID_B 512 diff --git a/source/preferences.cpp b/source/preferences.cpp index 97db4d5..02541f4 100644 --- a/source/preferences.cpp +++ b/source/preferences.cpp @@ -159,6 +159,8 @@ preparePrefsData () createXMLSetting("SFXVolume", "Sound Effects Volume", toStr(GCSettings.SFXVolume)); createXMLSetting("Rumble", "Rumble", toStr(GCSettings.Rumble)); createXMLSetting("language", "Language", toStr(GCSettings.language)); + createXMLSetting("DisplayMemory", "Display Virtual Memory", toStr(GCSettings.DisplayVM)); + createXMLSection("Controller", "Controller Settings"); @@ -333,7 +335,8 @@ decodePrefsData () loadXMLSetting(&GCSettings.SFXVolume, "SFXVolume"); loadXMLSetting(&GCSettings.Rumble, "Rumble"); loadXMLSetting(&GCSettings.language, "language"); - + loadXMLSetting(&GCSettings.DisplayVM, "DisplayMemory"); + // Controller Settings loadXMLSetting(&GCSettings.Controller, "Controller"); @@ -398,13 +401,13 @@ DefaultSettings () memset (&GCSettings, 0, sizeof (GCSettings)); ResetControls(); // controller button mappings - GCSettings.currpal = 1; // color palette + GCSettings.currpal = 0; // color palette GCSettings.timing = 2; // 0 - NTSC, 1 - PAL, 2 - Automatic GCSettings.videomode = 0; // automatic video mode detection GCSettings.Controller = CTRL_PAD2; // NES pad, Four Score, Zapper GCSettings.crosshair = 1; // show zapper crosshair GCSettings.spritelimit = 1; // enforce 8 sprite limit - GCSettings.gamegenie = 1; + GCSettings.gamegenie = 0; // Off GCSettings.render = 2; // Unfiltered GCSettings.hideoverscan = 2; // hide both horizontal and vertical @@ -420,6 +423,7 @@ DefaultSettings () GCSettings.MusicVolume = 40; GCSettings.SFXVolume = 40; GCSettings.Rumble = 1; + GCSettings.DisplayVM = 1; #ifdef HW_RVL GCSettings.language = CONF_GetLanguage(); @@ -437,7 +441,7 @@ DefaultSettings () sprintf (GCSettings.LoadFolder, "%s/roms", APPFOLDER); // Path to game files sprintf (GCSettings.SaveFolder, "%s/saves", APPFOLDER); // Path to save files sprintf (GCSettings.CheatFolder, "%s/cheats", APPFOLDER); // Path to cheat files - sprintf (GCSettings.CheatFolder, "%s/screenshots", APPFOLDER); // Path to cheat files + sprintf (GCSettings.ScreenshotsFolder, "%s/screenshots", APPFOLDER); // Path to screenshots files GCSettings.AutoLoad = 1; // Auto Load RAM GCSettings.AutoSave = 1; // Auto Save RAM } diff --git a/source/utils/vm/asm.h b/source/utils/vm/asm.h new file mode 100644 index 0000000..2feed00 --- /dev/null +++ b/source/utils/vm/asm.h @@ -0,0 +1,338 @@ +#ifndef __ASM_H__ +#define __ASM_H__ + +#ifdef _LANGUAGE_ASSEMBLY +/* Condition Register Bit Fields */ + +#define cr0 0 +#define cr1 1 +#define cr2 2 +#define cr3 3 +#define cr4 4 +#define cr5 5 +#define cr6 6 +#define cr7 7 + + +/* General Purpose Registers (GPRs) */ + +#define r0 0 +#define r1 1 +#define sp 1 +#define r2 2 +#define toc 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + + +/* Floating Point Registers (FPRs) */ + +#define fr0 0 +#define fr1 1 +#define fr2 2 +#define fr3 3 +#define fr4 4 +#define fr5 5 +#define fr6 6 +#define fr7 7 +#define fr8 8 +#define fr9 9 +#define fr10 10 +#define fr11 11 +#define fr12 12 +#define fr13 13 +#define fr14 14 +#define fr15 15 +#define fr16 16 +#define fr17 17 +#define fr18 18 +#define fr19 19 +#define fr20 20 +#define fr21 21 +#define fr22 22 +#define fr23 23 +#define fr24 24 +#define fr25 25 +#define fr26 26 +#define fr27 27 +#define fr28 28 +#define fr29 29 +#define fr30 30 +#define fr31 31 + +#define vr0 0 +#define vr1 1 +#define vr2 2 +#define vr3 3 +#define vr4 4 +#define vr5 5 +#define vr6 6 +#define vr7 7 +#define vr8 8 +#define vr9 9 +#define vr10 10 +#define vr11 11 +#define vr12 12 +#define vr13 13 +#define vr14 14 +#define vr15 15 +#define vr16 16 +#define vr17 17 +#define vr18 18 +#define vr19 19 +#define vr20 20 +#define vr21 21 +#define vr22 22 +#define vr23 23 +#define vr24 24 +#define vr25 25 +#define vr26 26 +#define vr27 27 +#define vr28 28 +#define vr29 29 +#define vr30 30 +#define vr31 31 + +#endif //_LANGUAGE_ASSEMBLY + +#define SPRG0 272 +#define SPRG1 273 +#define SPRG2 274 +#define SPRG3 275 + +#define PMC1 953 +#define PMC2 954 +#define PMC3 957 +#define PMC4 958 + +#define MMCR0 952 +#define MMCR1 956 + + +#define LINK_REGISTER_CALLEE_UPDATE_ROOM 4 +#define EXCEPTION_NUMBER 8 +#define SRR0_OFFSET 12 +#define SRR1_OFFSET 16 +#define GPR0_OFFSET 20 +#define GPR1_OFFSET 24 +#define GPR2_OFFSET 28 +#define GPR3_OFFSET 32 +#define GPR4_OFFSET 36 +#define GPR5_OFFSET 40 +#define GPR6_OFFSET 44 +#define GPR7_OFFSET 48 +#define GPR8_OFFSET 52 +#define GPR9_OFFSET 56 +#define GPR10_OFFSET 60 +#define GPR11_OFFSET 64 +#define GPR12_OFFSET 68 +#define GPR13_OFFSET 72 +#define GPR14_OFFSET 76 +#define GPR15_OFFSET 80 +#define GPR16_OFFSET 84 +#define GPR17_OFFSET 88 +#define GPR18_OFFSET 92 +#define GPR19_OFFSET 96 +#define GPR20_OFFSET 100 +#define GPR21_OFFSET 104 +#define GPR22_OFFSET 108 +#define GPR23_OFFSET 112 +#define GPR24_OFFSET 116 +#define GPR25_OFFSET 120 +#define GPR26_OFFSET 124 +#define GPR27_OFFSET 128 +#define GPR28_OFFSET 132 +#define GPR29_OFFSET 136 +#define GPR30_OFFSET 140 +#define GPR31_OFFSET 144 + +#define GQR0_OFFSET 148 +#define GQR1_OFFSET 152 +#define GQR2_OFFSET 156 +#define GQR3_OFFSET 160 +#define GQR4_OFFSET 164 +#define GQR5_OFFSET 168 +#define GQR6_OFFSET 172 +#define GQR7_OFFSET 176 + +#define CR_OFFSET 180 +#define LR_OFFSET 184 +#define CTR_OFFSET 188 +#define XER_OFFSET 192 +#define MSR_OFFSET 196 +#define DAR_OFFSET 200 + +#define STATE_OFFSET 204 +#define MODE_OFFSET 206 + +#define FPR0_OFFSET 208 +#define FPR1_OFFSET 216 +#define FPR2_OFFSET 224 +#define FPR3_OFFSET 232 +#define FPR4_OFFSET 240 +#define FPR5_OFFSET 248 +#define FPR6_OFFSET 256 +#define FPR7_OFFSET 264 +#define FPR8_OFFSET 272 +#define FPR9_OFFSET 280 +#define FPR10_OFFSET 288 +#define FPR11_OFFSET 296 +#define FPR12_OFFSET 304 +#define FPR13_OFFSET 312 +#define FPR14_OFFSET 320 +#define FPR15_OFFSET 328 +#define FPR16_OFFSET 336 +#define FPR17_OFFSET 344 +#define FPR18_OFFSET 352 +#define FPR19_OFFSET 360 +#define FPR20_OFFSET 368 +#define FPR21_OFFSET 376 +#define FPR22_OFFSET 384 +#define FPR23_OFFSET 392 +#define FPR24_OFFSET 400 +#define FPR25_OFFSET 408 +#define FPR26_OFFSET 416 +#define FPR27_OFFSET 424 +#define FPR28_OFFSET 432 +#define FPR29_OFFSET 440 +#define FPR30_OFFSET 448 +#define FPR31_OFFSET 456 + +#define FPSCR_OFFSET 464 + +#define PSR0_OFFSET 472 +#define PSR1_OFFSET 480 +#define PSR2_OFFSET 488 +#define PSR3_OFFSET 496 +#define PSR4_OFFSET 504 +#define PSR5_OFFSET 512 +#define PSR6_OFFSET 520 +#define PSR7_OFFSET 528 +#define PSR8_OFFSET 536 +#define PSR9_OFFSET 544 +#define PSR10_OFFSET 552 +#define PSR11_OFFSET 560 +#define PSR12_OFFSET 568 +#define PSR13_OFFSET 576 +#define PSR14_OFFSET 584 +#define PSR15_OFFSET 592 +#define PSR16_OFFSET 600 +#define PSR17_OFFSET 608 +#define PSR18_OFFSET 616 +#define PSR19_OFFSET 624 +#define PSR20_OFFSET 632 +#define PSR21_OFFSET 640 +#define PSR22_OFFSET 648 +#define PSR23_OFFSET 656 +#define PSR24_OFFSET 664 +#define PSR25_OFFSET 672 +#define PSR26_OFFSET 680 +#define PSR27_OFFSET 688 +#define PSR28_OFFSET 696 +#define PSR29_OFFSET 704 +#define PSR30_OFFSET 712 +#define PSR31_OFFSET 720 +/* + * maintain the EABI requested 8 bytes aligment + * As SVR4 ABI requires 16, make it 16 (as some + * exception may need more registers to be processed...) + */ +#define EXCEPTION_FRAME_END 728 + +#define IBAT0U 528 +#define IBAT0L 529 +#define IBAT1U 530 +#define IBAT1L 531 +#define IBAT2U 532 +#define IBAT2L 533 +#define IBAT3U 534 +#define IBAT3L 535 +#define IBAT4U 560 +#define IBAT4L 561 +#define IBAT5U 562 +#define IBAT5L 563 +#define IBAT6U 564 +#define IBAT6L 565 +#define IBAT7U 566 +#define IBAT7L 567 + +#define DBAT0U 536 +#define DBAT0L 537 +#define DBAT1U 538 +#define DBAT1L 539 +#define DBAT2U 540 +#define DBAT2L 541 +#define DBAT3U 542 +#define DBAT3L 543 +#define DBAT4U 568 +#define DBAT4L 569 +#define DBAT5U 570 +#define DBAT5L 571 +#define DBAT6U 572 +#define DBAT6L 573 +#define DBAT7U 574 +#define DBAT7L 575 + +#define HID0 1008 +#define HID1 1009 +#define HID2 920 +#define HID4 1011 + +#define GQR0 912 +#define GQR1 913 +#define GQR2 914 +#define GQR3 915 +#define GQR4 916 +#define GQR5 917 +#define GQR6 918 +#define GQR7 919 + +#define L2CR 1017 + +#define WPAR 921 + +#define DMAU 922 +#define DMAL 923 + +#define MSR_RI 0x00000002 +#define MSR_DR 0x00000010 +#define MSR_IR 0x00000020 +#define MSR_IP 0x00000040 +#define MSR_SE 0x00000400 +#define MSR_ME 0x00001000 +#define MSR_FP 0x00002000 +#define MSR_POW 0x00004000 +#define MSR_EE 0x00008000 + +#define PPC_ALIGNMENT 8 + +#define PPC_CACHE_ALIGNMENT 32 + +#endif //__ASM_H__ diff --git a/source/utils/vm/dsihandler.s b/source/utils/vm/dsihandler.s new file mode 100644 index 0000000..76041b9 --- /dev/null +++ b/source/utils/vm/dsihandler.s @@ -0,0 +1,72 @@ +/* Copyright 2013 tueidj All Rights Reserved + * This code may not be used in any project + * without explicit permission from the author. + */ + +#include +#include "asm.h" + + .extern vm_dsi_handler + .extern default_exceptionhandler + +FUNC_START(dsi_handler) + stwu sp,-EXCEPTION_FRAME_END(sp) + stw r6,GPR6_OFFSET(sp) + stw r7,GPR7_OFFSET(sp) + stw r8,GPR8_OFFSET(sp) + stw r9,GPR9_OFFSET(sp) + stw r10,GPR10_OFFSET(sp) + stw r11,GPR11_OFFSET(sp) + stw r12,GPR12_OFFSET(sp) + mfdsisr r4 + mfmsr r3 + ori r3,r3,MSR_RI + mtmsr r3 + + addi r3,sp,8 + bl vm_dsi_handler + + # check if it was handled correctly + cmplwi r3,0 + + lwz r6,GPR6_OFFSET(sp) + lwz r7,GPR7_OFFSET(sp) + lwz r8,GPR8_OFFSET(sp) + lwz r9,GPR9_OFFSET(sp) + lwz r10,GPR10_OFFSET(sp) + lwz r11,GPR11_OFFSET(sp) + lwz r12,GPR12_OFFSET(sp) + + # clear MSR_RI + mfmsr r3 + rlwinm r3,r3,0,31,29 + mtmsr r3 + + bne 1f + + # jump to libogc's default handler + addi sp,sp,EXCEPTION_FRAME_END + b default_exceptionhandler + +1: + lwz r3,CR_OFFSET(sp) + lwz r4,LR_OFFSET(sp) + lwz r5,CTR_OFFSET(sp) + lwz r0,XER_OFFSET(sp) + mtcr r3 + mtlr r4 + mtctr r5 + mtxer r0 + lwz r0,GPR0_OFFSET(sp) + lwz r5,GPR5_OFFSET(sp) + + lwz r3,SRR0_OFFSET(sp) + lwz r4,SRR1_OFFSET(sp) + mtsrr0 r3 + mtsrr1 r4 + lwz r3,GPR3_OFFSET(sp) + lwz r4,GPR4_OFFSET(sp) + lwz sp,GPR1_OFFSET(sp) + rfi +FUNC_END(dsi_handler) + diff --git a/source/utils/vm/vm.c b/source/utils/vm/vm.c new file mode 100644 index 0000000..73f3392 --- /dev/null +++ b/source/utils/vm/vm.c @@ -0,0 +1,367 @@ +/* Copyright 2013 tueidj All Rights Reserved + * This code may not be used in any project + * without explicit permission from the author. + */ + +#include +#include +#include +#include +#include +#include +#include "vm.h" + +#include + +typedef u8 vm_page[PAGE_SIZE]; + +static p_map phys_map[2048+(PTE_SIZE/PAGE_SIZE)]; +static vm_map virt_map[65536]; +static u16 pmap_max, pmap_head; + +static PTE* HTABORG; +static vm_page* VM_Base; +static vm_page* MEM_Base = NULL; + +static int pagefile_fd = -1; +static mutex_t vm_mutex = LWP_MUTEX_NULL; +static bool vm_initialized = 0; + +static __inline__ void tlbie(void* p) +{ + asm volatile("tlbie %0" :: "r"(p)); +} + +static u16 locate_oldest(void) +{ + u16 head = pmap_head; + + for(;;++head) + { + PTE *p; + + if (head >= pmap_max) + head = 0; + + if (!phys_map[head].valid || phys_map[head].locked) + continue; + + p = HTABORG+phys_map[head].pte_index; + tlbie(VM_Base+phys_map[head].page_index); + + if (p->C) + { + p->C = 0; + phys_map[head].dirty = 1; + continue; + } + + if (p->R) + { + p->R = 0; + continue; + } + + p->data[0] = 0; + + pmap_head = head+1; + return head; + } +} + +static PTE* StorePTE(PTEG pteg, u32 virtual, u32 physical, u8 WIMG, u8 PP, int secondary) +{ + int i; + PTE p = {{0}}; + + p.valid = 1; + p.VSID = VM_VSID; + p.hash = secondary ? 1:0; + p.API = virtual >> 22; + p.RPN = physical >> 12; + p.WIMG = WIMG; + p.PP = PP; + + for (i=0; i < 8; i++) + { + if (pteg[i].data[0] == p.data[0]) + { +// printf("Error: address %08x already had a PTE entry\r\n", virtual); +// abort(); + } + else if (pteg[i].valid) + continue; + + asm volatile("tlbie %0" : : "r"(virtual)); + pteg[i].data[1] = p.data[1]; + pteg[i].data[0] = p.data[0]; +// if (i || secondary) +// printf("PTE for address %08x/%08x in PTEG %p index %d (%s)\r\n", virtual, physical, pteg, i, secondary ? "secondary" : "primary"); + return pteg+i; + } + + return NULL; +} + +static PTEG CalcPTEG(u32 virtual, int secondary) +{ + uint32_t segment_index = (virtual >> 12) & 0xFFFF; + u32 ptr = MEM_VIRTUAL_TO_PHYSICAL(HTABORG); + u32 hash = segment_index ^ VM_VSID; + + if (secondary) hash = ~hash; + + hash &= (HTABMASK << 10) | 0x3FF; + ptr |= hash << 6; + + return (PTEG)MEM_PHYSICAL_TO_K0(ptr); +} + +static PTE* insert_pte(u16 index, u32 physical, u8 WIMG, u8 PP) +{ + PTE *pte; + int i; + u32 virtual = (u32)(VM_Base+index); + + for (i=0; i < 2; i++) + { + PTEG pteg = CalcPTEG(virtual, i); + pte = StorePTE(pteg, virtual, physical, WIMG, PP, i); + if (pte) + return pte; + } + +// printf("Failed to insert PTE for %p\r\n", VM_Base+index); +// abort(); + + return NULL; +} + +static void tlbia(void) +{ + int i; + for (i=0; i < 64; i++) + asm volatile("tlbie %0" :: "r" (i*PAGE_SIZE)); +} + +/* This definition is wrong, pHndl does not take frame_context* as a parameter, + * it has to adjust the stack pointer and finish filling frame_context itself + */ +void __exception_sethandler(u32 nExcept, void (*pHndl)(frame_context*)); +extern void default_exceptionhandler(); +// use our own exception stub because libogc stupidly requires it +extern void dsi_handler(); + +void* VM_Init(u32 VMSize, u32 MEMSize) +{ + u32 i; + u16 index, v_index; + + if (vm_initialized) + return VM_Base; + + // parameter checking + if (VMSize>MAX_VM_SIZE || MEMSizeMAX_MEM_SIZE) + { + errno = EINVAL; + return NULL; + } + + VMSize = (VMSize+PAGE_SIZE-1)&PAGE_MASK; + MEMSize = (MEMSize+PAGE_SIZE-1)&PAGE_MASK; + //VM_Base = (vm_page*)(0x80000000 - VMSize); + VM_Base = (vm_page*)(ARAM_VM_BASE); + pmap_max = MEMSize / PAGE_SIZE + 16; + +// printf("VMSize %08x MEMSize %08x VM_Base %p pmap_max %u\r\n", VMSize, MEMSize, VM_Base, pmap_max); + + if (VMSize <= MEMSize) + { + errno = EINVAL; + return NULL; + } + + if (LWP_MutexInit(&vm_mutex, 0) != 0) + { + errno = ENOLCK; + return NULL; + } + + pagefile_fd = AR_Init(NULL, 0); +// ISFS_Initialize(); + // doesn't matter if this fails, will be caught when file is opened +// ISFS_CreateFile(VM_FILENAME, 0, ISFS_OPEN_RW, ISFS_OPEN_RW, ISFS_OPEN_RW); + +// pagefile_fd = ISFS_Open(VM_FILENAME, ISFS_OPEN_RW); + if (pagefile_fd < 0) + { + errno = ENOENT; + return NULL; + } + + MEMSize += PTE_SIZE; + MEM_Base = (vm_page*)memalign(PAGE_SIZE, MEMSize); + +// printf("MEM_Base: %p\r\n", MEM_Base); + + if (MEM_Base==NULL) + { + AR_Reset(); +// ISFS_Close(pagefile_fd); + errno = ENOMEM; + return NULL; + } + + tlbia(); + DCZeroRange(MEM_Base, MEMSize); + HTABORG = (PTE*)(((u32)MEM_Base+0xFFFF)&~0xFFFF); +// printf("HTABORG: %p\r\n", HTABORG); + + // attempt to make the pagefile the correct size +/* ISFS_Seek(pagefile_fd, 0, SEEK_SET); + for (i=0; i MEMSize) + to_write = MEMSize; + + if (ISFS_Write(pagefile_fd, MEM_Base, to_write) != to_write) + { + free(MEM_Base); + ISFS_Close(pagefile_fd); + errno = ENOSPC; + return NULL; + } +// printf("Wrote %u bytes to offset %u\r\n", to_write, page); + i += to_write; + }*/ + + // initial commit: map pmap_max pages to fill PTEs with valid RPNs + for (index=0,v_index=0; index %u\r\n", index, index+(PTE_SIZE/PAGE_SIZE)); + for (i=0; i<(PTE_SIZE/PAGE_SIZE); ++i,++index) + phys_map[index].valid = 0; + + --index; + --v_index; + continue; + } + + phys_map[index].valid = 1; + phys_map[index].locked = 0; + phys_map[index].dirty = 0; + phys_map[index].page_index = v_index; + phys_map[index].pte_index = insert_pte(v_index, MEM_VIRTUAL_TO_PHYSICAL(MEM_Base+index), 0, 0b10) - HTABORG; + virt_map[v_index].committed = 0; + virt_map[v_index].p_map_index = index; + } + + // all indexes up to 65536 + for (; v_index; ++v_index) + { + virt_map[v_index].committed = 0; + virt_map[v_index].p_map_index = pmap_max; + } + + pmap_head = 0; + + // set SDR1 + mtspr(25, MEM_VIRTUAL_TO_PHYSICAL(HTABORG)|HTABMASK); + //printf("SDR1: %08x\r\n", MEM_VIRTUAL_TO_PHYSICAL(HTABORG)); + // enable SR + asm volatile("mtsrin %0,%1" :: "r"(VM_VSID), "r"(VM_Base)); + // hook DSI + __exception_sethandler(EX_DSI, dsi_handler); + + atexit(VM_Deinit); + + vm_initialized = 1; + + return VM_Base; +} + +void VM_Deinit(void) +{ + if (!vm_initialized) + return; + + // disable SR + asm volatile("mtsrin %0,%1" :: "r"(0x80000000), "r"(VM_Base)); + // restore default DSI handler + __exception_sethandler(EX_DSI, default_exceptionhandler); + + free(MEM_Base); + MEM_Base = NULL; + + if (vm_mutex != LWP_MUTEX_NULL) + { + LWP_MutexDestroy(vm_mutex); + vm_mutex = LWP_MUTEX_NULL; + } + + if (pagefile_fd) + { + AR_Reset(); +// ISFS_Close(pagefile_fd); + pagefile_fd = -1; +// ISFS_Delete(VM_FILENAME); + } + + vm_initialized = 0; +} + +int vm_dsi_handler(frame_context* state, u32 DSISR) +{ + u16 v_index; + u16 p_index; + + if (state->DAR<(u32)VM_Base || state->DAR>=0x80000000) + return 0; + if ((DSISR&~0x02000000)!=0x40000000) + return 0; + if (!vm_initialized) + return 0; + + LWP_MutexLock(vm_mutex); + + state->DAR &= ~0xFFF; + v_index = (vm_page*)state->DAR - VM_Base; + + p_index = locate_oldest(); + + // purge p_index if it's dirty + if (phys_map[p_index].dirty) + { + DCFlushRange(MEM_Base+p_index, PAGE_SIZE); + AR_StartDMA(AR_MRAMTOARAM,(u32)(MEM_Base+p_index),phys_map[p_index].page_index*PAGE_SIZE,PAGE_SIZE); + while (AR_GetDMAStatus()); + virt_map[phys_map[p_index].page_index].committed = 1; + virt_map[phys_map[p_index].page_index].p_map_index = pmap_max; + phys_map[p_index].dirty = 0; +// printf("VM page %d was purged\r\n", phys_map[p_index].page_index); + } + + // fetch v_index if it has been previously committed + if (virt_map[v_index].committed) + { + DCInvalidateRange(MEM_Base+p_index, PAGE_SIZE); + AR_StartDMA(AR_ARAMTOMRAM,(u32)(MEM_Base+p_index),v_index*PAGE_SIZE,PAGE_SIZE); + while (AR_GetDMAStatus()); +// printf("VM page %d was fetched\r\n", v_index); + } + else + DCZeroRange(MEM_Base+p_index, PAGE_SIZE); + +// printf("VM page %u (0x%08x) replaced page %u (%p)\r\n", v_index, state->DAR, phys_map[p_index].page_index, VM_Base+phys_map[p_index].page_index); + + virt_map[v_index].p_map_index = p_index; + phys_map[p_index].page_index = v_index; + phys_map[p_index].pte_index = insert_pte(v_index, MEM_VIRTUAL_TO_PHYSICAL(MEM_Base+p_index), 0, 0b10) - HTABORG; + + LWP_MutexUnlock(vm_mutex); + + return 1; +} diff --git a/source/utils/vm/vm.h b/source/utils/vm/vm.h new file mode 100644 index 0000000..1a86163 --- /dev/null +++ b/source/utils/vm/vm.h @@ -0,0 +1,90 @@ +/* Copyright 2013 tueidj All Rights Reserved + * This code may not be used in any project + * without explicit permission from the author. + */ + +#ifndef _VM_H_ +#define _VM_H_ + +#include +#include +#include +#include +#include +#include + +#define KB (1024) +#define MB (1024*KB) +#define MRAM_BACKING (4*MB) // Use 2MB to page our 16MB +#define ARAM_RESERVED (64*KB) // Reserved for DSP/AESND/etc +#define ARAM_VM_BASE (0x7F000000) // Map ARAM to here +#define ARAM_START (ARAM_RESERVED + ARAM_VM_BASE) +#define ARAM_SIZE ((16*MB) - ARAM_RESERVED) // ARAM is ~16MB + +// maximum virtual memory size +#define MAX_VM_SIZE (256*1024*1024) +// maximum physical memory size +#define MAX_MEM_SIZE ( 8*1024*1024) +// minimum physical memory size +#define MIN_MEM_SIZE (256*1024) +// page size as defined by hardware +#define PAGE_SIZE 4096 +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#define VM_VSID 0 +#define VM_SEGMENT 0x70000000 + +// use 64KB for PTEs +#define HTABMASK 0 +#define PTE_SIZE ((HTABMASK+1)*65536) +#define PTE_COUNT (PTE_SIZE>>3) + +//#define VM_FILENAME "/tmp/pagefile.sys" + +// keeps a record of each currently mapped page +typedef union +{ + u32 data; + struct + { + u32 valid : 1; + u32 locked : 1; + u32 dirty : 1; + u32 pte_index : 13; + u32 page_index : 16; + }; +} p_map; + +// maps VM addresses to mapped pages +typedef struct +{ + // data must be fetched when paging in? + u16 committed : 1; + u16 p_map_index: 12; +} vm_map; + +typedef union +{ + u32 data[2]; + struct + { + u32 valid : 1; + u32 VSID : 24; + u32 hash : 1; + u32 API : 6; + + u32 RPN : 20; + u32 pad0 : 3; + u32 R : 1; + u32 C : 1; + u32 WIMG : 4; + u32 pad1 : 1; + u32 PP : 2; + }; +} PTE; +typedef PTE* PTEG; + +extern void* VM_Init(u32 VMSize, u32 MEMSize); +extern void VM_Deinit(void); + +#endif \ No newline at end of file diff --git a/source/vmalloc.cpp b/source/vmalloc.cpp new file mode 100644 index 0000000..dd10c1f --- /dev/null +++ b/source/vmalloc.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** + * Snes9x Nintendo Wii/Gamecube Port + * + * emu_kidid 2015 + * + * vmalloc.cpp + * + * GC VM memory allocator + ***************************************************************************/ + +#ifdef USE_VM + +#include +#include +#include +#include +#include "utils/vm/vm.h" + +static heap_cntrl vm_heap; + +static int vm_initialised = 0; + +void InitVmManager () +{ + __lwp_heap_init(&vm_heap, (void *)ARAM_VM_BASE, ARAM_SIZE, 32); + vm_initialised = 1; +} + +void* vm_malloc(u32 size) +{ + if(!vm_initialised) InitVmManager(); + return __lwp_heap_allocate(&vm_heap, size); +} + +bool vm_free(void *ptr) +{ + if(!vm_initialised) InitVmManager(); + return __lwp_heap_free(&vm_heap, ptr); +} + +int vm_size_free() +{ + if(!vm_initialised) InitVmManager(); + heap_iblock info; + __lwp_heap_getinfo(&vm_heap,&info); + return info.free_size; +} + +#endif diff --git a/source/vmalloc.h b/source/vmalloc.h new file mode 100644 index 0000000..74a64b0 --- /dev/null +++ b/source/vmalloc.h @@ -0,0 +1,21 @@ +/**************************************************************************** + * Snes9x Nintendo Wii/Gamecube Port + * + * emu_kidid 2015 + * + * vmalloc.h + * + * GC VM memory allocator + ***************************************************************************/ + +#ifdef USE_VM + +#ifndef _VMMANAGER_H_ +#define _VMMANAGER_H_ + +void* vm_malloc(u32 size); +bool vm_free(void *ptr); +int vm_size_free(); +#endif + +#endif diff --git a/update.xml b/update.xml index 867994f..a0d9b01 100644 --- a/update.xml +++ b/update.xml @@ -1,4 +1,3 @@ - - +